fix(http): F-Q-008 add HttpError::InvalidArgs for user-input validation failures

http_service::run mapped `Method::from_bytes` failure on a user-supplied
HTTP method to HttpError::Backend with format!("invalid method: {}", …).
Same for HeaderName/HeaderValue validation in build_headers. But that's
user input, not a backend problem — misclassifying as Backend corrupts
retry policies (operators may retry "backend" but not "invalid input").

Add a new HttpError::InvalidArgs(String) variant. Reroute the three
validation paths in http_service (method, header name, header value) to
emit InvalidArgs instead of Backend.

The executor-side `map_http_err` uses Display, so the new variant
surfaces to scripts as "http: invalid method: …" — same format, more
structured behind it.

AUDIT.md anchor: F-Q-008.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
MechaCat02
2026-06-07 21:02:57 +02:00
parent c072d0474c
commit 59d4c043b0
2 changed files with 12 additions and 3 deletions

View File

@@ -205,8 +205,9 @@ impl HttpServiceImpl {
/// Core request path: validate, build headers, follow redirects
/// manually, read the response body with a cap.
async fn run(&self, req: HttpRequest) -> Result<HttpResponse, HttpError> {
// F-Q-008: bad method is user input, not a backend problem.
let method = Method::from_bytes(req.method.as_bytes())
.map_err(|_| HttpError::Backend(format!("invalid method: {}", req.method)))?;
.map_err(|_| HttpError::InvalidArgs(format!("invalid method: {}", req.method)))?;
let mut current = url::Url::parse(&req.url)
.map_err(|e| HttpError::InvalidUrl(format!("{}: {e}", req.url)))?;
@@ -336,10 +337,11 @@ fn build_headers(req: &HttpRequest, _url: &url::Url) -> Result<HeaderMap, HttpEr
let mut has_user_agent = false;
let mut has_content_type = false;
for (k, v) in &req.headers {
// F-Q-008: bad header name/value is user input.
let name = HeaderName::from_bytes(k.as_bytes())
.map_err(|_| HttpError::Backend(format!("invalid header name: {k}")))?;
.map_err(|_| HttpError::InvalidArgs(format!("invalid header name: {k}")))?;
let value = HeaderValue::from_str(v)
.map_err(|_| HttpError::Backend(format!("invalid header value for {k}")))?;
.map_err(|_| HttpError::InvalidArgs(format!("invalid header value for {k}")))?;
if name == USER_AGENT {
has_user_agent = true;
}