Broken redirects in Safari with HTTP/2
If you’re enabling HTTP/2 for your applications, remember that HTTP/2
implementations are generally much more strict than earlier versions of HTTP
. Especially on older systems, there might be some surprises waiting for you!
To give you an example, we ran into a strange redirect issue in Safari after we enabled HTTP/2
. Instead of being redirected, the resulting URL was broken and ended up in a 404. This always worked before, so what could be wrong now?
Looking closer, the response of the redirect contained multiple Location
headers:
< HTTP/2 301
< server: nginx
< content-type: text/html; charset=utf-8
< location: https://foo.bar/admin?view=dashboard
< location: https://foo.bar/admin?view=dashboard
< date: Fri, 19 Jan 2018 09:25:37 GMT
< cache-control: max-age=0, no-cache
This worked before without issues - in all browsers - so why was it failing now that we switched on HTTP/2
? Safari tried to concatenate these multiple Location
headers into https://foo.bar/admin?view=dashboard,%20 https://foo.bar/admin?view=dashboard
.
Turns out multiple Location
headers are actually a violation of the HTTP specification. From RFC 2616, section 4.2:
Multiple message-header fields with the same field-name MAY be present in a message if and only if the entire field-value for that header field is defined as a comma-separated list [i.e., #(values)](#). It MUST be possible to combine the multiple header fields into one “field-name: field-value” pair, without changing the semantics of the message, by appending each subsequent field-value to the first, each separated by a comma.
Oops! That means concatenating the location header values is actually expected behaviour. We didn’t we run into this before because HTTP 1.1
implementations are not as strict, apparently.
As soon as we fixed the bug in our application that was repeating the Location
header, Safari redirected the request successfully again.
Another issue we ran into was Chrome suddenly throwing ERR_SPDY_PROTOCOL_ERROR
errors on a certain page. Our system had a second bug which was sending a malformed Allow
header value. On HTTP 1.1
Chrome did not complain at all.
In conclusion, HTTP/2
implementations are not as lax with the HTTP specs compared to older HTTP 1.1
clients, which is a good thing. If you run into strange problems after enabling it, make sure to double check your (legacy) system’s response headers first!