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

Unified Diff: Source/core/xml/XMLHttpRequest.cpp

Issue 454313002: [WIP] XMLHttpRequest should parse as it receives chunks. (Closed) Base URL: svn://svn.chromium.org/blink/trunk
Patch Set: add test Created 6 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/xml/XMLHttpRequest.h ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: Source/core/xml/XMLHttpRequest.cpp
diff --git a/Source/core/xml/XMLHttpRequest.cpp b/Source/core/xml/XMLHttpRequest.cpp
index c661170d38fe3eb960cdecec83202f01d99879c1..35a7c0da9537dc5ab884af5657ae3e6185e53845 100644
--- a/Source/core/xml/XMLHttpRequest.cpp
+++ b/Source/core/xml/XMLHttpRequest.cpp
@@ -27,6 +27,7 @@
#include "core/FetchInitiatorTypeNames.h"
#include "core/dom/ContextFeatures.h"
#include "core/dom/DOMImplementation.h"
+#include "core/dom/DocumentParser.h"
#include "core/dom/ExceptionCode.h"
#include "core/dom/XMLDocument.h"
#include "core/editing/markup.h"
@@ -132,7 +133,7 @@ XMLHttpRequest::XMLHttpRequest(ExecutionContext* context, PassRefPtr<SecurityOri
, m_previousReadyStateChangeFireTime(0)
, m_async(true)
, m_includeCredentials(false)
- , m_createdDocument(false)
+ , m_parsedResponse(false)
, m_error(false)
, m_uploadEventsAllowed(true)
, m_uploadComplete(false)
@@ -187,6 +188,32 @@ ScriptString XMLHttpRequest::responseJSONSource()
return m_responseText;
}
+void XMLHttpRequest::initResponseDocument()
+{
+ AtomicString mimeType = responseMIMEType();
+ bool isHTML = equalIgnoringCase(mimeType, "text/html");
+
+ // The W3C spec requires the final MIME type to be some valid XML type, or text/html.
+ // If it is text/html, then the responseType of "document" must have been supplied explicitly.
+ if ((m_response.isHTTP() && !responseIsXML() && !isHTML)
+ || (isHTML && m_responseTypeCode == ResponseTypeDefault)
+ || executionContext()->isWorkerGlobalScope()) {
+ m_responseDocument = nullptr;
+ return;
+ }
+
+ DocumentInit init = DocumentInit::fromContext(document()->contextDocument(), m_url);
+ if (isHTML)
+ m_responseDocument = HTMLDocument::create(init);
+ else
+ m_responseDocument = XMLDocument::create(init);
+
+ // FIXME: Set Last-Modified.
+ m_responseDocument->setSecurityOrigin(securityOrigin());
+ m_responseDocument->setContextFeatures(document()->contextFeatures());
+ m_responseDocument->setMimeType(mimeType);
+}
+
Document* XMLHttpRequest::responseXML(ExceptionState& exceptionState)
{
if (m_responseTypeCode != ResponseTypeDefault && m_responseTypeCode != ResponseTypeDocument) {
@@ -197,31 +224,16 @@ Document* XMLHttpRequest::responseXML(ExceptionState& exceptionState)
if (m_error || m_state != DONE)
return 0;
- if (!m_createdDocument) {
- AtomicString mimeType = responseMIMEType();
- bool isHTML = equalIgnoringCase(mimeType, "text/html");
+ if (!m_parsedResponse) {
+ initResponseDocument();
+ if (!m_responseDocument)
+ return nullptr;
- // The W3C spec requires the final MIME type to be some valid XML type, or text/html.
- // If it is text/html, then the responseType of "document" must have been supplied explicitly.
- if ((m_response.isHTTP() && !responseIsXML() && !isHTML)
- || (isHTML && m_responseTypeCode == ResponseTypeDefault)
- || executionContext()->isWorkerGlobalScope()) {
+ m_responseDocument->setContent(m_responseText.flattenToString());
+ if (!m_responseDocument->wellFormed())
m_responseDocument = nullptr;
- } else {
- DocumentInit init = DocumentInit::fromContext(document()->contextDocument(), m_url);
- if (isHTML)
- m_responseDocument = HTMLDocument::create(init);
- else
- m_responseDocument = XMLDocument::create(init);
- // FIXME: Set Last-Modified.
- m_responseDocument->setContent(m_responseText.flattenToString());
- m_responseDocument->setSecurityOrigin(securityOrigin());
- m_responseDocument->setContextFeatures(document()->contextFeatures());
- m_responseDocument->setMimeType(mimeType);
- if (!m_responseDocument->wellFormed())
- m_responseDocument = nullptr;
- }
- m_createdDocument = true;
+
+ m_parsedResponse = true;
}
return m_responseDocument.get();
@@ -915,8 +927,9 @@ void XMLHttpRequest::clearResponse()
m_responseText.clear();
- m_createdDocument = false;
+ m_parsedResponse = false;
m_responseDocument = nullptr;
+ m_documentParser = nullptr;
m_responseBlob = nullptr;
m_downloadedBlobLength = 0;
@@ -1198,8 +1211,15 @@ void XMLHttpRequest::didFinishLoading(unsigned long identifier, double)
if (m_state < HEADERS_RECEIVED)
changeState(HEADERS_RECEIVED);
- if (m_decoder)
+ if (m_documentParser) {
+ m_documentParser->flush();
+ m_documentParser->finish();
+ m_documentParser = nullptr;
+
+ m_parsedResponse = true;
+ } else if (m_decoder) {
m_responseText = m_responseText.concatenateWith(m_decoder->flush());
+ }
if (m_responseStream)
m_responseStream->finalize();
@@ -1245,6 +1265,50 @@ void XMLHttpRequest::didReceiveResponse(unsigned long identifier, const Resource
m_responseEncoding = response.textEncodingName();
}
+void XMLHttpRequest::parseDocumentChunk(const char* data, int len)
+{
+ if (!m_documentParser) {
+ ASSERT(!m_responseDocument);
+ initResponseDocument();
+ if (!m_responseDocument)
+ return;
+
+ m_documentParser = m_responseDocument->implicitOpen();
+ }
+ ASSERT(m_documentParser);
+
+ if (m_documentParser->needsDecoder() && len)
+ m_documentParser->setDecoder(createDecoder());
+
+ m_documentParser->appendBytes(data, len);
+}
+
+PassOwnPtr<TextResourceDecoder> XMLHttpRequest::createDecoder() const
+{
+ if (m_responseTypeCode == ResponseTypeJSON)
+ return TextResourceDecoder::create("application/json", "UTF-8");
+
+ if (!m_responseEncoding.isEmpty())
+ return TextResourceDecoder::create("text/plain", m_responseEncoding);
+
+ // allow TextResourceDecoder to look inside the m_response if it's XML or HTML
+ if (responseIsXML()) {
+ OwnPtr<TextResourceDecoder> decoder = TextResourceDecoder::create("application/xml");
+ // Don't stop on encoding errors, unlike it is done for other kinds
+ // of XML resources. This matches the behavior of previous WebKit
+ // versions, Firefox and Opera.
+ decoder->useLenientXMLDecoding();
+
+ return decoder.release();
+ }
+
+ if (equalIgnoringCase(responseMIMEType(), "text/html")) {
+ return TextResourceDecoder::create("text/html", "UTF-8");
+ }
+
+ return TextResourceDecoder::create("text/plain", "UTF-8");
+}
+
void XMLHttpRequest::didReceiveData(const char* data, int len)
{
ASSERT(m_responseTypeCode != ResponseTypeBlob);
@@ -1255,34 +1319,18 @@ void XMLHttpRequest::didReceiveData(const char* data, int len)
if (m_state < HEADERS_RECEIVED)
changeState(HEADERS_RECEIVED);
- bool useDecoder = m_responseTypeCode == ResponseTypeDefault || m_responseTypeCode == ResponseTypeText || m_responseTypeCode == ResponseTypeJSON || m_responseTypeCode == ResponseTypeDocument;
-
- if (useDecoder && !m_decoder) {
- if (m_responseTypeCode == ResponseTypeJSON) {
- m_decoder = TextResourceDecoder::create("application/json", "UTF-8");
- } else if (!m_responseEncoding.isEmpty()) {
- m_decoder = TextResourceDecoder::create("text/plain", m_responseEncoding);
- // allow TextResourceDecoder to look inside the m_response if it's XML or HTML
- } else if (responseIsXML()) {
- m_decoder = TextResourceDecoder::create("application/xml");
- // Don't stop on encoding errors, unlike it is done for other kinds
- // of XML resources. This matches the behavior of previous WebKit
- // versions, Firefox and Opera.
- m_decoder->useLenientXMLDecoding();
- } else if (equalIgnoringCase(responseMIMEType(), "text/html")) {
- m_decoder = TextResourceDecoder::create("text/html", "UTF-8");
- } else {
- m_decoder = TextResourceDecoder::create("text/plain", "UTF-8");
- }
- }
-
if (!len)
return;
if (len == -1)
len = strlen(data);
- if (useDecoder) {
+ if (m_responseTypeCode == ResponseTypeDocument && m_response.isHTTP() && equalIgnoringCase(responseMIMEType(), "text/html")) {
+ parseDocumentChunk(data, len);
+ } else if (m_responseTypeCode == ResponseTypeDefault || m_responseTypeCode == ResponseTypeText || m_responseTypeCode == ResponseTypeJSON || m_responseTypeCode == ResponseTypeDocument) {
+ if (!m_decoder)
+ m_decoder = createDecoder();
+
m_responseText = m_responseText.concatenateWith(m_decoder->decode(data, len));
} else if (m_responseTypeCode == ResponseTypeArrayBuffer) {
// Buffer binary data.
« no previous file with comments | « Source/core/xml/XMLHttpRequest.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698