30

I've noticed that the results of and XMLHttpRequest.getResponseHeader() don't always match the real headers returned (if the request is made in a regular manner).

For example, assume I'm making an xhr request for https://foo.example.com/api/resource/100. In Chrome's developer console, under 'Network', I can see the response being made -- I can also see all of the response headers (say, 10). However (copy-pasted console):

> response
  XMLHttpRequest
> response.getAllResponseHeaders();
  "content-type: text/html
  " 

Are there any restrictions on what headers are available? Is this dependent on the response type? I remember getting a complete set of headers for 404s but just this one for 400s.

What gives?

maligree
  • 5,939
  • 10
  • 34
  • 51
  • If I make a request to `http://stackoverflow.com/` on this page, I am able to get all headers back. I'm not sure how to reproduce. – pimvdb Sep 18 '11 at 17:06
  • I'm aware of the vagueness -- trying to narrow down to a suitable case. The original request made is cross-origin request, with Access-Control-Allow-Origin. Excuse the rushed feeling of the question, will elaborate soon: I didn't have time to investigate this further at the moment. I was hoping this was some sort of a known restriction that I'm unaware of. – maligree Sep 18 '11 at 17:12

2 Answers2

37

The current state of standardizing the XMLHttpRequest API does only restrict the access to the Set-Cookie and Set-Cookie2 header fields:

client.getAllResponseHeaders()

Returns all headers from the response, with the exception of those whose field name is Set-Cookie or Set-Cookie2.

Any other header field should be returned.

But as you’re doing a cross-origin request, the browser needs to implement XMLHttpRequest Level 2 as the original XMLHttpRequest does only allow same-origin requests:

The XMLHttpRequest Level 2 specification enhances the XMLHttpRequest object with new features, such as cross-origin requests […]

There you can read that the “Cross-Origin Resource Sharing specification filters the headers that filters the headers that are exposed by getResponseHeader() for non same-origin requests.”. And that specification forbids access to any response header field other except the simple response header fields (i.e. Cache-Control, Content-Language, Content-Type, Expires, Last-Modified, and Pragma):

User agents must filter out all response headers other than those that are a simple response header […]

E.g. the getResponseHeader() method of XMLHttpRequest will therefore not expose any header not indicated above.

Gumbo
  • 643,351
  • 109
  • 780
  • 844
  • 1
    Right, thanks. There are still some mysteries left, though.. I've set a proper `Access-Control-Expose-Headers:` -- only to find out it works only in Gecko, not WebKit. WebKit happily "Refused to get unsafe header (..)", Gecko sees no problem. Second issue: `getAllResponseHeaders()` lies. I can `getResponseHeader()` headers that the former doesn't list as available. – maligree Sep 19 '11 at 07:16
  • @maligree: [WebKit doesn’t support the *Access-Control-Expose-Headers* yet.](https://bugs.webkit.org/show_bug.cgi?id=41210) But what about the other issue? What browser does that? – Gumbo Sep 19 '11 at 17:14
  • Yes, I've stumbled upon that bugzilla issue -- but seeing the date it was opened, I took it with a grain of salt . *And* as to the second issue, I'm seeing this in Firefox 6. `getAllResponseHeaders()` returns `""`, while a `getResponseHeader('content-length')` or `getResponseHeader('www-authenticate')` (which is one of the headers I'm setting and `Access-Control-Expose-Header`'ing) returns the proper header value. I'd rather not expose the URI used at this time, but if it helps, I can devise an isolated test case later. – maligree Sep 19 '11 at 19:56
  • @maligree you meant `null` right ? cf https://bugzilla.mozilla.org/show_bug.cgi?id=608735 – Knu Jan 14 '18 at 03:58
3

It's the Access-Control-Allow-Origin header and the way it allows to prevent which headers are exposed to the browser. Docs at mozilla.

maligree
  • 5,939
  • 10
  • 34
  • 51