Sat 27 June 2015
| tags: nginx apache webdav owncloud
Before doing a request (POST, GET, PUT, …) on another domain with Javascript,
web browsers will perform an OPTIONS request to verify that the request is
likely to be accepted by the server. They mostly check for CORS headers.
This doesn't cause any troubles if your service doesn't require authentication:
the OPTIONS request is performed without the authentication headers. So, for
instance, if you are trying to connect to an owncloud instance with the webdav
protocol, the OPTIONS request will failed due to a 401 unauthorized error.
To avoid that, you must make sure that when requested with the OPTIONS method,
the endpoint always respond with a 200 status code and with the proper header
even without authentication. You can either do it programmatically in the code
of your application or with your web server configuration.
I provide the correct configuration sample for nginx and apache. You should be
able to adapt them for other web server or for your favorite programming
language. Both include the headers and how to return the 200 status code on
options. I also provide a sample JS code that can make the request.
add_header 'Access-Control-Allow-Methods' 'GET,OPTIONS,PUT,DELETE' always ;
add_header 'Access-Control-Allow-Credentials' 'true' always ;
add_header 'Access-Control-Allow-Origin' ' $http_origin' always ;
add_header 'Access-Control-Allow-Headers' 'Authorization,DNT,User-Agent,Keep-Alive,Content-Type,accept,origin,X-Requested-With' always ;
if ( $request_method = OPTIONS ) {
return 200 ;
}
You may also need to add the Access-Control-Expose-Headers to allow the browser to export the headers. This will be required to use them from AngularJS for instance:
add_header 'Access-Control-Expose-Headers' 'Authorization,DNT,User-Agent,Keep-Alive,Content-Type,accept,origin,X-Requested-With,Content-Disposition' always ;
Header always set Access-Control-Allow-Origin "http://waffle"
Header always set Access-Control-Allow-Methods "POST, GET, OPTIONS"
Header always set Access-Control-Allow-Credentials "true"
Header always set Access-Control-Allow-Headers "Authorization,DNT,User-Agent,Keep-Alive,Content-Type,accept,origin,X-Requested-With"
RewriteCond %{REQUEST_METHOD} OPTIONS
RewriteRule ^(.*)$ $1 [R=200,L]
If you need Access-Control-Allow-Origin to be exactly the domain from the origin header, you can use:
SetEnvIf Origin "http(s)?://(.+)$" CORS=$0
Header always set Access-Control-Allow-Origin %{CORS}e env=CORS
You may also need to add the Access-Control-Expose-Headers to allow the browser to export the headers. This will be required to use them from AngularJS for instance:
Header always set Access-Control-Expose-Headers 'Authorization,DNT,User-Agent,Keep-Alive,Content-Type,accept,origin,X-Requested-With,Content-Disposition' ;
Your javascript code must supply the Authorization and Content-Type
headers. For instance, with the angular framework:
$http ({
method : 'POST' ,
url : scope . webdav . url ,
withCredentials : true ,
headers : {
Authorization : 'Basic ' + btoa ( user + ':' + password ),
'Content-Type' : 'application/vnd.google-earth.kml+xml; charset=utf-8'
},
data : getKml ()
})