| OLD | NEW |
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "config.h" | 5 #include "config.h" |
| 6 #include "modules/fetch/Request.h" | 6 #include "modules/fetch/Request.h" |
| 7 | 7 |
| 8 #include "bindings/core/v8/Dictionary.h" | 8 #include "bindings/core/v8/Dictionary.h" |
| 9 #include "core/dom/Document.h" | 9 #include "core/dom/Document.h" |
| 10 #include "core/dom/ExecutionContext.h" | 10 #include "core/dom/ExecutionContext.h" |
| 11 #include "core/fetch/FetchUtils.h" | 11 #include "core/fetch/FetchUtils.h" |
| 12 #include "core/fetch/ResourceLoaderOptions.h" | 12 #include "core/fetch/ResourceLoaderOptions.h" |
| 13 #include "core/loader/ThreadableLoader.h" | 13 #include "core/loader/ThreadableLoader.h" |
| 14 #include "modules/fetch/BodyStreamBuffer.h" |
| 15 #include "modules/fetch/FetchBlobDataConsumerHandle.h" |
| 14 #include "modules/fetch/FetchManager.h" | 16 #include "modules/fetch/FetchManager.h" |
| 15 #include "modules/fetch/RequestInit.h" | 17 #include "modules/fetch/RequestInit.h" |
| 16 #include "platform/network/HTTPParsers.h" | 18 #include "platform/network/HTTPParsers.h" |
| 17 #include "platform/network/ResourceRequest.h" | 19 #include "platform/network/ResourceRequest.h" |
| 18 #include "platform/weborigin/Referrer.h" | 20 #include "platform/weborigin/Referrer.h" |
| 19 #include "public/platform/WebServiceWorkerRequest.h" | 21 #include "public/platform/WebServiceWorkerRequest.h" |
| 20 #include "public/platform/WebURLRequest.h" | 22 #include "public/platform/WebURLRequest.h" |
| 21 | 23 |
| 22 namespace blink { | 24 namespace blink { |
| 23 | 25 |
| (...skipping 16 matching lines...) Expand all Loading... |
| 40 request->setMode(original->mode()); | 42 request->setMode(original->mode()); |
| 41 request->setCredentials(original->credentials()); | 43 request->setCredentials(original->credentials()); |
| 42 // FIXME: Set cache mode. | 44 // FIXME: Set cache mode. |
| 43 // TODO(yhirano): Set redirect mode. | 45 // TODO(yhirano): Set redirect mode. |
| 44 return request; | 46 return request; |
| 45 } | 47 } |
| 46 | 48 |
| 47 Request* Request::createRequestWithRequestOrString(ScriptState* scriptState, Req
uest* inputRequest, const String& inputString, const RequestInit& init, Exceptio
nState& exceptionState) | 49 Request* Request::createRequestWithRequestOrString(ScriptState* scriptState, Req
uest* inputRequest, const String& inputString, const RequestInit& init, Exceptio
nState& exceptionState) |
| 48 { | 50 { |
| 49 // "1. Let |temporaryBody| be null." | 51 // "1. Let |temporaryBody| be null." |
| 50 RefPtr<BlobDataHandle> temporaryBody; | 52 Request* temporaryBodyRequest = nullptr; |
| 53 BodyStreamBuffer* temporaryBodyBuffer = nullptr; |
| 51 | 54 |
| 52 if (inputRequest) { | 55 if (inputRequest) { |
| 53 // We check bodyUsed even when the body is null in spite of the | 56 // We check bodyUsed even when the body is null in spite of the |
| 54 // spec. See https://github.com/whatwg/fetch/issues/61 for details. | 57 // spec. See https://github.com/whatwg/fetch/issues/61 for details. |
| 55 if (inputRequest->bodyUsed()) { | 58 if (inputRequest->bodyUsed()) { |
| 56 exceptionState.throwTypeError("Cannot construct a Request with a Req
uest object that has already been used."); | 59 exceptionState.throwTypeError("Cannot construct a Request with a Req
uest object that has already been used."); |
| 57 return nullptr; | 60 return nullptr; |
| 58 } | 61 } |
| 59 } | 62 } |
| 60 | 63 |
| 61 // "2. If |input| is a Request object and |input|'s body is non-null, run | 64 // "2. If |input| is a Request object and |input|'s body is non-null, run |
| 62 // these substeps:" | 65 // these substeps:" |
| 63 if (inputRequest && inputRequest->hasBody()) { | 66 if (inputRequest && inputRequest->hasBody()) { |
| 64 // "1. If |input|'s used flag is set, throw a TypeError." | 67 // "1. If |input|'s used flag is set, throw a TypeError." |
| 65 // "2. Set |temporaryBody| to |input|'s body." | 68 // "2. Set |temporaryBody| to |input|'s body." |
| 66 if (inputRequest->bodyUsed()) { | 69 if (inputRequest->bodyUsed()) { |
| 67 exceptionState.throwTypeError("Cannot construct a Request with a Req
uest object that has already been used."); | 70 exceptionState.throwTypeError("Cannot construct a Request with a Req
uest object that has already been used."); |
| 68 return nullptr; | 71 return nullptr; |
| 69 } | 72 } |
| 70 if (inputRequest->isBodyConsumed()) { | 73 // We call createDrainingStream() later and not here, because |
| 71 // Currently the only methods that can consume body data without | 74 // createDrainingStream() has side effects on |inputRequest|'s body. |
| 72 // setting 'body passed' flag consume entire body (e.g. text()). | 75 temporaryBodyRequest = inputRequest; |
| 73 // Thus we can set an empty blob to the new request instead of | |
| 74 // creating a draining stream. | |
| 75 // TODO(yhirano): Fix this once Request.body is introduced. | |
| 76 OwnPtr<BlobData> blobData = BlobData::create(); | |
| 77 blobData->setContentType(inputRequest->blobDataHandle()->type()); | |
| 78 temporaryBody = BlobDataHandle::create(blobData.release(), 0); | |
| 79 } else { | |
| 80 temporaryBody = inputRequest->m_request->blobDataHandle(); | |
| 81 } | |
| 82 } | 76 } |
| 83 | 77 |
| 84 // "3. Let |request| be |input|'s request, if |input| is a Request object, | 78 // "3. Let |request| be |input|'s request, if |input| is a Request object, |
| 85 // and a new request otherwise." | 79 // and a new request otherwise." |
| 86 // "4. Set |request| to a new request whose url is |request|'s url, method | 80 // "4. Set |request| to a new request whose url is |request|'s url, method |
| 87 // is |request|'s method, header list is a copy of |request|'s header list, | 81 // is |request|'s method, header list is a copy of |request|'s header list, |
| 88 // unsafe request flag is set, client is entry settings object, origin is | 82 // unsafe request flag is set, client is entry settings object, origin is |
| 89 // entry settings object's origin, force Origin header flag is set, | 83 // entry settings object's origin, force Origin header flag is set, |
| 90 // same-origin data URL flag is set, context is the empty string, mode is | 84 // same-origin data URL flag is set, context is the empty string, mode is |
| 91 // |request|'s mode, credentials mode is |request|'s credentials mode, | 85 // |request|'s mode, credentials mode is |request|'s credentials mode, |
| (...skipping 120 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 212 r->headers()->fillWith(init.headersDictionary, exceptionState); | 206 r->headers()->fillWith(init.headersDictionary, exceptionState); |
| 213 } else { | 207 } else { |
| 214 ASSERT(headers); | 208 ASSERT(headers); |
| 215 r->headers()->fillWith(headers, exceptionState); | 209 r->headers()->fillWith(headers, exceptionState); |
| 216 } | 210 } |
| 217 if (exceptionState.hadException()) | 211 if (exceptionState.hadException()) |
| 218 return nullptr; | 212 return nullptr; |
| 219 | 213 |
| 220 // "27. If either |init|'s body member is present or |temporaryBody| is | 214 // "27. If either |init|'s body member is present or |temporaryBody| is |
| 221 // non-null, and |request|'s method is `GET` or `HEAD`, throw a TypeError. | 215 // non-null, and |request|'s method is `GET` or `HEAD`, throw a TypeError. |
| 222 if (init.bodyBlobHandle || temporaryBody) { | 216 if (init.bodyBlobHandle || temporaryBodyRequest) { |
| 223 if (request->method() == "GET" || request->method() == "HEAD") { | 217 if (request->method() == "GET" || request->method() == "HEAD") { |
| 224 exceptionState.throwTypeError("Request with GET/HEAD method cannot h
ave body."); | 218 exceptionState.throwTypeError("Request with GET/HEAD method cannot h
ave body."); |
| 225 return nullptr; | 219 return nullptr; |
| 226 } | 220 } |
| 227 } | 221 } |
| 228 | 222 |
| 229 // "28. If |init|'s body member is present, run these substeps:" | 223 // "28. If |init|'s body member is present, run these substeps:" |
| 230 if (init.bodyBlobHandle) { | 224 if (init.bodyBlobHandle) { |
| 231 // "1. Let |stream| and |Content-Type| be the result of extracting | 225 // "1. Let |stream| and |Content-Type| be the result of extracting |
| 232 // |init|'s body member." | 226 // |init|'s body member." |
| 233 // "2. Set |temporaryBody| to |stream|. | 227 // "2. Set |temporaryBody| to |stream|. |
| 234 // "3. If |Content-Type| is non-null and |r|'s request's header list | 228 // "3. If |Content-Type| is non-null and |r|'s request's header list |
| 235 // contains no header named `Content-Type`, append | 229 // contains no header named `Content-Type`, append |
| 236 // `Content-Type`/|Content-Type| to |r|'s Headers object. Rethrow any | 230 // `Content-Type`/|Content-Type| to |r|'s Headers object. Rethrow any |
| 237 // exception." | 231 // exception." |
| 238 temporaryBody = init.bodyBlobHandle; | 232 temporaryBodyBuffer = BodyStreamBuffer::create(FetchBlobDataConsumerHand
le::create(scriptState->executionContext(), init.bodyBlobHandle)); |
| 233 temporaryBodyRequest = nullptr; |
| 239 if (!init.bodyBlobHandle->type().isEmpty() && !r->headers()->has("Conten
t-Type", exceptionState)) { | 234 if (!init.bodyBlobHandle->type().isEmpty() && !r->headers()->has("Conten
t-Type", exceptionState)) { |
| 240 r->headers()->append("Content-Type", init.bodyBlobHandle->type(), ex
ceptionState); | 235 r->headers()->append("Content-Type", init.bodyBlobHandle->type(), ex
ceptionState); |
| 241 } | 236 } |
| 242 if (exceptionState.hadException()) | 237 if (exceptionState.hadException()) |
| 243 return nullptr; | 238 return nullptr; |
| 244 } | 239 } |
| 245 | 240 |
| 246 // "29. Set |r|'s body to |temporaryBody|. | 241 // "29. Set |r|'s body to |temporaryBody|. |
| 247 r->setBodyBlobHandle(temporaryBody.release()); | 242 if (temporaryBodyBuffer) |
| 243 r->setBuffer(temporaryBodyBuffer); |
| 244 else if (temporaryBodyRequest) |
| 245 r->setBuffer(temporaryBodyRequest->createDrainingStream()->leakBuffer())
; |
| 248 | 246 |
| 249 // "30. Set |r|'s MIME type to the result of extracting a MIME type from | 247 // "30. Set |r|'s MIME type to the result of extracting a MIME type from |
| 250 // |r|'s request's header list." | 248 // |r|'s request's header list." |
| 251 r->m_request->setMIMEType(r->m_request->headerList()->extractMIMEType()); | 249 r->m_request->setMIMEType(r->m_request->headerList()->extractMIMEType()); |
| 252 | 250 |
| 253 // "31. If |input| is a Request object and |input|'s body is non-null, run | 251 // "31. If |input| is a Request object and |input|'s body is non-null, run |
| 254 // these substeps:" | 252 // these substeps:" |
| 255 // We set bodyUsed even when the body is null in spite of the | 253 // We set bodyUsed even when the body is null in spite of the |
| 256 // spec. See https://github.com/whatwg/fetch/issues/61 for details. | 254 // spec. See https://github.com/whatwg/fetch/issues/61 for details. |
| 257 if (inputRequest) { | 255 if (inputRequest) { |
| 258 // "1. Set |input|'s body to null." | 256 // "1. Set |input|'s body to null." |
| 259 inputRequest->setBodyBlobHandle(nullptr); | 257 inputRequest->setBuffer(nullptr); |
| 260 // "2. Set |input|'s used flag." | 258 // "2. Set |input|'s used flag." |
| 261 inputRequest->lockBody(PassBody); | 259 inputRequest->lockBody(PassBody); |
| 262 } | 260 } |
| 263 | 261 |
| 264 // "32. Return |r|." | 262 // "32. Return |r|." |
| 265 return r; | 263 return r; |
| 266 } | 264 } |
| 267 | 265 |
| 268 Request* Request::create(ScriptState* scriptState, const RequestInfo& input, con
st Dictionary& init, ExceptionState& exceptionState) | 266 Request* Request::create(ScriptState* scriptState, const RequestInfo& input, con
st Dictionary& init, ExceptionState& exceptionState) |
| 269 { | 267 { |
| (...skipping 29 matching lines...) Expand all Loading... |
| 299 r->suspendIfNeeded(); | 297 r->suspendIfNeeded(); |
| 300 return r; | 298 return r; |
| 301 } | 299 } |
| 302 | 300 |
| 303 Request::Request(ExecutionContext* context, FetchRequestData* request) | 301 Request::Request(ExecutionContext* context, FetchRequestData* request) |
| 304 : Body(context) | 302 : Body(context) |
| 305 , m_request(request) | 303 , m_request(request) |
| 306 , m_headers(Headers::create(m_request->headerList())) | 304 , m_headers(Headers::create(m_request->headerList())) |
| 307 { | 305 { |
| 308 m_headers->setGuard(Headers::RequestGuard); | 306 m_headers->setGuard(Headers::RequestGuard); |
| 307 |
| 308 refreshBody(); |
| 309 } | 309 } |
| 310 | 310 |
| 311 Request::Request(ExecutionContext* context, FetchRequestData* request, Headers*
headers) | 311 Request::Request(ExecutionContext* context, FetchRequestData* request, Headers*
headers) |
| 312 : Body(context) , m_request(request) , m_headers(headers) { } | 312 : Body(context) , m_request(request) , m_headers(headers) |
| 313 { |
| 314 refreshBody(); |
| 315 } |
| 313 | 316 |
| 314 Request* Request::create(ExecutionContext* context, const WebServiceWorkerReques
t& webRequest) | 317 Request* Request::create(ExecutionContext* context, const WebServiceWorkerReques
t& webRequest) |
| 315 { | 318 { |
| 316 Request* r = new Request(context, webRequest); | 319 Request* r = new Request(context, webRequest); |
| 317 r->suspendIfNeeded(); | 320 r->suspendIfNeeded(); |
| 318 return r; | 321 return r; |
| 319 } | 322 } |
| 320 | 323 |
| 321 Request::Request(ExecutionContext* context, const WebServiceWorkerRequest& webRe
quest) | 324 Request::Request(ExecutionContext* context, const WebServiceWorkerRequest& webRe
quest) |
| 322 : Body(context) | 325 : Body(context) |
| 323 , m_request(FetchRequestData::create(webRequest)) | 326 , m_request(FetchRequestData::create(context, webRequest)) |
| 324 , m_headers(Headers::create(m_request->headerList())) | 327 , m_headers(Headers::create(m_request->headerList())) |
| 325 { | 328 { |
| 326 m_headers->setGuard(Headers::RequestGuard); | 329 m_headers->setGuard(Headers::RequestGuard); |
| 330 |
| 331 refreshBody(); |
| 327 } | 332 } |
| 328 | 333 |
| 329 String Request::method() const | 334 String Request::method() const |
| 330 { | 335 { |
| 331 // "The method attribute's getter must return request's method." | 336 // "The method attribute's getter must return request's method." |
| 332 return m_request->method(); | 337 return m_request->method(); |
| 333 } | 338 } |
| 334 | 339 |
| 335 KURL Request::url() const | 340 KURL Request::url() const |
| 336 { | 341 { |
| (...skipping 121 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 458 return "omit"; | 463 return "omit"; |
| 459 case WebURLRequest::FetchCredentialsModeSameOrigin: | 464 case WebURLRequest::FetchCredentialsModeSameOrigin: |
| 460 return "same-origin"; | 465 return "same-origin"; |
| 461 case WebURLRequest::FetchCredentialsModeInclude: | 466 case WebURLRequest::FetchCredentialsModeInclude: |
| 462 return "include"; | 467 return "include"; |
| 463 } | 468 } |
| 464 ASSERT_NOT_REACHED(); | 469 ASSERT_NOT_REACHED(); |
| 465 return ""; | 470 return ""; |
| 466 } | 471 } |
| 467 | 472 |
| 468 Request* Request::clone(ExceptionState& exceptionState) const | 473 Request* Request::clone(ExceptionState& exceptionState) |
| 469 { | 474 { |
| 470 if (bodyUsed()) { | 475 if (bodyUsed()) { |
| 471 exceptionState.throwTypeError("Request body is already used"); | 476 exceptionState.throwTypeError("Request body is already used"); |
| 472 return nullptr; | 477 return nullptr; |
| 473 } | 478 } |
| 474 | 479 |
| 475 FetchRequestData* request = m_request->clone(); | 480 if (OwnPtr<DrainingBodyStreamBuffer> buffer = createDrainingStream()) |
| 476 if (blobDataHandle() && isBodyConsumed()) { | 481 m_request->setBuffer(buffer->leakBuffer()); |
| 477 // Currently the only methods that can consume body data without | |
| 478 // setting 'body passed' flag consume entire body (e.g. text()). Thus | |
| 479 // we can set an empty blob to the new request instead of creating a | |
| 480 // draining stream. | |
| 481 // TODO(yhirano): Fix this once Request.body is introduced. | |
| 482 OwnPtr<BlobData> blobData = BlobData::create(); | |
| 483 blobData->setContentType(blobDataHandle()->type()); | |
| 484 request->setBlobDataHandle(BlobDataHandle::create(blobData.release(), 0)
); | |
| 485 } | |
| 486 | 482 |
| 483 FetchRequestData* request = m_request->clone(executionContext()); |
| 487 Headers* headers = Headers::create(request->headerList()); | 484 Headers* headers = Headers::create(request->headerList()); |
| 488 headers->setGuard(m_headers->guard()); | 485 headers->setGuard(m_headers->guard()); |
| 489 Request* r = new Request(executionContext(), request, headers); | 486 Request* r = new Request(executionContext(), request, headers); |
| 490 r->suspendIfNeeded(); | 487 r->suspendIfNeeded(); |
| 488 |
| 489 // Lock the old body and set |body| property to the new one. |
| 490 lockBody(); |
| 491 refreshBody(); |
| 491 return r; | 492 return r; |
| 492 } | 493 } |
| 493 | 494 |
| 494 FetchRequestData* Request::passRequestData() | 495 FetchRequestData* Request::passRequestData() |
| 495 { | 496 { |
| 496 ASSERT(!bodyUsed()); | 497 ASSERT(!bodyUsed()); |
| 498 |
| 499 if (OwnPtr<DrainingBodyStreamBuffer> buffer = createDrainingStream()) |
| 500 m_request->setBuffer(buffer->leakBuffer()); |
| 501 |
| 497 lockBody(PassBody); | 502 lockBody(PassBody); |
| 498 return m_request->pass(); | 503 FetchRequestData* newRequestData = m_request->pass(executionContext()); |
| 504 refreshBody(); |
| 505 return newRequestData; |
| 499 } | 506 } |
| 500 | 507 |
| 501 void Request::populateWebServiceWorkerRequest(WebServiceWorkerRequest& webReques
t) const | 508 void Request::populateWebServiceWorkerRequest(WebServiceWorkerRequest& webReques
t) const |
| 502 { | 509 { |
| 503 webRequest.setMethod(method()); | 510 webRequest.setMethod(method()); |
| 504 webRequest.setRequestContext(m_request->context()); | 511 webRequest.setRequestContext(m_request->context()); |
| 505 // This strips off the fragment part. | 512 // This strips off the fragment part. |
| 506 webRequest.setURL(url()); | 513 webRequest.setURL(url()); |
| 507 | 514 |
| 508 const FetchHeaderList* headerList = m_headers->headerList(); | 515 const FetchHeaderList* headerList = m_headers->headerList(); |
| 509 for (size_t i = 0, size = headerList->size(); i < size; ++i) { | 516 for (size_t i = 0, size = headerList->size(); i < size; ++i) { |
| 510 const FetchHeaderList::Header& header = headerList->entry(i); | 517 const FetchHeaderList::Header& header = headerList->entry(i); |
| 511 webRequest.appendHeader(header.first, header.second); | 518 webRequest.appendHeader(header.first, header.second); |
| 512 } | 519 } |
| 513 | 520 |
| 514 webRequest.setReferrer(m_request->referrer().referrer().referrer, static_cas
t<WebReferrerPolicy>(m_request->referrer().referrer().referrerPolicy)); | 521 webRequest.setReferrer(m_request->referrer().referrer().referrer, static_cas
t<WebReferrerPolicy>(m_request->referrer().referrer().referrerPolicy)); |
| 515 // FIXME: How can we set isReload properly? What is the correct place to loa
d it in to the Request object? We should investigate the right way | 522 // FIXME: How can we set isReload properly? What is the correct place to loa
d it in to the Request object? We should investigate the right way |
| 516 // to plumb this information in to here. | 523 // to plumb this information in to here. |
| 517 } | 524 } |
| 518 | 525 |
| 519 void Request::setBodyBlobHandle(PassRefPtr<BlobDataHandle> blobDataHandle) | 526 void Request::setBuffer(BodyStreamBuffer* buffer) |
| 520 { | 527 { |
| 521 m_request->setBlobDataHandle(blobDataHandle); | 528 m_request->setBuffer(buffer); |
| 522 setBody(m_request->blobDataHandle()); | 529 refreshBody(); |
| 530 } |
| 531 |
| 532 void Request::refreshBody() |
| 533 { |
| 534 setBody(m_request->buffer()); |
| 523 } | 535 } |
| 524 | 536 |
| 525 void Request::clearHeaderList() | 537 void Request::clearHeaderList() |
| 526 { | 538 { |
| 527 m_request->headerList()->clearList(); | 539 m_request->headerList()->clearList(); |
| 528 } | 540 } |
| 529 | 541 |
| 530 PassRefPtr<BlobDataHandle> Request::blobDataHandle() const | |
| 531 { | |
| 532 return m_request->blobDataHandle(); | |
| 533 } | |
| 534 | |
| 535 BodyStreamBuffer* Request::buffer() const | |
| 536 { | |
| 537 // We don't support BodyStreamBuffer for Request yet. | |
| 538 return nullptr; | |
| 539 } | |
| 540 | |
| 541 String Request::mimeType() const | 542 String Request::mimeType() const |
| 542 { | 543 { |
| 543 return m_request->mimeType(); | 544 return m_request->mimeType(); |
| 544 } | 545 } |
| 545 | 546 |
| 546 DEFINE_TRACE(Request) | 547 DEFINE_TRACE(Request) |
| 547 { | 548 { |
| 548 Body::trace(visitor); | 549 Body::trace(visitor); |
| 549 visitor->trace(m_request); | 550 visitor->trace(m_request); |
| 550 visitor->trace(m_headers); | 551 visitor->trace(m_headers); |
| 551 } | 552 } |
| 552 | 553 |
| 553 } // namespace blink | 554 } // namespace blink |
| OLD | NEW |