We're doing a fair amount of AJAX development these days, and ran into a problem with the REST convention. Thought I'd put my notes here in case somebody else runs into this.

REST, short for "Representational State Transfer" is a new-ish approach to managing state in a web application. With PHP, you typically manage state using its session features, which pass a cookie back and forth from the browser. Then the server needs to store values for each browser session, mirroring in some fashion the data in the browser with a cache on the server. This breaks down in a couple cases:

  1. You want to have multiple browser windows open into the same application
  2. Your application runs on a cluster of servers, and sessions cannot be safely/quickly retrieved (extremely high traffic sites)

REST is simply a set of guidelines for keeping all state in the browser, and passing all the necessary parameters the server needs to handle a request with every single request. And the REST architects are making use of the full HTTP specification, rather than just the parts that are in widespread use.

The vast majority of web sites make use of only two HTTP methods: GET, and POST. But there are quite a few others that are defined in the original specification, particularly PUT and DELETE that the REST practitioners rely on. It adds a couple useful verbs to the language that otherwise add more parameters to your simple POST.

The PHP language handles GET and POST very nicely, giving the programmer an array of variables passed by the browser. It can handle PUT and DELETE as well, but you have to access the body of these requests using a raw input stream. That much is fine. The problem I ran into when deploying an application that relies on PUT was that my PHP application never received the request. It did on my development machine, but when I moved it to an internal production machine, all the PUT requests were getting a "403 Unauthorized" error back from the server. Why would this work on one machine but not another?

It turns out to be a conflict with WebDAV. WebDAV is an extension of the HTTP protocol, which also uses PUT and DELETE, and adds a few others like OPTIONS, MKCOL, and more. We use WebDAV instead of FTP to allow our clients to copy files up to our servers--we can lock them into particular directories, and generally secure the server much better than we can with FTP.

However, apparently WebDAV intercepts ALL PUT requests to the server, even if it's for a different virtual host. A bug in the mod_dav module, or mod_dav_fs? Don't know. What's strange is that Subversion, which runs as a Dav handler, does not conflict with our use of PUT--only regular Dav.

So for those running into this, what we found is that as long as you don't have "Dav On" anywhere on that Apache server, PUT requests make it to the PHP handler just fine. Subversion can be enabled on particular servers or subdirectories, and then it becomes the PUT handler for those areas. The Dav modules can be loaded with no conflict. But as soon as you turn Dav On on any virtual host on the entire server, your PHP script will no longer get the request.

It is not an Apache bug:

'Apache has a particular design restriction in that only one "content handler" is
allowed to process a request.' (Read on at the link for more.)

OK, this doesn't resolve your problem -- how to get your PUT handlers to tell the difference between a REST and a DAV transaction -- but at least you now know it is an Apache quirk ;-)

Cliff

Hi, Cliff,

Thanks for your comment. I did see this page, while investigating the problem. I do think this is a bug, not in Apache itself, but in one of the Dav modules.

I can understand there being only one handler for a method, and I can even understand there only being one handler per virtual host. But the Dav module appears to preempt all others, and I don't see any way to stop it (other than not use Dav on the entire server).

Subversion seems to be much better behaved. It is a Dav module, but I have it running on the same virtual host as my REST application with no conflict at all--if you specify a location that is handled by Dav svn, the Subversion handler handles it. Otherwise, PHP gets it.

But as soon as I turned on the regular Dav module in a completely different virtual host, no PUT requests went to my PHP script at all. That's why I think it's a bug...

Cheers,
John

Add new comment

The content of this field is kept private and will not be shown publicly.

Filtered HTML

  • Web page addresses and email addresses turn into links automatically.
  • Allowed HTML tags: <a href hreflang> <em> <strong> <blockquote cite> <cite> <code> <ul type> <ol start type> <li> <dl> <dt> <dd> <h1> <h2 id> <h3 id> <h4 id> <h5 id> <p> <br> <img src alt height width>
  • Lines and paragraphs break automatically.
CAPTCHA
This question is for testing whether or not you are a human visitor and to prevent automated spam submissions.