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) |