Bug 1198544 - Prevent FetchDriver from creating multiple responses if OnStopRequest yields a failing status code. r=nsm

This commit is contained in:
Josh Matthews 2015-09-14 11:05:35 -04:00
parent 41dfa34f29
commit 3ec4478d82
6 changed files with 67 additions and 10 deletions

View File

@ -72,7 +72,7 @@ public:
}
void
OnResponseAvailable(InternalResponse* aResponse) override;
OnResponseAvailableInternal(InternalResponse* aResponse) override;
void
OnResponseEnd() override;
@ -99,7 +99,7 @@ public:
explicit MainThreadFetchResolver(Promise* aPromise);
void
OnResponseAvailable(InternalResponse* aResponse) override;
OnResponseAvailableInternal(InternalResponse* aResponse) override;
private:
~MainThreadFetchResolver();
@ -237,7 +237,7 @@ MainThreadFetchResolver::MainThreadFetchResolver(Promise* aPromise)
}
void
MainThreadFetchResolver::OnResponseAvailable(InternalResponse* aResponse)
MainThreadFetchResolver::OnResponseAvailableInternal(InternalResponse* aResponse)
{
NS_ASSERT_OWNINGTHREAD(MainThreadFetchResolver);
AssertIsOnMainThread();
@ -317,7 +317,7 @@ public:
};
void
WorkerFetchResolver::OnResponseAvailable(InternalResponse* aResponse)
WorkerFetchResolver::OnResponseAvailableInternal(InternalResponse* aResponse)
{
AssertIsOnMainThread();

View File

@ -884,13 +884,19 @@ FetchDriver::OnStopRequest(nsIRequest* aRequest,
nsresult aStatusCode)
{
workers::AssertIsOnMainThread();
if (mPipeOutputStream) {
mPipeOutputStream->Close();
if (NS_FAILED(aStatusCode)) {
nsCOMPtr<nsIAsyncOutputStream> outputStream = do_QueryInterface(mPipeOutputStream);
if (outputStream) {
outputStream->CloseWithStatus(NS_BINDING_FAILED);
}
// We proceed as usual here, since we've already created a successful response
// from OnStartRequest.
SucceedWithResponse();
return aStatusCode;
}
if (NS_FAILED(aStatusCode)) {
FailWithNetworkError();
return aStatusCode;
if (mPipeOutputStream) {
mPipeOutputStream->Close();
}
ContinueHttpFetchAfterNetworkFetch();

View File

@ -32,14 +32,27 @@ class InternalResponse;
class FetchDriverObserver
{
public:
FetchDriverObserver() : mGotResponseAvailable(false)
{ }
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(FetchDriverObserver);
virtual void OnResponseAvailable(InternalResponse* aResponse) = 0;
void OnResponseAvailable(InternalResponse* aResponse)
{
MOZ_ASSERT(!mGotResponseAvailable);
mGotResponseAvailable = true;
OnResponseAvailableInternal(aResponse);
}
virtual void OnResponseEnd()
{ };
protected:
virtual ~FetchDriverObserver()
{ };
virtual void OnResponseAvailableInternal(InternalResponse* aResponse) = 0;
private:
bool mGotResponseAvailable;
};
class FetchDriver final : public nsIStreamListener,

View File

@ -319,6 +319,23 @@ fetch(new Request('body-blob', {method: 'POST', body: new Blob(new String('my bo
finish();
});
expectAsyncResult();
fetch('interrupt.sjs')
.then(function(res) {
my_ok(true, "interrupted fetch succeeded");
res.text().then(function(body) {
my_ok(false, "interrupted fetch shouldn't have complete body");
finish();
},
function() {
my_ok(true, "interrupted fetch shouldn't have complete body");
finish();
})
}, function(e) {
my_ok(false, "interrupted fetch failed");
finish();
});
['DELETE', 'GET', 'HEAD', 'OPTIONS', 'POST', 'PUT'].forEach(function(method) {
fetchXHRWithMethod('xhr-method-test.txt', method, function(xhr) {
my_ok(xhr.status == 200, method + " load should be successful");

View File

@ -0,0 +1,20 @@
function handleRequest(request, response) {
var body = "a";
for (var i = 0; i < 20; i++) {
body += body;
}
response.seizePower();
response.write("HTTP/1.1 200 OK\r\n")
var count = 10;
response.write("Content-Length: " + body.length * count + "\r\n");
response.write("Content-Type: text/plain; charset=utf-8\r\n");
response.write("Cache-Control: no-cache, must-revalidate\r\n");
response.write("\r\n");
for (var i = 0; i < count; i++) {
response.write(body);
}
throw Components.results.NS_BINDING_ABORTED;
}

View File

@ -50,6 +50,7 @@ support-files =
fetch/https/clonedresponse/register.html
fetch/https/clonedresponse/unregister.html
fetch/https/clonedresponse/https_test.js
fetch/interrupt.sjs
fetch/origin/index.sjs
fetch/origin/index-to-https.sjs
fetch/origin/realindex.html