actix-web: Cannot force Content-Length header

Expected Behavior

I’m able to provide my value to Content-Length header.

Current Behavior

When I use HttpResponseBuilder (e.g. by HttpResponse::Ok()), my custom-provided content-length header value is ignored/overridden by real length of the response body.
This is very unfortunate when implementing HEAD endpoint where the headers should be equal to GET but with an empty body.

Steps to Reproduce

#[head("/update")]
async fn get_head() -> impl Responder {
    HttpResponse::Ok()
        .content_length(20)
        .content_type("application/octet-stream")
        .finish()
}

I also tried:

HttpResponse::Ok()
  .content_length(20)
  .content_type("application/octet-stream")
  .body(Body::Empty);
let mut response = HttpResponse::Ok()
    .content_length(20)
    .content_type("application/octet-stream")
    .body(Body::Empty); // also with finish()

response
    .headers_mut()
    .insert(header::CONTENT_LENGTH, HeaderValue::from(20));

response

Nothing has helped.

Context

I’m trying to implement HEAD endpoint. According to RFC:

The Content-Length entity-header field indicates ... the size of the entity-body that
would have been sent had the request been a GET.

This is currently impossible.

Your Environment

  • Rust Version: 1.42.0 stable
  • Actix Web Version: 2.0.0

About this issue

  • Original URL
  • State: closed
  • Created 4 years ago
  • Comments: 19 (13 by maintainers)

Commits related to this issue

Most upvoted comments

@omid I waited for @robjtede if he’s ok but I totally agree with him - this needs to be documented somewhere (it also goes with your goal to reduce issues).
I’d maybe go for new paragraph in Response docs, explaining that Content-Length is set up automatically and it cannot be forced to some value, however, it’s compliant with RFC and sets the value accordingly when responding to HEAD - or better, explain responding to HEAD more thoroughly.

Just one more question now crossed my mind: You’ve said You don't need to set the content-length. I felt like I cannot set it even when I want to, even though there’s content_length method on Response - but that seems to do nothing. Can you please explain it?

Thanks!

So it can happen also for the HEAD requests.

I mean, in the response to HEAD, I can send 100 for example, but later in the real GET it can be lesser because of compression. So we always need to have the complete response!

As far as I can see, we don’t need the content_length method, at least as pub!

@omid Oh. This solution really didn’t come to my mind. It’s kind of magical, but I guess it’s acceptable.
Thanks.

@jendakol I can see the appeal of absolute control over a handler’s response but it seems at odds with the purpose of actix-web being a higher level framework. The automatic content-length handling is very much an intentional feature of actix-web and one that cannot be worked around simply in the presence of middleware.

Scenario: You set the content-length in the handler manually. Then a compress middleware compresses the body. Does it now alter your manual content-length header or not?

If so, that violates your “right” to define the output content-length. If not, you produce an invalid HTTP response. This framework currently chooses to guarantee production of a valid HTTP response even in the absence of programmer’s perfect knowledge of actix-web’s internal handling.

I think a more reasonable feature request could be a seperate way to define handlers that allow raw access to request and response and don’t go through the usual middleware flow. What do you think?

I feel like this shouldn’t be closed unless this is documented somewhere.