Request* Request::clone(ExceptionState& exceptionState) const { if (bodyUsed()) { exceptionState.throwTypeError("Request body is already used"); return nullptr; } FetchRequestData* request = m_request->clone(); if (blobDataHandle() && 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(blobDataHandle()->type()); request->setBlobDataHandle(BlobDataHandle::create(blobData.release(), 0)); } Headers* headers = Headers::create(request->headerList()); headers->setGuard(m_headers->guard()); Request* r = new Request(executionContext(), request, headers); r->suspendIfNeeded(); return r; }
FetchRequestData* FetchRequestData::create(ScriptState* scriptState, const WebServiceWorkerRequest& webRequest) { FetchRequestData* request = FetchRequestData::create(); request->m_url = webRequest.url(); request->m_method = webRequest.method(); for (HTTPHeaderMap::const_iterator it = webRequest.headers().begin(); it != webRequest.headers().end(); ++it) request->m_headerList->append(it->key, it->value); if (webRequest.blobDataHandle()) request->setBuffer(new BodyStreamBuffer(scriptState, FetchBlobDataConsumerHandle::create(scriptState->getExecutionContext(), webRequest.blobDataHandle()))); request->setContext(webRequest.requestContext()); request->setReferrer(Referrer(webRequest.referrerUrl().string(), static_cast<ReferrerPolicy>(webRequest.referrerPolicy()))); request->setMode(webRequest.mode()); request->setCredentials(webRequest.credentialsMode()); request->setRedirect(webRequest.redirectMode()); request->setMIMEType(request->m_headerList->extractMIMEType()); 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." if (inputRequest->bodyUsed()) { exceptionState.throwTypeError("Cannot construct a Request with a Request object that has already been used."); return 0; } // "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 // 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." 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." // We don't use fallback values. We set these flags directly in below. // "7. 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." KURL parsedURL = context->completeURL(inputString); // "2. If |parsedURL| is failure, throw a TypeError." if (!parsedURL.isValid()) { exceptionState.throwTypeError("Failed to parse URL from " + inputString); return 0; } // "3. Set |request|'s url to |parsedURL|." request->setURL(parsedURL); // "4. Set |fallbackMode| to CORS." // "5. Set |fallbackCredentials| to omit." // "6. Set |fallbackCache| to default." // 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 // |fallbackMode| otherwise." // "9. 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") { request->setMode(WebURLRequest::FetchRequestModeNoCORS); } else if (init.mode == "cors") { request->setMode(WebURLRequest::FetchRequestModeCORS); } else { if (!inputRequest) request->setMode(WebURLRequest::FetchRequestModeCORS); } // "10. 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 // |credentials|. if (init.credentials == "omit") { request->setCredentials(WebURLRequest::FetchCredentialsModeOmit); } else if (init.credentials == "same-origin") { request->setCredentials(WebURLRequest::FetchCredentialsModeSameOrigin); } else if (init.credentials == "include") { request->setCredentials(WebURLRequest::FetchCredentialsModeInclude); } else { if (!inputRequest) request->setCredentials(WebURLRequest::FetchCredentialsModeOmit); } // FIXME: "12. 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 // |cache|." // "14. 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; } if (FetchUtils::isForbiddenMethod(init.method)) { exceptionState.throwTypeError("'" + init.method + "' HTTP method is unsupported."); return 0; } // "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." 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 // headers member." // We don't create a copy of r's Headers object when init's headers member // is present. Headers* headers = 0; if (!init.headers && init.headersDictionary.isUndefinedOrNull()) { headers = r->headers()->clone(); } // "18. Empty |r|'s request's header list." r->clearHeaderList(); // "19. 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; } // "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." if (init.headers) { ASSERT(init.headersDictionary.isUndefinedOrNull()); r->headers()->fillWith(init.headers.get(), exceptionState); } else if (!init.headersDictionary.isUndefinedOrNull()) { r->headers()->fillWith(init.headersDictionary, exceptionState); } else { ASSERT(headers); r->headers()->fillWith(headers, exceptionState); } if (exceptionState.hadException()) return 0; // "21. 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 // |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 // 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); 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; } // "22. 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|." return r; }
FetchRequestData* createCopyOfFetchRequestDataForFetch(ExecutionContext* context, const FetchRequestData* original) { FetchRequestData* request = FetchRequestData::create(); request->setURL(original->url()); 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. request->setSameOriginDataURLFlag(true); request->mutableReferrer()->setClient(); request->setContext(WebURLRequest::RequestContextFetch); request->setMode(original->mode()); request->setCredentials(original->credentials()); // FIXME: Set cache mode. return request; }