mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
bug 911325 - detect mismatch between 206 content-range and 200 content-length r=jduell
This commit is contained in:
parent
71a12b80e5
commit
947b301aa8
@ -2194,6 +2194,25 @@ nsHttpChannel::ProcessPartialContent()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int64_t cachedContentLength = mCachedResponseHead->ContentLength();
|
||||||
|
int64_t entitySize = mResponseHead->TotalEntitySize();
|
||||||
|
|
||||||
|
LOG(("nsHttpChannel::ProcessPartialContent [this=%p trans=%p] "
|
||||||
|
"original content-length %lld, entity-size %lld, content-range %s\n",
|
||||||
|
this, mTransaction.get(), cachedContentLength, entitySize,
|
||||||
|
mResponseHead->PeekHeader(nsHttp::Content_Range)));
|
||||||
|
|
||||||
|
if ((entitySize >= 0) && (cachedContentLength >= 0) &&
|
||||||
|
(entitySize != cachedContentLength)) {
|
||||||
|
LOG(("nsHttpChannel::ProcessPartialContent [this=%p] "
|
||||||
|
"206 has different total entity size than the content length "
|
||||||
|
"of the original partially cached entity.\n", this));
|
||||||
|
|
||||||
|
mCacheEntry->AsyncDoom(nullptr);
|
||||||
|
Cancel(NS_ERROR_CORRUPTED_CONTENT);
|
||||||
|
return CallOnStartRequest();
|
||||||
|
}
|
||||||
|
|
||||||
// suspend the current transaction
|
// suspend the current transaction
|
||||||
nsresult rv = mTransactionPump->Suspend();
|
nsresult rv = mTransactionPump->Suspend();
|
||||||
if (NS_FAILED(rv)) return rv;
|
if (NS_FAILED(rv)) return rv;
|
||||||
@ -5327,7 +5346,10 @@ nsHttpChannel::OnDataAvailable(nsIRequest *request, nsISupports *ctxt,
|
|||||||
|
|
||||||
uint64_t progressMax(uint64_t(mResponseHead->ContentLength()));
|
uint64_t progressMax(uint64_t(mResponseHead->ContentLength()));
|
||||||
uint64_t progress = mLogicalOffset + uint64_t(count);
|
uint64_t progress = mLogicalOffset + uint64_t(count);
|
||||||
MOZ_ASSERT(progress <= progressMax, "unexpected progress values");
|
|
||||||
|
if (progress > progressMax)
|
||||||
|
NS_WARNING("unexpected progress values - "
|
||||||
|
"is server exceeding content length?");
|
||||||
|
|
||||||
if (NS_IsMainThread()) {
|
if (NS_IsMainThread()) {
|
||||||
OnTransportStatus(nullptr, transportStatus, progress, progressMax);
|
OnTransportStatus(nullptr, transportStatus, progress, progressMax);
|
||||||
|
@ -11,6 +11,9 @@
|
|||||||
// 4) the cached entry does not have a Content-Encoding (see bug #613159)
|
// 4) the cached entry does not have a Content-Encoding (see bug #613159)
|
||||||
// 5) the request does not have a conditional-request header set by client
|
// 5) the request does not have a conditional-request header set by client
|
||||||
// 6) nsHttpResponseHead::IsResumable() is true for the cached entry
|
// 6) nsHttpResponseHead::IsResumable() is true for the cached entry
|
||||||
|
// 7) a basic positive test that makes sure byte ranges work
|
||||||
|
// 8) ensure NS_ERROR_CORRUPTED_CONTENT is thrown when total entity size
|
||||||
|
// of 206 does not match content-length of 200
|
||||||
//
|
//
|
||||||
// The test has one handler for each case and run_tests() fires one request
|
// The test has one handler for each case and run_tests() fires one request
|
||||||
// for each. None of the handlers should see a Range-header.
|
// for each. None of the handlers should see a Range-header.
|
||||||
@ -88,6 +91,28 @@ MyListener.prototype = {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
function FailedChannelListener(continueFn) {
|
||||||
|
this.continueFn = continueFn;
|
||||||
|
}
|
||||||
|
FailedChannelListener.prototype = {
|
||||||
|
QueryInterface: function(iid) {
|
||||||
|
if (iid.equals(Ci.nsIStreamListener) ||
|
||||||
|
iid.equals(Ci.nsIRequestObserver) ||
|
||||||
|
iid.equals(Ci.nsISupports))
|
||||||
|
return this;
|
||||||
|
throw Components.results.NS_ERROR_NO_INTERFACE;
|
||||||
|
},
|
||||||
|
onStartRequest: function(request, context) { },
|
||||||
|
|
||||||
|
onDataAvailable: function(request, context, stream, offset, count) { },
|
||||||
|
|
||||||
|
onStopRequest: function(request, context, status) {
|
||||||
|
do_check_eq(status, Components.results.NS_ERROR_CORRUPTED_CONTENT);
|
||||||
|
this.continueFn(request, null);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
function received_cleartext(request, data) {
|
function received_cleartext(request, data) {
|
||||||
do_check_eq(clearTextBody, data);
|
do_check_eq(clearTextBody, data);
|
||||||
testFinished();
|
testFinished();
|
||||||
@ -231,10 +256,93 @@ function received_partial_6(request, data) {
|
|||||||
chan.asyncOpen(new ChannelListener(received_cleartext, null), null);
|
chan.asyncOpen(new ChannelListener(received_cleartext, null), null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const simpleBody = "0123456789";
|
||||||
|
|
||||||
|
function received_simple(request, data) {
|
||||||
|
do_check_eq(simpleBody, data);
|
||||||
|
testFinished();
|
||||||
|
}
|
||||||
|
|
||||||
|
var case_7_request_no = 0;
|
||||||
|
function handler_7(metadata, response) {
|
||||||
|
switch (case_7_request_no) {
|
||||||
|
case 0:
|
||||||
|
do_check_false(metadata.hasHeader("Range"));
|
||||||
|
response.setHeader("Content-Type", "text/plain", false);
|
||||||
|
response.setHeader("ETag", "test7Etag");
|
||||||
|
response.setHeader("Accept-Ranges", "bytes");
|
||||||
|
response.setHeader("Cache-Control", "max-age=360000");
|
||||||
|
response.setHeader("Content-Length", "10");
|
||||||
|
response.processAsync();
|
||||||
|
response.bodyOutputStream.write(simpleBody.slice(0, 4), 4);
|
||||||
|
response.finish();
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
do_check_true(metadata.hasHeader("Range"));
|
||||||
|
do_check_true(metadata.hasHeader("If-Range"));
|
||||||
|
response.setStatusLine(metadata.httpVersion, 206, "Partial Content");
|
||||||
|
response.setHeader("Content-Type", "text/plain", false);
|
||||||
|
response.setHeader("ETag", "test7Etag");
|
||||||
|
response.setHeader("Accept-Ranges", "bytes");
|
||||||
|
response.setHeader("Content-Length", "6");
|
||||||
|
response.setHeader("Content-Range", "4-9/10");
|
||||||
|
response.bodyOutputStream.write(simpleBody.slice(4), 6);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
response.setStatusLine(metadata.httpVersion, 404, "Not Found");
|
||||||
|
}
|
||||||
|
case_7_request_no++;
|
||||||
|
}
|
||||||
|
function received_partial_7(request, data) {
|
||||||
|
// make sure we get the first 4 bytes
|
||||||
|
do_check_eq(4, data.length);
|
||||||
|
// do it again to get the rest
|
||||||
|
var chan = make_channel("http://localhost:" + port + "/test_7");
|
||||||
|
chan.asyncOpen(new ChannelListener(received_simple, null), null);
|
||||||
|
}
|
||||||
|
|
||||||
|
var case_8_request_no = 0;
|
||||||
|
function handler_8(metadata, response) {
|
||||||
|
switch (case_8_request_no) {
|
||||||
|
case 0:
|
||||||
|
do_check_false(metadata.hasHeader("Range"));
|
||||||
|
response.setHeader("Content-Type", "text/plain", false);
|
||||||
|
response.setHeader("ETag", "test8Etag");
|
||||||
|
response.setHeader("Accept-Ranges", "bytes");
|
||||||
|
response.setHeader("Cache-Control", "max-age=360000");
|
||||||
|
response.setHeader("Content-Length", "10");
|
||||||
|
response.processAsync();
|
||||||
|
response.bodyOutputStream.write(simpleBody.slice(0, 4), 4);
|
||||||
|
response.finish();
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
do_check_true(metadata.hasHeader("Range"));
|
||||||
|
do_check_true(metadata.hasHeader("If-Range"));
|
||||||
|
response.setStatusLine(metadata.httpVersion, 206, "Partial Content");
|
||||||
|
response.setHeader("Content-Type", "text/plain", false);
|
||||||
|
response.setHeader("ETag", "test8Etag");
|
||||||
|
response.setHeader("Accept-Ranges", "bytes");
|
||||||
|
response.setHeader("Content-Length", "5");
|
||||||
|
response.setHeader("Content-Range", "4-8/9"); // intentionally broken
|
||||||
|
response.bodyOutputStream.write(simpleBody.slice(4), 5);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
response.setStatusLine(metadata.httpVersion, 404, "Not Found");
|
||||||
|
}
|
||||||
|
case_8_request_no++;
|
||||||
|
}
|
||||||
|
function received_partial_8(request, data) {
|
||||||
|
// make sure we get the first 4 bytes
|
||||||
|
do_check_eq(4, data.length);
|
||||||
|
// do it again to get the rest
|
||||||
|
var chan = make_channel("http://localhost:" + port + "/test_8");
|
||||||
|
chan.asyncOpen(new FailedChannelListener(testFinished, null, CL_EXPECT_LATE_FAILURE), null);
|
||||||
|
}
|
||||||
|
|
||||||
// Simple mechanism to keep track of tests and stop the server
|
// Simple mechanism to keep track of tests and stop the server
|
||||||
var numTestsFinished = 0;
|
var numTestsFinished = 0;
|
||||||
function testFinished() {
|
function testFinished() {
|
||||||
if (++numTestsFinished == 5)
|
if (++numTestsFinished == 7)
|
||||||
httpserver.stop(do_test_finished);
|
httpserver.stop(do_test_finished);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -245,6 +353,8 @@ function run_test() {
|
|||||||
httpserver.registerPathHandler("/test_4", handler_4);
|
httpserver.registerPathHandler("/test_4", handler_4);
|
||||||
httpserver.registerPathHandler("/test_5", handler_5);
|
httpserver.registerPathHandler("/test_5", handler_5);
|
||||||
httpserver.registerPathHandler("/test_6", handler_6);
|
httpserver.registerPathHandler("/test_6", handler_6);
|
||||||
|
httpserver.registerPathHandler("/test_7", handler_7);
|
||||||
|
httpserver.registerPathHandler("/test_8", handler_8);
|
||||||
httpserver.start(-1);
|
httpserver.start(-1);
|
||||||
|
|
||||||
port = httpserver.identity.primaryPort;
|
port = httpserver.identity.primaryPort;
|
||||||
@ -272,5 +382,13 @@ function run_test() {
|
|||||||
var chan = make_channel("http://localhost:" + port + "/test_6");
|
var chan = make_channel("http://localhost:" + port + "/test_6");
|
||||||
chan.asyncOpen(new MyListener(received_partial_6), null);
|
chan.asyncOpen(new MyListener(received_partial_6), null);
|
||||||
|
|
||||||
|
// Case 7: a basic positive test
|
||||||
|
var chan = make_channel("http://localhost:" + port + "/test_7");
|
||||||
|
chan.asyncOpen(new MyListener(received_partial_7), null);
|
||||||
|
|
||||||
|
// Case 8: check that mismatched 206 and 200 sizes throw error
|
||||||
|
var chan = make_channel("http://localhost:" + port + "/test_8");
|
||||||
|
chan.asyncOpen(new MyListener(received_partial_8), null);
|
||||||
|
|
||||||
do_test_pending();
|
do_test_pending();
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user