Index: Source/modules/fetch/Request.cpp |
diff --git a/Source/modules/fetch/Request.cpp b/Source/modules/fetch/Request.cpp |
index af5c233853618bd09bcbf419ab42ad59049365c9..806a2961a06fb6eaa2882d1e18ccee85272c1bfd 100644 |
--- a/Source/modules/fetch/Request.cpp |
+++ b/Source/modules/fetch/Request.cpp |
@@ -28,7 +28,6 @@ FetchRequestData* createCopyOfFetchRequestDataForFetch(ExecutionContext* context |
request->setMethod(original->method()); |
request->setHeaderList(original->headerList()->clone()); |
request->setUnsafeRequestFlag(true); |
- request->setBlobDataHandle(original->blobDataHandle()); |
// FIXME: Set client. |
request->setOrigin(SecurityOrigin::create(context->url())); |
// FIXME: Set ForceOriginHeaderFlag. |
@@ -37,50 +36,57 @@ FetchRequestData* createCopyOfFetchRequestDataForFetch(ExecutionContext* context |
request->setMode(original->mode()); |
request->setCredentials(original->credentials()); |
// FIXME: Set cache mode. |
+ // TODO(yhirano): Set redirect mode. |
return request; |
} |
Request* Request::createRequestWithRequestOrString(ExecutionContext* context, Request* inputRequest, const String& inputString, const RequestInit& init, ExceptionState& exceptionState) |
{ |
- // "1. If input is a Request object, run these substeps:" |
- if (inputRequest) { |
- // "1. If input's used flag is set, throw a TypeError." |
+ // "1. Let |temporaryBody| be null." |
+ RefPtr<BlobDataHandle> temporaryBody; |
+ |
+ // "2. If |input| is a Request object and |input|'s body is non-null, run |
+ // these substeps:" |
+ if (inputRequest && inputRequest->hasBody()) { |
+ // "1. If |input|'s used flag is set, throw a TypeError." |
+ // "2. Set |temporaryBody| to |input|'s body." |
if (inputRequest->bodyUsed()) { |
exceptionState.throwTypeError("Cannot construct a Request with a Request object that has already been used."); |
- return 0; |
+ return nullptr; |
+ } |
+ if (inputRequest->isBodyConsumed()) { |
+ // Currently the only methods that can consume body data without |
+ // setting 'body passed' flag consume entire body (e.g. text()). |
+ // Thus we can set an empty blob to the new request instead of |
+ // creating a draining stream. |
+ // TODO(yhirano): Fix this once Request.body is introduced. |
+ OwnPtr<BlobData> blobData = BlobData::create(); |
+ blobData->setContentType(inputRequest->blobDataHandle()->type()); |
+ temporaryBody = BlobDataHandle::create(blobData.release(), 0); |
+ } else { |
+ temporaryBody = inputRequest->m_request->blobDataHandle(); |
} |
- // "2. Set input's used flag." |
- inputRequest->lockBody(PassBody); |
} |
- // "2. Let |request| be |input|'s associated request, if |input| is a |
- // Request object, and a new request otherwise." |
- // "3. Set |request| to a new request whose url is |request|'s url, method |
+ // "3. Let |request| be |input|'s request, if |input| is a Request object, |
+ // and a new request otherwise." |
+ // "4. Set |request| to a new request whose url is |request|'s url, method |
// is |request|'s method, header list is a copy of |request|'s header list, |
- // unsafe request flag is set, body is |request|'s body, client is entry |
- // settings object, origin is entry settings object's origin, force Origin |
- // header flag is set, same-origin data URL flag is set, referrer is client, |
- // context is fetch, mode is |request|'s mode, credentials mode is |
- // |request|'s credentials mode, and cache mode is |request|'s cache mode." |
+ // unsafe request flag is set, client is entry settings object, origin is |
+ // entry settings object's origin, force Origin header flag is set, |
+ // same-origin data URL flag is set, context is the empty string, mode is |
+ // |request|'s mode, credentials mode is |request|'s credentials mode, |
+ // cache mode is |request|'s cache mode, and redirect mode is request's |
+ // redirect mode." |
FetchRequestData* request = createCopyOfFetchRequestDataForFetch(context, inputRequest ? inputRequest->request() : FetchRequestData::create()); |
- if (inputRequest && inputRequest->blobDataHandle() && inputRequest->isBodyConsumed()) { |
- // Currently the only methods that can consume body data without |
- // setting 'body passed' flag consume entire body (e.g. text()). Thus |
- // we can set an empty blob to the new request instead of creating a |
- // draining stream. |
- // TODO(yhirano): Fix this once Request.body is introduced. |
- OwnPtr<BlobData> blobData = BlobData::create(); |
- blobData->setContentType(inputRequest->blobDataHandle()->type()); |
- request->setBlobDataHandle(BlobDataHandle::create(blobData.release(), 0)); |
- } |
- |
- // "4. Let |fallbackMode| be null." |
- // "5. Let |fallbackCredentials| be null." |
- // "6. Let |fallbackCache| be null." |
+ // "5. Let |fallbackMode| be null." |
+ // "6. Let |fallbackCredentials| be null." |
+ // "7. Let |fallbackCache| be null." |
+ // "8. Let |fallbackRedirect| be null." |
// We don't use fallback values. We set these flags directly in below. |
- // "7. If |input| is a string, run these substeps:" |
+ // "9. If |input| is a string, run these substeps:" |
if (!inputRequest) { |
// "1. Let |parsedURL| be the result of parsing |input| with entry |
// settings object's API base URL." |
@@ -88,19 +94,22 @@ Request* Request::createRequestWithRequestOrString(ExecutionContext* context, Re |
// "2. If |parsedURL| is failure, throw a TypeError." |
if (!parsedURL.isValid()) { |
exceptionState.throwTypeError("Failed to parse URL from " + inputString); |
- return 0; |
+ return nullptr; |
} |
- // "3. Set |request|'s url to |parsedURL|." |
+ // TODO(yhirano): "3. If |parsedURL| includes credentials, throw a |
+ // TypeError." |
+ // "4. Set |request|'s url to |parsedURL|." |
request->setURL(parsedURL); |
- // "4. Set |fallbackMode| to CORS." |
- // "5. Set |fallbackCredentials| to omit." |
- // "6. Set |fallbackCache| to default." |
+ // "5. Set |fallbackMode| to CORS." |
+ // "6. Set |fallbackCredentials| to omit." |
+ // "7. Set |fallbackCache| to default." |
+ // "8. Set |fallbackRedirect| to follow." |
// We don't use fallback values. We set these flags directly in below. |
} |
- // "8. Let |mode| be |init|'s mode member if it is present, and |
+ // "10. Let |mode| be |init|'s mode member if it is present, and |
// |fallbackMode| otherwise." |
- // "9. If |mode| is non-null, set |request|'s mode to |mode|." |
+ // "11. If |mode| is non-null, set |request|'s mode to |mode|." |
if (init.mode == "same-origin") { |
request->setMode(WebURLRequest::FetchRequestModeSameOrigin); |
} else if (init.mode == "no-cors") { |
@@ -112,9 +121,9 @@ Request* Request::createRequestWithRequestOrString(ExecutionContext* context, Re |
request->setMode(WebURLRequest::FetchRequestModeCORS); |
} |
- // "10. Let |credentials| be |init|'s credentials member if it is present, |
+ // "12. Let |credentials| be |init|'s credentials member if it is present, |
// and |fallbackCredentials| otherwise." |
- // "11. If |credentials| is non-null, set |request|'s credentials mode to |
+ // "13. If |credentials| is non-null, set |request|'s credentials mode to |
// |credentials|. |
if (init.credentials == "omit") { |
request->setCredentials(WebURLRequest::FetchCredentialsModeOmit); |
@@ -127,54 +136,62 @@ Request* Request::createRequestWithRequestOrString(ExecutionContext* context, Re |
request->setCredentials(WebURLRequest::FetchCredentialsModeOmit); |
} |
- // FIXME: "12. Let |cache| be |init|'s cache member if it is present, and |
+ // FIXME: "14. Let |cache| be |init|'s cache member if it is present, and |
// |fallbackCache| otherwise." |
- // FIXME: "13. If |cache| is non-null, set |request|'s cache mode to |
+ // FIXME: "15. If |cache| is non-null, set |request|'s cache mode to |
// |cache|." |
- |
- // "14. If |init|'s method member is present, let |method| be it and run |
+ // TODO(yhirano): "16. If |init|'s redirect member is present and its is |
+ // manual, throw a TypeError." |
+ // TODO(yhirano): "17. Let |redirect| be |init|'s redirect member if it is |
+ // present, and |fallbackRedirect| otherwise." |
+ // TODO(yhirano): "18 If |redirect| is non-null, set |request|'s redirect |
+ // mode to |redirect|." |
+ // TODO(yhirano): "19 If |request|'s redirect mode is manual, set it to |
+ // follow." |
+ |
+ // "20. If |init|'s method member is present, let |method| be it and run |
// these substeps:" |
if (!init.method.isNull()) { |
// "1. If |method| is not a method or method is a forbidden method, |
// throw a TypeError." |
if (!isValidHTTPToken(init.method)) { |
exceptionState.throwTypeError("'" + init.method + "' is not a valid HTTP method."); |
- return 0; |
+ return nullptr; |
} |
if (FetchUtils::isForbiddenMethod(init.method)) { |
exceptionState.throwTypeError("'" + init.method + "' HTTP method is unsupported."); |
- return 0; |
+ return nullptr; |
} |
// "2. Normalize |method|." |
// "3. Set |request|'s method to |method|." |
request->setMethod(FetchUtils::normalizeMethod(AtomicString(init.method))); |
} |
- // "15. Let |r| be a new Request object associated with |request|, and a new |
- // Headers object." |
+ // "21. Let |r| be a new Request object associated with |request| and a new |
+ // Headers object whose guard is request." |
Request* r = Request::create(context, request); |
- // "16. Let |headers| be a copy of |r|'s Headers object." |
- // "17. If |init|'s headers member is present, set |headers| to |init|'s |
+ // "22. Let |headers| be a copy of |r|'s Headers object." |
+ // "23. If |init|'s headers member is present, set |headers| to |init|'s |
// headers member." |
// We don't create a copy of r's Headers object when init's headers member |
// is present. |
- Headers* headers = 0; |
+ Headers* headers = nullptr; |
if (!init.headers && init.headersDictionary.isUndefinedOrNull()) { |
headers = r->headers()->clone(); |
} |
- // "18. Empty |r|'s request's header list." |
+ // "24. Empty |r|'s request's header list." |
r->clearHeaderList(); |
- // "19. If |r|'s request's mode is no CORS, run these substeps: |
+ // "25. If |r|'s request's mode is no CORS, run these substeps: |
if (r->request()->mode() == WebURLRequest::FetchRequestModeNoCORS) { |
// "1. If |r|'s request's method is not a simple method, throw a |
// TypeError." |
if (!FetchUtils::isSimpleMethod(r->request()->method())) { |
exceptionState.throwTypeError("'" + r->request()->method() + "' is unsupported in no-cors mode."); |
- return 0; |
+ return nullptr; |
} |
// "Set |r|'s Headers object's guard to |request-no-CORS|. |
r->headers()->setGuard(Headers::RequestNoCORSGuard); |
} |
- // "20. Fill |r|'s Headers object with |headers|. Rethrow any exceptions." |
+ // "26. Fill |r|'s Headers object with |headers|. Rethrow any exceptions." |
if (init.headers) { |
ASSERT(init.headersDictionary.isUndefinedOrNull()); |
r->headers()->fillWith(init.headers.get(), exceptionState); |
@@ -185,34 +202,51 @@ Request* Request::createRequestWithRequestOrString(ExecutionContext* context, Re |
r->headers()->fillWith(headers, exceptionState); |
} |
if (exceptionState.hadException()) |
- return 0; |
+ return nullptr; |
+ |
+ // "27. If either |init|'s body member is present or |temporaryBody| is |
+ // non-null, and |request|'s method is `GET` or `HEAD`, throw a TypeError. |
+ if (init.bodyBlobHandle || temporaryBody) { |
+ if (request->method() == "GET" || request->method() == "HEAD") { |
+ exceptionState.throwTypeError("Request with GET/HEAD method cannot have body."); |
+ return nullptr; |
+ } |
+ } |
- // "21. If |init|'s body member is present, run these substeps:" |
+ // "28. If |init|'s body member is present, run these substeps:" |
if (init.bodyBlobHandle) { |
- // "1. If request's method is `GET` or `HEAD`, throw a TypeError." |
- // "2. 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." |
- // "3. Set |r|'s request's body to |stream|." |
- // "4. If |Content-Type| is non-null and |r|'s request's header list |
+ // "2. Set |temporaryBody| to |stream|. |
+ // "3. If |Content-Type| is non-null and |r|'s request's header list |
// contains no header named `Content-Type`, append |
// `Content-Type`/|Content-Type| to |r|'s Headers object. Rethrow any |
// exception." |
- if (request->method() == "GET" || request->method() == "HEAD") { |
- exceptionState.throwTypeError("Request with GET/HEAD method cannot have body."); |
- return 0; |
- } |
- r->setBodyBlobHandle(init.bodyBlobHandle); |
+ temporaryBody = init.bodyBlobHandle; |
if (!init.bodyBlobHandle->type().isEmpty() && !r->headers()->has("Content-Type", exceptionState)) { |
r->headers()->append("Content-Type", init.bodyBlobHandle->type(), exceptionState); |
} |
if (exceptionState.hadException()) |
- return 0; |
+ return nullptr; |
} |
- // "22. Set |r|'s MIME type to the result of extracting a MIME type from |
+ |
+ // "29. Set |r|'s body to |temporaryBody|. |
+ r->setBodyBlobHandle(temporaryBody.release()); |
+ |
+ // "30. Set |r|'s MIME type to the result of extracting a MIME type from |
// |r|'s request's header list." |
r->m_request->setMIMEType(r->m_request->headerList()->extractMIMEType()); |
- // "23. Return |r|." |
+ // "31. If |input| is a Request object and |input|'s body is non-null, run |
+ // these substeps:" |
+ if (inputRequest && inputRequest->hasBody()) { |
+ // "1. Set |input|'s body to null." |
+ inputRequest->setBodyBlobHandle(nullptr); |
+ // "2. Set |input|'s used flag." |
+ inputRequest->lockBody(PassBody); |
+ } |
+ |
+ // "32. Return |r|." |
return r; |
} |
@@ -231,7 +265,7 @@ Request* Request::create(ExecutionContext* context, const String& input, Excepti |
Request* Request::create(ExecutionContext* context, const String& input, const Dictionary& init, ExceptionState& exceptionState) |
{ |
- return createRequestWithRequestOrString(context, 0, input, RequestInit(context, init, exceptionState), exceptionState); |
+ return createRequestWithRequestOrString(context, nullptr, input, RequestInit(context, init, exceptionState), exceptionState); |
} |
Request* Request::create(ExecutionContext* context, Request* input, ExceptionState& exceptionState) |