| 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/FetchManager.h" | 6 #include "modules/fetch/FetchManager.h" |
| 7 | 7 |
| 8 #include "bindings/core/v8/ExceptionState.h" | 8 #include "bindings/core/v8/ExceptionState.h" |
| 9 #include "bindings/core/v8/ScriptPromiseResolver.h" | 9 #include "bindings/core/v8/ScriptPromiseResolver.h" |
| 10 #include "bindings/core/v8/ScriptState.h" | 10 #include "bindings/core/v8/ScriptState.h" |
| 11 #include "bindings/core/v8/V8ThrowException.h" | 11 #include "bindings/core/v8/V8ThrowException.h" |
| 12 #include "core/dom/DOMArrayBuffer.h" | 12 #include "core/dom/DOMArrayBuffer.h" |
| 13 #include "core/dom/ExceptionCode.h" | 13 #include "core/dom/ExceptionCode.h" |
| 14 #include "core/fetch/FetchUtils.h" | 14 #include "core/fetch/FetchUtils.h" |
| 15 #include "core/fileapi/Blob.h" | 15 #include "core/fileapi/Blob.h" |
| 16 #include "core/frame/csp/ContentSecurityPolicy.h" | 16 #include "core/frame/csp/ContentSecurityPolicy.h" |
| 17 #include "core/inspector/ConsoleMessage.h" | 17 #include "core/inspector/ConsoleMessage.h" |
| 18 #include "core/loader/ThreadableLoader.h" | 18 #include "core/loader/ThreadableLoader.h" |
| 19 #include "core/loader/ThreadableLoaderClient.h" | 19 #include "core/loader/ThreadableLoaderClient.h" |
| 20 #include "modules/fetch/Body.h" | 20 #include "modules/fetch/Body.h" |
| 21 #include "modules/fetch/BodyStreamBuffer.h" | 21 #include "modules/fetch/BodyStreamBuffer.h" |
| 22 #include "modules/fetch/DataConsumerHandleUtil.h" |
| 22 #include "modules/fetch/FetchRequestData.h" | 23 #include "modules/fetch/FetchRequestData.h" |
| 23 #include "modules/fetch/Response.h" | 24 #include "modules/fetch/Response.h" |
| 24 #include "modules/fetch/ResponseInit.h" | 25 #include "modules/fetch/ResponseInit.h" |
| 25 #include "platform/network/ResourceError.h" | 26 #include "platform/network/ResourceError.h" |
| 26 #include "platform/network/ResourceRequest.h" | 27 #include "platform/network/ResourceRequest.h" |
| 27 #include "platform/network/ResourceResponse.h" | 28 #include "platform/network/ResourceResponse.h" |
| 28 #include "platform/weborigin/SecurityOrigin.h" | 29 #include "platform/weborigin/SecurityOrigin.h" |
| 29 #include "public/platform/WebURLRequest.h" | 30 #include "public/platform/WebURLRequest.h" |
| 30 #include "wtf/HashSet.h" | 31 #include "wtf/HashSet.h" |
| 31 | 32 |
| 32 namespace blink { | 33 namespace blink { |
| 33 | 34 |
| 34 class FetchManager::Loader final : public NoBaseWillBeGarbageCollectedFinalized<
FetchManager::Loader>, public ThreadableLoaderClient, public ContextLifecycleObs
erver { | 35 class FetchManager::Loader final : public NoBaseWillBeGarbageCollectedFinalized<
FetchManager::Loader>, public ThreadableLoaderClient, public ContextLifecycleObs
erver { |
| 35 WILL_BE_USING_GARBAGE_COLLECTED_MIXIN(FetchManager::Loader); | 36 WILL_BE_USING_GARBAGE_COLLECTED_MIXIN(FetchManager::Loader); |
| 36 public: | 37 public: |
| 37 static PassOwnPtrWillBeRawPtr<Loader> create(ExecutionContext* executionCont
ext, FetchManager* fetchManager, PassRefPtrWillBeRawPtr<ScriptPromiseResolver> r
esolver, FetchRequestData* request) | 38 static PassOwnPtrWillBeRawPtr<Loader> create(ExecutionContext* executionCont
ext, FetchManager* fetchManager, PassRefPtrWillBeRawPtr<ScriptPromiseResolver> r
esolver, FetchRequestData* request) |
| 38 { | 39 { |
| 39 return adoptPtrWillBeNoop(new Loader(executionContext, fetchManager, res
olver, request)); | 40 return adoptPtrWillBeNoop(new Loader(executionContext, fetchManager, res
olver, request)); |
| 40 } | 41 } |
| 41 | 42 |
| 42 ~Loader() override; | 43 ~Loader() override; |
| 43 DECLARE_VIRTUAL_TRACE(); | 44 DECLARE_VIRTUAL_TRACE(); |
| 44 | 45 |
| 45 void didReceiveResponse(unsigned long, const ResourceResponse&, PassOwnPtr<W
ebDataConsumerHandle>) override; | 46 void didReceiveResponse(unsigned long, const ResourceResponse&, PassOwnPtr<W
ebDataConsumerHandle>) override; |
| 46 void didReceiveData(const char*, unsigned) override; | |
| 47 void didFinishLoading(unsigned long, double) override; | 47 void didFinishLoading(unsigned long, double) override; |
| 48 void didFail(const ResourceError&) override; | 48 void didFail(const ResourceError&) override; |
| 49 void didFailAccessControlCheck(const ResourceError&) override; | 49 void didFailAccessControlCheck(const ResourceError&) override; |
| 50 void didFailRedirectCheck() override; | 50 void didFailRedirectCheck() override; |
| 51 | 51 |
| 52 void start(); | 52 void start(); |
| 53 void cancel(); | 53 void cancel(); |
| 54 void dispose(); | 54 void dispose(); |
| 55 | 55 |
| 56 private: | 56 private: |
| 57 class Canceller : public BodyStreamBuffer::Canceller { | |
| 58 public: | |
| 59 explicit Canceller(Loader* loader) : m_loader(loader) { } | |
| 60 void cancel() override | |
| 61 { | |
| 62 if (m_loader) | |
| 63 m_loader->cancel(); | |
| 64 } | |
| 65 | |
| 66 #if !ENABLE(OILPAN) | |
| 67 // FIXME: This function should go away once Oilpan is shipped. | |
| 68 void disconnect() { m_loader = nullptr; } | |
| 69 #endif | |
| 70 | |
| 71 DEFINE_INLINE_VIRTUAL_TRACE() | |
| 72 { | |
| 73 visitor->trace(m_loader); | |
| 74 BodyStreamBuffer::Canceller::trace(visitor); | |
| 75 } | |
| 76 | |
| 77 private: | |
| 78 // |m_loader| is a raw ptr in non-oilpan circumstance to avoid | |
| 79 // circular reference. It will be cleared when the loader is destructed. | |
| 80 RawPtrWillBeMember<Loader> m_loader; | |
| 81 }; | |
| 82 | |
| 83 | |
| 84 Loader(ExecutionContext*, FetchManager*, PassRefPtrWillBeRawPtr<ScriptPromis
eResolver>, FetchRequestData*); | 57 Loader(ExecutionContext*, FetchManager*, PassRefPtrWillBeRawPtr<ScriptPromis
eResolver>, FetchRequestData*); |
| 85 | 58 |
| 86 void performBasicFetch(); | 59 void performBasicFetch(); |
| 87 void performNetworkError(const String& message); | 60 void performNetworkError(const String& message); |
| 88 void performHTTPFetch(bool corsFlag, bool corsPreflightFlag); | 61 void performHTTPFetch(bool corsFlag, bool corsPreflightFlag); |
| 89 void failed(const String& message); | 62 void failed(const String& message); |
| 90 void notifyFinished(); | 63 void notifyFinished(); |
| 91 | 64 |
| 92 RawPtrWillBeMember<FetchManager> m_fetchManager; | 65 RawPtrWillBeMember<FetchManager> m_fetchManager; |
| 93 RefPtrWillBeMember<ScriptPromiseResolver> m_resolver; | 66 RefPtrWillBeMember<ScriptPromiseResolver> m_resolver; |
| 94 PersistentWillBeMember<FetchRequestData> m_request; | 67 PersistentWillBeMember<FetchRequestData> m_request; |
| 95 PersistentWillBeMember<BodyStreamBuffer> m_responseBuffer; | |
| 96 RefPtr<ThreadableLoader> m_loader; | 68 RefPtr<ThreadableLoader> m_loader; |
| 97 // Hold as a member in order to call |disconnect|. This member can be | |
| 98 // eliminated once Oilpan is shipped. | |
| 99 PersistentWillBeMember<Canceller> m_canceller; | |
| 100 bool m_failed; | 69 bool m_failed; |
| 101 bool m_finished; | 70 bool m_finished; |
| 102 }; | 71 }; |
| 103 | 72 |
| 104 FetchManager::Loader::Loader(ExecutionContext* executionContext, FetchManager* f
etchManager, PassRefPtrWillBeRawPtr<ScriptPromiseResolver> resolver, FetchReques
tData* request) | 73 FetchManager::Loader::Loader(ExecutionContext* executionContext, FetchManager* f
etchManager, PassRefPtrWillBeRawPtr<ScriptPromiseResolver> resolver, FetchReques
tData* request) |
| 105 : ContextLifecycleObserver(executionContext) | 74 : ContextLifecycleObserver(executionContext) |
| 106 , m_fetchManager(fetchManager) | 75 , m_fetchManager(fetchManager) |
| 107 , m_resolver(resolver) | 76 , m_resolver(resolver) |
| 108 , m_request(request) | 77 , m_request(request) |
| 109 , m_canceller(new Canceller(this)) | |
| 110 , m_failed(false) | 78 , m_failed(false) |
| 111 , m_finished(false) | 79 , m_finished(false) |
| 112 { | 80 { |
| 113 } | 81 } |
| 114 | 82 |
| 115 FetchManager::Loader::~Loader() | 83 FetchManager::Loader::~Loader() |
| 116 { | 84 { |
| 117 ASSERT(!m_loader); | 85 ASSERT(!m_loader); |
| 118 #if !ENABLE(OILPAN) | |
| 119 // FIXME: This should go away once Oilpan is shipped. | |
| 120 m_canceller->disconnect(); | |
| 121 #endif | |
| 122 } | 86 } |
| 123 | 87 |
| 124 DEFINE_TRACE(FetchManager::Loader) | 88 DEFINE_TRACE(FetchManager::Loader) |
| 125 { | 89 { |
| 126 visitor->trace(m_fetchManager); | 90 visitor->trace(m_fetchManager); |
| 127 visitor->trace(m_resolver); | 91 visitor->trace(m_resolver); |
| 128 visitor->trace(m_request); | 92 visitor->trace(m_request); |
| 129 visitor->trace(m_responseBuffer); | |
| 130 visitor->trace(m_canceller); | |
| 131 ContextLifecycleObserver::trace(visitor); | 93 ContextLifecycleObserver::trace(visitor); |
| 132 } | 94 } |
| 133 | 95 |
| 134 void FetchManager::Loader::didReceiveResponse(unsigned long, const ResourceRespo
nse& response, PassOwnPtr<WebDataConsumerHandle> handle) | 96 void FetchManager::Loader::didReceiveResponse(unsigned long, const ResourceRespo
nse& response, PassOwnPtr<WebDataConsumerHandle> handle) |
| 135 { | 97 { |
| 136 // FIXME: Use |handle|. | 98 ASSERT(handle); |
| 137 ASSERT_UNUSED(handle, !handle); | |
| 138 // Recompute the tainting if the request was redirected to a different | 99 // Recompute the tainting if the request was redirected to a different |
| 139 // origin. | 100 // origin. |
| 140 if (!SecurityOrigin::create(response.url())->isSameSchemeHostPort(m_request-
>origin().get())) { | 101 if (!SecurityOrigin::create(response.url())->isSameSchemeHostPort(m_request-
>origin().get())) { |
| 141 switch (m_request->mode()) { | 102 switch (m_request->mode()) { |
| 142 case WebURLRequest::FetchRequestModeSameOrigin: | 103 case WebURLRequest::FetchRequestModeSameOrigin: |
| 143 ASSERT_NOT_REACHED(); | 104 ASSERT_NOT_REACHED(); |
| 144 break; | 105 break; |
| 145 case WebURLRequest::FetchRequestModeNoCORS: | 106 case WebURLRequest::FetchRequestModeNoCORS: |
| 146 m_request->setResponseTainting(FetchRequestData::OpaqueTainting); | 107 m_request->setResponseTainting(FetchRequestData::OpaqueTainting); |
| 147 break; | 108 break; |
| 148 case WebURLRequest::FetchRequestModeCORS: | 109 case WebURLRequest::FetchRequestModeCORS: |
| 149 case WebURLRequest::FetchRequestModeCORSWithForcedPreflight: | 110 case WebURLRequest::FetchRequestModeCORSWithForcedPreflight: |
| 150 m_request->setResponseTainting(FetchRequestData::CORSTainting); | 111 m_request->setResponseTainting(FetchRequestData::CORSTainting); |
| 151 break; | 112 break; |
| 152 } | 113 } |
| 153 } | 114 } |
| 154 m_responseBuffer = new BodyStreamBuffer(m_canceller); | 115 FetchResponseData* responseData = FetchResponseData::createWithBuffer(create
FetchDataConsumerHandleFromWebHandle(handle)); |
| 155 FetchResponseData* responseData = FetchResponseData::createWithBuffer(m_resp
onseBuffer); | |
| 156 responseData->setStatus(response.httpStatusCode()); | 116 responseData->setStatus(response.httpStatusCode()); |
| 157 responseData->setStatusMessage(response.httpStatusText()); | 117 responseData->setStatusMessage(response.httpStatusText()); |
| 158 for (auto& it : response.httpHeaderFields()) | 118 for (auto& it : response.httpHeaderFields()) |
| 159 responseData->headerList()->append(it.key, it.value); | 119 responseData->headerList()->append(it.key, it.value); |
| 160 responseData->setURL(response.url()); | 120 responseData->setURL(response.url()); |
| 161 responseData->setMIMEType(response.mimeType()); | 121 responseData->setMIMEType(response.mimeType()); |
| 162 | 122 |
| 163 FetchResponseData* taintedResponse = responseData; | 123 FetchResponseData* taintedResponse = responseData; |
| 164 switch (m_request->tainting()) { | 124 switch (m_request->tainting()) { |
| 165 case FetchRequestData::BasicTainting: | 125 case FetchRequestData::BasicTainting: |
| 166 taintedResponse = responseData->createBasicFilteredResponse(); | 126 taintedResponse = responseData->createBasicFilteredResponse(); |
| 167 break; | 127 break; |
| 168 case FetchRequestData::CORSTainting: | 128 case FetchRequestData::CORSTainting: |
| 169 taintedResponse = responseData->createCORSFilteredResponse(); | 129 taintedResponse = responseData->createCORSFilteredResponse(); |
| 170 break; | 130 break; |
| 171 case FetchRequestData::OpaqueTainting: | 131 case FetchRequestData::OpaqueTainting: |
| 172 taintedResponse = responseData->createOpaqueFilteredResponse(); | 132 taintedResponse = responseData->createOpaqueFilteredResponse(); |
| 173 break; | 133 break; |
| 174 } | 134 } |
| 175 Response* r = Response::create(m_resolver->executionContext(), taintedRespon
se); | 135 Response* r = Response::create(m_resolver->executionContext(), taintedRespon
se); |
| 176 r->headers()->setGuard(Headers::ImmutableGuard); | 136 r->headers()->setGuard(Headers::ImmutableGuard); |
| 177 m_resolver->resolve(r); | 137 m_resolver->resolve(r); |
| 178 m_resolver.clear(); | 138 m_resolver.clear(); |
| 179 } | 139 } |
| 180 | 140 |
| 181 void FetchManager::Loader::didReceiveData(const char* data, unsigned size) | |
| 182 { | |
| 183 m_responseBuffer->write(DOMArrayBuffer::create(data, size)); | |
| 184 } | |
| 185 | |
| 186 void FetchManager::Loader::didFinishLoading(unsigned long, double) | 141 void FetchManager::Loader::didFinishLoading(unsigned long, double) |
| 187 { | 142 { |
| 188 ASSERT(m_responseBuffer); | |
| 189 ASSERT(!m_failed); | 143 ASSERT(!m_failed); |
| 190 m_responseBuffer->close(); | |
| 191 m_responseBuffer.clear(); | |
| 192 m_finished = true; | 144 m_finished = true; |
| 193 notifyFinished(); | 145 notifyFinished(); |
| 194 } | 146 } |
| 195 | 147 |
| 196 void FetchManager::Loader::didFail(const ResourceError& error) | 148 void FetchManager::Loader::didFail(const ResourceError& error) |
| 197 { | 149 { |
| 198 if (error.isCancellation() || error.isTimeout() || error.domain() != errorDo
mainBlinkInternal) | 150 if (error.isCancellation() || error.isTimeout() || error.domain() != errorDo
mainBlinkInternal) |
| 199 failed(String()); | 151 failed(String()); |
| 200 else | 152 else |
| 201 failed("Fetch API cannot load " + error.failingURL() + ". " + error.loca
lizedDescription()); | 153 failed("Fetch API cannot load " + error.failingURL() + ". " + error.loca
lizedDescription()); |
| (...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 305 performHTTPFetch(true, false); | 257 performHTTPFetch(true, false); |
| 306 } | 258 } |
| 307 | 259 |
| 308 void FetchManager::Loader::cancel() | 260 void FetchManager::Loader::cancel() |
| 309 { | 261 { |
| 310 m_finished = true; | 262 m_finished = true; |
| 311 if (m_loader) { | 263 if (m_loader) { |
| 312 m_loader->cancel(); | 264 m_loader->cancel(); |
| 313 m_loader.clear(); | 265 m_loader.clear(); |
| 314 } | 266 } |
| 315 if (m_responseBuffer) { | |
| 316 m_responseBuffer->close(); | |
| 317 m_responseBuffer.clear(); | |
| 318 } | |
| 319 if (m_resolver) { | 267 if (m_resolver) { |
| 320 // Note: In the current implementation this branch is never taken | 268 // Note: In the current implementation this branch is never taken |
| 321 // because this function can be called only through the body stream. | 269 // because this function can be called only through the body stream. |
| 322 ScriptState* scriptState = m_resolver->scriptState(); | 270 ScriptState* scriptState = m_resolver->scriptState(); |
| 323 ScriptState::Scope scope(scriptState); | 271 ScriptState::Scope scope(scriptState); |
| 324 m_resolver->reject(V8ThrowException::createTypeError(scriptState->isolat
e(), "fetch is cancelled")); | 272 m_resolver->reject(V8ThrowException::createTypeError(scriptState->isolat
e(), "fetch is cancelled")); |
| 325 m_resolver.clear(); | 273 m_resolver.clear(); |
| 326 } | 274 } |
| 327 | 275 |
| 328 notifyFinished(); | 276 notifyFinished(); |
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 375 | 323 |
| 376 if (m_request->method() != "GET" && m_request->method() != "HEAD") { | 324 if (m_request->method() != "GET" && m_request->method() != "HEAD") { |
| 377 RefPtr<BlobDataHandle> blobDataHandle = m_request->blobDataHandle(); | 325 RefPtr<BlobDataHandle> blobDataHandle = m_request->blobDataHandle(); |
| 378 if (blobDataHandle.get()) { | 326 if (blobDataHandle.get()) { |
| 379 RefPtr<FormData> httpBody(FormData::create()); | 327 RefPtr<FormData> httpBody(FormData::create()); |
| 380 httpBody->appendBlob(blobDataHandle->uuid(), blobDataHandle); | 328 httpBody->appendBlob(blobDataHandle->uuid(), blobDataHandle); |
| 381 request.setHTTPBody(httpBody); | 329 request.setHTTPBody(httpBody); |
| 382 } | 330 } |
| 383 } | 331 } |
| 384 | 332 |
| 333 request.setUseStreamOnResponse(true); |
| 334 |
| 385 // "2. Append `Referer`/empty byte sequence, if |HTTPRequest|'s |referrer| | 335 // "2. Append `Referer`/empty byte sequence, if |HTTPRequest|'s |referrer| |
| 386 // is none, and `Referer`/|HTTPRequest|'s referrer, serialized and utf-8 | 336 // is none, and `Referer`/|HTTPRequest|'s referrer, serialized and utf-8 |
| 387 // encoded, otherwise, to HTTPRequest's header list. | 337 // encoded, otherwise, to HTTPRequest's header list. |
| 388 // We set the referrer using workerGlobalScope's URL in | 338 // We set the referrer using workerGlobalScope's URL in |
| 389 // WorkerThreadableLoader. | 339 // WorkerThreadableLoader. |
| 390 | 340 |
| 391 // "3. Append `Host`, ..." | 341 // "3. Append `Host`, ..." |
| 392 // FIXME: Implement this when the spec is fixed. | 342 // FIXME: Implement this when the spec is fixed. |
| 393 | 343 |
| 394 // "4.If |HTTPRequest|'s force Origin header flag is set, append `Origin`/ | 344 // "4.If |HTTPRequest|'s force Origin header flag is set, append `Origin`/ |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 431 performNetworkError("Can't create ThreadableLoader"); | 381 performNetworkError("Can't create ThreadableLoader"); |
| 432 } | 382 } |
| 433 | 383 |
| 434 void FetchManager::Loader::failed(const String& message) | 384 void FetchManager::Loader::failed(const String& message) |
| 435 { | 385 { |
| 436 if (m_failed || m_finished) | 386 if (m_failed || m_finished) |
| 437 return; | 387 return; |
| 438 m_failed = true; | 388 m_failed = true; |
| 439 if (!message.isEmpty()) | 389 if (!message.isEmpty()) |
| 440 executionContext()->addConsoleMessage(ConsoleMessage::create(JSMessageSo
urce, ErrorMessageLevel, message)); | 390 executionContext()->addConsoleMessage(ConsoleMessage::create(JSMessageSo
urce, ErrorMessageLevel, message)); |
| 441 if (m_responseBuffer) { | 391 if (m_resolver) { |
| 442 m_responseBuffer->error(DOMException::create(NetworkError, "Failed to fe
tch")); | |
| 443 m_responseBuffer.clear(); | |
| 444 } else if (m_resolver) { | |
| 445 if (!m_resolver->executionContext() || m_resolver->executionContext()->a
ctiveDOMObjectsAreStopped()) | 392 if (!m_resolver->executionContext() || m_resolver->executionContext()->a
ctiveDOMObjectsAreStopped()) |
| 446 return; | 393 return; |
| 447 ScriptState* state = m_resolver->scriptState(); | 394 ScriptState* state = m_resolver->scriptState(); |
| 448 ScriptState::Scope scope(state); | 395 ScriptState::Scope scope(state); |
| 449 m_resolver->reject(V8ThrowException::createTypeError(state->isolate(), "
Failed to fetch")); | 396 m_resolver->reject(V8ThrowException::createTypeError(state->isolate(), "
Failed to fetch")); |
| 450 } | 397 } |
| 451 notifyFinished(); | 398 notifyFinished(); |
| 452 } | 399 } |
| 453 | 400 |
| 454 void FetchManager::Loader::notifyFinished() | 401 void FetchManager::Loader::notifyFinished() |
| (...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 502 | 449 |
| 503 DEFINE_TRACE(FetchManager) | 450 DEFINE_TRACE(FetchManager) |
| 504 { | 451 { |
| 505 #if ENABLE(OILPAN) | 452 #if ENABLE(OILPAN) |
| 506 visitor->trace(m_executionContext); | 453 visitor->trace(m_executionContext); |
| 507 visitor->trace(m_loaders); | 454 visitor->trace(m_loaders); |
| 508 #endif | 455 #endif |
| 509 } | 456 } |
| 510 | 457 |
| 511 } // namespace blink | 458 } // namespace blink |
| OLD | NEW |