Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

POST request with no body trouble #3503

Open
smokingplaya opened this issue Nov 16, 2024 · 1 comment
Open

POST request with no body trouble #3503

smokingplaya opened this issue Nov 16, 2024 · 1 comment

Comments

@smokingplaya
Copy link

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)

  1. Make a POST endpoint via actix-web
  2. Send POST request to that endpoint with empty body
  3. Profit

Your Environment

  • Rust Version (I.e, output of rustc -V): 1.81.0 (eeb90cda1 2024-09-04)
  • Actix Web Version: 4.9.0
@fraillt
Copy link

fraillt commented Feb 6, 2025

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" }

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants