Location Header not being matched case-insensitive

According to https://tools.ietf.org/html/rfc7230#section-3.2 and https://tools.ietf.org/html/rfc7540#section-8.1.2 field names of headers should be matched case-insensitive.

Yet when I issue a request against http://bit.ly/1InhKyt and get

HttpResponse(301 Moved Permanently,List(Server: nginx, Date: Tue, 24 Apr 2018 14:51:44 GMT, Connection: keep-alive, Cache-Control: private, max-age=90, location: http://store.elsevier.com/product.jsp?isbn=9780444635273&utm_source=socialmedia&utm_medium=chemistry&utm_campaign=Fundamentals and Analytical Applications of Multi-way Calibration, 1st Edition&sf13365293=1, Set-Cookie: _bit=i3oePI-4be01ccd5a0a948bc6-00T; Expires=Sun, 21 Oct 2018 14:51:44 GMT; Domain=bit.ly),HttpEntity.Strict(text/html; charset=UTF-8,<html>
<head><title>Bitly</title></head>
<body><a href="http://store.elsevier.com/product.jsp?isbn=9780444635273&amp;utm_source=socialmedia&amp;utm_medium=chemistry&amp;utm_campaign=Fundamentals and Analytical Applications of Multi-way Calibration, 1st Edition&amp;sf13365293=1">moved here</a></body>
</html>),HttpProtocol(HTTP/1.1))

the location header is not matched when using

val Loc = response.header[Location]

but is when I manually filter for it

val loc = response.headers.filter(h => h.lowercaseName().equals("location"))

Is that by design or choice?

The parser is most definitely case-insensitive, as indicated by the spec.
Have you disabled parsing modeled headers maybe?
The .header[Type] lookup is optimized and looks up by class instance, which assumes that the header was properly parsed into the expected Type.

    # If set to `off`, only essential headers will be parsed into their model classes. All other ones will be provided
    # as instances of `RawHeader`. Currently, `Connection`, `Host`, and `Expect` headers will still be provided in their
    # typed model. The full list of headers still provided as modeled instances can be found in the source code of
    # `akka.http.impl.engine.parsing.HttpHeaderParser.alwaysParsedHeaders`. Note that (regardless of this setting)
    # some headers like `Content-Type` are treated specially and will never be provided in the list of headers.
    modeled-header-parsing = on

The only option I use is client.parsing.illegal-header-warnings = off.

But when you say "properly parsed " you also mean successfully converted to the appropriate type, in my case the String to a Uri.

I turned back on the warnings and was greeted with "[…] Illegal header: Illegal ‘location’ header: Invalid input ’ ', expected raw-query-char, ‘#’ or ‘EOI’ (line 1, column 127): http://store.elsevier.com/product.jsp?isbn=9780444635273&utm_source=socialmedia&utm_medium=chemistry&utm_campaign=Fundamentals and Analytical Applications of Multi-way Calibration, 1st Edition&sf13365293=1`

Ugh. akka was doing the right thing. It was just that the location value was malformed (containing whitespace) and someone (me) ignored the warnings. akka actually does one better and still provides the malformed header as the raw value.

Thanks for the help!

Glad you found the issue – yeah our parsing logic tries to be as close to the spec as possible, with loosening up where we know that “real world” actually is not as the spec dictates.

Yes in those cases you can always get the header by name (since it should be still around as Raw one).

Happy hakking