Index: third_party/WebKit/Source/core/dom/ScriptLoader.cpp |
diff --git a/third_party/WebKit/Source/core/dom/ScriptLoader.cpp b/third_party/WebKit/Source/core/dom/ScriptLoader.cpp |
index 471a724b2edecac67d544a5c94e8991e2f113b74..865a37e8cf446011ff071e2a2172ff28649eff28 100644 |
--- a/third_party/WebKit/Source/core/dom/ScriptLoader.cpp |
+++ b/third_party/WebKit/Source/core/dom/ScriptLoader.cpp |
@@ -36,6 +36,7 @@ |
#include "core/events/Event.h" |
#include "core/fetch/AccessControlStatus.h" |
#include "core/fetch/FetchRequest.h" |
+#include "core/fetch/MemoryCache.h" |
#include "core/fetch/ResourceFetcher.h" |
#include "core/fetch/ScriptResource.h" |
#include "core/frame/LocalFrame.h" |
@@ -50,6 +51,7 @@ |
#include "core/svg/SVGScriptElement.h" |
#include "platform/MIMETypeRegistry.h" |
#include "platform/weborigin/SecurityOrigin.h" |
+#include "public/platform/WebCachePolicy.h" |
#include "public/platform/WebFrameScheduler.h" |
#include "wtf/StdLibExtras.h" |
#include "wtf/text/StringBuilder.h" |
@@ -70,6 +72,7 @@ ScriptLoader::ScriptLoader(Element* element, bool parserInserted, bool alreadySt |
, m_willExecuteWhenDocumentFinishedParsing(false) |
, m_forceAsync(!parserInserted) |
, m_createdDuringDocumentWrite(createdDuringDocumentWrite) |
+ , m_documentWriteIntervention(DocumentWriteIntervention::DocumentWriteInterventionNone) |
{ |
DCHECK(m_element); |
if (parserInserted && element->document().scriptableDocumentParser() && !element->document().isInDocumentWrite()) |
@@ -88,6 +91,12 @@ DEFINE_TRACE(ScriptLoader) |
ScriptResourceClient::trace(visitor); |
} |
+void ScriptLoader::setBlockedDocWriteScriptAsyncFetch() |
+{ |
+ DCHECK(!m_createdDuringDocumentWrite); |
+ m_documentWriteIntervention = DocumentWriteIntervention::AsyncLowPriorityFetchForBlockedScript; |
+} |
+ |
void ScriptLoader::didNotifySubtreeInsertionsToDocument() |
{ |
if (!m_parserInserted) |
@@ -238,12 +247,22 @@ bool ScriptLoader::prepareScript(const TextPosition& scriptStartPosition, Legacy |
if (client->hasSourceAttribute()) { |
FetchRequest::DeferOption defer = FetchRequest::NoDefer; |
- if (!m_parserInserted || client->asyncAttributeValue() || client->deferAttributeValue()) |
+ if (!m_parserInserted || client->asyncAttributeValue() || client->deferAttributeValue() |
+ || m_documentWriteIntervention == DocumentWriteIntervention::AsyncLowPriorityFetchForBlockedScript) |
defer = FetchRequest::LazyLoad; |
if (!fetchScript(client->sourceAttributeValue(), defer)) |
return false; |
} |
+ // Since the asynchronous, low priority fetch for doc.written blocked |
+ // script is not for execution, return early from here. Watch for its |
+ // completion to be able to remove it from the memory cache. |
+ if (m_documentWriteIntervention == DocumentWriteIntervention::AsyncLowPriorityFetchForBlockedScript) { |
+ m_pendingScript = PendingScript::create(m_element, m_resource.get()); |
+ m_pendingScript->watchForLoad(this); |
+ return true; |
+ } |
+ |
if (client->hasSourceAttribute() && client->deferAttributeValue() && m_parserInserted && !client->asyncAttributeValue()) { |
m_willExecuteWhenDocumentFinishedParsing = true; |
m_willBeParserExecuted = true; |
@@ -317,16 +336,28 @@ bool ScriptLoader::fetchScript(const String& sourceUrl, FetchRequest::DeferOptio |
request.setIntegrityMetadata(metadataSet); |
} |
+ if (m_documentWriteIntervention == DocumentWriteIntervention::AsyncLowPriorityFetchForBlockedScript) { |
+ // Set interventions info in resourceRequest so that priority can |
+ // be set accordingly. |
+ request.mutableResourceRequest().setInterventionsInfo(InterventionsFlag::InterventionBlockedDocWriteScriptAsyncFetch); |
+ request.mutableResourceRequest().setHTTPHeaderField("Intervention", "<https://www.chromestatus.com/feature/5718547946799104>"); |
+ } |
+ |
m_resource = ScriptResource::fetch(request, elementDocument->fetcher()); |
m_isExternalScript = true; |
} |
- if (m_resource) |
- return true; |
+ if (!m_resource) { |
+ dispatchErrorEvent(); |
+ return false; |
+ } |
- dispatchErrorEvent(); |
- return false; |
+ if (m_createdDuringDocumentWrite && m_resource->resourceRequest().getCachePolicy() == WebCachePolicy::ReturnCacheDataDontLoad) { |
+ m_documentWriteIntervention = DocumentWriteIntervention::DisallowedFetchForDocWrittenScript; |
+ } |
+ |
+ return true; |
} |
bool isHTMLScriptLoader(Element* element) |
@@ -459,6 +490,16 @@ void ScriptLoader::notifyFinished(Resource* resource) |
{ |
DCHECK(!m_willBeParserExecuted); |
+ // We do not need this script in the memory cache. The primary goals of |
+ // sending this fetch request are to let the third party server know |
+ // about the document.write scripts intervention and populate the http |
+ // cache for subsequent uses. |
+ if (m_documentWriteIntervention == DocumentWriteIntervention::AsyncLowPriorityFetchForBlockedScript) { |
+ memoryCache()->remove(resource); |
+ m_pendingScript->stopWatchingForLoad(); |
+ return; |
+ } |
+ |
Document* contextDocument = m_element->document().contextDocument(); |
if (!contextDocument) { |
detach(); |