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 OwnPtr<DrainingBodyStreamBuffer> temporaryBody = nullptr; |
51 | 53 |
52 if (inputRequest) { | 54 if (inputRequest) { |
53 // We check bodyUsed even when the body is null in spite of the | 55 // 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. | 56 // spec. See https://github.com/whatwg/fetch/issues/61 for details. |
55 if (inputRequest->bodyUsed()) { | 57 if (inputRequest->bodyUsed()) { |
56 exceptionState.throwTypeError("Cannot construct a Request with a Req uest object that has already been used."); | 58 exceptionState.throwTypeError("Cannot construct a Request with a Req uest object that has already been used."); |
57 return nullptr; | 59 return nullptr; |
58 } | 60 } |
59 } | 61 } |
60 | 62 |
61 // "2. If |input| is a Request object and |input|'s body is non-null, run | 63 // "2. If |input| is a Request object and |input|'s body is non-null, run |
62 // these substeps:" | 64 // these substeps:" |
63 if (inputRequest && inputRequest->hasBody()) { | 65 if (inputRequest && inputRequest->hasBody()) { |
64 // "1. If |input|'s used flag is set, throw a TypeError." | 66 // "1. If |input|'s used flag is set, throw a TypeError." |
65 // "2. Set |temporaryBody| to |input|'s body." | 67 // "2. Set |temporaryBody| to |input|'s body." |
66 if (inputRequest->bodyUsed()) { | 68 if (inputRequest->bodyUsed()) { |
67 exceptionState.throwTypeError("Cannot construct a Request with a Req uest object that has already been used."); | 69 exceptionState.throwTypeError("Cannot construct a Request with a Req uest object that has already been used."); |
68 return nullptr; | 70 return nullptr; |
69 } | 71 } |
70 if (inputRequest->isBodyConsumed()) { | 72 temporaryBody = inputRequest->createDrainingStream(); |
yhirano
2015/07/03 04:42:28
The spec intends to not mutate |inputRequest|'s bo
hiroshige
2015/07/05 07:30:25
Yes.
I modified the code to remove the side effect
| |
71 // Currently the only methods that can consume body data without | |
72 // setting 'body passed' flag consume entire body (e.g. text()). | |
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 } | 73 } |
83 | 74 |
84 // "3. Let |request| be |input|'s request, if |input| is a Request object, | 75 // "3. Let |request| be |input|'s request, if |input| is a Request object, |
85 // and a new request otherwise." | 76 // and a new request otherwise." |
86 // "4. Set |request| to a new request whose url is |request|'s url, method | 77 // "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, | 78 // 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 | 79 // unsafe request flag is set, client is entry settings object, origin is |
89 // entry settings object's origin, force Origin header flag is set, | 80 // 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 | 81 // 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, | 82 // |request|'s mode, credentials mode is |request|'s credentials mode, |
(...skipping 136 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
228 | 219 |
229 // "28. If |init|'s body member is present, run these substeps:" | 220 // "28. If |init|'s body member is present, run these substeps:" |
230 if (init.bodyBlobHandle) { | 221 if (init.bodyBlobHandle) { |
231 // "1. Let |stream| and |Content-Type| be the result of extracting | 222 // "1. Let |stream| and |Content-Type| be the result of extracting |
232 // |init|'s body member." | 223 // |init|'s body member." |
233 // "2. Set |temporaryBody| to |stream|. | 224 // "2. Set |temporaryBody| to |stream|. |
234 // "3. If |Content-Type| is non-null and |r|'s request's header list | 225 // "3. If |Content-Type| is non-null and |r|'s request's header list |
235 // contains no header named `Content-Type`, append | 226 // contains no header named `Content-Type`, append |
236 // `Content-Type`/|Content-Type| to |r|'s Headers object. Rethrow any | 227 // `Content-Type`/|Content-Type| to |r|'s Headers object. Rethrow any |
237 // exception." | 228 // exception." |
238 temporaryBody = init.bodyBlobHandle; | 229 temporaryBody = DrainingBodyStreamBuffer::create(BodyStreamBuffer::creat e(FetchBlobDataConsumerHandle::create(scriptState->executionContext(), init.body BlobHandle)), nullptr); |
239 if (!init.bodyBlobHandle->type().isEmpty() && !r->headers()->has("Conten t-Type", exceptionState)) { | 230 if (!init.bodyBlobHandle->type().isEmpty() && !r->headers()->has("Conten t-Type", exceptionState)) { |
240 r->headers()->append("Content-Type", init.bodyBlobHandle->type(), ex ceptionState); | 231 r->headers()->append("Content-Type", init.bodyBlobHandle->type(), ex ceptionState); |
241 } | 232 } |
242 if (exceptionState.hadException()) | 233 if (exceptionState.hadException()) |
243 return nullptr; | 234 return nullptr; |
244 } | 235 } |
245 | 236 |
246 // "29. Set |r|'s body to |temporaryBody|. | 237 // "29. Set |r|'s body to |temporaryBody|. |
247 r->setBodyBlobHandle(temporaryBody.release()); | 238 if (temporaryBody) |
239 r->setBuffer(temporaryBody->leak()); | |
248 | 240 |
249 // "30. Set |r|'s MIME type to the result of extracting a MIME type from | 241 // "30. Set |r|'s MIME type to the result of extracting a MIME type from |
250 // |r|'s request's header list." | 242 // |r|'s request's header list." |
251 r->m_request->setMIMEType(r->m_request->headerList()->extractMIMEType()); | 243 r->m_request->setMIMEType(r->m_request->headerList()->extractMIMEType()); |
252 | 244 |
253 // "31. If |input| is a Request object and |input|'s body is non-null, run | 245 // "31. If |input| is a Request object and |input|'s body is non-null, run |
254 // these substeps:" | 246 // these substeps:" |
255 // We set bodyUsed even when the body is null in spite of the | 247 // 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. | 248 // spec. See https://github.com/whatwg/fetch/issues/61 for details. |
257 if (inputRequest) { | 249 if (inputRequest) { |
258 // "1. Set |input|'s body to null." | 250 // "1. Set |input|'s body to null." |
259 inputRequest->setBodyBlobHandle(nullptr); | 251 inputRequest->setBuffer(nullptr); |
260 // "2. Set |input|'s used flag." | 252 // "2. Set |input|'s used flag." |
261 inputRequest->lockBody(PassBody); | 253 inputRequest->lockBody(PassBody); |
262 } | 254 } |
263 | 255 |
264 // "32. Return |r|." | 256 // "32. Return |r|." |
265 return r; | 257 return r; |
266 } | 258 } |
267 | 259 |
268 Request* Request::create(ScriptState* scriptState, const RequestInfo& input, con st Dictionary& init, ExceptionState& exceptionState) | 260 Request* Request::create(ScriptState* scriptState, const RequestInfo& input, con st Dictionary& init, ExceptionState& exceptionState) |
269 { | 261 { |
(...skipping 29 matching lines...) Expand all Loading... | |
299 r->suspendIfNeeded(); | 291 r->suspendIfNeeded(); |
300 return r; | 292 return r; |
301 } | 293 } |
302 | 294 |
303 Request::Request(ExecutionContext* context, FetchRequestData* request) | 295 Request::Request(ExecutionContext* context, FetchRequestData* request) |
304 : Body(context) | 296 : Body(context) |
305 , m_request(request) | 297 , m_request(request) |
306 , m_headers(Headers::create(m_request->headerList())) | 298 , m_headers(Headers::create(m_request->headerList())) |
307 { | 299 { |
308 m_headers->setGuard(Headers::RequestGuard); | 300 m_headers->setGuard(Headers::RequestGuard); |
301 | |
302 refreshBody(); | |
309 } | 303 } |
310 | 304 |
311 Request::Request(ExecutionContext* context, FetchRequestData* request, Headers* headers) | 305 Request::Request(ExecutionContext* context, FetchRequestData* request, Headers* headers) |
312 : Body(context) , m_request(request) , m_headers(headers) { } | 306 : Body(context) , m_request(request) , m_headers(headers) |
307 { | |
308 refreshBody(); | |
309 } | |
313 | 310 |
314 Request* Request::create(ExecutionContext* context, const WebServiceWorkerReques t& webRequest) | 311 Request* Request::create(ExecutionContext* context, const WebServiceWorkerReques t& webRequest) |
315 { | 312 { |
316 Request* r = new Request(context, webRequest); | 313 Request* r = new Request(context, webRequest); |
317 r->suspendIfNeeded(); | 314 r->suspendIfNeeded(); |
318 return r; | 315 return r; |
319 } | 316 } |
320 | 317 |
321 Request::Request(ExecutionContext* context, const WebServiceWorkerRequest& webRe quest) | 318 Request::Request(ExecutionContext* context, const WebServiceWorkerRequest& webRe quest) |
322 : Body(context) | 319 : Body(context) |
323 , m_request(FetchRequestData::create(webRequest)) | 320 , m_request(FetchRequestData::create(context, webRequest)) |
324 , m_headers(Headers::create(m_request->headerList())) | 321 , m_headers(Headers::create(m_request->headerList())) |
325 { | 322 { |
326 m_headers->setGuard(Headers::RequestGuard); | 323 m_headers->setGuard(Headers::RequestGuard); |
324 | |
325 refreshBody(); | |
327 } | 326 } |
328 | 327 |
329 String Request::method() const | 328 String Request::method() const |
330 { | 329 { |
331 // "The method attribute's getter must return request's method." | 330 // "The method attribute's getter must return request's method." |
332 return m_request->method(); | 331 return m_request->method(); |
333 } | 332 } |
334 | 333 |
335 KURL Request::url() const | 334 KURL Request::url() const |
336 { | 335 { |
(...skipping 121 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
458 return "omit"; | 457 return "omit"; |
459 case WebURLRequest::FetchCredentialsModeSameOrigin: | 458 case WebURLRequest::FetchCredentialsModeSameOrigin: |
460 return "same-origin"; | 459 return "same-origin"; |
461 case WebURLRequest::FetchCredentialsModeInclude: | 460 case WebURLRequest::FetchCredentialsModeInclude: |
462 return "include"; | 461 return "include"; |
463 } | 462 } |
464 ASSERT_NOT_REACHED(); | 463 ASSERT_NOT_REACHED(); |
465 return ""; | 464 return ""; |
466 } | 465 } |
467 | 466 |
468 Request* Request::clone(ExceptionState& exceptionState) const | 467 Request* Request::clone(ExceptionState& exceptionState) |
469 { | 468 { |
470 if (bodyUsed()) { | 469 if (bodyUsed()) { |
471 exceptionState.throwTypeError("Request body is already used"); | 470 exceptionState.throwTypeError("Request body is already used"); |
472 return nullptr; | 471 return nullptr; |
473 } | 472 } |
474 | 473 |
475 FetchRequestData* request = m_request->clone(); | 474 if (OwnPtr<DrainingBodyStreamBuffer> buffer = createDrainingStream()) |
476 if (blobDataHandle() && isBodyConsumed()) { | 475 m_request->setBuffer(buffer->leak()); |
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 | 476 |
477 FetchRequestData* request = m_request->clone(executionContext()); | |
487 Headers* headers = Headers::create(request->headerList()); | 478 Headers* headers = Headers::create(request->headerList()); |
488 headers->setGuard(m_headers->guard()); | 479 headers->setGuard(m_headers->guard()); |
489 Request* r = new Request(executionContext(), request, headers); | 480 Request* r = new Request(executionContext(), request, headers); |
490 r->suspendIfNeeded(); | 481 r->suspendIfNeeded(); |
482 | |
483 // Lock the old body and set |body| property to the new one. | |
484 lockBody(); | |
485 refreshBody(); | |
491 return r; | 486 return r; |
492 } | 487 } |
493 | 488 |
494 FetchRequestData* Request::passRequestData() | 489 FetchRequestData* Request::passRequestData() |
495 { | 490 { |
496 ASSERT(!bodyUsed()); | 491 ASSERT(!bodyUsed()); |
492 | |
493 if (OwnPtr<DrainingBodyStreamBuffer> buffer = createDrainingStream()) | |
494 m_request->setBuffer(buffer->leak()); | |
495 | |
497 lockBody(PassBody); | 496 lockBody(PassBody); |
498 return m_request->pass(); | 497 FetchRequestData* newRequestData = m_request->pass(executionContext()); |
498 refreshBody(); | |
499 return newRequestData; | |
499 } | 500 } |
500 | 501 |
501 void Request::populateWebServiceWorkerRequest(WebServiceWorkerRequest& webReques t) const | 502 void Request::populateWebServiceWorkerRequest(WebServiceWorkerRequest& webReques t) const |
502 { | 503 { |
503 webRequest.setMethod(method()); | 504 webRequest.setMethod(method()); |
504 webRequest.setRequestContext(m_request->context()); | 505 webRequest.setRequestContext(m_request->context()); |
505 // This strips off the fragment part. | 506 // This strips off the fragment part. |
506 webRequest.setURL(url()); | 507 webRequest.setURL(url()); |
507 | 508 |
508 const FetchHeaderList* headerList = m_headers->headerList(); | 509 const FetchHeaderList* headerList = m_headers->headerList(); |
509 for (size_t i = 0, size = headerList->size(); i < size; ++i) { | 510 for (size_t i = 0, size = headerList->size(); i < size; ++i) { |
510 const FetchHeaderList::Header& header = headerList->entry(i); | 511 const FetchHeaderList::Header& header = headerList->entry(i); |
511 webRequest.appendHeader(header.first, header.second); | 512 webRequest.appendHeader(header.first, header.second); |
512 } | 513 } |
513 | 514 |
514 webRequest.setReferrer(m_request->referrer().referrer().referrer, static_cas t<WebReferrerPolicy>(m_request->referrer().referrer().referrerPolicy)); | 515 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 | 516 // 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. | 517 // to plumb this information in to here. |
517 } | 518 } |
518 | 519 |
519 void Request::setBodyBlobHandle(PassRefPtr<BlobDataHandle> blobDataHandle) | 520 void Request::setBuffer(BodyStreamBuffer* buffer) |
520 { | 521 { |
521 m_request->setBlobDataHandle(blobDataHandle); | 522 m_request->setBuffer(buffer); |
522 setBody(m_request->blobDataHandle()); | 523 refreshBody(); |
524 } | |
525 | |
526 void Request::refreshBody() | |
527 { | |
528 setBody(m_request->buffer()); | |
523 } | 529 } |
524 | 530 |
525 void Request::clearHeaderList() | 531 void Request::clearHeaderList() |
526 { | 532 { |
527 m_request->headerList()->clearList(); | 533 m_request->headerList()->clearList(); |
528 } | 534 } |
529 | 535 |
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 | 536 String Request::mimeType() const |
542 { | 537 { |
543 return m_request->mimeType(); | 538 return m_request->mimeType(); |
544 } | 539 } |
545 | 540 |
546 DEFINE_TRACE(Request) | 541 DEFINE_TRACE(Request) |
547 { | 542 { |
548 Body::trace(visitor); | 543 Body::trace(visitor); |
549 visitor->trace(m_request); | 544 visitor->trace(m_request); |
550 visitor->trace(m_headers); | 545 visitor->trace(m_headers); |
551 } | 546 } |
552 | 547 |
553 } // namespace blink | 548 } // namespace blink |
OLD | NEW |