Bug 1134609 -Make Fetch Request constructor less destructive to input on error r=bkelly

This commit is contained in:
Antonio de Luna Lopez 2015-08-10 12:06:00 -07:00
parent da9b9d9f75
commit de40152198
4 changed files with 35 additions and 9 deletions

View File

@ -319,7 +319,7 @@ public:
SetBody(nsIInputStream* aStream)
{
// A request's body may not be reset once set.
MOZ_ASSERT(!mBodyStream);
MOZ_ASSERT_IF(aStream, !mBodyStream);
mBodyStream = aStream;
}

View File

@ -163,8 +163,8 @@ Request::Constructor(const GlobalObject& aGlobal,
const RequestOrUSVString& aInput,
const RequestInit& aInit, ErrorResult& aRv)
{
nsCOMPtr<nsIInputStream> temporaryBody;
nsRefPtr<InternalRequest> request;
bool inputRequestHasBody = false;
nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(aGlobal.GetAsSupports());
@ -173,13 +173,11 @@ Request::Constructor(const GlobalObject& aGlobal,
nsCOMPtr<nsIInputStream> body;
inputReq->GetBody(getter_AddRefs(body));
if (body) {
inputRequestHasBody = true;
if (inputReq->BodyUsed()) {
aRv.ThrowTypeError(MSG_FETCH_BODY_CONSUMED_ERROR);
return nullptr;
} else {
inputReq->SetBodyUsed();
}
temporaryBody = body;
}
request = inputReq->GetInternalRequest();
@ -327,7 +325,7 @@ Request::Constructor(const GlobalObject& aGlobal,
return nullptr;
}
if (aInit.mBody.WasPassed() || inputRequestHasBody) {
if (aInit.mBody.WasPassed() || temporaryBody) {
// HEAD and GET are not allowed to have a body.
nsAutoCString method;
request->GetMethod(method);
@ -347,8 +345,8 @@ Request::Constructor(const GlobalObject& aGlobal,
if (NS_WARN_IF(aRv.Failed())) {
return nullptr;
}
request->ClearCreatedByFetchEvent();
request->SetBody(stream);
temporaryBody = stream;
if (!contentType.IsVoid() &&
!requestHeaders->Has(NS_LITERAL_CSTRING("Content-Type"), aRv)) {
@ -356,13 +354,26 @@ Request::Constructor(const GlobalObject& aGlobal,
contentType, aRv);
}
if (aRv.Failed()) {
if (NS_WARN_IF(aRv.Failed())) {
return nullptr;
}
request->ClearCreatedByFetchEvent();
request->SetBody(temporaryBody);
}
nsRefPtr<Request> domRequest = new Request(global, request);
domRequest->SetMimeType();
if (aInput.IsRequest()) {
nsRefPtr<Request> inputReq = &aInput.GetAsRequest();
nsCOMPtr<nsIInputStream> body;
inputReq->GetBody(getter_AddRefs(body));
if (body) {
inputReq->SetBody(nullptr);
inputReq->SetBodyUsed();
}
}
return domRequest.forget();
}

View File

@ -105,6 +105,9 @@ public:
void
GetBody(nsIInputStream** aStream) { return mRequest->GetBody(aStream); }
void
SetBody(nsIInputStream* aStream) { return mRequest->SetBody(aStream); }
static already_AddRefed<Request>
Constructor(const GlobalObject& aGlobal, const RequestOrUSVString& aInput,
const RequestInit& aInit, ErrorResult& rv);

View File

@ -456,6 +456,17 @@ function testBug1154268() {
});
}
function testRequestConsumedByFailedConstructor(){
var r1 = new Request('http://example.com', { method: 'POST', body: 'hello world' });
try{
var r2 = new Request(r1, { method: 'GET' });
ok(false, 'GET Request copied from POST Request with body should fail.');
} catch(e) {
ok(true, 'GET Request copied from POST Request with body should fail.');
}
ok(!r1.bodyUsed, 'Initial request should not be consumed by failed Request constructor');
}
function runTest() {
testDefaultCtor();
testSimpleUrlParse();
@ -465,6 +476,7 @@ function runTest() {
testHeaderGuard();
testModeCorsPreflightEnumValue();
testBug1154268();
testRequestConsumedByFailedConstructor();
return Promise.resolve()
.then(testBodyCreation)