Chromium Code Reviews| Index: Source/modules/fetch/FetchManager.cpp |
| diff --git a/Source/modules/fetch/FetchManager.cpp b/Source/modules/fetch/FetchManager.cpp |
| index 989297dbe59509b104bd2b9edd2ab7dba3c3915e..a965f9f33c61dff82393be471ac6363b4c60edf9 100644 |
| --- a/Source/modules/fetch/FetchManager.cpp |
| +++ b/Source/modules/fetch/FetchManager.cpp |
| @@ -15,6 +15,7 @@ |
| #include "core/fetch/FetchUtils.h" |
| #include "core/fileapi/Blob.h" |
| #include "core/frame/Frame.h" |
| +#include "core/frame/SubresourceIntegrity.h" |
| #include "core/frame/csp/ContentSecurityPolicy.h" |
| #include "core/inspector/ConsoleMessage.h" |
| #include "core/inspector/InspectorInstrumentation.h" |
| @@ -24,6 +25,7 @@ |
| #include "core/page/Page.h" |
| #include "modules/fetch/Body.h" |
| #include "modules/fetch/BodyStreamBuffer.h" |
| +#include "modules/fetch/CompositeDataConsumerHandle.h" |
| #include "modules/fetch/DataConsumerHandleUtil.h" |
| #include "modules/fetch/FetchRequestData.h" |
| #include "modules/fetch/Response.h" |
| @@ -34,6 +36,8 @@ |
| #include "platform/weborigin/SecurityOrigin.h" |
| #include "public/platform/WebURLRequest.h" |
| #include "wtf/HashSet.h" |
| +#include "wtf/Vector.h" |
| +#include "wtf/text/WTFString.h" |
| namespace blink { |
| @@ -66,6 +70,74 @@ public: |
| void start(); |
| void dispose(); |
| + class SRIVerifier : public GarbageCollectedFinalized<SRIVerifier>, public WebDataConsumerHandle::Client { |
| + public: |
| + // SRIVerifier takes ownership of |handle| and |response|. |
| + // |updater| must be garbage collected. The other arguments |
| + // all must have the lifetime of the give loader. |
| + SRIVerifier(PassOwnPtr<WebDataConsumerHandle> handle, CompositeDataConsumerHandle::Updater* updater, PassOwnPtr<Response> response, FetchManager::Loader* loader, String integrityMetadata, const KURL& url) |
| + : m_handle(handle) |
| + , m_updater(updater) |
| + , m_response(response) |
| + , m_loader(loader) |
| + , m_integrityMetadata(integrityMetadata) |
| + , m_url(url) |
| + { |
| + m_reader = m_handle->obtainReader(this); |
| + } |
| + |
| + void didGetReadable() override |
| + { |
| + ASSERT(m_reader); |
| + ASSERT(m_loader); |
| + ASSERT(m_response); |
| + |
| + WebDataConsumerHandle::Result r = WebDataConsumerHandle::Ok; |
| + while (r == WebDataConsumerHandle::Ok) { |
| + const void* buffer; |
| + size_t size; |
| + r = m_reader->beginRead(&buffer, WebDataConsumerHandle::FlagNone, &size); |
| + if (r == WebDataConsumerHandle::Ok) { |
| + m_buffer.append(static_cast<const char*>(buffer), size); |
| + m_reader->endRead(size); |
| + } |
| + } |
| + if (r == WebDataConsumerHandle::ShouldWait) |
| + return; |
| + String errorMessage = "Unknown error occurred while trying to verify integrity."; |
| + if (r == WebDataConsumerHandle::Done) { |
| + if (SubresourceIntegrity::CheckSubresourceIntegrity(m_integrityMetadata, String(m_buffer.data(), m_buffer.size()), m_url, *m_loader->document(), errorMessage)) { |
| + // TODO waiting for commit of FetchFormDataConsumerHandle |
| + // m_updater->update(FetchFormDataConsumerHandler::create(buffer)); |
| + m_loader->m_resolver->resolve(m_response.leakPtr()); |
| + m_loader->m_resolver.clear(); |
| + // FetchManager::Loader::didFinishLoading() can |
| + // be called before didGetReadable() is called |
| + // when the data is ready. In that case, |
| + // didFinishLoading() doesn't clean up and call |
| + // notifyFinished(), so it is necessary to |
| + // manually finish the loader here. |
| + if (m_loader->m_didFinishLoading) |
| + m_loader->loadSucceeded(); |
| + return; |
| + } |
| + } |
| + m_updater->update(createUnexpectedErrorDataConsumerHandle()); |
| + m_loader->performNetworkError(errorMessage); |
| + } |
| + |
| + DEFINE_INLINE_TRACE() { visitor->trace(m_updater); } |
|
yhirano
2015/08/17 11:53:45
You need to list m_loader and m_response in the tr
jww
2015/08/17 15:40:59
Done.
|
| + private: |
| + OwnPtr<WebDataConsumerHandle> m_handle; |
| + Member<CompositeDataConsumerHandle::Updater> m_updater; |
| + OwnPtr<Response> m_response; |
|
yhirano
2015/08/17 11:53:45
Member<Response>
jww
2015/08/17 15:40:59
Done.
|
| + FetchManager::Loader* m_loader; |
|
yhirano
2015/08/17 11:53:45
RawPtrWillBeMember<...>
jww
2015/08/17 15:40:59
Done, although out of curiosity, why should it be
yhirano
2015/08/18 09:31:53
Because FetchManager::loader inherits NoBaseWillBe
|
| + String m_integrityMetadata; |
| + KURL m_url; |
| + OwnPtr<WebDataConsumerHandle::Reader> m_reader; |
| + Vector<char> m_buffer; |
| + }; |
| + |
| private: |
| Loader(ExecutionContext*, FetchManager*, ScriptPromiseResolver*, FetchRequestData*); |
| @@ -75,6 +147,7 @@ private: |
| void failed(const String& message); |
| void notifyFinished(); |
| Document* document() const; |
| + void loadSucceeded(); |
| RawPtrWillBeMember<FetchManager> m_fetchManager; |
| PersistentWillBeMember<ScriptPromiseResolver> m_resolver; |
| @@ -83,6 +156,8 @@ private: |
| bool m_failed; |
| bool m_finished; |
| int m_responseHttpStatusCode; |
| + Member<SRIVerifier> m_integrityVerifier; |
| + bool m_didFinishLoading; |
| }; |
| FetchManager::Loader::Loader(ExecutionContext* executionContext, FetchManager* fetchManager, ScriptPromiseResolver* resolver, FetchRequestData* request) |
| @@ -93,6 +168,8 @@ FetchManager::Loader::Loader(ExecutionContext* executionContext, FetchManager* f |
| , m_failed(false) |
| , m_finished(false) |
| , m_responseHttpStatusCode(0) |
| + , m_integrityVerifier(nullptr) |
| + , m_didFinishLoading(false) |
| { |
| } |
| @@ -131,7 +208,13 @@ void FetchManager::Loader::didReceiveResponse(unsigned long, const ResourceRespo |
| break; |
| } |
| } |
| - FetchResponseData* responseData = FetchResponseData::createWithBuffer(new BodyStreamBuffer(createFetchDataConsumerHandleFromWebHandle(handle))); |
| + |
| + FetchResponseData* responseData = nullptr; |
| + CompositeDataConsumerHandle::Updater* updater = nullptr; |
| + if (m_request->integrity().isEmpty()) |
| + responseData = FetchResponseData::createWithBuffer(new BodyStreamBuffer(createFetchDataConsumerHandleFromWebHandle(handle))); |
| + else |
| + responseData = FetchResponseData::createWithBuffer(new BodyStreamBuffer(createFetchDataConsumerHandleFromWebHandle(CompositeDataConsumerHandle::create(createWaitingDataConsumerHandle(), &updater)))); |
| responseData->setStatus(response.httpStatusCode()); |
| responseData->setStatusMessage(response.httpStatusText()); |
| for (auto& it : response.httpHeaderFields()) |
| @@ -173,23 +256,26 @@ void FetchManager::Loader::didReceiveResponse(unsigned long, const ResourceRespo |
| break; |
| } |
| } |
| + |
| Response* r = Response::create(m_resolver->executionContext(), taintedResponse); |
| r->headers()->setGuard(Headers::ImmutableGuard); |
| - m_resolver->resolve(r); |
| - m_resolver.clear(); |
| + |
| + if (m_request->integrity().isEmpty()) { |
| + m_resolver->resolve(r); |
| + m_resolver.clear(); |
| + } else { |
| + ASSERT(!m_integrityVerifier); |
| + m_integrityVerifier = new SRIVerifier(handle, updater, adoptPtr(r), this, m_request->integrity(), response.url()); |
|
yhirano
2015/08/17 11:53:45
adoptPtr is not needed.
jww
2015/08/17 15:40:59
Done.
|
| + } |
| } |
| void FetchManager::Loader::didFinishLoading(unsigned long, double) |
| { |
| - ASSERT(!m_failed); |
| - m_finished = true; |
| + m_didFinishLoading = true; |
| + if (m_integrityVerifier || m_finished) |
| + return; |
|
yhirano
2015/08/17 11:53:45
I think loadSucceeded will not be be called when t
yhirano
2015/08/17 11:54:44
s/faster/earlier/
jww
2015/08/17 15:40:59
Yes, good call. I've removed the "|| m_finished" c
yhirano
2015/08/18 09:31:53
I think you need isFinished predicated here.
if (
jww
2015/08/18 19:26:20
Done.
|
| - if (document() && document()->frame() && document()->frame()->page() |
| - && m_responseHttpStatusCode >= 200 && m_responseHttpStatusCode < 300) { |
| - document()->frame()->page()->chromeClient().ajaxSucceeded(document()->frame()); |
| - } |
| - InspectorInstrumentation::didFinishFetch(executionContext(), this, m_request->method(), m_request->url().string()); |
| - notifyFinished(); |
| + loadSucceeded(); |
| } |
| void FetchManager::Loader::didFail(const ResourceError& error) |
| @@ -221,6 +307,20 @@ Document* FetchManager::Loader::document() const |
| return nullptr; |
| } |
| +void FetchManager::Loader::loadSucceeded() |
| +{ |
| + ASSERT(!m_failed); |
| + |
| + m_finished = true; |
| + |
| + if (document() && document()->frame() && document()->frame()->page() |
| + && m_responseHttpStatusCode >= 200 && m_responseHttpStatusCode < 300) { |
| + document()->frame()->page()->chromeClient().ajaxSucceeded(document()->frame()); |
| + } |
| + InspectorInstrumentation::didFinishFetch(executionContext(), this, m_request->method(), m_request->url().string()); |
| + notifyFinished(); |
| +} |
| + |
| void FetchManager::Loader::start() |
| { |
| // "1. If |request|'s url contains a Known HSTS Host, modify it per the |