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

Side by Side 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 unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « Source/core/xml/XMLHttpRequest.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 /* 1 /*
2 * Copyright (C) 2004, 2006, 2008 Apple Inc. All rights reserved. 2 * Copyright (C) 2004, 2006, 2008 Apple Inc. All rights reserved.
3 * Copyright (C) 2005-2007 Alexey Proskuryakov <ap@webkit.org> 3 * Copyright (C) 2005-2007 Alexey Proskuryakov <ap@webkit.org>
4 * Copyright (C) 2007, 2008 Julien Chaffraix <jchaffraix@webkit.org> 4 * Copyright (C) 2007, 2008 Julien Chaffraix <jchaffraix@webkit.org>
5 * Copyright (C) 2008, 2011 Google Inc. All rights reserved. 5 * Copyright (C) 2008, 2011 Google Inc. All rights reserved.
6 * Copyright (C) 2012 Intel Corporation 6 * Copyright (C) 2012 Intel Corporation
7 * 7 *
8 * This library is free software; you can redistribute it and/or 8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public 9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either 10 * License as published by the Free Software Foundation; either
11 * version 2 of the License, or (at your option) any later version. 11 * version 2 of the License, or (at your option) any later version.
12 * 12 *
13 * This library is distributed in the hope that it will be useful, 13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details. 16 * Lesser General Public License for more details.
17 * 17 *
18 * You should have received a copy of the GNU Lesser General Public 18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software 19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 U SA 20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 U SA
21 */ 21 */
22 22
23 #include "config.h" 23 #include "config.h"
24 #include "core/xml/XMLHttpRequest.h" 24 #include "core/xml/XMLHttpRequest.h"
25 25
26 #include "bindings/core/v8/ExceptionState.h" 26 #include "bindings/core/v8/ExceptionState.h"
27 #include "core/FetchInitiatorTypeNames.h" 27 #include "core/FetchInitiatorTypeNames.h"
28 #include "core/dom/ContextFeatures.h" 28 #include "core/dom/ContextFeatures.h"
29 #include "core/dom/DOMImplementation.h" 29 #include "core/dom/DOMImplementation.h"
30 #include "core/dom/DocumentParser.h"
30 #include "core/dom/ExceptionCode.h" 31 #include "core/dom/ExceptionCode.h"
31 #include "core/dom/XMLDocument.h" 32 #include "core/dom/XMLDocument.h"
32 #include "core/editing/markup.h" 33 #include "core/editing/markup.h"
33 #include "core/events/Event.h" 34 #include "core/events/Event.h"
34 #include "core/fetch/FetchUtils.h" 35 #include "core/fetch/FetchUtils.h"
35 #include "core/fileapi/Blob.h" 36 #include "core/fileapi/Blob.h"
36 #include "core/fileapi/File.h" 37 #include "core/fileapi/File.h"
37 #include "core/frame/Settings.h" 38 #include "core/frame/Settings.h"
38 #include "core/frame/UseCounter.h" 39 #include "core/frame/UseCounter.h"
39 #include "core/frame/csp/ContentSecurityPolicy.h" 40 #include "core/frame/csp/ContentSecurityPolicy.h"
(...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after
125 , m_downloadedBlobLength(0) 126 , m_downloadedBlobLength(0)
126 , m_receivedLength(0) 127 , m_receivedLength(0)
127 , m_lastSendLineNumber(0) 128 , m_lastSendLineNumber(0)
128 , m_exceptionCode(0) 129 , m_exceptionCode(0)
129 , m_progressEventThrottle(this) 130 , m_progressEventThrottle(this)
130 , m_responseTypeCode(ResponseTypeDefault) 131 , m_responseTypeCode(ResponseTypeDefault)
131 , m_securityOrigin(securityOrigin) 132 , m_securityOrigin(securityOrigin)
132 , m_previousReadyStateChangeFireTime(0) 133 , m_previousReadyStateChangeFireTime(0)
133 , m_async(true) 134 , m_async(true)
134 , m_includeCredentials(false) 135 , m_includeCredentials(false)
135 , m_createdDocument(false) 136 , m_parsedResponse(false)
136 , m_error(false) 137 , m_error(false)
137 , m_uploadEventsAllowed(true) 138 , m_uploadEventsAllowed(true)
138 , m_uploadComplete(false) 139 , m_uploadComplete(false)
139 , m_sameOriginRequest(true) 140 , m_sameOriginRequest(true)
140 { 141 {
141 #ifndef NDEBUG 142 #ifndef NDEBUG
142 xmlHttpRequestCounter.increment(); 143 xmlHttpRequestCounter.increment();
143 #endif 144 #endif
144 ScriptWrappable::init(this); 145 ScriptWrappable::init(this);
145 } 146 }
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
180 181
181 ScriptString XMLHttpRequest::responseJSONSource() 182 ScriptString XMLHttpRequest::responseJSONSource()
182 { 183 {
183 ASSERT(m_responseTypeCode == ResponseTypeJSON); 184 ASSERT(m_responseTypeCode == ResponseTypeJSON);
184 185
185 if (m_error || m_state != DONE) 186 if (m_error || m_state != DONE)
186 return ScriptString(); 187 return ScriptString();
187 return m_responseText; 188 return m_responseText;
188 } 189 }
189 190
191 void XMLHttpRequest::initResponseDocument()
192 {
193 AtomicString mimeType = responseMIMEType();
194 bool isHTML = equalIgnoringCase(mimeType, "text/html");
195
196 // The W3C spec requires the final MIME type to be some valid XML type, or t ext/html.
197 // If it is text/html, then the responseType of "document" must have been su pplied explicitly.
198 if ((m_response.isHTTP() && !responseIsXML() && !isHTML)
199 || (isHTML && m_responseTypeCode == ResponseTypeDefault)
200 || executionContext()->isWorkerGlobalScope()) {
201 m_responseDocument = nullptr;
202 return;
203 }
204
205 DocumentInit init = DocumentInit::fromContext(document()->contextDocument(), m_url);
206 if (isHTML)
207 m_responseDocument = HTMLDocument::create(init);
208 else
209 m_responseDocument = XMLDocument::create(init);
210
211 // FIXME: Set Last-Modified.
212 m_responseDocument->setSecurityOrigin(securityOrigin());
213 m_responseDocument->setContextFeatures(document()->contextFeatures());
214 m_responseDocument->setMimeType(mimeType);
215 }
216
190 Document* XMLHttpRequest::responseXML(ExceptionState& exceptionState) 217 Document* XMLHttpRequest::responseXML(ExceptionState& exceptionState)
191 { 218 {
192 if (m_responseTypeCode != ResponseTypeDefault && m_responseTypeCode != Respo nseTypeDocument) { 219 if (m_responseTypeCode != ResponseTypeDefault && m_responseTypeCode != Respo nseTypeDocument) {
193 exceptionState.throwDOMException(InvalidStateError, "The value is only a ccessible if the object's 'responseType' is '' or 'document' (was '" + responseT ype() + "')."); 220 exceptionState.throwDOMException(InvalidStateError, "The value is only a ccessible if the object's 'responseType' is '' or 'document' (was '" + responseT ype() + "').");
194 return 0; 221 return 0;
195 } 222 }
196 223
197 if (m_error || m_state != DONE) 224 if (m_error || m_state != DONE)
198 return 0; 225 return 0;
199 226
200 if (!m_createdDocument) { 227 if (!m_parsedResponse) {
201 AtomicString mimeType = responseMIMEType(); 228 initResponseDocument();
202 bool isHTML = equalIgnoringCase(mimeType, "text/html"); 229 if (!m_responseDocument)
230 return nullptr;
203 231
204 // The W3C spec requires the final MIME type to be some valid XML type, or text/html. 232 m_responseDocument->setContent(m_responseText.flattenToString());
205 // If it is text/html, then the responseType of "document" must have bee n supplied explicitly. 233 if (!m_responseDocument->wellFormed())
206 if ((m_response.isHTTP() && !responseIsXML() && !isHTML)
207 || (isHTML && m_responseTypeCode == ResponseTypeDefault)
208 || executionContext()->isWorkerGlobalScope()) {
209 m_responseDocument = nullptr; 234 m_responseDocument = nullptr;
210 } else { 235
211 DocumentInit init = DocumentInit::fromContext(document()->contextDoc ument(), m_url); 236 m_parsedResponse = true;
212 if (isHTML)
213 m_responseDocument = HTMLDocument::create(init);
214 else
215 m_responseDocument = XMLDocument::create(init);
216 // FIXME: Set Last-Modified.
217 m_responseDocument->setContent(m_responseText.flattenToString());
218 m_responseDocument->setSecurityOrigin(securityOrigin());
219 m_responseDocument->setContextFeatures(document()->contextFeatures() );
220 m_responseDocument->setMimeType(mimeType);
221 if (!m_responseDocument->wellFormed())
222 m_responseDocument = nullptr;
223 }
224 m_createdDocument = true;
225 } 237 }
226 238
227 return m_responseDocument.get(); 239 return m_responseDocument.get();
228 } 240 }
229 241
230 Blob* XMLHttpRequest::responseBlob() 242 Blob* XMLHttpRequest::responseBlob()
231 { 243 {
232 ASSERT(m_responseTypeCode == ResponseTypeBlob); 244 ASSERT(m_responseTypeCode == ResponseTypeBlob);
233 ASSERT(!m_binaryResponseBuilder.get()); 245 ASSERT(!m_binaryResponseBuilder.get());
234 246
(...skipping 673 matching lines...) Expand 10 before | Expand all | Expand 10 after
908 void XMLHttpRequest::clearResponse() 920 void XMLHttpRequest::clearResponse()
909 { 921 {
910 // FIXME: when we add the support for multi-part XHR, we will have to 922 // FIXME: when we add the support for multi-part XHR, we will have to
911 // be careful with this initialization. 923 // be careful with this initialization.
912 m_receivedLength = 0; 924 m_receivedLength = 0;
913 925
914 m_response = ResourceResponse(); 926 m_response = ResourceResponse();
915 927
916 m_responseText.clear(); 928 m_responseText.clear();
917 929
918 m_createdDocument = false; 930 m_parsedResponse = false;
919 m_responseDocument = nullptr; 931 m_responseDocument = nullptr;
932 m_documentParser = nullptr;
920 933
921 m_responseBlob = nullptr; 934 m_responseBlob = nullptr;
922 m_downloadedBlobLength = 0; 935 m_downloadedBlobLength = 0;
923 936
924 m_responseStream = nullptr; 937 m_responseStream = nullptr;
925 938
926 // These variables may referred by the response accessors. So, we can clear 939 // These variables may referred by the response accessors. So, we can clear
927 // this only when we clear the response holder variables above. 940 // this only when we clear the response holder variables above.
928 m_binaryResponseBuilder.clear(); 941 m_binaryResponseBuilder.clear();
929 m_responseArrayBuffer.clear(); 942 m_responseArrayBuffer.clear();
(...skipping 261 matching lines...) Expand 10 before | Expand all | Expand 10 after
1191 void XMLHttpRequest::didFinishLoading(unsigned long identifier, double) 1204 void XMLHttpRequest::didFinishLoading(unsigned long identifier, double)
1192 { 1205 {
1193 WTF_LOG(Network, "XMLHttpRequest %p didFinishLoading(%lu)", this, identifier ); 1206 WTF_LOG(Network, "XMLHttpRequest %p didFinishLoading(%lu)", this, identifier );
1194 1207
1195 if (m_error) 1208 if (m_error)
1196 return; 1209 return;
1197 1210
1198 if (m_state < HEADERS_RECEIVED) 1211 if (m_state < HEADERS_RECEIVED)
1199 changeState(HEADERS_RECEIVED); 1212 changeState(HEADERS_RECEIVED);
1200 1213
1201 if (m_decoder) 1214 if (m_documentParser) {
1215 m_documentParser->flush();
1216 m_documentParser->finish();
1217 m_documentParser = nullptr;
1218
1219 m_parsedResponse = true;
1220 } else if (m_decoder) {
1202 m_responseText = m_responseText.concatenateWith(m_decoder->flush()); 1221 m_responseText = m_responseText.concatenateWith(m_decoder->flush());
1222 }
1203 1223
1204 if (m_responseStream) 1224 if (m_responseStream)
1205 m_responseStream->finalize(); 1225 m_responseStream->finalize();
1206 1226
1207 clearVariablesForLoading(); 1227 clearVariablesForLoading();
1208 1228
1209 InspectorInstrumentation::didFinishXHRLoading(executionContext(), this, this , identifier, m_responseText, m_method, m_url, m_lastSendURL, m_lastSendLineNumb er); 1229 InspectorInstrumentation::didFinishXHRLoading(executionContext(), this, this , identifier, m_responseText, m_method, m_url, m_lastSendURL, m_lastSendLineNumb er);
1210 1230
1211 if (m_loader) 1231 if (m_loader)
1212 m_loader = nullptr; 1232 m_loader = nullptr;
(...skipping 25 matching lines...) Expand all
1238 m_response = response; 1258 m_response = response;
1239 if (!m_mimeTypeOverride.isEmpty()) { 1259 if (!m_mimeTypeOverride.isEmpty()) {
1240 m_response.setHTTPHeaderField("Content-Type", m_mimeTypeOverride); 1260 m_response.setHTTPHeaderField("Content-Type", m_mimeTypeOverride);
1241 m_responseEncoding = extractCharsetFromMediaType(m_mimeTypeOverride); 1261 m_responseEncoding = extractCharsetFromMediaType(m_mimeTypeOverride);
1242 } 1262 }
1243 1263
1244 if (m_responseEncoding.isEmpty()) 1264 if (m_responseEncoding.isEmpty())
1245 m_responseEncoding = response.textEncodingName(); 1265 m_responseEncoding = response.textEncodingName();
1246 } 1266 }
1247 1267
1268 void XMLHttpRequest::parseDocumentChunk(const char* data, int len)
1269 {
1270 if (!m_documentParser) {
1271 ASSERT(!m_responseDocument);
1272 initResponseDocument();
1273 if (!m_responseDocument)
1274 return;
1275
1276 m_documentParser = m_responseDocument->implicitOpen();
1277 }
1278 ASSERT(m_documentParser);
1279
1280 if (m_documentParser->needsDecoder() && len)
1281 m_documentParser->setDecoder(createDecoder());
1282
1283 m_documentParser->appendBytes(data, len);
1284 }
1285
1286 PassOwnPtr<TextResourceDecoder> XMLHttpRequest::createDecoder() const
1287 {
1288 if (m_responseTypeCode == ResponseTypeJSON)
1289 return TextResourceDecoder::create("application/json", "UTF-8");
1290
1291 if (!m_responseEncoding.isEmpty())
1292 return TextResourceDecoder::create("text/plain", m_responseEncoding);
1293
1294 // allow TextResourceDecoder to look inside the m_response if it's XML or HT ML
1295 if (responseIsXML()) {
1296 OwnPtr<TextResourceDecoder> decoder = TextResourceDecoder::create("appli cation/xml");
1297 // Don't stop on encoding errors, unlike it is done for other kinds
1298 // of XML resources. This matches the behavior of previous WebKit
1299 // versions, Firefox and Opera.
1300 decoder->useLenientXMLDecoding();
1301
1302 return decoder.release();
1303 }
1304
1305 if (equalIgnoringCase(responseMIMEType(), "text/html")) {
1306 return TextResourceDecoder::create("text/html", "UTF-8");
1307 }
1308
1309 return TextResourceDecoder::create("text/plain", "UTF-8");
1310 }
1311
1248 void XMLHttpRequest::didReceiveData(const char* data, int len) 1312 void XMLHttpRequest::didReceiveData(const char* data, int len)
1249 { 1313 {
1250 ASSERT(m_responseTypeCode != ResponseTypeBlob); 1314 ASSERT(m_responseTypeCode != ResponseTypeBlob);
1251 1315
1252 if (m_error) 1316 if (m_error)
1253 return; 1317 return;
1254 1318
1255 if (m_state < HEADERS_RECEIVED) 1319 if (m_state < HEADERS_RECEIVED)
1256 changeState(HEADERS_RECEIVED); 1320 changeState(HEADERS_RECEIVED);
1257 1321
1258 bool useDecoder = m_responseTypeCode == ResponseTypeDefault || m_responseTyp eCode == ResponseTypeText || m_responseTypeCode == ResponseTypeJSON || m_respons eTypeCode == ResponseTypeDocument;
1259
1260 if (useDecoder && !m_decoder) {
1261 if (m_responseTypeCode == ResponseTypeJSON) {
1262 m_decoder = TextResourceDecoder::create("application/json", "UTF-8") ;
1263 } else if (!m_responseEncoding.isEmpty()) {
1264 m_decoder = TextResourceDecoder::create("text/plain", m_responseEnco ding);
1265 // allow TextResourceDecoder to look inside the m_response if it's XML o r HTML
1266 } else if (responseIsXML()) {
1267 m_decoder = TextResourceDecoder::create("application/xml");
1268 // Don't stop on encoding errors, unlike it is done for other kinds
1269 // of XML resources. This matches the behavior of previous WebKit
1270 // versions, Firefox and Opera.
1271 m_decoder->useLenientXMLDecoding();
1272 } else if (equalIgnoringCase(responseMIMEType(), "text/html")) {
1273 m_decoder = TextResourceDecoder::create("text/html", "UTF-8");
1274 } else {
1275 m_decoder = TextResourceDecoder::create("text/plain", "UTF-8");
1276 }
1277 }
1278
1279 if (!len) 1322 if (!len)
1280 return; 1323 return;
1281 1324
1282 if (len == -1) 1325 if (len == -1)
1283 len = strlen(data); 1326 len = strlen(data);
1284 1327
1285 if (useDecoder) { 1328 if (m_responseTypeCode == ResponseTypeDocument && m_response.isHTTP() && equ alIgnoringCase(responseMIMEType(), "text/html")) {
1329 parseDocumentChunk(data, len);
1330 } else if (m_responseTypeCode == ResponseTypeDefault || m_responseTypeCode = = ResponseTypeText || m_responseTypeCode == ResponseTypeJSON || m_responseTypeCo de == ResponseTypeDocument) {
1331 if (!m_decoder)
1332 m_decoder = createDecoder();
1333
1286 m_responseText = m_responseText.concatenateWith(m_decoder->decode(data, len)); 1334 m_responseText = m_responseText.concatenateWith(m_decoder->decode(data, len));
1287 } else if (m_responseTypeCode == ResponseTypeArrayBuffer) { 1335 } else if (m_responseTypeCode == ResponseTypeArrayBuffer) {
1288 // Buffer binary data. 1336 // Buffer binary data.
1289 if (!m_binaryResponseBuilder) 1337 if (!m_binaryResponseBuilder)
1290 m_binaryResponseBuilder = SharedBuffer::create(); 1338 m_binaryResponseBuilder = SharedBuffer::create();
1291 m_binaryResponseBuilder->append(data, len); 1339 m_binaryResponseBuilder->append(data, len);
1292 } else if (m_responseTypeCode == ResponseTypeLegacyStream) { 1340 } else if (m_responseTypeCode == ResponseTypeLegacyStream) {
1293 if (!m_responseStream) 1341 if (!m_responseStream)
1294 m_responseStream = Stream::create(executionContext(), responseMIMETy pe()); 1342 m_responseStream = Stream::create(executionContext(), responseMIMETy pe());
1295 m_responseStream->addData(data, len); 1343 m_responseStream->addData(data, len);
(...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after
1382 { 1430 {
1383 visitor->trace(m_responseBlob); 1431 visitor->trace(m_responseBlob);
1384 visitor->trace(m_responseStream); 1432 visitor->trace(m_responseStream);
1385 visitor->trace(m_responseDocument); 1433 visitor->trace(m_responseDocument);
1386 visitor->trace(m_progressEventThrottle); 1434 visitor->trace(m_progressEventThrottle);
1387 visitor->trace(m_upload); 1435 visitor->trace(m_upload);
1388 XMLHttpRequestEventTarget::trace(visitor); 1436 XMLHttpRequestEventTarget::trace(visitor);
1389 } 1437 }
1390 1438
1391 } // namespace blink 1439 } // namespace blink
OLDNEW
« 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