Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

CORS preflight request returning HTTP 405

I am trying to create a RESTful web service and have gotten stuck on implementing PUT requests. I have tried and failed to follow other answers on this site and various articles from Mozilla.

The request is generated from the domain wwwtest.dev-box and it's going to test.dev-box (basically a front-end app calling the back-end app). Here are the headers I have captured from Live HTTP headers:

http://test.dev-box/resource/v1/data/user/1

OPTIONS /resource/v1/data/user/1 HTTP/1.1
Host: test.dev-box
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:24.0) Gecko/20100101 Firefox/24.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Origin: http://wwwtest.dev-box
Access-Control-Request-Method: PUT
Connection: keep-alive

HTTP/1.1 405 Method Not Allowed
Date: Wed, 16 Oct 2013 16:15:58 GMT
Server: Apache/2.2.15 (Red Hat)
x-powered-by: PHP/5.3.27
Access-Control-Allow-Origin: http://wwwtest.dev-box
Access-Control-Allow-Methods: POST, GET, PUT, OPTIONS
Access-Control-Max-Age: 1728000
Content-Length: 0
Allow: PUT
Cache-Control: no-cache
Connection: close
Content-Type: text/html; charset=UTF-8

I'm using a framework so everything is routed to web.php, which contains the following code at the top of the page (taken from this MDN article):

if ($_SERVER['REQUEST_METHOD'] == 'OPTIONS') {
    header('Access-Control-Allow-Origin: http://wwwtest.dev-box');
    header('Access-Control-Allow-Methods: POST, GET, PUT, OPTIONS');
    header('Access-Control-Max-Age: 1728000');
    header("Content-Length: 0");
    header("Content-Type: text/plain");
} else {
    header("HTTP/1.1 403 Access Forbidden");
    header("Content-Type: text/plain");
}

Before my code makes the PUT request it sends the CORS preflight OPTIONS request first (as you can see from the capture above). The necessary headers should be attached to the response and tell the requester that PUT is allowed. Unfortunately as you can see from the response headers above it is still returning 405 Method Not Allowed even though PUT is in the response access-control-allow-methods.

This is the .htaccess file for the framework I'm using (Silex):

<IfModule mod_rewrite.c>
    Options -MultiViews

    RewriteEngine On
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteRule ^ web.php [QSA,L]
</IfModule>
like image 964
Matt K Avatar asked Oct 16 '13 16:10

Matt K


People also ask

How do you handle CORS preflight request?

A CORS preflight request is a CORS request that checks to see if the CORS protocol is understood and a server is aware using specific methods and headers. It is an OPTIONS request, using three HTTP request headers: Access-Control-Request-Method , Access-Control-Request-Headers , and the Origin header.

What causes HTTP 405 error?

The 405 Method Not Allowed error occurs when the web server is configured in a way that does not allow you to perform a specific action for a particular URL. It's an HTTP response status code that indicates that the request method is known by the server but is not supported by the target resource.

What does HTTP 405 mean?

The HyperText Transfer Protocol (HTTP) 405 Method Not Allowed response status code indicates that the server knows the request method, but the target resource doesn't support this method. The server must generate an Allow header field in a 405 status code response.


2 Answers

I've found the answer to be a cross between Apache and framework configuration.

  1. For the Apache config you can either put the following into your VirtualHost directive, or in the .htaccess file of the requested domain (if it's in the .htaccess remember to encapsulate with IfModule mod_headers.c tags). Setting the headers on the page that mod_rewrite redirects to does not work:
    Header set Access-Control-Allow-Origin "http://wwwtest.dev-box"
    Header set Access-Control-Allow-Methods "GET,POST,HEAD,DELETE,PUT,OPTIONS"
  1. For the Silex config, place the following into your application routes. It basically sends an HTTP 200 OK for any OPTIONS request it receives. Code found on the Silex Google Group:
    $app->match("{url}", function($url) use ($app) {
        return "OK";
    })->assert('url', '.*')->method("OPTIONS");

Both steps need to be completed for the RESTful application to function properly.

like image 74
Matt K Avatar answered Nov 10 '22 02:11

Matt K


The 405 is in reference to the actual preflight/OPTIONS request. Your server is rejecting the preflight outright as OPTIONS requests in general are not accepted by your server. You'll need to modify your server configuration to accept OPTIONS requests. Simply including code in a PHP file may not be enough. Most likely your web/application server is not aware of this verb and is rejecting the request before it hits your PHP code.

like image 44
Ray Nicholus Avatar answered Nov 10 '22 00:11

Ray Nicholus