Commit 7a930bbc authored by kouhei@chromium.org's avatar kouhei@chromium.org

Make XHR use background HTML parser

This patch enables background html parser for documents with no frames,
which are XMLHttpRequest response documents. HTML imports and
inspector/DOMPatchSupport will still to use the synchronous mode as the
current code expect the change to happen synchronously.

Before this change, XMLHttpRequest immediately set its state to DONE after
receiving the last data. After this change, XMLHttpRequest will wait for
|Document::finishedParsing| before changing its state to DONE if it has
responseType == "document". This is needed because |DocumentParser::finish()|
do not synchronously give the complete document, but we have to wait until all
tokens from the background parser is processed.

BUG=409461

Review URL: https://codereview.chromium.org/521363002

git-svn-id: svn://svn.chromium.org/blink/trunk@181684 bbb929c8-8fbe-4397-9dbb-9b2b20218538
parent 815d713b
...@@ -744,8 +744,10 @@ void HTMLDocumentParser::startBackgroundParser() ...@@ -744,8 +744,10 @@ void HTMLDocumentParser::startBackgroundParser()
m_backgroundParser = WeakPtr<BackgroundHTMLParser>(reference); m_backgroundParser = WeakPtr<BackgroundHTMLParser>(reference);
// TODO(oysteine): Disabled due to crbug.com/398076 until a full fix can be implemented. // TODO(oysteine): Disabled due to crbug.com/398076 until a full fix can be implemented.
if (RuntimeEnabledFeatures::threadedParserDataReceiverEnabled()) if (RuntimeEnabledFeatures::threadedParserDataReceiverEnabled()) {
document()->loader()->attachThreadedDataReceiver(adoptPtr(new ParserDataReceiver(m_backgroundParser))); if (DocumentLoader* loader = document()->loader())
loader->attachThreadedDataReceiver(adoptPtr(new ParserDataReceiver(m_backgroundParser)));
}
OwnPtr<BackgroundHTMLParser::Configuration> config = adoptPtr(new BackgroundHTMLParser::Configuration); OwnPtr<BackgroundHTMLParser::Configuration> config = adoptPtr(new BackgroundHTMLParser::Configuration);
config->options = m_options; config->options = m_options;
......
...@@ -40,16 +40,15 @@ HTMLParserOptions::HTMLParserOptions(Document* document) ...@@ -40,16 +40,15 @@ HTMLParserOptions::HTMLParserOptions(Document* document)
scriptEnabled = frame && frame->script().canExecuteScripts(NotAboutToExecuteScript); scriptEnabled = frame && frame->script().canExecuteScripts(NotAboutToExecuteScript);
pluginsEnabled = frame && frame->loader().allowPlugins(NotAboutToInstantiatePlugin); pluginsEnabled = frame && frame->loader().allowPlugins(NotAboutToInstantiatePlugin);
// We force the main-thread parser for two cases: // We force the main-thread parser for three cases:
// - about:blank and javascript (which uses about:blank) for compatibility // - about:blank and javascript (which uses about:blank) for compatibility
// with historical synchronous loading/parsing behavior. // with historical synchronous loading/parsing behavior.
// - instances where the Document has no Frame (this happens sometimes for // - HTML imports (FIXME: enable off-thread parser for this case)
// HTML imports, and possibly other cases). // - inspector/DOMPatchSupport replacing the whole document.
// FIXME: We want to use the threaded parser for XHRs (where there is no // (DOMPatchSupport calls in |DocumentParser::pinToMainThread()| for this case)
// frame) so the second case should go away eventually.
// FIXME: Gecko does not load javascript: urls synchronously, why do we? // FIXME: Gecko does not load javascript: urls synchronously, why do we?
// See LayoutTests/loader/iframe-sync-loads.html // See LayoutTests/loader/iframe-sync-loads.html
useThreading = document && document->frame() && !document->url().isAboutBlankURL(); useThreading = document && !document->importsController() && !document->url().isAboutBlankURL();
} }
} }
...@@ -97,6 +97,7 @@ void DOMPatchSupport::patchDocument(const String& markup) ...@@ -97,6 +97,7 @@ void DOMPatchSupport::patchDocument(const String& markup)
parser = HTMLDocumentParser::create(toHTMLDocument(*newDocument), false); parser = HTMLDocumentParser::create(toHTMLDocument(*newDocument), false);
else else
parser = XMLDocumentParser::create(*newDocument, 0); parser = XMLDocumentParser::create(*newDocument, 0);
parser->pinToMainThread();
parser->insert(markup); // Use insert() so that the parser will not yield. parser->insert(markup); // Use insert() so that the parser will not yield.
parser->finish(); parser->finish();
parser->detach(); parser->detach();
......
...@@ -144,6 +144,7 @@ PassRefPtrWillBeRawPtr<XMLHttpRequest> XMLHttpRequest::create(ExecutionContext* ...@@ -144,6 +144,7 @@ PassRefPtrWillBeRawPtr<XMLHttpRequest> XMLHttpRequest::create(ExecutionContext*
XMLHttpRequest::XMLHttpRequest(ExecutionContext* context, PassRefPtr<SecurityOrigin> securityOrigin) XMLHttpRequest::XMLHttpRequest(ExecutionContext* context, PassRefPtr<SecurityOrigin> securityOrigin)
: ActiveDOMObject(context) : ActiveDOMObject(context)
, m_timeoutMilliseconds(0) , m_timeoutMilliseconds(0)
, m_loaderIdentifier(0)
, m_state(UNSENT) , m_state(UNSENT)
, m_downloadedBlobLength(0) , m_downloadedBlobLength(0)
, m_receivedLength(0) , m_receivedLength(0)
...@@ -912,6 +913,7 @@ void XMLHttpRequest::clearVariablesForLoading() ...@@ -912,6 +913,7 @@ void XMLHttpRequest::clearVariablesForLoading()
m_decoder.clear(); m_decoder.clear();
if (m_responseDocumentParser) { if (m_responseDocumentParser) {
m_responseDocumentParser->removeClient(this);
#if !ENABLE(OILPAN) #if !ENABLE(OILPAN)
m_responseDocumentParser->detach(); m_responseDocumentParser->detach();
#endif #endif
...@@ -1280,19 +1282,20 @@ void XMLHttpRequest::didFinishLoading(unsigned long identifier, double) ...@@ -1280,19 +1282,20 @@ void XMLHttpRequest::didFinishLoading(unsigned long identifier, double)
if (m_state < HEADERS_RECEIVED) if (m_state < HEADERS_RECEIVED)
changeState(HEADERS_RECEIVED); changeState(HEADERS_RECEIVED);
m_loaderIdentifier = identifier;
if (m_responseDocumentParser) { if (m_responseDocumentParser) {
// |DocumentParser::finish()| tells the parser that we have reached end of the data.
// When using |HTMLDocumentParser|, which works asynchronously, we do not have the
// complete document just after the |DocumentParser::finish()| call.
// Wait for the parser to call us back in |notifyParserStopped| to progress state.
m_responseDocumentParser->finish(); m_responseDocumentParser->finish();
m_responseDocumentParser = nullptr; ASSERT(m_responseDocument);
return;
m_responseDocument->implicitClose(); }
if (!m_responseDocument->wellFormed())
m_responseDocument = nullptr;
m_parsedResponse = true; if (m_decoder)
} else if (m_decoder) {
m_responseText = m_responseText.concatenateWith(m_decoder->flush()); m_responseText = m_responseText.concatenateWith(m_decoder->flush());
}
if (m_responseLegacyStream) if (m_responseLegacyStream)
m_responseLegacyStream->finalize(); m_responseLegacyStream->finalize();
...@@ -1301,11 +1304,40 @@ void XMLHttpRequest::didFinishLoading(unsigned long identifier, double) ...@@ -1301,11 +1304,40 @@ void XMLHttpRequest::didFinishLoading(unsigned long identifier, double)
m_responseStream->close(); m_responseStream->close();
clearVariablesForLoading(); clearVariablesForLoading();
endLoading();
}
void XMLHttpRequest::notifyParserStopped()
{
// This should only be called when response document is parsed asynchronously.
ASSERT(m_responseDocumentParser);
ASSERT(!m_responseDocumentParser->isParsing());
ASSERT(!m_responseLegacyStream);
ASSERT(!m_responseStream);
// Do nothing if we are called from |internalAbort()|.
if (m_error)
return;
clearVariablesForLoading();
m_responseDocument->implicitClose();
InspectorInstrumentation::didFinishXHRLoading(executionContext(), this, this, identifier, m_responseText, m_method, m_url, m_lastSendURL, m_lastSendLineNumber); if (!m_responseDocument->wellFormed())
m_responseDocument = nullptr;
m_parsedResponse = true;
endLoading();
}
void XMLHttpRequest::endLoading()
{
InspectorInstrumentation::didFinishXHRLoading(executionContext(), this, this, m_loaderIdentifier, m_responseText, m_method, m_url, m_lastSendURL, m_lastSendLineNumber);
if (m_loader) if (m_loader)
m_loader = nullptr; m_loader = nullptr;
m_loaderIdentifier = 0;
changeState(DONE); changeState(DONE);
} }
...@@ -1350,6 +1382,7 @@ void XMLHttpRequest::parseDocumentChunk(const char* data, int len) ...@@ -1350,6 +1382,7 @@ void XMLHttpRequest::parseDocumentChunk(const char* data, int len)
return; return;
m_responseDocumentParser = m_responseDocument->implicitOpen(); m_responseDocumentParser = m_responseDocument->implicitOpen();
m_responseDocumentParser->addClient(this);
} }
ASSERT(m_responseDocumentParser); ASSERT(m_responseDocumentParser);
......
...@@ -24,6 +24,7 @@ ...@@ -24,6 +24,7 @@
#include "bindings/core/v8/ScriptString.h" #include "bindings/core/v8/ScriptString.h"
#include "core/dom/ActiveDOMObject.h" #include "core/dom/ActiveDOMObject.h"
#include "core/dom/DocumentParserClient.h"
#include "core/events/EventListener.h" #include "core/events/EventListener.h"
#include "core/loader/ThreadableLoaderClient.h" #include "core/loader/ThreadableLoaderClient.h"
#include "core/streams/ReadableStreamImpl.h" #include "core/streams/ReadableStreamImpl.h"
...@@ -58,6 +59,7 @@ class XMLHttpRequest FINAL ...@@ -58,6 +59,7 @@ class XMLHttpRequest FINAL
: public RefCountedWillBeGarbageCollectedFinalized<XMLHttpRequest> : public RefCountedWillBeGarbageCollectedFinalized<XMLHttpRequest>
, public XMLHttpRequestEventTarget , public XMLHttpRequestEventTarget
, private ThreadableLoaderClient , private ThreadableLoaderClient
, public DocumentParserClient
, public ActiveDOMObject { , public ActiveDOMObject {
DEFINE_WRAPPERTYPEINFO(); DEFINE_WRAPPERTYPEINFO();
REFCOUNTED_EVENT_TARGET(XMLHttpRequest); REFCOUNTED_EVENT_TARGET(XMLHttpRequest);
...@@ -166,6 +168,11 @@ private: ...@@ -166,6 +168,11 @@ private:
virtual void didFail(const ResourceError&) OVERRIDE; virtual void didFail(const ResourceError&) OVERRIDE;
virtual void didFailRedirectCheck() OVERRIDE; virtual void didFailRedirectCheck() OVERRIDE;
// DocumentParserClient
virtual void notifyParserStopped() OVERRIDE;
void endLoading();
// Returns the MIME type part of m_mimeTypeOverride if present and // Returns the MIME type part of m_mimeTypeOverride if present and
// successfully parsed, or returns one of the "Content-Type" header value // successfully parsed, or returns one of the "Content-Type" header value
// of the received response. // of the received response.
...@@ -244,6 +251,7 @@ private: ...@@ -244,6 +251,7 @@ private:
PersistentWillBeMember<UnderlyingSource> m_streamSource; PersistentWillBeMember<UnderlyingSource> m_streamSource;
RefPtr<ThreadableLoader> m_loader; RefPtr<ThreadableLoader> m_loader;
unsigned long m_loaderIdentifier;
State m_state; State m_state;
ResourceResponse m_response; ResourceResponse m_response;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment