зеркало из https://github.com/mozilla/gecko-dev.git
bug 717350 doom cache entry on last-modified mismatch r=honzab
--HG-- extra : rebase_source : 5c8692c94bf7e5dcb2d381a85e06bddbabffe22c
This commit is contained in:
Родитель
5f20e88e8c
Коммит
b4527a1fee
|
@ -1973,6 +1973,33 @@ nsHttpChannel::ProcessNotModified()
|
||||||
NS_ENSURE_TRUE(mCachedResponseHead, NS_ERROR_NOT_INITIALIZED);
|
NS_ENSURE_TRUE(mCachedResponseHead, NS_ERROR_NOT_INITIALIZED);
|
||||||
NS_ENSURE_TRUE(mCacheEntry, NS_ERROR_NOT_INITIALIZED);
|
NS_ENSURE_TRUE(mCacheEntry, NS_ERROR_NOT_INITIALIZED);
|
||||||
|
|
||||||
|
// If the 304 response contains a Last-Modified different than the
|
||||||
|
// one in our cache that is pretty suspicious and is, in at least the
|
||||||
|
// case of bug 716840, a sign of the server having previously corrupted
|
||||||
|
// our cache with a bad response. Take the minor step here of just dooming
|
||||||
|
// that cache entry so there is a fighting chance of getting things on the
|
||||||
|
// right track as well as disabling pipelining for that host.
|
||||||
|
|
||||||
|
nsCAutoString lastModified;
|
||||||
|
nsCAutoString lastModified304;
|
||||||
|
|
||||||
|
rv = mCachedResponseHead->GetHeader(nsHttp::Last_Modified,
|
||||||
|
lastModified);
|
||||||
|
if (NS_SUCCEEDED(rv))
|
||||||
|
rv = mResponseHead->GetHeader(nsHttp::Last_Modified,
|
||||||
|
lastModified304);
|
||||||
|
if (NS_SUCCEEDED(rv) && !lastModified304.Equals(lastModified)) {
|
||||||
|
LOG(("Cache Entry and 304 Last-Modified Headers Do Not Match "
|
||||||
|
"%s and %s\n", lastModified.get(), lastModified304.get()));
|
||||||
|
|
||||||
|
mCacheEntry->Doom();
|
||||||
|
if (mConnectionInfo)
|
||||||
|
gHttpHandler->ConnMgr()->
|
||||||
|
PipelineFeedbackInfo(mConnectionInfo,
|
||||||
|
nsHttpConnectionMgr::RedCorruptedContent,
|
||||||
|
nsnull, 0);
|
||||||
|
}
|
||||||
|
|
||||||
// merge any new headers with the cached response headers
|
// merge any new headers with the cached response headers
|
||||||
rv = mCachedResponseHead->UpdateHeaders(mResponseHead->Headers());
|
rv = mCachedResponseHead->UpdateHeaders(mResponseHead->Headers());
|
||||||
if (NS_FAILED(rv)) return rv;
|
if (NS_FAILED(rv)) return rv;
|
||||||
|
|
|
@ -160,8 +160,9 @@ public:
|
||||||
// pipelining list is received
|
// pipelining list is received
|
||||||
RedBannedServer = kPipelineInfoTypeRed | kPipelineInfoTypeBad | 0x0002,
|
RedBannedServer = kPipelineInfoTypeRed | kPipelineInfoTypeBad | 0x0002,
|
||||||
|
|
||||||
// Used when a response is terminated early, or when it fails an
|
// Used when a response is terminated early, when it fails an
|
||||||
// integrity check such as assoc-req
|
// integrity check such as assoc-req or when a 304 contained a Last-Modified
|
||||||
|
// differnet than the entry being validated.
|
||||||
RedCorruptedContent = kPipelineInfoTypeRed | kPipelineInfoTypeBad | 0x0004,
|
RedCorruptedContent = kPipelineInfoTypeRed | kPipelineInfoTypeBad | 0x0004,
|
||||||
|
|
||||||
// Used when a pipeline is only partly satisfied - for instance if the
|
// Used when a pipeline is only partly satisfied - for instance if the
|
||||||
|
|
|
@ -0,0 +1,126 @@
|
||||||
|
do_load_httpd_js();
|
||||||
|
var httpserver = new nsHttpServer();
|
||||||
|
var cacheService;
|
||||||
|
var ios;
|
||||||
|
|
||||||
|
// Test the handling of a cache revalidation with mismatching last-modified
|
||||||
|
// headers. If we get such a revalidation the cache entry should be purged.
|
||||||
|
// see bug 717350
|
||||||
|
|
||||||
|
// In this test the wrong data is from 11-16-1994 with a value of 'A',
|
||||||
|
// and the right data is from 11-15-1994 with a value of 'B'.
|
||||||
|
|
||||||
|
// the same URL is requested 3 times. the first time the wrong data comes
|
||||||
|
// back, the second time that wrong data is revalidated with a 304 but
|
||||||
|
// a L-M header of the right data (this triggers a cache purge), and
|
||||||
|
// the third time the right data is returned.
|
||||||
|
|
||||||
|
var listener_3 = {
|
||||||
|
// this listener is used to process the the request made after
|
||||||
|
// the cache invalidation. it expects to see the 'right data'
|
||||||
|
|
||||||
|
onStartRequest: function test_onStartR(request, ctx) {},
|
||||||
|
|
||||||
|
onDataAvailable: function test_ODA(request, cx, inputStream,
|
||||||
|
offset, count) {
|
||||||
|
var data = new BinaryInputStream(inputStream).readByteArray(count);
|
||||||
|
|
||||||
|
// This is 'B'
|
||||||
|
do_check_eq(data, 66);
|
||||||
|
},
|
||||||
|
|
||||||
|
onStopRequest: function test_onStopR(request, ctx, status) {
|
||||||
|
httpserver.stop(do_test_finished);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var listener_2 = {
|
||||||
|
// this listener is used to process the revalidation of the
|
||||||
|
// corrupted cache entry. its revalidation prompts it to be cleaned
|
||||||
|
|
||||||
|
onStartRequest: function test_onStartR(request, ctx) {},
|
||||||
|
|
||||||
|
onDataAvailable: function test_ODA(request, cx, inputStream,
|
||||||
|
offset, count) {
|
||||||
|
var data = new BinaryInputStream(inputStream).readByteArray(count);
|
||||||
|
|
||||||
|
// This is 'A' from a cache revalidation, but that reval will clean the cache
|
||||||
|
// because of mismatched last-modified response headers
|
||||||
|
|
||||||
|
do_check_eq(data, 65);
|
||||||
|
},
|
||||||
|
|
||||||
|
onStopRequest: function test_onStopR(request, ctx, status) {
|
||||||
|
var channel = request.QueryInterface(Ci.nsIHttpChannel);
|
||||||
|
|
||||||
|
var chan = ios.newChannel("http://localhost:4444/test1", "", null);
|
||||||
|
var httpChan = chan.QueryInterface(Ci.nsIHttpChannel);
|
||||||
|
httpChan.requestMethod = "GET";
|
||||||
|
httpChan.asyncOpen(listener_3, null);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var listener_1 = {
|
||||||
|
// this listener processes the initial request from a empty cache.
|
||||||
|
// the server responds with the wrong data ('A')
|
||||||
|
|
||||||
|
onStartRequest: function test_onStartR(request, ctx) {},
|
||||||
|
|
||||||
|
onDataAvailable: function test_ODA(request, cx, inputStream,
|
||||||
|
offset, count) {
|
||||||
|
var data = new BinaryInputStream(inputStream).readByteArray(count);
|
||||||
|
do_check_eq(data, 65);
|
||||||
|
},
|
||||||
|
|
||||||
|
onStopRequest: function test_onStopR(request, ctx, status) {
|
||||||
|
var channel = request.QueryInterface(Ci.nsIHttpChannel);
|
||||||
|
|
||||||
|
var chan = ios.newChannel("http://localhost:4444/test1", "", null);
|
||||||
|
var httpChan = chan.QueryInterface(Ci.nsIHttpChannel);
|
||||||
|
httpChan.requestMethod = "GET";
|
||||||
|
httpChan.asyncOpen(listener_2, null);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
function run_test() {
|
||||||
|
do_get_profile();
|
||||||
|
cacheService = Cc["@mozilla.org/network/cache-service;1"].
|
||||||
|
getService(Ci.nsICacheService);
|
||||||
|
ios = Cc["@mozilla.org/network/io-service;1"]
|
||||||
|
.getService(Ci.nsIIOService);
|
||||||
|
|
||||||
|
cacheService.evictEntries(Ci.nsICache.STORE_ANYWHERE);
|
||||||
|
|
||||||
|
httpserver.registerPathHandler("/test1", handler);
|
||||||
|
httpserver.start(4444);
|
||||||
|
|
||||||
|
var chan = ios.newChannel("http://localhost:4444/test1", "", null);
|
||||||
|
var httpChan = chan.QueryInterface(Ci.nsIHttpChannel);
|
||||||
|
httpChan.requestMethod = "GET";
|
||||||
|
httpChan.asyncOpen(listener_1, null);
|
||||||
|
|
||||||
|
do_test_pending();
|
||||||
|
}
|
||||||
|
|
||||||
|
var iter=0;
|
||||||
|
function handler(metadata, response) {
|
||||||
|
iter++;
|
||||||
|
if (metadata.hasHeader("If-Modified-Since")) {
|
||||||
|
response.setStatusLine(metadata.httpVersion, 304, "Not Modified");
|
||||||
|
response.setHeader("Last-Modified", "Tue, 15 Nov 1994 12:45:26 GMT", false);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
response.setStatusLine(metadata.httpVersion, 200, "OK");
|
||||||
|
response.setHeader("Cache-Control", "max-age=0", false)
|
||||||
|
if (iter == 1) {
|
||||||
|
// simulated wrong response
|
||||||
|
response.setHeader("Last-Modified", "Wed, 16 Nov 1994 00:00:00 GMT", false);
|
||||||
|
response.bodyOutputStream.write("A", 1);
|
||||||
|
}
|
||||||
|
if (iter == 3) {
|
||||||
|
// 'correct' response
|
||||||
|
response.setHeader("Last-Modified", "Tue, 15 Nov 1994 12:45:26 GMT", false);
|
||||||
|
response.bodyOutputStream.write("B", 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -132,6 +132,7 @@ skip-if = os == "android"
|
||||||
[test_httpsuspend.js]
|
[test_httpsuspend.js]
|
||||||
[test_idnservice.js]
|
[test_idnservice.js]
|
||||||
[test_localstreams.js]
|
[test_localstreams.js]
|
||||||
|
[test_mismatch_lm.js]
|
||||||
[test_MIME_params.js]
|
[test_MIME_params.js]
|
||||||
[test_multipart_streamconv.js]
|
[test_multipart_streamconv.js]
|
||||||
[test_multipart_streamconv_missing_lead_boundary.js]
|
[test_multipart_streamconv_missing_lead_boundary.js]
|
||||||
|
|
Загрузка…
Ссылка в новой задаче