Why does a cross-origin HEAD request need a preflight check?
Asked Answered
P

1

15

I was reading the spec on CORS requests, and I found this about preflight requests:

These are requests to a non same origin URL with an HTTP request method other than GET that first need to be authorized using either a preflight result cache entry or a preflight request.

I had thought the purpose of preflight requests was to check whether a request was allowed before making it, in case it (illegitimately) changed server state.

But HEAD and OPTIONS don't modify server state. I must misunderstand the reason for preflight check.

What is the purpose (aka the reason, motivation, or rationale) for doing a preflight check for HEAD and OPTIONS but not GET? What is special about GET?

Pandanus answered 28/2, 2014 at 23:23 Comment(0)
L
27

The primary intent of preflighting is to ensure that servers aren't suddenly sent cross-origin browser-based requests that they could have never received before the CORS spec was implemented.

Before the CORS spec, it was impossible to send any browser-based cross-origin requests other than GET or POST. The browser simply would not allow you to fire up an XHR instance, set the method to PUT (for example) and send it off to an endpoint on a different origin. You couldn't send GET or POST cross-origin requests via XHR either, but you COULD send a cross-origin GET or POST via a form submit, or a cross-origin GET via an <img> or <script> tag, for example (which made JSONP the only option pre-CORS). Once browsers implemented the CORS spec, this changed. Now it IS possible to send any cross-origin ajax request, provided the server opts-in.

The CORS spec defines "simple" methods (GET and POST) along with "simple" request headers. These correspond to the types of cross-origin requests that you could already send from the browser pre-CORS spec. Non-simple cross-origin requests, such as PUT or POST/GET requests with an X-header (for example) could not be sent from a browser pre-CORS spec. So, for these types of requests, the concept of preflighting was written into the spec to ensure servers do not receive these types of non-simple cross-origin browser-based requests without explicitly opting in. In other words, if you don't want to allow these types of requests, you don't have to change your server at all. The preflight will fail, and the browser will never send the underlying request.

Directly addressing your question: HEAD requests do not normally result in a preflight. HEAD is considered a simple request method according to the CORS spec. As you know, HEAD requests are just GETs without a response payload. This is the most likely reason why HEAD and GET requests are treated the same, even though you could not send a cross-origin HEAD request pre-CORS from the browser. If your HEAD contains non-simple headers, it will be preflighted though, just like GET.

Lawley answered 1/3, 2014 at 1:15 Comment(5)
I quoted the spec, and it says "with an HTTP request method other than GET". Doesn't that mean HEAD as well?Pandanus
You quoted a very old and outdated draft of the spec. Here's a current version: w3.org/TR/corsLawley
Ah, that makes me feel much better.Pandanus
I should mention, it appears that AngularJS always issues a preflight request, even for HEAD. This was a surprise for me so be aware in case you were expecting other behavior.Harrietharriett
Angular JS doesn't issue preflights, only the browser does this. And preflights are definitely not always sent when making Ajax requests from angular. If your app is sending Ajax HEAD requests that are preflights, then this means you are sending some non-standard header with the request, such as an X- header. Once you remove this, there will be no preflight.Lawley

© 2022 - 2024 — McMap. All rights reserved.