Adding support for etags in $.ajax() - and simplified the if-modified-since implement...
authorJohn Resig <jeresig@gmail.com>
Mon, 15 Jun 2009 13:36:12 +0000 (13:36 +0000)
committerJohn Resig <jeresig@gmail.com>
Mon, 15 Jun 2009 13:36:12 +0000 (13:36 +0000)
src/ajax.js
test/data/etag.php [new file with mode: 0644]
test/data/if_modified_since.php [new file with mode: 0644]
test/unit/ajax.js

index 4db08a4..2365387 100644 (file)
@@ -170,6 +170,7 @@ jQuery.extend({
 
        // Last-Modified header cache for next request
        lastModified: {},
+       etag: {},
 
        ajax: function( s ) {
                // Extend the settings, but re-extend 's' so that it can be
@@ -298,10 +299,13 @@ jQuery.extend({
                        if ( s.data )
                                xhr.setRequestHeader("Content-Type", s.contentType);
 
-                       // Set the If-Modified-Since header, if ifModified mode.
-                       if ( s.ifModified )
-                               xhr.setRequestHeader("If-Modified-Since",
-                                       jQuery.lastModified[s.url] || "Thu, 01 Jan 1970 00:00:00 GMT" );
+                               // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode.
+                               if ( s.ifModified ) {
+                                       if (jQuery.lastModified[s.url])
+                                               xhr.setRequestHeader("If-Modified-Since", jQuery.lastModified[s.url]);
+                                       if (jQuery.etag[s.url])
+                                               xhr.setRequestHeader("If-None-Match", jQuery.etag[s.url]);
+                               }
 
                        // Set header so the called script knows that it's an XMLHttpRequest
                        xhr.setRequestHeader("X-Requested-With", "XMLHttpRequest");
@@ -363,16 +367,7 @@ jQuery.extend({
                                }
 
                                // Make sure that the request was successful or notmodified
-                               if ( status == "success" ) {
-                                       // Cache Last-Modified header, if ifModified mode.
-                                       var modRes;
-                                       try {
-                                               modRes = xhr.getResponseHeader("Last-Modified");
-                                       } catch(e) {} // swallow exception thrown by FF if header is not available
-
-                                       if ( s.ifModified && modRes )
-                                               jQuery.lastModified[s.url] = modRes;
-
+                               if ( status == "success" || status == "notmodified" ) {
                                        // JSONP handles its own success callback
                                        if ( !jsonp )
                                                success();
@@ -467,13 +462,16 @@ jQuery.extend({
 
        // Determines if an XMLHttpRequest returns NotModified
        httpNotModified: function( xhr, url ) {
-               try {
-                       var xhrRes = xhr.getResponseHeader("Last-Modified");
+               var last_modified = xhr.getResponseHeader("Last-Modified");
+               var etag = xhr.getResponseHeader("Etag");
 
-                       // Firefox always returns 200. check Last-Modified date
-                       return xhr.status == 304 || xhrRes == jQuery.lastModified[url];
-               } catch(e){}
-               return false;
+               if (last_modified) 
+                       jQuery.lastModified[url] = last_modified;
+
+               if (etag) 
+                       jQuery.etag[url] = etag;
+
+               return xhr.status == 304;
        },
 
        httpData: function( xhr, type, s ) {
diff --git a/test/data/etag.php b/test/data/etag.php
new file mode 100644 (file)
index 0000000..ad05ba8
--- /dev/null
@@ -0,0 +1,16 @@
+<?php
+error_reporting(0);
+
+$ts = $_REQUEST['ts'];
+$etag = md5($ts);
+
+$ifNoneMatch = isset($_SERVER['HTTP_IF_NONE_MATCH']) ? stripslashes($_SERVER['HTTP_IF_NONE_MATCH']) : false;
+if ($ifNoneMatch == $etag) {
+    header('HTTP/1.0 304 Not Modified');
+    die; // stop processing
+}
+
+header("Etag: " . $etag);
+echo "OK: " . $etag;
+
+?>
diff --git a/test/data/if_modified_since.php b/test/data/if_modified_since.php
new file mode 100644 (file)
index 0000000..013f446
--- /dev/null
@@ -0,0 +1,15 @@
+<?php
+error_reporting(0);
+
+$ts = $_REQUEST['ts'];
+
+$ifModifiedSince = isset($_SERVER['HTTP_IF_MODIFIED_SINCE']) ? stripslashes($_SERVER['HTTP_IF_MODIFIED_SINCE']) : false;
+if ($ifModifiedSince == $ts) {
+    header('HTTP/1.0 304 Not Modified');
+    die; // stop processing
+}
+
+header("Last-Modified: " . $ts);
+echo "OK: " . $ts;
+
+?>
index fbff2d8..499d9ff 100644 (file)
@@ -874,6 +874,58 @@ test("data option: evaluate function values (#2806)", function() {
        })
 });
 
+test("jQuery.ajax - If-Modified-Since support", function() {
+       expect( 3 );
+
+       stop();
+
+       var url = "data/if_modified_since.php?ts=" + new Date();
+
+       jQuery.ajax({
+               url: url,
+               ifModified: true,
+               success: function(data, status) { 
+                       equals(status, "success");
+                       
+                       jQuery.ajax({
+                               url: url,
+               ifModified: true,
+                               success: function(data, status) { 
+                                       equals(status, "notmodified");
+                                       ok(data == null, "response body should be empty")
+                                       start();
+                               }
+                       });
+               }
+       });
+});
+
+test("jQuery.ajax - Etag support", function() {
+       expect( 3 );
+
+       stop();
+
+       var url = "data/etag.php?ts=" + new Date();
+
+       jQuery.ajax({
+               url: url,
+               ifModified: true,
+               success: function(data, status) { 
+                       equals(status, "success");
+                       
+                       jQuery.ajax({
+                               url: url,
+                               ifModified: true,
+                               success: function(data, status) { 
+                                       equals(status, "notmodified");
+                                       ok(data == null, "response body should be empty")
+                                       start();
+                               }
+                       });
+               }
+       });
+});
+
 }
 
 //}