rtomayko/rack-cache — Issue #44: Not Modified Returned on POST/PUT
Author: cfis
Created: 2012-01-05 00:41:14+00:00
State: open

In certain circumstances, rack-cache returns 304 Not Modified on POST and PUT requests. The specific example I am seeing:

1. iPhone app does a POST to a Rails server to the path /login

2. The response is returned with a http tatus code of 200 and an etag added by rack/etag.rb. Note the response has a custom auth token http header, but rack only takes into consideration the response body. Often times POST to login will do a redirect, but in this case its a JSON api so no reason to redirect.

3. User closes app

4. User opens app, logs in again. The iphone app makes the same request as before, but this time includes the etag it got back the first time.

5. rack-cache, in context.rb, notices this is a post and invalidates the cache (not that there is anything in the cache), then passes the request along to rest of rack stack and rails.

6. Once Rails has fulfilled the request, on the return code path rack-cache in context.rb, around line 98 does this:

response.not_modified! if not_modified?(response)

That changes the response to 304 because the etag from the client matches the etag figured out by rack (see #2 above), although this is a POST.

7. iphone client sees a 304, looks in its cache, pulls out the previous reponse. But that response has an old auth token that has been invalidated. So the next request the iPhone app makes will fail due to an authentication error.

I believe that rack-cache is incorrect here, it should only change the response status to 304 for GET and HEAD requests. Although it seems strange for the server to return an etag on a POST/PUT and the client to then return it, there is a use case in WebDav:

http://www.webdav.org/specs/rfc4918.html#rfc.section.12.1

The etag is used for a server to detect if a resource about to be updated has been updated by someone else. If it has, then instead of a 304 a 412 should be returned. Of course that is outside of the realm of rack-cache, so it should just return the response with out changing its status to 304.

Thoughts?