Chromium Code Reviews| Index: Source/modules/fetch/FetchManager.cpp |
| diff --git a/Source/modules/fetch/FetchManager.cpp b/Source/modules/fetch/FetchManager.cpp |
| index 634370cc1daf4525dcf6ac9b0528a77a25634745..ce435be62d882e75d4b19acca8e0b4e56e200dc4 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" |
| @@ -57,6 +58,85 @@ public: |
| void start(); |
| void dispose(); |
| + class IntegrityVerifiedDataConsumerHandle : public WebDataConsumerHandle { |
| + public: |
| + IntegrityVerifiedDataConsumerHandle(PassOwnPtr<WebDataConsumerHandle> handle, String integrityMetadata, const KURL& url, FetchManager::Loader* loader) |
| + : m_handle(handle) |
| + , m_integrityMetadata(integrityMetadata) |
| + , m_url(url) |
| + , m_loader(loader) |
| + , m_response(nullptr) |
| + { |
| + } |
| + |
| + void setResponse(Response* response) { m_response = response; } |
| + |
| + private: |
| + class ReaderImpl final : public WebDataConsumerHandle::Reader { |
| + public: |
| + ReaderImpl(PassOwnPtr<WebDataConsumerHandle::Reader> reader, String integrityMetadata, const KURL& url, FetchManager::Loader* loader, Response* response) |
| + : m_reader(reader) |
| + , m_integrityMetadata(integrityMetadata) |
| + , m_url(url) |
| + , m_loader(loader) |
| + , m_response(response) |
| + , m_firstRun(true) |
| + { |
| + } |
| + Result read(void* data, size_t size, Flags flags, size_t* readSize) override |
| + { |
| + if (m_firstRun) { |
| + m_firstRun = false; |
| + String content; |
| + char buf[1000]; |
| + size_t amt; |
| + while (m_reader->read(buf, 1000, flags, &amt) == Ok) |
|
yhirano
2015/08/11 09:22:08
Do you want to read all data from the pipe with th
jww
2015/08/12 16:40:14
This is addressed by your suggestion of implementi
yhirano
2015/08/13 18:10:36
Yes.
|
| + content.append(buf, amt); |
| + String errorMessage; |
| + if (!SubresourceIntegrity::CheckSubresourceIntegrity(m_integrityMetadata, content, m_url, *m_loader->document(), errorMessage)) { |
|
yhirano
2015/08/11 09:22:08
This function can be called on a different thread
jww
2015/08/12 16:40:14
This is no longer a problem if your suggestion of
|
| + m_loader->performNetworkError(errorMessage); |
| + return UnexpectedError; |
| + } |
| + m_loader->m_resolver->resolve(m_response); |
| + m_loader->m_resolver.clear(); |
| + m_response = nullptr; |
| + } |
| + |
| + return m_reader->read(data, size, flags, readSize); |
| + } |
| + |
| + Result beginRead(const void** buffer, Flags flags, size_t* available) override |
| + { |
| + return m_reader->beginRead(buffer, flags, available); |
| + } |
| + |
| + Result endRead(size_t readSize) override |
| + { |
| + return m_reader->endRead(readSize); |
| + } |
| + |
| + private: |
| + OwnPtr<WebDataConsumerHandle::Reader> m_reader; |
| + String m_integrityMetadata; |
| + KURL m_url; |
| + FetchManager::Loader* m_loader; |
| + Response* m_response; |
| + bool m_firstRun; |
| + }; |
| + |
| + Reader* obtainReaderInternal(Client* client) override |
|
yhirano
2015/08/11 09:22:08
A difficult point is that obtainReaderInternal can
jww
2015/08/12 16:40:14
Acknowledged.
|
| + { |
| + return new ReaderImpl(m_handle->obtainReader(client), m_integrityMetadata, m_url, m_loader, m_response); |
| + } |
| + const char* debugName() const override { return m_handle->debugName(); } |
| + |
| + OwnPtr<WebDataConsumerHandle> m_handle; |
| + String m_integrityMetadata; |
| + KURL m_url; |
| + FetchManager::Loader* m_loader; |
| + Response* m_response; |
| + }; |
| + |
| private: |
| Loader(ExecutionContext*, FetchManager*, ScriptPromiseResolver*, FetchRequestData*); |
| @@ -122,7 +202,15 @@ void FetchManager::Loader::didReceiveResponse(unsigned long, const ResourceRespo |
| break; |
| } |
| } |
| - FetchResponseData* responseData = FetchResponseData::createWithBuffer(new BodyStreamBuffer(createFetchDataConsumerHandleFromWebHandle(handle))); |
| + |
| + FetchResponseData* responseData; |
| + IntegrityVerifiedDataConsumerHandle* integrityVerifier = nullptr; |
| + if (m_request->integrity().isEmpty()) { |
| + responseData = FetchResponseData::createWithBuffer(new BodyStreamBuffer(createFetchDataConsumerHandleFromWebHandle(handle))); |
| + } else { |
| + integrityVerifier = new IntegrityVerifiedDataConsumerHandle(handle, m_request->integrity(), m_request->url(), this); |
| + responseData = FetchResponseData::createWithBuffer(new BodyStreamBuffer(createFetchDataConsumerHandleFromWebHandle(adoptPtr(integrityVerifier)))); |
| + } |
| responseData->setStatus(response.httpStatusCode()); |
| responseData->setStatusMessage(response.httpStatusText()); |
| for (auto& it : response.httpHeaderFields()) |
| @@ -142,10 +230,16 @@ void FetchManager::Loader::didReceiveResponse(unsigned long, const ResourceRespo |
| taintedResponse = responseData->createOpaqueFilteredResponse(); |
| break; |
| } |
| + |
| Response* r = Response::create(m_resolver->executionContext(), taintedResponse); |
| r->headers()->setGuard(Headers::ImmutableGuard); |
| - m_resolver->resolve(r); |
| - m_resolver.clear(); |
| + |
| + if (integrityVerifier) { |
| + integrityVerifier->setResponse(r); |
| + } else { |
| + m_resolver->resolve(r); |
| + m_resolver.clear(); |
| + } |
| } |
| void FetchManager::Loader::didFinishLoading(unsigned long, double) |