actix-web
actix-web copied to clipboard
POST request with no body trouble
Looking like this issue
Expected Behavior
The request should be processed by actix_web and output something
Current Behavior
If I run a POST request with an empty body, actix_web starts outputting the following:
[2024-11-16T14:23:01Z DEBUG actix_http::h1::decoder] no Content-Length specified for HTTP/1.0 POST request
[2024-11-16T14:23:01Z ERROR actix_http::h1::dispatcher] stream error: request parse error: invalid Header provided
Possible Solution
i have no ideas
Steps to Reproduce (for bugs)
- Make a POST endpoint via actix-web
- Send POST request to that endpoint with empty body
- Profit
Your Environment
- Rust Version (I.e, output of
rustc -V): 1.81.0 (eeb90cda1 2024-09-04) - Actix Web Version: 4.9.0
It turns out, this is correct behavior.
[2024-11-16T14:23:01Z DEBUG actix_http::h1::decoder] no Content-Length specified for HTTP/1.0 POST request
From HTTP1.0 [specification](
A valid Content-Length is required on all HTTP/1.0 POST requests. An HTTP/1.0 server should respond with a 400 (bad request) message if it cannot determine the length of the request message's content.
I actually even written tests, to verify that actix actually behaves as it should.
// lib.rs
use std::net::TcpListener;
use actix_web::{rt::spawn, App, HttpServer, Responder};
#[actix_web::post("/")]
async fn index() -> impl Responder {
"Hello world!"
}
pub fn spawn_test_server() -> u16 {
let listener = TcpListener::bind("0.0.0.0:0").expect("Failed to bind to local address");
let addr = listener.local_addr().unwrap();
let srv = HttpServer::new(|| App::new().service(index))
.listen(listener)
.unwrap()
.run();
spawn(srv);
addr.port()
}
#[cfg(test)]
mod tests {
use reqwest::{Client, StatusCode, Version};
use super::*;
// https://www.rfc-editor.org/rfc/rfc9110.html#name-content-length
// > A user agent SHOULD send Content-Length in a request when the method defines a
// > meaning for enclosed content and it is not sending Transfer-Encoding
// MY NOTE: SHOULD not MUST
#[actix_web::test]
async fn http_11_post_without_content_length_is_ok() {
let port = spawn_test_server();
let resp = Client::new()
.post(format!("http://localhost:{port}"))
.version(Version::HTTP_11)
.send()
.await
.unwrap();
assert_eq!(resp.status(), StatusCode::OK);
}
// https://www.w3.org/Protocols/HTTP/1.0/spec.html
// > A valid Content-Length is required on all HTTP/1.0 POST requests.
// MY NOTE: this document doesn't follow rfc2119, so required is equal to MUST
#[actix_web::test]
async fn http_10_post_with_content_length_is_ok() {
let port = spawn_test_server();
let resp = Client::new()
.post(format!("http://localhost:{port}"))
.version(Version::HTTP_10)
.header("Content-Length", 0)
.send()
.await
.unwrap();
assert_eq!(resp.status(), StatusCode::OK);
}
// > An HTTP/1.0 server should respond with a 400 (bad request) message if it
// > cannot determine the length of the request message's content.
#[actix_web::test]
async fn http_10_post_without_content_length_is_bad_request() {
let port = spawn_test_server();
let resp = Client::new()
.post(format!("http://localhost:{port}"))
.version(Version::HTTP_10)
.send()
.await
.unwrap();
assert_eq!(resp.status(), StatusCode::BAD_REQUEST);
}
}
# Cargo.toml
[dependencies]
actix-web = "4.9.0"
reqwest = { version = "0.12.12" }