Commit 91bca10f authored by dmurph@chromium.org's avatar dmurph@chromium.org

Request construction spec changes to use the 'used' flag.

This adds the following behavior:
1. If input is a Request object, run these substeps:
  1. If input's used flag is set, throw a TypeError.
  2. Set input's used flag.

Outlined in this change:
https://github.com/whatwg/fetch/commit/a898f9a2941350aa625aa79b24673628ac2b2a8e#diff-1feda49b40370635faef8b655f144f64R2681

Spec:
http://fetch.spec.whatwg.org/#dom-request

BUG=413072

Review URL: https://codereview.chromium.org/562413003

git-svn-id: svn://svn.chromium.org/blink/trunk@181934 bbb929c8-8fbe-4397-9dbb-9b2b20218538
parent bf044902
...@@ -97,6 +97,10 @@ test(function() { ...@@ -97,6 +97,10 @@ test(function() {
assert_equals(request1.mode, mode1 ? mode1 : 'cors', 'Request.mode should match'); assert_equals(request1.mode, mode1 ? mode1 : 'cors', 'Request.mode should match');
METHODS.forEach(function(method2) { METHODS.forEach(function(method2) {
MODES.forEach(function(mode2) { MODES.forEach(function(mode2) {
// We need to construct a new request1 because as soon as it
// is used in a constructor it will be flagged as 'used',
// and we can no longer construct objects with it.
request1 = new Request(URL, init1);
var init2 = {}; var init2 = {};
if (method2 != undefined) { init2['method'] = method2; } if (method2 != undefined) { init2['method'] = method2; }
if (mode2 != undefined) { init2['mode'] = mode2; } if (mode2 != undefined) { init2['mode'] = mode2; }
...@@ -132,6 +136,7 @@ test(function() { ...@@ -132,6 +136,7 @@ test(function() {
request1 = new Request(request1); request1 = new Request(request1);
assert_equals(request1.credentials, credentials1 ? credentials1 : 'omit', 'Request.credentials should match'); assert_equals(request1.credentials, credentials1 ? credentials1 : 'omit', 'Request.credentials should match');
CREDENTIALS.forEach(function(credentials2) { CREDENTIALS.forEach(function(credentials2) {
request1 = new Request(URL, init1);
var init2 = {}; var init2 = {};
if (credentials2 != undefined) { init2['credentials'] = credentials2; } if (credentials2 != undefined) { init2['credentials'] = credentials2; }
request2 = new Request(request1, init2); request2 = new Request(request1, init2);
...@@ -284,6 +289,21 @@ test(function() { ...@@ -284,6 +289,21 @@ test(function() {
}); });
}, 'Request method names are normalized'); }, 'Request method names are normalized');
test(function() {
var req = new Request(URL);
assert_false(req.bodyUsed,
"Request should not be flagged as used if it has not been consumed.");
var req2 = new Request(req);
assert_true(req.bodyUsed,
"Request should be flagged as used if it is used as a construction " +
"argument of another Request.");
assert_false(req2.bodyUsed,
"Request should not be flagged as used if it has not been consumed.");
assert_throws(new TypeError(), function() { new Request(req); },
"Request cannot be constructed with a request that has been flagged as used.");
}, 'Request construction behavior regarding "used" body flag and exceptions.');
async_test(function(t) { async_test(function(t) {
var getContentType = function(headers) { var getContentType = function(headers) {
var content_type = ''; var content_type = '';
......
...@@ -107,6 +107,11 @@ bool Body::bodyUsed() const ...@@ -107,6 +107,11 @@ bool Body::bodyUsed() const
return m_bodyUsed; return m_bodyUsed;
} }
void Body::setBodyUsed()
{
m_bodyUsed = true;
}
void Body::stop() void Body::stop()
{ {
// Canceling the load will call didFail which will remove the resolver. // Canceling the load will call didFail which will remove the resolver.
......
...@@ -50,6 +50,11 @@ public: ...@@ -50,6 +50,11 @@ public:
virtual void trace(Visitor*) { } virtual void trace(Visitor*) { }
protected:
// Sets the bodyUsed flag to true. This signifies that the contents of the
// body have been consumed and cannot be accessed again.
void setBodyUsed();
private: private:
ScriptPromise readAsync(ScriptState*, ResponseType); ScriptPromise readAsync(ScriptState*, ResponseType);
void resolveJSON(); void resolveJSON();
......
...@@ -46,9 +46,9 @@ private: ...@@ -46,9 +46,9 @@ private:
Request* createRequestWithRequestData(ExecutionContext* context, FetchRequestData* request, const RequestInit& init, FetchRequestData::Mode mode, FetchRequestData::Credentials credentials, ExceptionState& exceptionState) Request* createRequestWithRequestData(ExecutionContext* context, FetchRequestData* request, const RequestInit& init, FetchRequestData::Mode mode, FetchRequestData::Credentials credentials, ExceptionState& exceptionState)
{ {
// "6. Let |mode| be |init|'s mode member if it is present, and // "7. Let |mode| be |init|'s mode member if it is present, and
// |fallbackMode| otherwise." // |fallbackMode| otherwise."
// "7. If |mode| is non-null, set |request|'s mode to |mode|." // "8. If |mode| is non-null, set |request|'s mode to |mode|."
if (init.mode == "same-origin") { if (init.mode == "same-origin") {
request->setMode(FetchRequestData::SameOriginMode); request->setMode(FetchRequestData::SameOriginMode);
} else if (init.mode == "no-cors") { } else if (init.mode == "no-cors") {
...@@ -61,9 +61,9 @@ Request* createRequestWithRequestData(ExecutionContext* context, FetchRequestDat ...@@ -61,9 +61,9 @@ Request* createRequestWithRequestData(ExecutionContext* context, FetchRequestDat
request->setMode(mode); request->setMode(mode);
} }
// "8. Let |credentials| be |init|'s credentials member if it is present, // "9. Let |credentials| be |init|'s credentials member if it is present,
// and |fallbackCredentials| otherwise." // and |fallbackCredentials| otherwise."
// "9. If |credentials| is non-null, set |request|'s credentials mode to // "10. If |credentials| is non-null, set |request|'s credentials mode to
// |credentials|. // |credentials|.
if (init.credentials == "omit") { if (init.credentials == "omit") {
request->setCredentials(FetchRequestData::OmitCredentials); request->setCredentials(FetchRequestData::OmitCredentials);
...@@ -77,7 +77,7 @@ Request* createRequestWithRequestData(ExecutionContext* context, FetchRequestDat ...@@ -77,7 +77,7 @@ Request* createRequestWithRequestData(ExecutionContext* context, FetchRequestDat
request->setCredentials(credentials); request->setCredentials(credentials);
} }
// "10. If |init|'s method member is present, let |method| be it and run // "11. If |init|'s method member is present, let |method| be it and run
// these substeps:" // these substeps:"
if (!init.method.isEmpty()) { if (!init.method.isEmpty()) {
// "1. If |method| is not a useful method, throw a TypeError." // "1. If |method| is not a useful method, throw a TypeError."
...@@ -93,12 +93,12 @@ Request* createRequestWithRequestData(ExecutionContext* context, FetchRequestDat ...@@ -93,12 +93,12 @@ Request* createRequestWithRequestData(ExecutionContext* context, FetchRequestDat
// "3. Set |request|'s method to |method|." // "3. Set |request|'s method to |method|."
request->setMethod(XMLHttpRequest::uppercaseKnownHTTPMethod(AtomicString(init.method))); request->setMethod(XMLHttpRequest::uppercaseKnownHTTPMethod(AtomicString(init.method)));
} }
// "11. Let |r| be a new Request object associated with |request|, Headers // "12. Let |r| be a new Request object associated with |request|, Headers
// object." // object."
Request* r = Request::create(context, request); Request* r = Request::create(context, request);
// "12. Let |headers| be a copy of |r|'s Headers object." // "13. Let |headers| be a copy of |r|'s Headers object."
// "13. If |init|'s headers member is present, set |headers| to |init|'s // "14. If |init|'s headers member is present, set |headers| to |init|'s
// headers member." // headers member."
// We don't create a copy of r's Headers object when init's headers member // We don't create a copy of r's Headers object when init's headers member
// is present. // is present.
...@@ -106,10 +106,10 @@ Request* createRequestWithRequestData(ExecutionContext* context, FetchRequestDat ...@@ -106,10 +106,10 @@ Request* createRequestWithRequestData(ExecutionContext* context, FetchRequestDat
if (!init.headers && init.headersDictionary.isUndefinedOrNull()) { if (!init.headers && init.headersDictionary.isUndefinedOrNull()) {
headers = r->headers()->createCopy(); headers = r->headers()->createCopy();
} }
// "14. Empty |r|'s request's header list." // "15. Empty |r|'s request's header list."
r->request()->headerList()->clearList(); r->request()->headerList()->clearList();
// "15. If |r|'s request's mode is no CORS, run these substeps: // "16. If |r|'s request's mode is no CORS, run these substeps:
if (r->request()->mode() == FetchRequestData::NoCORSMode) { if (r->request()->mode() == FetchRequestData::NoCORSMode) {
// "1. If |r|'s request's method is not a simple method, throw a // "1. If |r|'s request's method is not a simple method, throw a
// TypeError." // TypeError."
...@@ -121,7 +121,7 @@ Request* createRequestWithRequestData(ExecutionContext* context, FetchRequestDat ...@@ -121,7 +121,7 @@ Request* createRequestWithRequestData(ExecutionContext* context, FetchRequestDat
r->headers()->setGuard(Headers::RequestNoCORSGuard); r->headers()->setGuard(Headers::RequestNoCORSGuard);
} }
// "16. Fill |r|'s Headers object with |headers|. Rethrow any exceptions." // "17. Fill |r|'s Headers object with |headers|. Rethrow any exceptions."
if (init.headers) { if (init.headers) {
ASSERT(init.headersDictionary.isUndefinedOrNull()); ASSERT(init.headersDictionary.isUndefinedOrNull());
r->headers()->fillWith(init.headers.get(), exceptionState); r->headers()->fillWith(init.headers.get(), exceptionState);
...@@ -133,7 +133,7 @@ Request* createRequestWithRequestData(ExecutionContext* context, FetchRequestDat ...@@ -133,7 +133,7 @@ Request* createRequestWithRequestData(ExecutionContext* context, FetchRequestDat
} }
if (exceptionState.hadException()) if (exceptionState.hadException())
return 0; return 0;
// "17. If |init|'s body member is present, run these substeps:" // "18. If |init|'s body member is present, run these substeps:"
if (init.bodyBlobHandle) { if (init.bodyBlobHandle) {
// "1. Let |stream| and |Content-Type| be the result of extracting // "1. Let |stream| and |Content-Type| be the result of extracting
// |init|'s body member." // |init|'s body member."
...@@ -149,11 +149,11 @@ Request* createRequestWithRequestData(ExecutionContext* context, FetchRequestDat ...@@ -149,11 +149,11 @@ Request* createRequestWithRequestData(ExecutionContext* context, FetchRequestDat
if (exceptionState.hadException()) if (exceptionState.hadException())
return 0; return 0;
} }
// "18. Set |r|'s MIME type to the result of extracting a MIME type from // "19. Set |r|'s MIME type to the result of extracting a MIME type from
// |r|'s request's header list." // |r|'s request's header list."
// FIXME: We don't have MIME type in Request object yet. // FIXME: We don't have MIME type in Request object yet.
// "19. Return |r|." // "20. Return |r|."
return r; return r;
} }
...@@ -166,12 +166,12 @@ Request* Request::create(ExecutionContext* context, const String& input, Excepti ...@@ -166,12 +166,12 @@ Request* Request::create(ExecutionContext* context, const String& input, Excepti
Request* Request::create(ExecutionContext* context, const String& input, const Dictionary& init, ExceptionState& exceptionState) Request* Request::create(ExecutionContext* context, const String& input, const Dictionary& init, ExceptionState& exceptionState)
{ {
// "1. Let |request| be |input|'s associated request, if |input| is a // "2. Let |request| be |input|'s associated request, if |input| is a
// Request object, and a new request otherwise." // Request object, and a new request otherwise."
FetchRequestData* request(FetchRequestData::create(context)); FetchRequestData* request(FetchRequestData::create(context));
// "2. Set |request| to a restricted copy of itself." // "3. Set |request| to a restricted copy of itself."
request = request->createRestrictedCopy(context, SecurityOrigin::create(context->url())); request = request->createRestrictedCopy(context, SecurityOrigin::create(context->url()));
// "5. If |input| is a string, run these substeps:" // "6. If |input| is a string, run these substeps:"
// "1. Let |parsedURL| be the result of parsing |input| with entry settings // "1. Let |parsedURL| be the result of parsing |input| with entry settings
// object's API base URL." // object's API base URL."
KURL parsedURL = context->completeURL(input); KURL parsedURL = context->completeURL(input);
...@@ -194,12 +194,21 @@ Request* Request::create(ExecutionContext* context, Request* input, ExceptionSta ...@@ -194,12 +194,21 @@ Request* Request::create(ExecutionContext* context, Request* input, ExceptionSta
Request* Request::create(ExecutionContext* context, Request* input, const Dictionary& init, ExceptionState& exceptionState) Request* Request::create(ExecutionContext* context, Request* input, const Dictionary& init, ExceptionState& exceptionState)
{ {
// "1. Let |request| be |input|'s associated request, if |input| is a // "1. If input is a Request object, run these substeps:"
// " 1. If input's used flag is set, throw a TypeError."
// " 2. Set input's used flag."
if (input->bodyUsed()) {
exceptionState.throwTypeError(
"Cannot construct a Request with a Request object that has already been used.");
return 0;
}
input->setBodyUsed();
// "2. Let |request| be |input|'s associated request, if |input| is a
// Request object, and a new request otherwise." // Request object, and a new request otherwise."
// "2. Set |request| to a restricted copy of itself." // "3. Set |request| to a restricted copy of itself."
FetchRequestData* request(input->request()->createRestrictedCopy(context, SecurityOrigin::create(context->url()))); FetchRequestData* request(input->request()->createRestrictedCopy(context, SecurityOrigin::create(context->url())));
// "3. Let |fallbackMode| be null." // "4. Let |fallbackMode| be null."
// "4. Let |fallbackCredentials| be null." // "5. Let |fallbackCredentials| be null."
// Instead of using null as a special fallback value, just pass the current // Instead of using null as a special fallback value, just pass the current
// mode and credentials; it has the same effect. // mode and credentials; it has the same effect.
const FetchRequestData::Mode currentMode = request->mode(); const FetchRequestData::Mode currentMode = request->mode();
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment