Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1581)

Unified Diff: Source/modules/fetch/FetchManager.cpp

Issue 1279163005: Initial Fetch integration for Subresource Integrity (Closed) Base URL: https://chromium.googlesource.com/chromium/blink.git@master
Patch Set: Fix test expectations Created 5 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « Source/core/html/HTMLLinkElement.cpp ('k') | Source/modules/fetch/FetchRequestData.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: Source/modules/fetch/FetchManager.cpp
diff --git a/Source/modules/fetch/FetchManager.cpp b/Source/modules/fetch/FetchManager.cpp
index 7886a7c85b2cb4ed60ee7c5df9a8134f2da09de5..3bc85626789af65ff5d3f21a72cbd496518ea0c4 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,7 +25,9 @@
#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/FetchFormDataConsumerHandle.h"
#include "modules/fetch/FetchRequestData.h"
#include "modules/fetch/Response.h"
#include "modules/fetch/ResponseInit.h"
@@ -34,6 +37,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 +71,83 @@ public:
void start();
void dispose();
+ class SRIVerifier final : 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, 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_finished(false)
+ {
+ 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.";
+ m_finished = true;
+ if (r == WebDataConsumerHandle::Done) {
+ if (SubresourceIntegrity::CheckSubresourceIntegrity(m_integrityMetadata, String(m_buffer.data(), m_buffer.size()), m_url, *m_loader->document(), errorMessage)) {
+ m_updater->update(FetchFormDataConsumerHandle::create(m_buffer.data(), m_buffer.size()));
+ m_loader->m_resolver->resolve(m_response);
+ 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
+ // explicitly finish the loader here.
+ if (m_loader->m_didFinishLoading)
+ m_loader->loadSucceeded();
+ return;
+ }
+ }
+ m_updater->update(createUnexpectedErrorDataConsumerHandle());
+ m_loader->performNetworkError(errorMessage);
+ }
+
+ bool isFinished() const { return m_finished; }
+
+ DEFINE_INLINE_TRACE()
+ {
+ visitor->trace(m_updater);
+ visitor->trace(m_response);
+ visitor->trace(m_loader);
+ }
+ private:
+ OwnPtr<WebDataConsumerHandle> m_handle;
+ Member<CompositeDataConsumerHandle::Updater> m_updater;
+ Member<Response> m_response;
+ RawPtrWillBeMember<FetchManager::Loader> m_loader;
+ String m_integrityMetadata;
+ KURL m_url;
+ OwnPtr<WebDataConsumerHandle::Reader> m_reader;
+ Vector<char> m_buffer;
+ bool m_finished;
+ };
+
private:
Loader(ExecutionContext*, FetchManager*, ScriptPromiseResolver*, FetchRequestData*);
@@ -75,6 +157,7 @@ private:
void failed(const String& message);
void notifyFinished();
Document* document() const;
+ void loadSucceeded();
RawPtrWillBeMember<FetchManager> m_fetchManager;
PersistentWillBeMember<ScriptPromiseResolver> m_resolver;
@@ -83,6 +166,8 @@ private:
bool m_failed;
bool m_finished;
int m_responseHttpStatusCode;
+ PersistentWillBeMember<SRIVerifier> m_integrityVerifier;
+ bool m_didFinishLoading;
};
FetchManager::Loader::Loader(ExecutionContext* executionContext, FetchManager* fetchManager, ScriptPromiseResolver* resolver, FetchRequestData* request)
@@ -93,6 +178,8 @@ FetchManager::Loader::Loader(ExecutionContext* executionContext, FetchManager* f
, m_failed(false)
, m_finished(false)
, m_responseHttpStatusCode(0)
+ , m_integrityVerifier(nullptr)
+ , m_didFinishLoading(false)
{
}
@@ -106,6 +193,7 @@ DEFINE_TRACE(FetchManager::Loader)
visitor->trace(m_fetchManager);
visitor->trace(m_resolver);
visitor->trace(m_request);
+ visitor->trace(m_integrityVerifier);
ContextLifecycleObserver::trace(visitor);
}
@@ -131,7 +219,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 +267,29 @@ 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, r, this, m_request->integrity(), response.url());
+ }
}
void FetchManager::Loader::didFinishLoading(unsigned long, double)
{
- ASSERT(!m_failed);
- m_finished = true;
+ m_didFinishLoading = true;
+ // If there is an integrity verifier, and it has not already finished, it
+ // will take care of finishing the load or performing a network error when
+ // verification is complete.
+ if (m_integrityVerifier && !m_integrityVerifier->isFinished())
+ return;
- 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 +321,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
« no previous file with comments | « Source/core/html/HTMLLinkElement.cpp ('k') | Source/modules/fetch/FetchRequestData.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698