| 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" |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 42 request->setMode(original->mode()); | 42 request->setMode(original->mode()); |
| 43 request->setCredentials(original->credentials()); | 43 request->setCredentials(original->credentials()); |
| 44 // FIXME: Set cache mode. | 44 // FIXME: Set cache mode. |
| 45 // TODO(yhirano): Set redirect mode. | 45 // TODO(yhirano): Set redirect mode. |
| 46 return request; | 46 return request; |
| 47 } | 47 } |
| 48 | 48 |
| 49 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) |
| 50 { | 50 { |
| 51 // "1. Let |temporaryBody| be null." | 51 // "1. Let |temporaryBody| be null." |
| 52 Request* temporaryBodyRequest = nullptr; | 52 BodyStreamBuffer* temporaryBody = nullptr; |
| 53 BodyStreamBuffer* temporaryBodyBuffer = nullptr; | |
| 54 | 53 |
| 55 if (inputRequest) { | 54 if (inputRequest) { |
| 56 // 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 |
| 57 // spec. See https://github.com/whatwg/fetch/issues/61 for details. | 56 // spec. See https://github.com/whatwg/fetch/issues/61 for details. |
| 58 if (inputRequest->bodyUsed()) { | 57 if (inputRequest->bodyUsed()) { |
| 59 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."); |
| 60 return nullptr; | 59 return nullptr; |
| 61 } | 60 } |
| 62 } | 61 } |
| 63 | 62 |
| 64 // "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 |
| 65 // these substeps:" | 64 // these substeps:" |
| 66 if (inputRequest && inputRequest->hasBody()) { | 65 if (inputRequest && inputRequest->hasBody()) { |
| 67 // "1. If |input|'s used flag is set, throw a TypeError." | 66 // "1. If |input|'s used flag is set, throw a TypeError." |
| 68 // "2. Set |temporaryBody| to |input|'s body." | 67 // "2. Set |temporaryBody| to |input|'s body." |
| 69 if (inputRequest->bodyUsed()) { | 68 if (inputRequest->bodyUsed()) { |
| 70 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."); |
| 71 return nullptr; | 70 return nullptr; |
| 72 } | 71 } |
| 73 // We call createDrainingStream() later and not here, because | 72 temporaryBody = inputRequest->bodyBuffer(); |
| 74 // createDrainingStream() has side effects on |inputRequest|'s body. | |
| 75 temporaryBodyRequest = inputRequest; | |
| 76 } | 73 } |
| 77 | 74 |
| 78 // "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, |
| 79 // and a new request otherwise." | 76 // and a new request otherwise." |
| 80 // "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 |
| 81 // 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, |
| 82 // 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 |
| 83 // entry settings object's origin, force Origin header flag is set, | 80 // entry settings object's origin, force Origin header flag is set, |
| 84 // 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 |
| 85 // |request|'s mode, credentials mode is |request|'s credentials mode, | 82 // |request|'s mode, credentials mode is |request|'s credentials mode, |
| (...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 179 // "22. Let |headers| be a copy of |r|'s Headers object." | 176 // "22. Let |headers| be a copy of |r|'s Headers object." |
| 180 // "23. If |init|'s headers member is present, set |headers| to |init|'s | 177 // "23. If |init|'s headers member is present, set |headers| to |init|'s |
| 181 // headers member." | 178 // headers member." |
| 182 // We don't create a copy of r's Headers object when init's headers member | 179 // We don't create a copy of r's Headers object when init's headers member |
| 183 // is present. | 180 // is present. |
| 184 Headers* headers = nullptr; | 181 Headers* headers = nullptr; |
| 185 if (!init.headers && init.headersDictionary.isUndefinedOrNull()) { | 182 if (!init.headers && init.headersDictionary.isUndefinedOrNull()) { |
| 186 headers = r->headers()->clone(); | 183 headers = r->headers()->clone(); |
| 187 } | 184 } |
| 188 // "24. Empty |r|'s request's header list." | 185 // "24. Empty |r|'s request's header list." |
| 189 r->clearHeaderList(); | 186 r->m_request->headerList()->clearList(); |
| 190 // "25. If |r|'s request's mode is no CORS, run these substeps: | 187 // "25. If |r|'s request's mode is no CORS, run these substeps: |
| 191 if (r->request()->mode() == WebURLRequest::FetchRequestModeNoCORS) { | 188 if (r->request()->mode() == WebURLRequest::FetchRequestModeNoCORS) { |
| 192 // "1. If |r|'s request's method is not a simple method, throw a | 189 // "1. If |r|'s request's method is not a simple method, throw a |
| 193 // TypeError." | 190 // TypeError." |
| 194 if (!FetchUtils::isSimpleMethod(r->request()->method())) { | 191 if (!FetchUtils::isSimpleMethod(r->request()->method())) { |
| 195 exceptionState.throwTypeError("'" + r->request()->method() + "' is u
nsupported in no-cors mode."); | 192 exceptionState.throwTypeError("'" + r->request()->method() + "' is u
nsupported in no-cors mode."); |
| 196 return nullptr; | 193 return nullptr; |
| 197 } | 194 } |
| 198 // "Set |r|'s Headers object's guard to |request-no-CORS|. | 195 // "Set |r|'s Headers object's guard to |request-no-CORS|. |
| 199 r->headers()->setGuard(Headers::RequestNoCORSGuard); | 196 r->headers()->setGuard(Headers::RequestNoCORSGuard); |
| 200 } | 197 } |
| 201 // "26. Fill |r|'s Headers object with |headers|. Rethrow any exceptions." | 198 // "26. Fill |r|'s Headers object with |headers|. Rethrow any exceptions." |
| 202 if (init.headers) { | 199 if (init.headers) { |
| 203 ASSERT(init.headersDictionary.isUndefinedOrNull()); | 200 ASSERT(init.headersDictionary.isUndefinedOrNull()); |
| 204 r->headers()->fillWith(init.headers.get(), exceptionState); | 201 r->headers()->fillWith(init.headers.get(), exceptionState); |
| 205 } else if (!init.headersDictionary.isUndefinedOrNull()) { | 202 } else if (!init.headersDictionary.isUndefinedOrNull()) { |
| 206 r->headers()->fillWith(init.headersDictionary, exceptionState); | 203 r->headers()->fillWith(init.headersDictionary, exceptionState); |
| 207 } else { | 204 } else { |
| 208 ASSERT(headers); | 205 ASSERT(headers); |
| 209 r->headers()->fillWith(headers, exceptionState); | 206 r->headers()->fillWith(headers, exceptionState); |
| 210 } | 207 } |
| 211 if (exceptionState.hadException()) | 208 if (exceptionState.hadException()) |
| 212 return nullptr; | 209 return nullptr; |
| 213 | 210 |
| 214 // "27. If either |init|'s body member is present or |temporaryBody| is | 211 // "27. If either |init|'s body member is present or |temporaryBody| is |
| 215 // non-null, and |request|'s method is `GET` or `HEAD`, throw a TypeError. | 212 // non-null, and |request|'s method is `GET` or `HEAD`, throw a TypeError. |
| 216 if (init.bodyBlobHandle || temporaryBodyRequest) { | 213 if (init.bodyBlobHandle || temporaryBody) { |
| 217 if (request->method() == "GET" || request->method() == "HEAD") { | 214 if (request->method() == "GET" || request->method() == "HEAD") { |
| 218 exceptionState.throwTypeError("Request with GET/HEAD method cannot h
ave body."); | 215 exceptionState.throwTypeError("Request with GET/HEAD method cannot h
ave body."); |
| 219 return nullptr; | 216 return nullptr; |
| 220 } | 217 } |
| 221 } | 218 } |
| 222 | 219 |
| 223 // "28. If |init|'s body member is present, run these substeps:" | 220 // "28. If |init|'s body member is present, run these substeps:" |
| 224 if (init.bodyBlobHandle) { | 221 if (init.bodyBlobHandle) { |
| 225 // "1. Let |stream| and |Content-Type| be the result of extracting | 222 // "1. Let |stream| and |Content-Type| be the result of extracting |
| 226 // |init|'s body member." | 223 // |init|'s body member." |
| 227 // "2. Set |temporaryBody| to |stream|. | 224 // "2. Set |temporaryBody| to |stream|. |
| 228 // "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 |
| 229 // contains no header named `Content-Type`, append | 226 // contains no header named `Content-Type`, append |
| 230 // `Content-Type`/|Content-Type| to |r|'s Headers object. Rethrow any | 227 // `Content-Type`/|Content-Type| to |r|'s Headers object. Rethrow any |
| 231 // exception." | 228 // exception." |
| 232 temporaryBodyBuffer = BodyStreamBuffer::create(FetchBlobDataConsumerHand
le::create(scriptState->executionContext(), init.bodyBlobHandle)); | 229 temporaryBody = new BodyStreamBuffer(FetchBlobDataConsumerHandle::create
(scriptState->executionContext(), init.bodyBlobHandle)); |
| 233 temporaryBodyRequest = nullptr; | |
| 234 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)) { |
| 235 r->headers()->append("Content-Type", init.bodyBlobHandle->type(), ex
ceptionState); | 231 r->headers()->append("Content-Type", init.bodyBlobHandle->type(), ex
ceptionState); |
| 236 } | 232 } |
| 237 if (exceptionState.hadException()) | 233 if (exceptionState.hadException()) |
| 238 return nullptr; | 234 return nullptr; |
| 239 } | 235 } |
| 240 | 236 |
| 241 // "29. Set |r|'s body to |temporaryBody|. | 237 // "29. Set |r|'s body to |temporaryBody|. |
| 242 if (temporaryBodyBuffer) | 238 if (temporaryBody) |
| 243 r->setBuffer(temporaryBodyBuffer); | 239 r->m_request->setBuffer(temporaryBody); |
| 244 else if (temporaryBodyRequest) | |
| 245 r->setBuffer(temporaryBodyRequest->createDrainingStream()->leakBuffer())
; | |
| 246 | 240 |
| 247 // "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 |
| 248 // |r|'s request's header list." | 242 // |r|'s request's header list." |
| 249 r->m_request->setMIMEType(r->m_request->headerList()->extractMIMEType()); | 243 r->m_request->setMIMEType(r->m_request->headerList()->extractMIMEType()); |
| 250 | 244 |
| 251 // "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 |
| 252 // these substeps:" | 246 // these substeps:" |
| 253 // 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 |
| 254 // spec. See https://github.com/whatwg/fetch/issues/61 for details. | 248 // spec. See https://github.com/whatwg/fetch/issues/61 for details. |
| 255 if (inputRequest) { | 249 if (inputRequest) { |
| 256 // "1. Set |input|'s body to null." | 250 // "1. Set |input|'s body to null." |
| 257 inputRequest->setBuffer(nullptr); | 251 inputRequest->m_request->setBuffer(new BodyStreamBuffer); |
| 258 // "2. Set |input|'s used flag." | 252 // "2. Set |input|'s used flag." |
| 259 inputRequest->lockBody(PassBody); | 253 inputRequest->setBodyPassed(); |
| 260 } | 254 } |
| 261 | 255 |
| 262 // "32. Return |r|." | 256 // "32. Return |r|." |
| 263 return r; | 257 return r; |
| 264 } | 258 } |
| 265 | 259 |
| 266 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) |
| 267 { | 261 { |
| 268 ASSERT(!input.isNull()); | 262 ASSERT(!input.isNull()); |
| 269 if (input.isUSVString()) | 263 if (input.isUSVString()) |
| (...skipping 16 matching lines...) Expand all Loading... |
| 286 return create(scriptState, input, Dictionary(), exceptionState); | 280 return create(scriptState, input, Dictionary(), exceptionState); |
| 287 } | 281 } |
| 288 | 282 |
| 289 Request* Request::create(ScriptState* scriptState, Request* input, const Diction
ary& init, ExceptionState& exceptionState) | 283 Request* Request::create(ScriptState* scriptState, Request* input, const Diction
ary& init, ExceptionState& exceptionState) |
| 290 { | 284 { |
| 291 return createRequestWithRequestOrString(scriptState, input, String(), Reques
tInit(scriptState->executionContext(), init, exceptionState), exceptionState); | 285 return createRequestWithRequestOrString(scriptState, input, String(), Reques
tInit(scriptState->executionContext(), init, exceptionState), exceptionState); |
| 292 } | 286 } |
| 293 | 287 |
| 294 Request* Request::create(ExecutionContext* context, FetchRequestData* request) | 288 Request* Request::create(ExecutionContext* context, FetchRequestData* request) |
| 295 { | 289 { |
| 296 Request* r = new Request(context, request); | 290 return new Request(context, request); |
| 297 r->suspendIfNeeded(); | |
| 298 return r; | |
| 299 } | 291 } |
| 300 | 292 |
| 301 Request::Request(ExecutionContext* context, FetchRequestData* request) | 293 Request::Request(ExecutionContext* context, FetchRequestData* request) |
| 302 : Body(context) | 294 : Body(context) |
| 303 , m_request(request) | 295 , m_request(request) |
| 304 , m_headers(Headers::create(m_request->headerList())) | 296 , m_headers(Headers::create(m_request->headerList())) |
| 305 { | 297 { |
| 306 m_headers->setGuard(Headers::RequestGuard); | 298 m_headers->setGuard(Headers::RequestGuard); |
| 307 | |
| 308 refreshBody(); | |
| 309 } | 299 } |
| 310 | 300 |
| 311 Request::Request(ExecutionContext* context, FetchRequestData* request, Headers*
headers) | 301 Request::Request(ExecutionContext* context, FetchRequestData* request, Headers*
headers) |
| 312 : Body(context) , m_request(request) , m_headers(headers) | 302 : Body(context) , m_request(request) , m_headers(headers) {} |
| 313 { | |
| 314 refreshBody(); | |
| 315 } | |
| 316 | 303 |
| 317 Request* Request::create(ExecutionContext* context, const WebServiceWorkerReques
t& webRequest) | 304 Request* Request::create(ExecutionContext* context, const WebServiceWorkerReques
t& webRequest) |
| 318 { | 305 { |
| 319 Request* r = new Request(context, webRequest); | 306 return new Request(context, webRequest); |
| 320 r->suspendIfNeeded(); | |
| 321 return r; | |
| 322 } | 307 } |
| 323 | 308 |
| 324 Request::Request(ExecutionContext* context, const WebServiceWorkerRequest& webRe
quest) | 309 Request::Request(ExecutionContext* context, const WebServiceWorkerRequest& webRe
quest) |
| 325 : Body(context) | 310 : Body(context) |
| 326 , m_request(FetchRequestData::create(context, webRequest)) | 311 , m_request(FetchRequestData::create(context, webRequest)) |
| 327 , m_headers(Headers::create(m_request->headerList())) | 312 , m_headers(Headers::create(m_request->headerList())) |
| 328 { | 313 { |
| 329 m_headers->setGuard(Headers::RequestGuard); | 314 m_headers->setGuard(Headers::RequestGuard); |
| 330 | |
| 331 refreshBody(); | |
| 332 } | 315 } |
| 333 | 316 |
| 334 String Request::method() const | 317 String Request::method() const |
| 335 { | 318 { |
| 336 // "The method attribute's getter must return request's method." | 319 // "The method attribute's getter must return request's method." |
| 337 return m_request->method(); | 320 return m_request->method(); |
| 338 } | 321 } |
| 339 | 322 |
| 340 KURL Request::url() const | 323 KURL Request::url() const |
| 341 { | 324 { |
| (...skipping 128 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 470 return ""; | 453 return ""; |
| 471 } | 454 } |
| 472 | 455 |
| 473 Request* Request::clone(ExceptionState& exceptionState) | 456 Request* Request::clone(ExceptionState& exceptionState) |
| 474 { | 457 { |
| 475 if (bodyUsed()) { | 458 if (bodyUsed()) { |
| 476 exceptionState.throwTypeError("Request body is already used"); | 459 exceptionState.throwTypeError("Request body is already used"); |
| 477 return nullptr; | 460 return nullptr; |
| 478 } | 461 } |
| 479 | 462 |
| 480 if (OwnPtr<DrainingBodyStreamBuffer> buffer = createDrainingStream()) | |
| 481 m_request->setBuffer(buffer->leakBuffer()); | |
| 482 | |
| 483 FetchRequestData* request = m_request->clone(executionContext()); | 463 FetchRequestData* request = m_request->clone(executionContext()); |
| 484 Headers* headers = Headers::create(request->headerList()); | 464 Headers* headers = Headers::create(request->headerList()); |
| 485 headers->setGuard(m_headers->guard()); | 465 headers->setGuard(m_headers->guard()); |
| 486 Request* r = new Request(executionContext(), request, headers); | 466 return new Request(executionContext(), request, headers); |
| 487 r->suspendIfNeeded(); | |
| 488 | |
| 489 // Lock the old body and set |body| property to the new one. | |
| 490 lockBody(); | |
| 491 refreshBody(); | |
| 492 return r; | |
| 493 } | 467 } |
| 494 | 468 |
| 495 FetchRequestData* Request::passRequestData() | 469 FetchRequestData* Request::passRequestData() |
| 496 { | 470 { |
| 497 ASSERT(!bodyUsed()); | 471 ASSERT(!bodyUsed()); |
| 472 setBodyPassed(); |
| 473 FetchRequestData* newRequestData = m_request->pass(executionContext()); |
| 474 return newRequestData; |
| 475 } |
| 498 | 476 |
| 499 if (OwnPtr<DrainingBodyStreamBuffer> buffer = createDrainingStream()) | 477 bool Request::hasBody() const |
| 500 m_request->setBuffer(buffer->leakBuffer()); | 478 { |
| 501 | 479 return bodyBuffer()->hasBody(); |
| 502 lockBody(PassBody); | |
| 503 FetchRequestData* newRequestData = m_request->pass(executionContext()); | |
| 504 refreshBody(); | |
| 505 return newRequestData; | |
| 506 } | 480 } |
| 507 | 481 |
| 508 void Request::populateWebServiceWorkerRequest(WebServiceWorkerRequest& webReques
t) const | 482 void Request::populateWebServiceWorkerRequest(WebServiceWorkerRequest& webReques
t) const |
| 509 { | 483 { |
| 510 webRequest.setMethod(method()); | 484 webRequest.setMethod(method()); |
| 511 webRequest.setRequestContext(m_request->context()); | 485 webRequest.setRequestContext(m_request->context()); |
| 512 // This strips off the fragment part. | 486 // This strips off the fragment part. |
| 513 webRequest.setURL(url()); | 487 webRequest.setURL(url()); |
| 514 | 488 |
| 515 const FetchHeaderList* headerList = m_headers->headerList(); | 489 const FetchHeaderList* headerList = m_headers->headerList(); |
| 516 for (size_t i = 0, size = headerList->size(); i < size; ++i) { | 490 for (size_t i = 0, size = headerList->size(); i < size; ++i) { |
| 517 const FetchHeaderList::Header& header = headerList->entry(i); | 491 const FetchHeaderList::Header& header = headerList->entry(i); |
| 518 webRequest.appendHeader(header.first, header.second); | 492 webRequest.appendHeader(header.first, header.second); |
| 519 } | 493 } |
| 520 | 494 |
| 521 webRequest.setReferrer(m_request->referrer().referrer().referrer, static_cas
t<WebReferrerPolicy>(m_request->referrer().referrer().referrerPolicy)); | 495 webRequest.setReferrer(m_request->referrer().referrer().referrer, static_cas
t<WebReferrerPolicy>(m_request->referrer().referrer().referrerPolicy)); |
| 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 | 496 // 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 |
| 523 // to plumb this information in to here. | 497 // to plumb this information in to here. |
| 524 } | 498 } |
| 525 | 499 |
| 526 void Request::setBuffer(BodyStreamBuffer* buffer) | |
| 527 { | |
| 528 m_request->setBuffer(buffer); | |
| 529 refreshBody(); | |
| 530 } | |
| 531 | |
| 532 void Request::refreshBody() | |
| 533 { | |
| 534 setBody(m_request->buffer()); | |
| 535 } | |
| 536 | |
| 537 void Request::clearHeaderList() | |
| 538 { | |
| 539 m_request->headerList()->clearList(); | |
| 540 } | |
| 541 | |
| 542 String Request::mimeType() const | 500 String Request::mimeType() const |
| 543 { | 501 { |
| 544 return m_request->mimeType(); | 502 return m_request->mimeType(); |
| 545 } | 503 } |
| 546 | 504 |
| 547 DEFINE_TRACE(Request) | 505 DEFINE_TRACE(Request) |
| 548 { | 506 { |
| 549 Body::trace(visitor); | 507 Body::trace(visitor); |
| 550 visitor->trace(m_request); | 508 visitor->trace(m_request); |
| 551 visitor->trace(m_headers); | 509 visitor->trace(m_headers); |
| 552 } | 510 } |
| 553 | 511 |
| 554 } // namespace blink | 512 } // namespace blink |
| OLD | NEW |