Why does Apache return a 405 error code on a PUT request to a file or directory that doesn’t exist

apache-2.2

I recently discovered that when I make a PUT request to Apache to a file or directory that does not exist I get a 405 Method Not Allowed error instead of a 404 Not Found error. I am curious as to why?

PUT request from curl:

curl -i -X PUT -d '{"var":"val"}' "http://server/doesNotExist.htm"

Response from server:

HTTP/1.1 405 Method Not Allowed
Date: Sat, 16 Dec 2017 03:31:18 GMT
Server: Apache/2.2.15 (CentOS)
Allow: GET,HEAD,POST,OPTIONS,TRACE
Content-Length: 316
Connection: close
Content-Type: text/html; charset=iso-8859-1

<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<html><head>
<title>405 Method Not Allowed</title>
</head><body>
<h1>Method Not Allowed</h1>
<p>The requested method PUT is not allowed for the URL /doesNotExist.htm.</p>
<hr>
<address>Apache/2.2.15 (CentOS) Server at xxx.xxx.xxx.xxx Port 80</address>
</body></html>

When making a call to a directory that does not exist, I get the same 405 error instead of the expected 404. I am running Apache 2.2.15 on CentOS 6.9 with PHP 5.6.31. The httpd.conf file has not been modified.

What is Apache doing? Is there any way to make it return a 404 instead of the 405 if a file does not exist?

UPDATE:

When making a PUT request to a file that does exist I get a 200 OK.

HTTP/1.1 200 OK
Date: Sat, 16 Dec 2017 04:38:21 GMT
Server: Apache/2.2.15 (CentOS)
X-Powered-By: PHP/5.6.31
Content-Length: 2742
Connection: close
Content-Type: text/html; charset=UTF-8

<content of file here>

UPDATE 2:

I noticed that if I make a PUT request to a .php file that does not exist i.e. "doesnotexist.php" I get a 404. If I make a PUT request to a .htm file i.e. "doesnotexist.htm" or to a directory i.e. "http://server/doesnotexist" I get a 405.

Best Answer

The evidence you have provided suggests that the 405's occur when a PUT request is directed to the default request handler. (The PUT behavior is different for the PHP handler.)

The default handler is checking the request method before it checks whether the resource exists and has the correct permissions. Since the default handler doesn't support PUT unless this is enabled, you are seeing 405's rather than 404's.

The PUT method is typically enabled by listing it in the <limit> config.