Working with cross domain HTTP requests in JavaScript is generally acknowledged to be a bit of a minefield.
Recently I discovered a new CORS header, Access-Control-Expose-Header, which I hadn’t know about previously. As I had to do a lot of digging to get any information about it, I thought I’d make a note.
The context was that we were making a cross-domain HEAD request to establish the Content-Length of a download before performing the AJAX request.
All was going well – the Content-Length was coming back (in the Chrome network inspector) – but when it came to getting the content length in the JavaScript code, it was not being returned:
>>> xhr.getResponseHeader("content-length"); null
It turns out that only 6 “simple” headers are allowed to be returned (for security reasons) on CORS requests. As listed in the spec, they are:
- Cache-Control
- Content-Language
- Content-Type
- Expires
- Last-Modified
- Pragma
Obviously Content-Length is not one of these. In order to allow it to be read, you must specify the content-length header with the Access-Control-Expose-Headers response header. The value is a comma-separated list of headers, but as we only have one we want to expose, the response header needs to look like this:
Access-Control-Expose-Headers: content-length
Note that the content-length section after the colon is case insensitive, as per the HTTP Headers specification.
If you are using Jetty 8 (after Jetty 8.1.12) you can use the following syntax in your CrossOriginFilter in your web.xml to set this up:
<init-param> <param-name>exposedHeaders</param-name> <param-value>content-length</param-value> </init-param>
So there’s another thing to learn about CORS – but once you have it working, it is extremely effective.