Fixes #8095. Properly handles the case where browser cache needs to be bypassed while server-side logic still delivers proper 304 responses. Unit test added.

This commit is contained in:
jaubourg 2011-01-31 19:59:53 +01:00
parent e0b1bb8e3d
commit f43572d3b8
2 changed files with 99 additions and 84 deletions

View file

@ -350,6 +350,8 @@ jQuery.extend({
completeDeferred = jQuery._Deferred(), completeDeferred = jQuery._Deferred(),
// Status-dependent callbacks // Status-dependent callbacks
statusCode = s.statusCode || {}, statusCode = s.statusCode || {},
// ifModified key
ifModifiedKey,
// Headers (they are sent all at once) // Headers (they are sent all at once)
requestHeaders = {}, requestHeaders = {},
// Response headers // Response headers
@ -453,10 +455,10 @@ jQuery.extend({
if ( s.ifModified ) { if ( s.ifModified ) {
if ( ( lastModified = jXHR.getResponseHeader( "Last-Modified" ) ) ) { if ( ( lastModified = jXHR.getResponseHeader( "Last-Modified" ) ) ) {
jQuery.lastModified[ s.url ] = lastModified; jQuery.lastModified[ ifModifiedKey ] = lastModified;
} }
if ( ( etag = jXHR.getResponseHeader( "Etag" ) ) ) { if ( ( etag = jXHR.getResponseHeader( "Etag" ) ) ) {
jQuery.etag[ s.url ] = etag; jQuery.etag[ ifModifiedKey ] = etag;
} }
} }
@ -590,6 +592,9 @@ jQuery.extend({
s.url += ( rquery.test( s.url ) ? "&" : "?" ) + s.data; s.url += ( rquery.test( s.url ) ? "&" : "?" ) + s.data;
} }
// Get ifModifiedKey before adding the anti-cache parameter
ifModifiedKey = s.url;
// Add anti-cache in url if needed // Add anti-cache in url if needed
if ( s.cache === false ) { if ( s.cache === false ) {
@ -609,11 +614,12 @@ jQuery.extend({
// Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode. // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode.
if ( s.ifModified ) { if ( s.ifModified ) {
if ( jQuery.lastModified[ s.url ] ) { ifModifiedKey = ifModifiedKey || s.url;
requestHeaders[ "if-modified-since" ] = jQuery.lastModified[ s.url ]; if ( jQuery.lastModified[ ifModifiedKey ] ) {
requestHeaders[ "if-modified-since" ] = jQuery.lastModified[ ifModifiedKey ];
} }
if ( jQuery.etag[ s.url ] ) { if ( jQuery.etag[ ifModifiedKey ] ) {
requestHeaders[ "if-none-match" ] = jQuery.etag[ s.url ]; requestHeaders[ "if-none-match" ] = jQuery.etag[ ifModifiedKey ];
} }
} }

View file

@ -1867,26 +1867,32 @@ test("data option: empty bodies for non-GET requests", function() {
}); });
}); });
test("jQuery.ajax - If-Modified-Since support", function() { var ifModifiedNow = new Date();
jQuery.each( { " (cache)": true, " (no cache)": false }, function( label, cache ) {
test("jQuery.ajax - If-Modified-Since support" + label, function() {
expect( 3 ); expect( 3 );
stop(); stop();
var url = "data/if_modified_since.php?ts=" + new Date(); var url = "data/if_modified_since.php?ts=" + ifModifiedNow++;
jQuery.ajax({ jQuery.ajax({
url: url, url: url,
ifModified: true, ifModified: true,
cache: cache,
success: function(data, status) { success: function(data, status) {
equals(status, "success" ); equals(status, "success" );
jQuery.ajax({ jQuery.ajax({
url: url, url: url,
ifModified: true, ifModified: true,
cache: cache,
success: function(data, status) { success: function(data, status) {
if ( data === "FAIL" ) { if ( data === "FAIL" ) {
ok(true, "Opera is incapable of doing .setRequestHeader('If-Modified-Since')."); ok(jQuery.browser.opera, "Opera is incapable of doing .setRequestHeader('If-Modified-Since').");
ok(true, "Opera is incapable of doing .setRequestHeader('If-Modified-Since')."); ok(jQuery.browser.opera, "Opera is incapable of doing .setRequestHeader('If-Modified-Since').");
} else { } else {
equals(status, "notmodified"); equals(status, "notmodified");
ok(data == null, "response body should be empty"); ok(data == null, "response body should be empty");
@ -1914,26 +1920,28 @@ test("jQuery.ajax - If-Modified-Since support", function() {
}); });
}); });
test("jQuery.ajax - Etag support", function() { test("jQuery.ajax - Etag support" + label, function() {
expect( 3 ); expect( 3 );
stop(); stop();
var url = "data/etag.php?ts=" + new Date(); var url = "data/etag.php?ts=" + ifModifiedNow++;
jQuery.ajax({ jQuery.ajax({
url: url, url: url,
ifModified: true, ifModified: true,
cache: cache,
success: function(data, status) { success: function(data, status) {
equals(status, "success" ); equals(status, "success" );
jQuery.ajax({ jQuery.ajax({
url: url, url: url,
ifModified: true, ifModified: true,
cache: cache,
success: function(data, status) { success: function(data, status) {
if ( data === "FAIL" ) { if ( data === "FAIL" ) {
ok(true, "Opera is incapable of doing .setRequestHeader('If-None-Match')."); ok(jQuery.browser.opera, "Opera is incapable of doing .setRequestHeader('If-None-Match').");
ok(true, "Opera is incapable of doing .setRequestHeader('If-None-Match')."); ok(jQuery.browser.opera, "Opera is incapable of doing .setRequestHeader('If-None-Match').");
} else { } else {
equals(status, "notmodified"); equals(status, "notmodified");
ok(data == null, "response body should be empty"); ok(data == null, "response body should be empty");
@ -1959,6 +1967,7 @@ test("jQuery.ajax - Etag support", function() {
} }
}); });
}); });
});
test("jQuery ajax - failing cross-domain", function() { test("jQuery ajax - failing cross-domain", function() {