Yaakov Online

I fight with computers




HTTP/2 Header Casing

HTTP/2 is slowly becoming more and more widespread, and as it does, confusion gets to spread with it.

Recently a colleague at work asked why they were getting lowercase header names from their local development web server.

After a few hours of digging, it turns out that:

  1. This developer had recently upgraded their machine to Windows 10
  2. Windows 10 ships with IIS 10
  3. IIS 10 adds support for HTTP/2

HTTP/2 uses HPACK header compression (RFC 7541). Without getting into all the details, there are a few important points regarding headers:

With regards to the headers defined in the static table, these are defined in the specification as being in lowercase.

Furthermore, the HTTP/2 specification (RFC 7540) states:

Just as in HTTP/1.x, header field names are strings of ASCII characters that are compared in a case-insensitive fashion. However, header field names MUST be converted to lowercase prior to their encoding in HTTP/2. A request or response containing uppercase header field names MUST be treated as malformed -- RFC 7540, Hypertext Transfer Protocol Version 2 (HTTP/2), Section 8.1.2

So with the rollout of HTTP/2, all headers are now being converted to lowercase.

If you have any code that treats headers as case-sensitive, this code is wrong. This isn't new though. As the excerpt above hints at, RFC 2616 states:

Each header field consists of a name followed by a colon (":") and the field value. Field names are case-insensitive. -- RFC 2616, Hypertext Transfer Protocol -- HTTP/1.1, Section 4.2

HTTP header names have been case-insensitive since 1999.[1] If you have code anywhere that cares about case sensitivity of HTTP headers, go fix it.

With the rollout of HTTP/2 though, you're now more likely to encounter the case of the header keys not being what you expected it to be.

  1. Shout out to John McCaskey of Valve Corporation who first pointed this out to me a few years ago when I got mad that one of the Steam Web API headers was kebab-case instead of Train-Case. ↩︎