HTTP Status Code Handling

I was recently writing some code for the Mozilla Observatory to store and interact with the HTTP status codes. As part of my code, I wanted to ensure that I would only store these status codes if they were an integer as per the HTTP/1.1 specification:

 The status-code element is a three-digit integer code giving the
 result of the attempt to understand and satisfy the request.

While it is easy to create test cases for conditions that don't satisfy this requirement, it is somewhat more difficult to determine how third-party libraries will handle HTTP requests that fall outside this constraint. I looked around the internet for websites to help me test weird status codes, but most of them only let me test with the known status codes. As such, I decided to add arbitrary HTTP status codes to my naughty httpbin fork, called misbehaving.site.

What I discovered is that the various browser manufacturers have wildly different behavior with how they handle unknown HTTP status codes. Here is what the HTTP specification says that browsers should do:

 HTTP status codes are extensible.  HTTP clients are not required to
 understand the meaning of all registered status codes, though such
 understanding is obviously desirable.  However, a client MUST
 understand the class of any status code, as indicated by the first
 digit, and treat an unrecognized status code as being equivalent to
 the x00 status code of that class, with the exception that a
 recipient MUST NOT cache a response with an unrecognized status code.

…so what happens in reality?

Chrome

Chrome's behavior is strange, but surprisingly not the strangest of the major browsers:

Chrome's HTTP status code behavior

For negative status codes, Chrome always displays HTTP status code 200. For 0, it simply displays Finished instead of the actual status code. It otherwise simply reflects the status code, unless it exceeds 2147483647 (231-1), in which case it displays 2147483647.

Note that when exceeding 2147483647, it displays this error in the console, despite the page otherwise loading normally:

Chrome's HTTP status code behavior

Firefox

It actually took me quite a while to figure out Firefox's behavior. Let's take a look:

Firefox's HTTP status code behavior

Status codes in Firefox are modulo 65536 (216), unless it works out to 0, in which it displays status code 200.

This works up to a certain point, when it starts to display different behavior:

Firefox's HTTP status code behavior

Note how the status icon (blue dot, yellow triangle, etc.) is dependent on the first digit of the status code, once Firefox has finished interpreting it.

Safari

Safari only accepts status codes between 1 and 999. Should the status code fall outside that range, it reflects the entire HTTP request as plaintext, headers and all:

Safari's HTTP status code behavior

It also displays this error in the browser console. I'm not sure why, as the output is just JSON and there isn't any script on the page:

Safari's HTTP status code behavior

Note if you serve from localhost instead of a remote server, it displays a different error:

Safari's HTTP status code behavior

Edge

Not to be left behind, Edge also has some unusual HTTP status code handling:

Edge's HTTP status code behavior

For status code 0, it displays (Pending), although the page otherwise loads normally. For negative status codes, it displays them as the status code modulo 4294967296 (232). This is unless the status code is less than -4294967295, in which case it displays 1.

For positive status codes, it simply reflects them. This is until the status code reaches 4294967296 or higher, in which case it shows (Pending) and the browser displays this error:

Edge's HTTP status code behavior

Final words

Those who have been around in computing for a long time are likely familiar with Postel's Law:

 Be liberal in what you accept, and conservative in what you send.

While it seems like the neighborly thing to do, it is the bane of those of us who enjoy consistent software behavior. If the specification had simply stated that status codes falling outside 100-599 should be treated as an unrecoverable error, then we wouldn't see the unusual behavior that we see today.

Luckily, while all of the browsers have their own idiosyracies, none of them are actually harmful in this case.

If you enjoyed this post and would like to test how browsers handle other quirky HTTP responses, please consider opening an issue or sending a pull request to the misbehaving.site github repository.

[Category: Security] [Tags: HTTP, Browser]