Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to avoid CORS preflight request on file upload?

I am using jquery-fileupload to allow users to upload files to an external service (Cloudinary to be more specific):

<input type='file' name='file' class='cloudinary-fileupload' 
  data-url='https://api.cloudinary.com/v1_1/wya/auto/upload' />
<script>
  $('.cloudinary-fileupload').fileupload();
</script>

Since it is an external target, the browser initiates a CORS request. However, I noticed that the browser prepends a CORS preflight request. http://www.html5rocks.com/en/tutorials/cors/ gives pretty good insights about when a preflight request is triggered and when not. As far as I see, my request fulfills all criteria for being a CORS simple request (see section 'Types of CORS requests').

The file upload request that is sent to the external service:

POST /v1_1/wya/image/upload HTTP/1.1
Host: api.cloudinary.com
Connection: keep-alive
Content-Length: 22214
Accept: */*
Origin: http://wya.herokuapp.com
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/32.0.1700.107 Safari/537.36
Content-Type: multipart/form-data; boundary=----WebKitFormBoundarym73rCIa6t8eTNkTa
Referer: http://wya.herokuapp.com/
Accept-Encoding: gzip,deflate,sdch
Accept-Language: sv-SE,sv;q=0.8,en-US;q=0.6,en;q=0.4,de;q=0.2

The additional preflight request which is sent to the external service prior to the file upload request:

OPTIONS /v1_1/wya/image/upload HTTP/1.1
Host: api.cloudinary.com
Connection: keep-alive
Access-Control-Request-Method: POST
Origin: http://wya.herokuapp.com
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/32.0.1700.107 Safari/537.36
Access-Control-Request-Headers: accept, content-type
Accept: */*
Referer: http://wya.herokuapp.com/
Accept-Encoding: gzip,deflate,sdch
Accept-Language: sv-SE,sv;q=0.8,en-US;q=0.6,en;q=0.4,de;q=0.2

Is there a way to avoid this extra preflight request? As far as I see it, the file upload request is a CORS simple request as it is an HTTP POST with Content-Type multipart/form-data and only simple request HTTP headers.


The reason why I want to get rid of the extra preflight request is that Cloudinary sends an HTTP 302/304 redirect as a response to the file upload. Browsers do not follow those redirects. Chrome fails with the following message:

XMLHttpRequest cannot load https://api.cloudinary.com/v1_1/wya/image/upload. 
The request was redirected to 'http://wya.herokuapp.com/upload?bytes=21534&created_at=2014-02-12T09%3A04%3…d5b62ebb92b9236e5be6d472df242d016&type=upload&version=1392195882&width=723', 
which is disallowed for cross-origin requests that require preflight. 
like image 222
andreas Avatar asked Feb 12 '14 09:02

andreas


People also ask

How do I block preflight requests?

You can set a Access-Control-Max-Age for the OPTIONS request, so that it will not check the permission again until it is expired. Access-Control-Max-Age gives the value in seconds for how long the response to the preflight request can be cached for without sending another preflight request.

What triggers a CORS preflight?

A CORS preflight OPTIONS request can be triggered just by adding a Content-Type header to a request — if the value's anything except application/x-www-form-urlencoded , text/plain , or multipart/form-data .

How do I identify CORS preflight request?

Check for the existence of these essential information present in a preflight request: The request's HTTP method is OPTIONS. It has an Origin header. It has an Access-Control-Request-Method header, indicating what's the actual method it's trying to use to consume your service/resource.


1 Answers

The problem is that the XHR header is not sent with the request to Cloudinary which causes Cloudinary to redirect (IE fallback) instead of returning the JSON. This is usually caused because of improper initialization of the widget. You usually don't need to call $('.cloudinary-fileupload').fileupload() yourself as this is done by the included Javascript. If you still need to initialize the widget manually, please use $('.cloudinary-fileupload').cloudinary_fileupload().

like image 161
Tal Lev-Ami Avatar answered Oct 03 '22 10:10

Tal Lev-Ami