| 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" |
| (...skipping 19 matching lines...) Expand all Loading... |
| 30 #include "modules/fetch/ResponseInit.h" | 30 #include "modules/fetch/ResponseInit.h" |
| 31 #include "platform/network/ResourceError.h" | 31 #include "platform/network/ResourceError.h" |
| 32 #include "platform/network/ResourceRequest.h" | 32 #include "platform/network/ResourceRequest.h" |
| 33 #include "platform/network/ResourceResponse.h" | 33 #include "platform/network/ResourceResponse.h" |
| 34 #include "platform/weborigin/SecurityOrigin.h" | 34 #include "platform/weborigin/SecurityOrigin.h" |
| 35 #include "public/platform/WebURLRequest.h" | 35 #include "public/platform/WebURLRequest.h" |
| 36 #include "wtf/HashSet.h" | 36 #include "wtf/HashSet.h" |
| 37 | 37 |
| 38 namespace blink { | 38 namespace blink { |
| 39 | 39 |
| 40 namespace { | |
| 41 | |
| 42 bool IsRedirectStatusCode(int statusCode) | |
| 43 { | |
| 44 return (statusCode == 301 || statusCode == 302 || statusCode == 303 || statu
sCode == 307 || statusCode == 308); | |
| 45 } | |
| 46 | |
| 47 } // namespace | |
| 48 | |
| 49 class FetchManager::Loader final : public NoBaseWillBeGarbageCollectedFinalized<
FetchManager::Loader>, public ThreadableLoaderClient, public ContextLifecycleObs
erver { | 40 class FetchManager::Loader final : public NoBaseWillBeGarbageCollectedFinalized<
FetchManager::Loader>, public ThreadableLoaderClient, public ContextLifecycleObs
erver { |
| 50 WILL_BE_USING_GARBAGE_COLLECTED_MIXIN(FetchManager::Loader); | 41 WILL_BE_USING_GARBAGE_COLLECTED_MIXIN(FetchManager::Loader); |
| 51 public: | 42 public: |
| 52 static PassOwnPtrWillBeRawPtr<Loader> create(ExecutionContext* executionCont
ext, FetchManager* fetchManager, ScriptPromiseResolver* resolver, FetchRequestDa
ta* request) | 43 static PassOwnPtrWillBeRawPtr<Loader> create(ExecutionContext* executionCont
ext, FetchManager* fetchManager, ScriptPromiseResolver* resolver, FetchRequestDa
ta* request) |
| 53 { | 44 { |
| 54 return adoptPtrWillBeNoop(new Loader(executionContext, fetchManager, res
olver, request)); | 45 return adoptPtrWillBeNoop(new Loader(executionContext, fetchManager, res
olver, request)); |
| 55 } | 46 } |
| 56 | 47 |
| 57 ~Loader() override; | 48 ~Loader() override; |
| 58 DECLARE_VIRTUAL_TRACE(); | 49 DECLARE_VIRTUAL_TRACE(); |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 104 DEFINE_TRACE(FetchManager::Loader) | 95 DEFINE_TRACE(FetchManager::Loader) |
| 105 { | 96 { |
| 106 visitor->trace(m_fetchManager); | 97 visitor->trace(m_fetchManager); |
| 107 visitor->trace(m_resolver); | 98 visitor->trace(m_resolver); |
| 108 visitor->trace(m_request); | 99 visitor->trace(m_request); |
| 109 ContextLifecycleObserver::trace(visitor); | 100 ContextLifecycleObserver::trace(visitor); |
| 110 } | 101 } |
| 111 | 102 |
| 112 void FetchManager::Loader::didReceiveResponse(unsigned long, const ResourceRespo
nse& response, PassOwnPtr<WebDataConsumerHandle> handle) | 103 void FetchManager::Loader::didReceiveResponse(unsigned long, const ResourceRespo
nse& response, PassOwnPtr<WebDataConsumerHandle> handle) |
| 113 { | 104 { |
| 114 ASSERT(handle); | |
| 115 | |
| 116 m_responseHttpStatusCode = response.httpStatusCode(); | 105 m_responseHttpStatusCode = response.httpStatusCode(); |
| 117 | 106 |
| 118 // Recompute the tainting if the request was redirected to a different | 107 // Recompute the tainting if the request was redirected to a different |
| 119 // origin. | 108 // origin. |
| 120 if (!SecurityOrigin::create(response.url())->isSameSchemeHostPort(m_request-
>origin().get())) { | 109 if (!SecurityOrigin::create(response.url())->isSameSchemeHostPort(m_request-
>origin().get())) { |
| 121 switch (m_request->mode()) { | 110 switch (m_request->mode()) { |
| 122 case WebURLRequest::FetchRequestModeSameOrigin: | 111 case WebURLRequest::FetchRequestModeSameOrigin: |
| 123 ASSERT_NOT_REACHED(); | 112 ASSERT_NOT_REACHED(); |
| 124 break; | 113 break; |
| 125 case WebURLRequest::FetchRequestModeNoCORS: | 114 case WebURLRequest::FetchRequestModeNoCORS: |
| 126 m_request->setResponseTainting(FetchRequestData::OpaqueTainting); | 115 m_request->setResponseTainting(FetchRequestData::OpaqueTainting); |
| 127 break; | 116 break; |
| 128 case WebURLRequest::FetchRequestModeCORS: | 117 case WebURLRequest::FetchRequestModeCORS: |
| 129 case WebURLRequest::FetchRequestModeCORSWithForcedPreflight: | 118 case WebURLRequest::FetchRequestModeCORSWithForcedPreflight: |
| 130 m_request->setResponseTainting(FetchRequestData::CORSTainting); | 119 m_request->setResponseTainting(FetchRequestData::CORSTainting); |
| 131 break; | 120 break; |
| 132 } | 121 } |
| 133 } | 122 } |
| 134 FetchResponseData* responseData = FetchResponseData::createWithBuffer(new Bo
dyStreamBuffer(createFetchDataConsumerHandleFromWebHandle(handle))); | 123 |
| 124 bool isRedirectResponse = false; |
| 125 FetchResponseData* responseData = nullptr; |
| 126 if (!handle) { |
| 127 ASSERT(IsRedirectStatusCode(m_responseHttpStatusCode)); |
| 128 ASSERT(m_request->redirect() == WebURLRequest::FetchRedirectModeManual); |
| 129 isRedirectResponse = true; |
| 130 responseData = FetchResponseData::create(); |
| 131 } else { |
| 132 responseData = FetchResponseData::createWithBuffer(new BodyStreamBuffer(
createFetchDataConsumerHandleFromWebHandle(handle))); |
| 133 } |
| 135 responseData->setStatus(response.httpStatusCode()); | 134 responseData->setStatus(response.httpStatusCode()); |
| 136 responseData->setStatusMessage(response.httpStatusText()); | 135 responseData->setStatusMessage(response.httpStatusText()); |
| 137 for (auto& it : response.httpHeaderFields()) | 136 for (auto& it : response.httpHeaderFields()) |
| 138 responseData->headerList()->append(it.key, it.value); | 137 responseData->headerList()->append(it.key, it.value); |
| 139 responseData->setURL(response.url()); | 138 responseData->setURL(response.url()); |
| 140 responseData->setMIMEType(response.mimeType()); | 139 responseData->setMIMEType(response.mimeType()); |
| 141 | 140 |
| 142 FetchResponseData* taintedResponse = nullptr; | 141 FetchResponseData* taintedResponse = nullptr; |
| 143 | 142 |
| 144 if (IsRedirectStatusCode(m_responseHttpStatusCode)) { | 143 if (isRedirectResponse) { |
| 145 Vector<String> locations; | 144 taintedResponse = responseData->createOpaqueRedirectFilteredResponse(); |
| 146 responseData->headerList()->getAll("location", locations); | 145 } else { |
| 147 if (locations.size() > 1) { | |
| 148 performNetworkError("Multiple Location header."); | |
| 149 return; | |
| 150 } | |
| 151 if (locations.size() == 1) { | |
| 152 KURL locationURL(m_request->url(), locations[0]); | |
| 153 if (!locationURL.isValid()) { | |
| 154 performNetworkError("Invalid Location header."); | |
| 155 return; | |
| 156 } | |
| 157 ASSERT(m_request->redirect() == WebURLRequest::FetchRedirectModeManu
al); | |
| 158 taintedResponse = responseData->createOpaqueRedirectFilteredResponse
(); | |
| 159 } | |
| 160 // When the location header doesn't exist, we don't treat the response | |
| 161 // as a redirect response, and execute tainting. | |
| 162 } | |
| 163 if (!taintedResponse) { | |
| 164 switch (m_request->tainting()) { | 146 switch (m_request->tainting()) { |
| 165 case FetchRequestData::BasicTainting: | 147 case FetchRequestData::BasicTainting: |
| 166 taintedResponse = responseData->createBasicFilteredResponse(); | 148 taintedResponse = responseData->createBasicFilteredResponse(); |
| 167 break; | 149 break; |
| 168 case FetchRequestData::CORSTainting: | 150 case FetchRequestData::CORSTainting: |
| 169 taintedResponse = responseData->createCORSFilteredResponse(); | 151 taintedResponse = responseData->createCORSFilteredResponse(); |
| 170 break; | 152 break; |
| 171 case FetchRequestData::OpaqueTainting: | 153 case FetchRequestData::OpaqueTainting: |
| 172 taintedResponse = responseData->createOpaqueFilteredResponse(); | 154 taintedResponse = responseData->createOpaqueFilteredResponse(); |
| 173 break; | 155 break; |
| 174 } | 156 } |
| 175 } | 157 } |
| 176 Response* r = Response::create(m_resolver->executionContext(), taintedRespon
se); | 158 Response* r = Response::create(m_resolver->executionContext(), taintedRespon
se); |
| 177 r->headers()->setGuard(Headers::ImmutableGuard); | 159 r->headers()->setGuard(Headers::ImmutableGuard); |
| 178 m_resolver->resolve(r); | 160 m_resolver->resolve(r); |
| 179 m_resolver.clear(); | 161 m_resolver.clear(); |
| 162 |
| 163 if (isRedirectResponse) { |
| 164 // There is no need to read the body of redirect response because there |
| 165 // is no way to read the body of opaque-redirect filtered response's |
| 166 // internal response. |
| 167 // TODO(horo): If we support any API which expose the internal body, we |
| 168 // will have to read the body. And also HTTPCache changes will be needed |
| 169 // because it doesn't store the body of redirect responses. |
| 170 notifyFinished(); |
| 171 } |
| 180 } | 172 } |
| 181 | 173 |
| 182 void FetchManager::Loader::didFinishLoading(unsigned long, double) | 174 void FetchManager::Loader::didFinishLoading(unsigned long, double) |
| 183 { | 175 { |
| 184 ASSERT(!m_failed); | 176 ASSERT(!m_failed); |
| 185 m_finished = true; | 177 m_finished = true; |
| 186 | 178 |
| 187 if (document() && document()->frame() && document()->frame()->page() | 179 if (document() && document()->frame() && document()->frame()->page() |
| 188 && m_responseHttpStatusCode >= 200 && m_responseHttpStatusCode < 300) { | 180 && m_responseHttpStatusCode >= 200 && m_responseHttpStatusCode < 300) { |
| 189 document()->frame()->page()->chromeClient().ajaxSucceeded(document()->fr
ame()); | 181 document()->frame()->page()->chromeClient().ajaxSucceeded(document()->fr
ame()); |
| (...skipping 298 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 488 | 480 |
| 489 DEFINE_TRACE(FetchManager) | 481 DEFINE_TRACE(FetchManager) |
| 490 { | 482 { |
| 491 #if ENABLE(OILPAN) | 483 #if ENABLE(OILPAN) |
| 492 visitor->trace(m_executionContext); | 484 visitor->trace(m_executionContext); |
| 493 visitor->trace(m_loaders); | 485 visitor->trace(m_loaders); |
| 494 #endif | 486 #endif |
| 495 } | 487 } |
| 496 | 488 |
| 497 } // namespace blink | 489 } // namespace blink |
| OLD | NEW |