Opened 9 years ago

Closed 9 years ago

Last modified 9 years ago

#93 closed enhancement (wontfix)

If-Modified-Since rfc compliance

Reported by: adrian ilarion ciobanu Owned by: somebody
Priority: minor Milestone: 1.2.0
Component: nginx-core Version: 1.1.x
Keywords: If-Modified-Since Cc:
uname -a: Linux localhost 2.6.32-5-686-bigmem #1 SMP Wed Jan 11 13:17:56 UTC 2012 i686 GNU/Linux
nginx -V: nginx version: nginx/1.1.14
built by gcc 4.4.5 (Debian 4.4.5-8)
configure arguments:

Description

Shouldn't if_modified_since be set by default to NGX_HTTP_IMS_BEFORE to make nginx more RFC compliant? Isn't NGX_HTTP_IMS_EXACT more like a tweak if one follows rfc guidelines?

Plus, I have this feeling that using _BEFORE by default gives nginx more chances to be bandwidth saviour than by using _EXACT.

The If-Modified-Since request-header field is used with a method to make it conditional: if the requested variant has not been modified since the time specified in this field, an entity will not be returned from the server; instead, a 304 (not modified) response will be returned without any message-body. (rfc2616)

Then, the SHOULD specifier we can read at http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.3.5 can be interpreted through _EXACT or _MULTIVERSE logic modifiers.

Nginx default configuration makes the flow a little bit mind-effing, back-to-the-future style.

The file's server timestamp is Tue, 31 Jan 2012 10:43:58 GMT.
Client sends a request with If-Modified-Since set to Tue, 31 Jan 2012 10:43:59 GMT
Client gets a 200 OK
Client sends a request with If-Modified-Since set to Tue, 31 Jan 2012 10:43:58 GMT.
Client gets a 304 Not Modified.

One expects "304 Not Modified" in both usecases. It makes sense. Unless the sysadmin explicitly configured the server to act like this.

HEAD -Se http://localhost/somefile |grep Last-Modified
Last-Modified: Tue, 31 Jan 2012 10:43:58 GMT
HEAD -H 'If-Modified-Since: Tue, 31 Jan 2012 10:43:59 GMT' http://localhost/somefile | head -1
200 OK
HEAD -H 'If-Modified-Since: Tue, 31 Jan 2012 10:43:58 GMT' http://localhost/somefile | head -1
304 Not Modified

If I have a good point, the patch seems trivial

--- http/ngx_http_core_module.c_orig    2012-01-31 12:45:37.000000000 +0100
+++ http/ngx_http_core_module.c 2012-01-31 12:45:53.000000000 +0100
@@ -3486,7 +3486,7 @@
     ngx_conf_merge_uint_value(conf->satisfy, prev->satisfy,
                               NGX_HTTP_SATISFY_ALL);
     ngx_conf_merge_uint_value(conf->if_modified_since, prev->if_modified_since,
-                              NGX_HTTP_IMS_EXACT);
+                              NGX_HTTP_IMS_BEFORE);
     ngx_conf_merge_uint_value(conf->max_ranges, prev->max_ranges,
                               NGX_MAX_INT32_VALUE);
     ngx_conf_merge_uint_value(conf->client_body_in_file_only,

Thank you,

Change History (3)

comment:1 by Maxim Dounin, 9 years ago

Resolution: wontfix
Status: newclosed

Use of "if_modified_since before" makes Last-Modified time a week validator (see http://tools.ietf.org/html/rfc2616#section-13.3.3), so this isn't going to be a default behaviour.

comment:2 by adrian ilarion ciobanu, 9 years ago

But in the default configuration you are using Last-Modified / If-Modified-Since like a cheap ETag (timestamps instead of checksums) with two names, almost dropping the real meaning and functionality of If-Modified-Since.

Since I have to save the Last-Modified time on the client side (so I can use it later, like an etag) because the server won't reply honestly while keeping account of my If-Modified-Since value, why bother using it? Why not use an ETag? They look exactly the same now. unless before is used.

I don't follow on the weakness of Last-Modified validator? How does before makes it weaker? Last-Modified is a strong validator only if it is used like an ETag, together with If-Modified-Since, that is, your "default" configuration which is broken, that is, it is strong because you made it so. On the other hand, you're still computing timestamps diffs against it, on the server side, no one ignores it. Nowhere in rfcs is mentioned that If-Modified-Since "should be either equal or less than Last-Modified otherwise server should autofix it"

comment:3 by Maxim Dounin, 9 years ago

Yes, we are using Last-Modified much like ETag. Obvious advantage of Last-Modified over ETag is that Last-Modified is the only one present in HTTP/1.0 (and hence must be supported anyway). Please also see the following note from RFC 2616:

Note: When handling an If-Modified-Since header field, some
servers will use an exact date comparison function, rather than a
less-than function, for deciding whether to send a 304 (Not
Modified) response. To get best results when sending an If-
Modified-Since header field for cache validation, clients are
advised to use the exact date string received in a previous Last-
Modified header field whenever possible.

This behaviour is at least conditionally complaint (following RFC 2616 terminology) and believed to be much more robust than "less-than" comparison, which is expected to cause much more "false" 304 responses (with cached entity not matching one present on server). Moreover, using "less-than" comparison just not going to work with conditional range requests as exact match is required there (though it's somewhat unrelated, as the "if_modified_since" directive doesn't change conditional range requests behaviour anyway).

I wouldn't say that exact comparison "drops the real meaning and functionality of If-Modified-Since". As clearly stated in RFC,

The purpose of this feature is to allow efficient updates of cached
information with a minimum amount of transaction overhead.

and exact comparison clearly allows this, while also addressing some of the reasons why ETag header appeared in HTTP/1.1 in addition to Last-Modified one.

Note: See TracTickets for help on using tickets.