OLD | NEW |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 |
OLD | NEW |