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