I am receiving a 411 length required error when sending HTTP2 POST requests without a body to an Azure API Management (but this is not a question about Azure). my request is:
curl --location --request POST "..." --header "Content-Type: application/json" --verbose --http2
I'm getting the following logs from curl:
...
Using HTTP2, server supports multi-use
...
* Connection state changed (MAX_CONCURRENT_STREAMS == 100)!
< HTTP/2 411
< content-type: text/html; charset=us-ascii
...
< content-length: 344
<
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML
4.01//EN""http://www.w3.org/TR/html4/strict.dtd">
<HTML><HEAD><TITLE>Length Required</TITLE>
<META HTTP-EQUIV="Content-Type" Content="text/html; charset=us-ascii"></HEAD>
<BODY><h2>Length Required</h2>
<hr><p>HTTP Error 411. The request must be chunked or have a content length.</p>
I thought this was not necessary for HTTP2, and tried reading what the HTTP2 RFC says about it, but found it confusing:
A request or response that includes a payload body can include a content-length header field.
But what about requests that don't have a body?
Who is correct here, the client who does not send the header, or the server who does not accept the request?
For HTTP/1.1 POST
requests, client SHOULD send the Content-Length
header, see https://datatracker.ietf.org/doc/html/rfc7230#section-3.3.2.
For HTTP/2, the Content-Length
header is not mandated (see https://datatracker.ietf.org/doc/html/rfc7540#section-8.1.2.6), since the protocol has the endStream
flag to signal the end of the content.
However, server-side applications are typically written against a higher level HTTP semantic: they don't care whether the request came as HTTP/1.1 or HTTP/2, they just care if it was a POST with some header and some content that they want to process. See RFC 9110 for the definition of the high level HTTP semantic.
Given that HTTP/1.1 lasted for 20+ years and HTTP/2 is relatively new, server-side applications may still assume HTTP/1.1 and complain if some header that is present in HTTP/1.1 is missing because the request came as HTTP/2.
For example, HTTP/2 requests do not have the Host
header anymore (instead, they have an :authority
pseudo-header); however, HTTP/2 specifies that when translating HTTP/2 to HTTP/1.1 the Host
header must be synthetically generated (see here).
The same may happen to the Content-Length
header: an old server-side application that assumes HTTP/1.1 expects the Content-Length
header to be there, but when the request comes as HTTP/2 it may not have it because for HTTP/2 it is not strictly necessary.
Here, "server-side application" may mean a reverse-proxy feature provided by a front-end server, or some Azure translation layer, or the final application reached by the request.
The most portable solution with curl
would be for you to add Content-Length: 0
, or to specify an empty body with -d ''
(so that curl
adds the Content-Length: 0
header).