Move parseFontFaceDescriptor to CSSPropertyParser.cpp
[chromium-blink-merge.git] / third_party / WebKit / Source / core / xmlhttprequest / XMLHttpRequest.cpp
blob7e5e8ef292b0cdce0a6fcd28d3c14b48ba903465
1 /*
2 * Copyright (C) 2004, 2006, 2008 Apple Inc. All rights reserved.
3 * Copyright (C) 2005-2007 Alexey Proskuryakov <ap@webkit.org>
4 * Copyright (C) 2007, 2008 Julien Chaffraix <jchaffraix@webkit.org>
5 * Copyright (C) 2008, 2011 Google Inc. All rights reserved.
6 * Copyright (C) 2012 Intel Corporation
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
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
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
23 #include "config.h"
24 #include "core/xmlhttprequest/XMLHttpRequest.h"
26 #include "bindings/core/v8/DOMWrapperWorld.h"
27 #include "bindings/core/v8/ExceptionState.h"
28 #include "bindings/core/v8/ScriptState.h"
29 #include "bindings/core/v8/UnionTypesCore.h"
30 #include "core/dom/DOMArrayBuffer.h"
31 #include "core/dom/DOMArrayBufferView.h"
32 #include "core/dom/DOMException.h"
33 #include "core/dom/DOMImplementation.h"
34 #include "core/dom/DOMTypedArray.h"
35 #include "core/dom/DocumentInit.h"
36 #include "core/dom/DocumentParser.h"
37 #include "core/dom/ExceptionCode.h"
38 #include "core/dom/ExecutionContext.h"
39 #include "core/dom/XMLDocument.h"
40 #include "core/editing/serializers/Serialization.h"
41 #include "core/events/Event.h"
42 #include "core/fetch/CrossOriginAccessControl.h"
43 #include "core/fetch/FetchInitiatorTypeNames.h"
44 #include "core/fetch/FetchUtils.h"
45 #include "core/fetch/ResourceLoaderOptions.h"
46 #include "core/fileapi/Blob.h"
47 #include "core/fileapi/File.h"
48 #include "core/fileapi/FileReaderLoader.h"
49 #include "core/fileapi/FileReaderLoaderClient.h"
50 #include "core/frame/Settings.h"
51 #include "core/frame/UseCounter.h"
52 #include "core/frame/csp/ContentSecurityPolicy.h"
53 #include "core/html/FormData.h"
54 #include "core/html/HTMLDocument.h"
55 #include "core/html/parser/TextResourceDecoder.h"
56 #include "core/inspector/ConsoleMessage.h"
57 #include "core/inspector/InspectorInstrumentation.h"
58 #include "core/inspector/InspectorTraceEvents.h"
59 #include "core/loader/ThreadableLoader.h"
60 #include "core/page/ChromeClient.h"
61 #include "core/page/Page.h"
62 #include "core/streams/Stream.h"
63 #include "core/xmlhttprequest/XMLHttpRequestProgressEvent.h"
64 #include "core/xmlhttprequest/XMLHttpRequestUpload.h"
65 #include "platform/Logging.h"
66 #include "platform/RuntimeEnabledFeatures.h"
67 #include "platform/SharedBuffer.h"
68 #include "platform/blob/BlobData.h"
69 #include "platform/network/HTTPParsers.h"
70 #include "platform/network/ParsedContentType.h"
71 #include "platform/network/ResourceError.h"
72 #include "platform/network/ResourceRequest.h"
73 #include "public/platform/WebURLRequest.h"
74 #include "wtf/Assertions.h"
75 #include "wtf/StdLibExtras.h"
76 #include "wtf/text/CString.h"
78 namespace blink {
80 namespace {
82 // This class protects the wrapper of the associated XMLHttpRequest object
83 // via hasPendingActivity method which returns true if
84 // m_eventDispatchRecursionLevel is positive.
85 class ScopedEventDispatchProtect final {
86 public:
87 explicit ScopedEventDispatchProtect(int* level) : m_level(level)
89 ++*m_level;
91 ~ScopedEventDispatchProtect()
93 ASSERT(*m_level > 0);
94 --*m_level;
97 private:
98 int* const m_level;
101 bool isSetCookieHeader(const AtomicString& name)
103 return equalIgnoringCase(name, "set-cookie") || equalIgnoringCase(name, "set-cookie2");
106 void replaceCharsetInMediaType(String& mediaType, const String& charsetValue)
108 unsigned pos = 0, len = 0;
110 findCharsetInMediaType(mediaType, pos, len);
112 if (!len) {
113 // When no charset found, do nothing.
114 return;
117 // Found at least one existing charset, replace all occurrences with new charset.
118 while (len) {
119 mediaType.replace(pos, len, charsetValue);
120 unsigned start = pos + charsetValue.length();
121 findCharsetInMediaType(mediaType, pos, len, start);
125 void logConsoleError(ExecutionContext* context, const String& message)
127 if (!context)
128 return;
129 // FIXME: It's not good to report the bad usage without indicating what source line it came from.
130 // We should pass additional parameters so we can tell the console where the mistake occurred.
131 context->addConsoleMessage(ConsoleMessage::create(JSMessageSource, ErrorMessageLevel, message));
134 } // namespace
136 class XMLHttpRequest::BlobLoader final : public GarbageCollectedFinalized<XMLHttpRequest::BlobLoader>, public FileReaderLoaderClient {
137 public:
138 static BlobLoader* create(XMLHttpRequest* xhr, PassRefPtr<BlobDataHandle> handle)
140 return new BlobLoader(xhr, handle);
143 // FileReaderLoaderClient functions.
144 void didStartLoading() override {}
145 void didReceiveDataForClient(const char* data, unsigned length) override
147 ASSERT(length <= INT_MAX);
148 m_xhr->didReceiveData(data, length);
150 void didFinishLoading() override
152 m_xhr->didFinishLoadingFromBlob();
154 void didFail(FileError::ErrorCode error) override
156 m_xhr->didFailLoadingFromBlob();
159 void cancel()
161 m_loader.cancel();
164 DEFINE_INLINE_TRACE()
166 visitor->trace(m_xhr);
169 private:
170 BlobLoader(XMLHttpRequest* xhr, PassRefPtr<BlobDataHandle> handle)
171 : m_xhr(xhr)
172 , m_loader(FileReaderLoader::ReadByClient, this)
174 m_loader.start(m_xhr->executionContext(), handle);
177 Member<XMLHttpRequest> m_xhr;
178 FileReaderLoader m_loader;
181 XMLHttpRequest* XMLHttpRequest::create(ScriptState* scriptState)
183 ExecutionContext* context = scriptState->executionContext();
184 DOMWrapperWorld& world = scriptState->world();
185 RefPtr<SecurityOrigin> securityOrigin = world.isIsolatedWorld() ? world.isolatedWorldSecurityOrigin() : nullptr;
186 XMLHttpRequest* xmlHttpRequest = new XMLHttpRequest(context, securityOrigin);
187 xmlHttpRequest->suspendIfNeeded();
189 return xmlHttpRequest;
192 XMLHttpRequest* XMLHttpRequest::create(ExecutionContext* context)
194 XMLHttpRequest* xmlHttpRequest = new XMLHttpRequest(context, nullptr);
195 xmlHttpRequest->suspendIfNeeded();
197 return xmlHttpRequest;
200 XMLHttpRequest::XMLHttpRequest(ExecutionContext* context, PassRefPtr<SecurityOrigin> securityOrigin)
201 : ActiveDOMObject(context)
202 , m_timeoutMilliseconds(0)
203 , m_state(UNSENT)
204 , m_lengthDownloadedToFile(0)
205 , m_receivedLength(0)
206 , m_exceptionCode(0)
207 , m_progressEventThrottle(XMLHttpRequestProgressEventThrottle::create(this))
208 , m_responseTypeCode(ResponseTypeDefault)
209 , m_securityOrigin(securityOrigin)
210 , m_eventDispatchRecursionLevel(0)
211 , m_async(true)
212 , m_includeCredentials(false)
213 , m_parsedResponse(false)
214 , m_error(false)
215 , m_uploadEventsAllowed(true)
216 , m_uploadComplete(false)
217 , m_sameOriginRequest(true)
218 , m_downloadingToFile(false)
219 , m_responseTextOverflow(false)
221 #if ENABLE(ASSERT) && !ENABLE(OILPAN)
222 // Verify that this object was allocated on the 'eager' heap.
223 // (this check comes 'for free' with Oilpan enabled.)
224 ASSERT(IS_EAGERLY_FINALIZED());
225 #endif
228 XMLHttpRequest::~XMLHttpRequest()
232 Document* XMLHttpRequest::document() const
234 ASSERT(executionContext()->isDocument());
235 return toDocument(executionContext());
238 SecurityOrigin* XMLHttpRequest::securityOrigin() const
240 return m_securityOrigin ? m_securityOrigin.get() : executionContext()->securityOrigin();
243 XMLHttpRequest::State XMLHttpRequest::readyState() const
245 return m_state;
248 ScriptString XMLHttpRequest::responseText(ExceptionState& exceptionState)
250 if (m_responseTypeCode != ResponseTypeDefault && m_responseTypeCode != ResponseTypeText) {
251 exceptionState.throwDOMException(InvalidStateError, "The value is only accessible if the object's 'responseType' is '' or 'text' (was '" + responseType() + "').");
252 return ScriptString();
254 if (m_error || (m_state != LOADING && m_state != DONE))
255 return ScriptString();
256 return m_responseText;
259 ScriptString XMLHttpRequest::responseJSONSource()
261 ASSERT(m_responseTypeCode == ResponseTypeJSON);
263 if (m_error || m_state != DONE)
264 return ScriptString();
265 return m_responseText;
268 void XMLHttpRequest::initResponseDocument()
270 // The W3C spec requires the final MIME type to be some valid XML type, or text/html.
271 // If it is text/html, then the responseType of "document" must have been supplied explicitly.
272 bool isHTML = responseIsHTML();
273 if ((m_response.isHTTP() && !responseIsXML() && !isHTML)
274 || (isHTML && m_responseTypeCode == ResponseTypeDefault)
275 || executionContext()->isWorkerGlobalScope()) {
276 m_responseDocument = nullptr;
277 return;
280 DocumentInit init = DocumentInit::fromContext(document()->contextDocument(), m_url);
281 if (isHTML)
282 m_responseDocument = HTMLDocument::create(init);
283 else
284 m_responseDocument = XMLDocument::create(init);
286 // FIXME: Set Last-Modified.
287 m_responseDocument->setSecurityOrigin(securityOrigin());
288 m_responseDocument->setContextFeatures(document()->contextFeatures());
289 m_responseDocument->setMimeType(finalResponseMIMETypeWithFallback());
292 Document* XMLHttpRequest::responseXML(ExceptionState& exceptionState)
294 if (m_responseTypeCode != ResponseTypeDefault && m_responseTypeCode != ResponseTypeDocument) {
295 exceptionState.throwDOMException(InvalidStateError, "The value is only accessible if the object's 'responseType' is '' or 'document' (was '" + responseType() + "').");
296 return nullptr;
299 if (m_error || m_state != DONE)
300 return nullptr;
302 if (!m_parsedResponse) {
303 initResponseDocument();
304 if (!m_responseDocument)
305 return nullptr;
307 m_responseDocument->setContent(m_responseText.flattenToString());
308 if (!m_responseDocument->wellFormed())
309 m_responseDocument = nullptr;
311 m_parsedResponse = true;
314 return m_responseDocument.get();
317 Blob* XMLHttpRequest::responseBlob()
319 ASSERT(m_responseTypeCode == ResponseTypeBlob);
321 // We always return null before DONE.
322 if (m_error || m_state != DONE)
323 return nullptr;
325 if (!m_responseBlob) {
326 if (m_downloadingToFile) {
327 ASSERT(!m_binaryResponseBuilder);
329 // When responseType is set to "blob", we redirect the downloaded
330 // data to a file-handle directly in the browser process. We get
331 // the file-path from the ResourceResponse directly instead of
332 // copying the bytes between the browser and the renderer.
333 m_responseBlob = Blob::create(createBlobDataHandleFromResponse());
334 } else {
335 OwnPtr<BlobData> blobData = BlobData::create();
336 size_t size = 0;
337 if (m_binaryResponseBuilder && m_binaryResponseBuilder->size()) {
338 size = m_binaryResponseBuilder->size();
339 blobData->appendBytes(m_binaryResponseBuilder->data(), size);
340 blobData->setContentType(finalResponseMIMETypeWithFallback().lower());
341 m_binaryResponseBuilder.clear();
343 m_responseBlob = Blob::create(BlobDataHandle::create(blobData.release(), size));
347 return m_responseBlob;
350 DOMArrayBuffer* XMLHttpRequest::responseArrayBuffer()
352 ASSERT(m_responseTypeCode == ResponseTypeArrayBuffer);
354 if (m_error || m_state != DONE)
355 return nullptr;
357 if (!m_responseArrayBuffer) {
358 if (m_binaryResponseBuilder && m_binaryResponseBuilder->size()) {
359 RefPtr<DOMArrayBuffer> buffer = DOMArrayBuffer::createUninitialized(m_binaryResponseBuilder->size(), 1);
360 if (!m_binaryResponseBuilder->getAsBytes(buffer->data(), buffer->byteLength())) {
361 // m_binaryResponseBuilder failed to allocate an ArrayBuffer.
362 // We need to crash the renderer since there's no way defined in
363 // the spec to tell this to the user.
364 CRASH();
366 m_responseArrayBuffer = buffer.release();
367 m_binaryResponseBuilder.clear();
368 } else {
369 m_responseArrayBuffer = DOMArrayBuffer::create(nullptr, 0);
373 return m_responseArrayBuffer.get();
376 Stream* XMLHttpRequest::responseLegacyStream()
378 ASSERT(m_responseTypeCode == ResponseTypeLegacyStream);
380 if (m_error || (m_state != LOADING && m_state != DONE))
381 return nullptr;
383 return m_responseLegacyStream;
386 void XMLHttpRequest::setTimeout(unsigned timeout, ExceptionState& exceptionState)
388 // FIXME: Need to trigger or update the timeout Timer here, if needed. http://webkit.org/b/98156
389 // XHR2 spec, 4.7.3. "This implies that the timeout attribute can be set while fetching is in progress. If that occurs it will still be measured relative to the start of fetching."
390 if (executionContext()->isDocument() && !m_async) {
391 exceptionState.throwDOMException(InvalidAccessError, "Timeouts cannot be set for synchronous requests made from a document.");
392 return;
395 m_timeoutMilliseconds = timeout;
397 // From http://www.w3.org/TR/XMLHttpRequest/#the-timeout-attribute:
398 // Note: This implies that the timeout attribute can be set while fetching is in progress. If
399 // that occurs it will still be measured relative to the start of fetching.
401 // The timeout may be overridden after send.
402 if (m_loader)
403 m_loader->overrideTimeout(timeout);
406 void XMLHttpRequest::setResponseType(const String& responseType, ExceptionState& exceptionState)
408 if (m_state >= LOADING) {
409 exceptionState.throwDOMException(InvalidStateError, "The response type cannot be set if the object's state is LOADING or DONE.");
410 return;
413 // Newer functionality is not available to synchronous requests in window contexts, as a spec-mandated
414 // attempt to discourage synchronous XHR use. responseType is one such piece of functionality.
415 if (!m_async && executionContext()->isDocument()) {
416 exceptionState.throwDOMException(InvalidAccessError, "The response type cannot be changed for synchronous requests made from a document.");
417 return;
420 if (responseType == "") {
421 m_responseTypeCode = ResponseTypeDefault;
422 } else if (responseType == "text") {
423 m_responseTypeCode = ResponseTypeText;
424 } else if (responseType == "json") {
425 m_responseTypeCode = ResponseTypeJSON;
426 } else if (responseType == "document") {
427 m_responseTypeCode = ResponseTypeDocument;
428 } else if (responseType == "blob") {
429 m_responseTypeCode = ResponseTypeBlob;
430 } else if (responseType == "arraybuffer") {
431 m_responseTypeCode = ResponseTypeArrayBuffer;
432 } else if (responseType == "legacystream") {
433 if (RuntimeEnabledFeatures::experimentalStreamEnabled())
434 m_responseTypeCode = ResponseTypeLegacyStream;
435 else
436 return;
437 } else {
438 ASSERT_NOT_REACHED();
442 String XMLHttpRequest::responseType()
444 switch (m_responseTypeCode) {
445 case ResponseTypeDefault:
446 return "";
447 case ResponseTypeText:
448 return "text";
449 case ResponseTypeJSON:
450 return "json";
451 case ResponseTypeDocument:
452 return "document";
453 case ResponseTypeBlob:
454 return "blob";
455 case ResponseTypeArrayBuffer:
456 return "arraybuffer";
457 case ResponseTypeLegacyStream:
458 return "legacystream";
460 return "";
463 String XMLHttpRequest::responseURL()
465 KURL responseURL(m_response.url());
466 if (!responseURL.isNull())
467 responseURL.removeFragmentIdentifier();
468 return responseURL.string();
471 XMLHttpRequestUpload* XMLHttpRequest::upload()
473 if (!m_upload)
474 m_upload = XMLHttpRequestUpload::create(this);
475 return m_upload.get();
478 void XMLHttpRequest::trackProgress(long long length)
480 m_receivedLength += length;
482 if (m_state != LOADING) {
483 changeState(LOADING);
484 } else {
485 // Dispatch a readystatechange event because many applications use
486 // it to track progress although this is not specified.
488 // FIXME: Stop dispatching this event for progress tracking.
489 dispatchReadyStateChangeEvent();
491 if (m_async)
492 dispatchProgressEventFromSnapshot(EventTypeNames::progress);
495 void XMLHttpRequest::changeState(State newState)
497 if (m_state != newState) {
498 m_state = newState;
499 dispatchReadyStateChangeEvent();
503 void XMLHttpRequest::dispatchReadyStateChangeEvent()
505 if (!executionContext())
506 return;
508 // We need this protection because dispatchReadyStateChangeEvent may
509 // dispatch multiple events.
510 ScopedEventDispatchProtect protect(&m_eventDispatchRecursionLevel);
511 if (m_async || (m_state <= OPENED || m_state == DONE)) {
512 TRACE_EVENT1("devtools.timeline", "XHRReadyStateChange", "data", InspectorXhrReadyStateChangeEvent::data(executionContext(), this));
513 XMLHttpRequestProgressEventThrottle::DeferredEventAction action = XMLHttpRequestProgressEventThrottle::Ignore;
514 if (m_state == DONE) {
515 if (m_error)
516 action = XMLHttpRequestProgressEventThrottle::Clear;
517 else
518 action = XMLHttpRequestProgressEventThrottle::Flush;
520 m_progressEventThrottle->dispatchReadyStateChangeEvent(Event::create(EventTypeNames::readystatechange), action);
521 TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("devtools.timeline"), "UpdateCounters", TRACE_EVENT_SCOPE_THREAD, "data", InspectorUpdateCountersEvent::data());
524 if (m_state == DONE && !m_error) {
525 TRACE_EVENT1("devtools.timeline", "XHRLoad", "data", InspectorXhrLoadEvent::data(executionContext(), this));
526 dispatchProgressEventFromSnapshot(EventTypeNames::load);
527 dispatchProgressEventFromSnapshot(EventTypeNames::loadend);
528 TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("devtools.timeline"), "UpdateCounters", TRACE_EVENT_SCOPE_THREAD, "data", InspectorUpdateCountersEvent::data());
532 void XMLHttpRequest::setWithCredentials(bool value, ExceptionState& exceptionState)
534 if (m_state > OPENED || m_loader) {
535 exceptionState.throwDOMException(InvalidStateError, "The value may only be set if the object's state is UNSENT or OPENED.");
536 return;
539 // FIXME: According to XMLHttpRequest Level 2 we should throw InvalidAccessError exception here.
540 // However for time being only print warning message to warn web developers.
541 if (!m_async)
542 UseCounter::countDeprecation(executionContext(), UseCounter::SyncXHRWithCredentials);
544 m_includeCredentials = value;
547 void XMLHttpRequest::open(const AtomicString& method, const String& urlString, ExceptionState& exceptionState)
549 open(method, executionContext()->completeURL(urlString), true, exceptionState);
552 void XMLHttpRequest::open(const AtomicString& method, const String& urlString, bool async, const String& username, const String& password, ExceptionState& exceptionState)
554 KURL url(executionContext()->completeURL(urlString));
555 if (!username.isNull())
556 url.setUser(username);
557 if (!password.isNull())
558 url.setPass(password);
560 open(method, url, async, exceptionState);
563 void XMLHttpRequest::open(const AtomicString& method, const KURL& url, bool async, ExceptionState& exceptionState)
565 WTF_LOG(Network, "XMLHttpRequest %p open('%s', '%s', %d)", this, method.utf8().data(), url.elidedString().utf8().data(), async);
567 if (!internalAbort())
568 return;
570 State previousState = m_state;
571 m_state = UNSENT;
572 m_error = false;
573 m_uploadComplete = false;
575 if (!isValidHTTPToken(method)) {
576 exceptionState.throwDOMException(SyntaxError, "'" + method + "' is not a valid HTTP method.");
577 return;
580 if (FetchUtils::isForbiddenMethod(method)) {
581 exceptionState.throwSecurityError("'" + method + "' HTTP method is unsupported.");
582 return;
585 if (!ContentSecurityPolicy::shouldBypassMainWorld(executionContext()) && !executionContext()->contentSecurityPolicy()->allowConnectToSource(url)) {
586 // We can safely expose the URL to JavaScript, as these checks happen synchronously before redirection. JavaScript receives no new information.
587 exceptionState.throwSecurityError("Refused to connect to '" + url.elidedString() + "' because it violates the document's Content Security Policy.");
588 return;
591 if (!async && executionContext()->isDocument()) {
592 if (document()->settings() && !document()->settings()->syncXHRInDocumentsEnabled()) {
593 exceptionState.throwDOMException(InvalidAccessError, "Synchronous requests are disabled for this page.");
594 return;
597 // Newer functionality is not available to synchronous requests in window contexts, as a spec-mandated
598 // attempt to discourage synchronous XHR use. responseType is one such piece of functionality.
599 if (m_responseTypeCode != ResponseTypeDefault) {
600 exceptionState.throwDOMException(InvalidAccessError, "Synchronous requests from a document must not set a response type.");
601 return;
604 // Similarly, timeouts are disabled for synchronous requests as well.
605 if (m_timeoutMilliseconds > 0) {
606 exceptionState.throwDOMException(InvalidAccessError, "Synchronous requests must not set a timeout.");
607 return;
610 // Here we just warn that firing sync XHR's may affect responsiveness.
611 // Eventually sync xhr will be deprecated and an "InvalidAccessError" exception thrown.
612 // Refer : https://xhr.spec.whatwg.org/#sync-warning
613 // Use count for XHR synchronous requests on main thread only.
614 if (!document()->processingBeforeUnload())
615 UseCounter::countDeprecation(executionContext(), UseCounter::XMLHttpRequestSynchronousInNonWorkerOutsideBeforeUnload);
618 m_method = FetchUtils::normalizeMethod(method);
620 m_url = url;
622 m_async = async;
624 ASSERT(!m_loader);
626 // Check previous state to avoid dispatching readyState event
627 // when calling open several times in a row.
628 if (previousState != OPENED)
629 changeState(OPENED);
630 else
631 m_state = OPENED;
634 bool XMLHttpRequest::initSend(ExceptionState& exceptionState)
636 if (!executionContext())
637 return false;
639 if (m_state != OPENED || m_loader) {
640 exceptionState.throwDOMException(InvalidStateError, "The object's state must be OPENED.");
641 return false;
644 m_error = false;
645 return true;
648 void XMLHttpRequest::send(const ArrayBufferOrArrayBufferViewOrBlobOrDocumentOrStringOrFormData& body, ExceptionState& exceptionState)
650 InspectorInstrumentation::willSendXMLHttpRequest(executionContext(), url());
652 if (body.isNull()) {
653 send(String(), exceptionState);
654 return;
657 if (body.isArrayBuffer()) {
658 send(body.getAsArrayBuffer().get(), exceptionState);
659 return;
662 if (body.isArrayBufferView()) {
663 send(body.getAsArrayBufferView().get(), exceptionState);
664 return;
667 if (body.isBlob()) {
668 send(body.getAsBlob(), exceptionState);
669 return;
672 if (body.isDocument()) {
673 send(body.getAsDocument().get(), exceptionState);
674 return;
677 if (body.isFormData()) {
678 send(body.getAsFormData(), exceptionState);
679 return;
682 ASSERT(body.isString());
683 send(body.getAsString(), exceptionState);
686 bool XMLHttpRequest::areMethodAndURLValidForSend()
688 return m_method != "GET" && m_method != "HEAD" && m_url.protocolIsInHTTPFamily();
691 void XMLHttpRequest::send(Document* document, ExceptionState& exceptionState)
693 WTF_LOG(Network, "XMLHttpRequest %p send() Document %p", this, document);
695 ASSERT(document);
697 if (!initSend(exceptionState))
698 return;
700 RefPtr<EncodedFormData> httpBody;
702 if (areMethodAndURLValidForSend()) {
703 // FIXME: Per https://xhr.spec.whatwg.org/#dom-xmlhttprequest-send the
704 // Content-Type header and whether to serialize as HTML or XML should
705 // depend on |document->isHTMLDocument()|.
706 if (getRequestHeader("Content-Type").isEmpty())
707 setRequestHeaderInternal("Content-Type", "application/xml;charset=UTF-8");
709 String body = createMarkup(document);
711 httpBody = EncodedFormData::create(UTF8Encoding().encode(body, WTF::EntitiesForUnencodables));
714 createRequest(httpBody.release(), exceptionState);
717 void XMLHttpRequest::send(const String& body, ExceptionState& exceptionState)
719 WTF_LOG(Network, "XMLHttpRequest %p send() String '%s'", this, body.utf8().data());
721 if (!initSend(exceptionState))
722 return;
724 RefPtr<EncodedFormData> httpBody;
726 if (!body.isNull() && areMethodAndURLValidForSend()) {
727 String contentType = getRequestHeader("Content-Type");
728 if (contentType.isEmpty()) {
729 setRequestHeaderInternal("Content-Type", "text/plain;charset=UTF-8");
730 } else {
731 replaceCharsetInMediaType(contentType, "UTF-8");
732 m_requestHeaders.set("Content-Type", AtomicString(contentType));
735 httpBody = EncodedFormData::create(UTF8Encoding().encode(body, WTF::EntitiesForUnencodables));
738 createRequest(httpBody.release(), exceptionState);
741 void XMLHttpRequest::send(Blob* body, ExceptionState& exceptionState)
743 WTF_LOG(Network, "XMLHttpRequest %p send() Blob '%s'", this, body->uuid().utf8().data());
745 if (!initSend(exceptionState))
746 return;
748 RefPtr<EncodedFormData> httpBody;
750 if (areMethodAndURLValidForSend()) {
751 if (getRequestHeader("Content-Type").isEmpty()) {
752 const String& blobType = body->type();
753 if (!blobType.isEmpty() && isValidContentType(blobType)) {
754 setRequestHeaderInternal("Content-Type", AtomicString(blobType));
758 // FIXME: add support for uploading bundles.
759 httpBody = EncodedFormData::create();
760 if (body->hasBackingFile()) {
761 File* file = toFile(body);
762 if (!file->path().isEmpty())
763 httpBody->appendFile(file->path());
764 else if (!file->fileSystemURL().isEmpty())
765 httpBody->appendFileSystemURL(file->fileSystemURL());
766 else
767 ASSERT_NOT_REACHED();
768 } else {
769 httpBody->appendBlob(body->uuid(), body->blobDataHandle());
773 createRequest(httpBody.release(), exceptionState);
776 void XMLHttpRequest::send(FormData* body, ExceptionState& exceptionState)
778 WTF_LOG(Network, "XMLHttpRequest %p send() FormData %p", this, body);
780 if (!initSend(exceptionState))
781 return;
783 RefPtr<EncodedFormData> httpBody;
785 if (areMethodAndURLValidForSend()) {
786 httpBody = body->encodeMultiPartFormData();
788 if (getRequestHeader("Content-Type").isEmpty()) {
789 AtomicString contentType = AtomicString("multipart/form-data; boundary=", AtomicString::ConstructFromLiteral) + httpBody->boundary().data();
790 setRequestHeaderInternal("Content-Type", contentType);
794 createRequest(httpBody.release(), exceptionState);
797 void XMLHttpRequest::send(DOMArrayBuffer* body, ExceptionState& exceptionState)
799 WTF_LOG(Network, "XMLHttpRequest %p send() ArrayBuffer %p", this, body);
801 sendBytesData(body->data(), body->byteLength(), exceptionState);
804 void XMLHttpRequest::send(DOMArrayBufferView* body, ExceptionState& exceptionState)
806 WTF_LOG(Network, "XMLHttpRequest %p send() ArrayBufferView %p", this, body);
808 sendBytesData(body->baseAddress(), body->byteLength(), exceptionState);
811 void XMLHttpRequest::sendBytesData(const void* data, size_t length, ExceptionState& exceptionState)
813 if (!initSend(exceptionState))
814 return;
816 RefPtr<EncodedFormData> httpBody;
818 if (areMethodAndURLValidForSend()) {
819 httpBody = EncodedFormData::create(data, length);
822 createRequest(httpBody.release(), exceptionState);
825 void XMLHttpRequest::sendForInspectorXHRReplay(PassRefPtr<EncodedFormData> formData, ExceptionState& exceptionState)
827 createRequest(formData ? formData->deepCopy() : nullptr, exceptionState);
828 m_exceptionCode = exceptionState.code();
831 void XMLHttpRequest::throwForLoadFailureIfNeeded(ExceptionState& exceptionState, const String& reason)
833 if (m_error && !m_exceptionCode)
834 m_exceptionCode = NetworkError;
836 if (!m_exceptionCode)
837 return;
839 String message = "Failed to load '" + m_url.elidedString() + "'";
840 if (reason.isNull()) {
841 message.append(".");
842 } else {
843 message.append(": ");
844 message.append(reason);
847 exceptionState.throwDOMException(m_exceptionCode, message);
850 void XMLHttpRequest::createRequest(PassRefPtr<EncodedFormData> httpBody, ExceptionState& exceptionState)
852 // Only GET request is supported for blob URL.
853 if (m_url.protocolIs("blob") && m_method != "GET") {
854 handleNetworkError();
856 if (!m_async) {
857 throwForLoadFailureIfNeeded(exceptionState, "'GET' is the only method allowed for 'blob:' URLs.");
859 return;
862 // The presence of upload event listeners forces us to use preflighting because POSTing to an URL that does not
863 // permit cross origin requests should look exactly like POSTing to an URL that does not respond at all.
864 // Also, only async requests support upload progress events.
865 bool uploadEvents = false;
866 if (m_async) {
867 dispatchProgressEvent(EventTypeNames::loadstart, 0, 0);
868 if (httpBody && m_upload) {
869 uploadEvents = m_upload->hasEventListeners();
870 m_upload->dispatchEvent(XMLHttpRequestProgressEvent::create(EventTypeNames::loadstart));
874 m_sameOriginRequest = securityOrigin()->canRequestNoSuborigin(m_url);
876 // We also remember whether upload events should be allowed for this request in case the upload listeners are
877 // added after the request is started.
878 m_uploadEventsAllowed = m_sameOriginRequest || uploadEvents || !FetchUtils::isSimpleRequest(m_method, m_requestHeaders);
880 ASSERT(executionContext());
881 ExecutionContext& executionContext = *this->executionContext();
883 ResourceRequest request(m_url);
884 request.setHTTPMethod(m_method);
885 request.setRequestContext(WebURLRequest::RequestContextXMLHttpRequest);
886 request.setFetchCredentialsMode(m_includeCredentials ? WebURLRequest::FetchCredentialsModeInclude : WebURLRequest::FetchCredentialsModeSameOrigin);
888 InspectorInstrumentation::willLoadXHR(&executionContext, this, this, m_method, m_url, m_async, httpBody ? httpBody->deepCopy() : nullptr, m_requestHeaders, m_includeCredentials);
890 if (httpBody) {
891 ASSERT(m_method != "GET");
892 ASSERT(m_method != "HEAD");
893 request.setHTTPBody(httpBody);
896 if (m_requestHeaders.size() > 0)
897 request.addHTTPHeaderFields(m_requestHeaders);
899 ThreadableLoaderOptions options;
900 options.preflightPolicy = uploadEvents ? ForcePreflight : ConsiderPreflight;
901 options.crossOriginRequestPolicy = UseAccessControl;
902 options.initiator = FetchInitiatorTypeNames::xmlhttprequest;
903 options.contentSecurityPolicyEnforcement = ContentSecurityPolicy::shouldBypassMainWorld(&executionContext) ? DoNotEnforceContentSecurityPolicy : EnforceConnectSrcDirective;
904 options.timeoutMilliseconds = m_timeoutMilliseconds;
906 ResourceLoaderOptions resourceLoaderOptions;
907 resourceLoaderOptions.allowCredentials = (m_sameOriginRequest || m_includeCredentials) ? AllowStoredCredentials : DoNotAllowStoredCredentials;
908 resourceLoaderOptions.credentialsRequested = m_includeCredentials ? ClientRequestedCredentials : ClientDidNotRequestCredentials;
909 resourceLoaderOptions.securityOrigin = securityOrigin();
911 // When responseType is set to "blob", we redirect the downloaded data to a
912 // file-handle directly.
913 m_downloadingToFile = responseTypeCode() == ResponseTypeBlob;
914 if (m_downloadingToFile) {
915 request.setDownloadToFile(true);
916 resourceLoaderOptions.dataBufferingPolicy = DoNotBufferData;
919 m_exceptionCode = 0;
920 m_error = false;
922 if (m_async) {
923 UseCounter::count(&executionContext, UseCounter::XMLHttpRequestAsynchronous);
924 if (m_upload)
925 request.setReportUploadProgress(true);
927 // ThreadableLoader::create can return null here, for example if we're no longer attached to a page.
928 // This is true while running onunload handlers.
929 // FIXME: Maybe we need to be able to send XMLHttpRequests from onunload, <http://bugs.webkit.org/show_bug.cgi?id=10904>.
930 // FIXME: Maybe create() can return null for other reasons too?
931 ASSERT(!m_loader);
932 m_loader = ThreadableLoader::create(executionContext, this, request, options, resourceLoaderOptions);
934 return;
937 // Use count for XHR synchronous requests.
938 UseCounter::count(&executionContext, UseCounter::XMLHttpRequestSynchronous);
939 ThreadableLoader::loadResourceSynchronously(executionContext, request, *this, options, resourceLoaderOptions);
941 throwForLoadFailureIfNeeded(exceptionState, String());
944 void XMLHttpRequest::abort()
946 WTF_LOG(Network, "XMLHttpRequest %p abort()", this);
948 // internalAbort() clears |m_loader|. Compute |sendFlag| now.
950 // |sendFlag| corresponds to "the send() flag" defined in the XHR spec.
952 // |sendFlag| is only set when we have an active, asynchronous loader.
953 // Don't use it as "the send() flag" when the XHR is in sync mode.
954 bool sendFlag = m_loader;
956 // internalAbort() clears the response. Save the data needed for
957 // dispatching ProgressEvents.
958 long long expectedLength = m_response.expectedContentLength();
959 long long receivedLength = m_receivedLength;
961 if (!internalAbort())
962 return;
964 // The script never gets any chance to call abort() on a sync XHR between
965 // send() call and transition to the DONE state. It's because a sync XHR
966 // doesn't dispatch any event between them. So, if |m_async| is false, we
967 // can skip the "request error steps" (defined in the XHR spec) without any
968 // state check.
970 // FIXME: It's possible open() is invoked in internalAbort() and |m_async|
971 // becomes true by that. We should implement more reliable treatment for
972 // nested method invocations at some point.
973 if (m_async) {
974 if ((m_state == OPENED && sendFlag) || m_state == HEADERS_RECEIVED || m_state == LOADING) {
975 ASSERT(!m_loader);
976 handleRequestError(0, EventTypeNames::abort, receivedLength, expectedLength);
979 m_state = UNSENT;
982 void XMLHttpRequest::clearVariablesForLoading()
984 if (m_blobLoader) {
985 m_blobLoader->cancel();
986 m_blobLoader = nullptr;
989 m_decoder.clear();
991 if (m_responseDocumentParser) {
992 m_responseDocumentParser->removeClient(this);
993 #if !ENABLE(OILPAN)
994 m_responseDocumentParser->detach();
995 #endif
996 m_responseDocumentParser = nullptr;
999 m_finalResponseCharset = String();
1002 bool XMLHttpRequest::internalAbort()
1004 m_error = true;
1006 if (m_responseDocumentParser && !m_responseDocumentParser->isStopped())
1007 m_responseDocumentParser->stopParsing();
1009 clearVariablesForLoading();
1011 if (m_responseLegacyStream && m_state != DONE)
1012 m_responseLegacyStream->abort();
1014 clearResponse();
1015 clearRequest();
1017 if (!m_loader)
1018 return true;
1020 // Cancelling the ThreadableLoader m_loader may result in calling
1021 // window.onload synchronously. If such an onload handler contains open()
1022 // call on the same XMLHttpRequest object, reentry happens.
1024 // If, window.onload contains open() and send(), m_loader will be set to
1025 // non 0 value. So, we cannot continue the outer open(). In such case,
1026 // just abort the outer open() by returning false.
1027 RefPtr<ThreadableLoader> loader = m_loader.release();
1028 loader->cancel();
1030 // If abort() called internalAbort() and a nested open() ended up
1031 // clearing the error flag, but didn't send(), make sure the error
1032 // flag is still set.
1033 bool newLoadStarted = m_loader;
1034 if (!newLoadStarted)
1035 m_error = true;
1037 return !newLoadStarted;
1040 void XMLHttpRequest::clearResponse()
1042 // FIXME: when we add the support for multi-part XHR, we will have to
1043 // be careful with this initialization.
1044 m_receivedLength = 0;
1046 m_response = ResourceResponse();
1048 m_responseText.clear();
1050 m_parsedResponse = false;
1051 m_responseDocument = nullptr;
1053 m_responseBlob = nullptr;
1055 m_downloadingToFile = false;
1056 m_lengthDownloadedToFile = 0;
1058 m_responseLegacyStream = nullptr;
1060 // These variables may referred by the response accessors. So, we can clear
1061 // this only when we clear the response holder variables above.
1062 m_binaryResponseBuilder.clear();
1063 m_responseArrayBuffer.clear();
1066 void XMLHttpRequest::clearRequest()
1068 m_requestHeaders.clear();
1071 void XMLHttpRequest::dispatchProgressEvent(const AtomicString& type, long long receivedLength, long long expectedLength)
1073 bool lengthComputable = expectedLength > 0 && receivedLength <= expectedLength;
1074 unsigned long long loaded = receivedLength >= 0 ? static_cast<unsigned long long>(receivedLength) : 0;
1075 unsigned long long total = lengthComputable ? static_cast<unsigned long long>(expectedLength) : 0;
1077 m_progressEventThrottle->dispatchProgressEvent(type, lengthComputable, loaded, total);
1079 if (type == EventTypeNames::loadend)
1080 InspectorInstrumentation::didDispatchXHRLoadendEvent(executionContext(), this);
1083 void XMLHttpRequest::dispatchProgressEventFromSnapshot(const AtomicString& type)
1085 dispatchProgressEvent(type, m_receivedLength, m_response.expectedContentLength());
1088 void XMLHttpRequest::handleNetworkError()
1090 WTF_LOG(Network, "XMLHttpRequest %p handleNetworkError()", this);
1092 // Response is cleared next, save needed progress event data.
1093 long long expectedLength = m_response.expectedContentLength();
1094 long long receivedLength = m_receivedLength;
1096 if (!internalAbort())
1097 return;
1099 handleRequestError(NetworkError, EventTypeNames::error, receivedLength, expectedLength);
1102 void XMLHttpRequest::handleDidCancel()
1104 WTF_LOG(Network, "XMLHttpRequest %p handleDidCancel()", this);
1106 // Response is cleared next, save needed progress event data.
1107 long long expectedLength = m_response.expectedContentLength();
1108 long long receivedLength = m_receivedLength;
1110 if (!internalAbort())
1111 return;
1113 handleRequestError(AbortError, EventTypeNames::abort, receivedLength, expectedLength);
1116 void XMLHttpRequest::handleRequestError(ExceptionCode exceptionCode, const AtomicString& type, long long receivedLength, long long expectedLength)
1118 WTF_LOG(Network, "XMLHttpRequest %p handleRequestError()", this);
1120 InspectorInstrumentation::didFailXHRLoading(executionContext(), this, this, m_method, m_url);
1122 if (!m_async) {
1123 ASSERT(exceptionCode);
1124 m_state = DONE;
1125 m_exceptionCode = exceptionCode;
1126 return;
1129 // With m_error set, the state change steps are minimal: any pending
1130 // progress event is flushed + a readystatechange is dispatched.
1131 // No new progress events dispatched; as required, that happens at
1132 // the end here.
1133 ASSERT(m_error);
1134 changeState(DONE);
1136 if (!m_uploadComplete) {
1137 m_uploadComplete = true;
1138 if (m_upload && m_uploadEventsAllowed)
1139 m_upload->handleRequestError(type);
1142 // Note: The below event dispatch may be called while |hasPendingActivity() == false|,
1143 // when |handleRequestError| is called after |internalAbort()|.
1144 // This is safe, however, as |this| will be kept alive from a strong ref |Event::m_target|.
1145 dispatchProgressEvent(EventTypeNames::progress, receivedLength, expectedLength);
1146 dispatchProgressEvent(type, receivedLength, expectedLength);
1147 dispatchProgressEvent(EventTypeNames::loadend, receivedLength, expectedLength);
1150 void XMLHttpRequest::overrideMimeType(const AtomicString& mimeType, ExceptionState& exceptionState)
1152 if (m_state == LOADING || m_state == DONE) {
1153 exceptionState.throwDOMException(InvalidStateError, "MimeType cannot be overridden when the state is LOADING or DONE.");
1154 return;
1157 m_mimeTypeOverride = mimeType;
1160 void XMLHttpRequest::setRequestHeader(const AtomicString& name, const AtomicString& value, ExceptionState& exceptionState)
1162 if (m_state != OPENED || m_loader) {
1163 exceptionState.throwDOMException(InvalidStateError, "The object's state must be OPENED.");
1164 return;
1167 if (!isValidHTTPToken(name)) {
1168 exceptionState.throwDOMException(SyntaxError, "'" + name + "' is not a valid HTTP header field name.");
1169 return;
1172 if (!isValidHTTPHeaderValue(value)) {
1173 exceptionState.throwDOMException(SyntaxError, "'" + value + "' is not a valid HTTP header field value.");
1174 return;
1177 // Show deprecation warnings and count occurrences of such deprecated header values.
1178 if (!value.isEmpty() && !isValidHTTPFieldContentRFC7230(value))
1179 UseCounter::countDeprecation(executionContext(), UseCounter::HeaderValueNotMatchingRFC7230);
1181 // No script (privileged or not) can set unsafe headers.
1182 if (FetchUtils::isForbiddenHeaderName(name)) {
1183 logConsoleError(executionContext(), "Refused to set unsafe header \"" + name + "\"");
1184 return;
1187 setRequestHeaderInternal(name, value);
1190 void XMLHttpRequest::setRequestHeaderInternal(const AtomicString& name, const AtomicString& value)
1192 HTTPHeaderMap::AddResult result = m_requestHeaders.add(name, value);
1193 if (!result.isNewEntry)
1194 result.storedValue->value = result.storedValue->value + ", " + value;
1197 const AtomicString& XMLHttpRequest::getRequestHeader(const AtomicString& name) const
1199 return m_requestHeaders.get(name);
1202 String XMLHttpRequest::getAllResponseHeaders() const
1204 if (m_state < HEADERS_RECEIVED || m_error)
1205 return "";
1207 StringBuilder stringBuilder;
1209 HTTPHeaderSet accessControlExposeHeaderSet;
1210 parseAccessControlExposeHeadersAllowList(m_response.httpHeaderField("Access-Control-Expose-Headers"), accessControlExposeHeaderSet);
1211 HTTPHeaderMap::const_iterator end = m_response.httpHeaderFields().end();
1212 for (HTTPHeaderMap::const_iterator it = m_response.httpHeaderFields().begin(); it!= end; ++it) {
1213 // Hide Set-Cookie header fields from the XMLHttpRequest client for these reasons:
1214 // 1) If the client did have access to the fields, then it could read HTTP-only
1215 // cookies; those cookies are supposed to be hidden from scripts.
1216 // 2) There's no known harm in hiding Set-Cookie header fields entirely; we don't
1217 // know any widely used technique that requires access to them.
1218 // 3) Firefox has implemented this policy.
1219 if (isSetCookieHeader(it->key) && !securityOrigin()->canLoadLocalResources())
1220 continue;
1222 if (!m_sameOriginRequest && !isOnAccessControlResponseHeaderWhitelist(it->key) && !accessControlExposeHeaderSet.contains(it->key))
1223 continue;
1225 stringBuilder.append(it->key);
1226 stringBuilder.append(':');
1227 stringBuilder.append(' ');
1228 stringBuilder.append(it->value);
1229 stringBuilder.append('\r');
1230 stringBuilder.append('\n');
1233 return stringBuilder.toString();
1236 const AtomicString& XMLHttpRequest::getResponseHeader(const AtomicString& name) const
1238 if (m_state < HEADERS_RECEIVED || m_error)
1239 return nullAtom;
1241 // See comment in getAllResponseHeaders above.
1242 if (isSetCookieHeader(name) && !securityOrigin()->canLoadLocalResources()) {
1243 logConsoleError(executionContext(), "Refused to get unsafe header \"" + name + "\"");
1244 return nullAtom;
1247 HTTPHeaderSet accessControlExposeHeaderSet;
1248 parseAccessControlExposeHeadersAllowList(m_response.httpHeaderField("Access-Control-Expose-Headers"), accessControlExposeHeaderSet);
1250 if (!m_sameOriginRequest && !isOnAccessControlResponseHeaderWhitelist(name) && !accessControlExposeHeaderSet.contains(name)) {
1251 logConsoleError(executionContext(), "Refused to get unsafe header \"" + name + "\"");
1252 return nullAtom;
1254 return m_response.httpHeaderField(name);
1257 AtomicString XMLHttpRequest::finalResponseMIMEType() const
1259 AtomicString overriddenType = extractMIMETypeFromMediaType(m_mimeTypeOverride);
1260 if (!overriddenType.isEmpty())
1261 return overriddenType;
1263 if (m_response.isHTTP())
1264 return extractMIMETypeFromMediaType(m_response.httpHeaderField("Content-Type"));
1266 return m_response.mimeType();
1269 AtomicString XMLHttpRequest::finalResponseMIMETypeWithFallback() const
1271 AtomicString finalType = finalResponseMIMEType();
1272 if (!finalType.isEmpty())
1273 return finalType;
1275 // FIXME: This fallback is not specified in the final MIME type algorithm
1276 // of the XHR spec. Move this to more appropriate place.
1277 return AtomicString("text/xml", AtomicString::ConstructFromLiteral);
1280 bool XMLHttpRequest::responseIsXML() const
1282 return DOMImplementation::isXMLMIMEType(finalResponseMIMETypeWithFallback());
1285 bool XMLHttpRequest::responseIsHTML() const
1287 return equalIgnoringCase(finalResponseMIMEType(), "text/html");
1290 int XMLHttpRequest::status() const
1292 if (m_state == UNSENT || m_state == OPENED || m_error)
1293 return 0;
1295 if (m_response.httpStatusCode())
1296 return m_response.httpStatusCode();
1298 return 0;
1301 String XMLHttpRequest::statusText() const
1303 if (m_state == UNSENT || m_state == OPENED || m_error)
1304 return String();
1306 if (!m_response.httpStatusText().isNull())
1307 return m_response.httpStatusText();
1309 return String();
1312 void XMLHttpRequest::didFail(const ResourceError& error)
1314 WTF_LOG(Network, "XMLHttpRequest %p didFail()", this);
1315 ScopedEventDispatchProtect protect(&m_eventDispatchRecursionLevel);
1317 // If we are already in an error state, for instance we called abort(), bail out early.
1318 if (m_error)
1319 return;
1321 if (error.isCancellation()) {
1322 handleDidCancel();
1323 // Now the XMLHttpRequest instance may be dead.
1324 return;
1327 if (error.isTimeout()) {
1328 handleDidTimeout();
1329 // Now the XMLHttpRequest instance may be dead.
1330 return;
1333 // Network failures are already reported to Web Inspector by ResourceLoader.
1334 if (error.domain() == errorDomainBlinkInternal)
1335 logConsoleError(executionContext(), "XMLHttpRequest cannot load " + error.failingURL() + ". " + error.localizedDescription());
1337 handleNetworkError();
1338 // Now the XMLHttpRequest instance may be dead.
1341 void XMLHttpRequest::didFailRedirectCheck()
1343 WTF_LOG(Network, "XMLHttpRequest %p didFailRedirectCheck()", this);
1344 ScopedEventDispatchProtect protect(&m_eventDispatchRecursionLevel);
1346 handleNetworkError();
1347 // Now the XMLHttpRequest instance may be dead.
1350 void XMLHttpRequest::didFinishLoading(unsigned long identifier, double)
1352 WTF_LOG(Network, "XMLHttpRequest %p didFinishLoading(%lu)", this, identifier);
1353 ScopedEventDispatchProtect protect(&m_eventDispatchRecursionLevel);
1355 if (m_error)
1356 return;
1358 if (m_state < HEADERS_RECEIVED)
1359 changeState(HEADERS_RECEIVED);
1361 if (m_downloadingToFile && m_responseTypeCode != ResponseTypeBlob && m_lengthDownloadedToFile) {
1362 ASSERT(m_state == LOADING);
1363 // In this case, we have sent the request with DownloadToFile true,
1364 // but the user changed the response type after that. Hence we need to
1365 // read the response data and provide it to this object.
1366 m_blobLoader = BlobLoader::create(this, createBlobDataHandleFromResponse());
1367 } else {
1368 didFinishLoadingInternal();
1372 void XMLHttpRequest::didFinishLoadingInternal()
1374 if (m_responseDocumentParser) {
1375 // |DocumentParser::finish()| tells the parser that we have reached end of the data.
1376 // When using |HTMLDocumentParser|, which works asynchronously, we do not have the
1377 // complete document just after the |DocumentParser::finish()| call.
1378 // Wait for the parser to call us back in |notifyParserStopped| to progress state.
1379 m_responseDocumentParser->finish();
1380 ASSERT(m_responseDocument);
1381 return;
1384 if (m_decoder) {
1385 auto text = m_decoder->flush();
1386 if (!text.isEmpty() && !m_responseTextOverflow) {
1387 m_responseText = m_responseText.concatenateWith(text);
1388 m_responseTextOverflow = m_responseText.isEmpty();
1392 if (m_responseLegacyStream)
1393 m_responseLegacyStream->finalize();
1395 clearVariablesForLoading();
1396 endLoading();
1399 void XMLHttpRequest::didFinishLoadingFromBlob()
1401 WTF_LOG(Network, "XMLHttpRequest %p didFinishLoadingFromBlob", this);
1402 ScopedEventDispatchProtect protect(&m_eventDispatchRecursionLevel);
1404 didFinishLoadingInternal();
1407 void XMLHttpRequest::didFailLoadingFromBlob()
1409 WTF_LOG(Network, "XMLHttpRequest %p didFailLoadingFromBlob()", this);
1410 ScopedEventDispatchProtect protect(&m_eventDispatchRecursionLevel);
1412 if (m_error)
1413 return;
1414 handleNetworkError();
1417 PassRefPtr<BlobDataHandle> XMLHttpRequest::createBlobDataHandleFromResponse()
1419 ASSERT(m_downloadingToFile);
1420 OwnPtr<BlobData> blobData = BlobData::create();
1421 String filePath = m_response.downloadedFilePath();
1422 // If we errored out or got no data, we return an empty handle.
1423 if (!filePath.isEmpty() && m_lengthDownloadedToFile) {
1424 blobData->appendFile(filePath);
1425 // FIXME: finalResponseMIMETypeWithFallback() defaults to
1426 // text/xml which may be incorrect. Replace it with
1427 // finalResponseMIMEType() after compatibility investigation.
1428 blobData->setContentType(finalResponseMIMETypeWithFallback().lower());
1430 return BlobDataHandle::create(blobData.release(), m_lengthDownloadedToFile);
1433 void XMLHttpRequest::notifyParserStopped()
1435 ScopedEventDispatchProtect protect(&m_eventDispatchRecursionLevel);
1437 // This should only be called when response document is parsed asynchronously.
1438 ASSERT(m_responseDocumentParser);
1439 ASSERT(!m_responseDocumentParser->isParsing());
1440 ASSERT(!m_responseLegacyStream);
1442 // Do nothing if we are called from |internalAbort()|.
1443 if (m_error)
1444 return;
1446 clearVariablesForLoading();
1448 m_responseDocument->implicitClose();
1450 if (!m_responseDocument->wellFormed())
1451 m_responseDocument = nullptr;
1453 m_parsedResponse = true;
1455 endLoading();
1458 void XMLHttpRequest::endLoading()
1460 InspectorInstrumentation::didFinishXHRLoading(executionContext(), this, this, m_method, m_url);
1462 if (m_loader)
1463 m_loader = nullptr;
1465 changeState(DONE);
1467 if (!executionContext()->isDocument() || !document() || !document()->frame() || !document()->frame()->page())
1468 return;
1470 if (status() >= 200 && status() < 300) {
1471 document()->frame()->page()->chromeClient().ajaxSucceeded(document()->frame());
1475 void XMLHttpRequest::didSendData(unsigned long long bytesSent, unsigned long long totalBytesToBeSent)
1477 WTF_LOG(Network, "XMLHttpRequest %p didSendData(%llu, %llu)", this, bytesSent, totalBytesToBeSent);
1478 ScopedEventDispatchProtect protect(&m_eventDispatchRecursionLevel);
1480 if (!m_upload)
1481 return;
1483 if (m_uploadEventsAllowed)
1484 m_upload->dispatchProgressEvent(bytesSent, totalBytesToBeSent);
1486 if (bytesSent == totalBytesToBeSent && !m_uploadComplete) {
1487 m_uploadComplete = true;
1488 if (m_uploadEventsAllowed)
1489 m_upload->dispatchEventAndLoadEnd(EventTypeNames::load, true, bytesSent, totalBytesToBeSent);
1493 void XMLHttpRequest::didReceiveResponse(unsigned long identifier, const ResourceResponse& response, PassOwnPtr<WebDataConsumerHandle> handle)
1495 ASSERT_UNUSED(handle, !handle);
1496 WTF_LOG(Network, "XMLHttpRequest %p didReceiveResponse(%lu)", this, identifier);
1497 ScopedEventDispatchProtect protect(&m_eventDispatchRecursionLevel);
1499 m_response = response;
1500 if (!m_mimeTypeOverride.isEmpty()) {
1501 m_response.setHTTPHeaderField("Content-Type", m_mimeTypeOverride);
1502 m_finalResponseCharset = extractCharsetFromMediaType(m_mimeTypeOverride);
1505 if (m_finalResponseCharset.isEmpty())
1506 m_finalResponseCharset = response.textEncodingName();
1509 void XMLHttpRequest::parseDocumentChunk(const char* data, unsigned len)
1511 if (!m_responseDocumentParser) {
1512 ASSERT(!m_responseDocument);
1513 initResponseDocument();
1514 if (!m_responseDocument)
1515 return;
1517 m_responseDocumentParser = m_responseDocument->implicitOpen(AllowAsynchronousParsing);
1518 m_responseDocumentParser->addClient(this);
1520 ASSERT(m_responseDocumentParser);
1522 if (m_responseDocumentParser->needsDecoder())
1523 m_responseDocumentParser->setDecoder(createDecoder());
1525 m_responseDocumentParser->appendBytes(data, len);
1528 PassOwnPtr<TextResourceDecoder> XMLHttpRequest::createDecoder() const
1530 if (m_responseTypeCode == ResponseTypeJSON)
1531 return TextResourceDecoder::create("application/json", "UTF-8");
1533 if (!m_finalResponseCharset.isEmpty())
1534 return TextResourceDecoder::create("text/plain", m_finalResponseCharset);
1536 // allow TextResourceDecoder to look inside the m_response if it's XML or HTML
1537 if (responseIsXML()) {
1538 OwnPtr<TextResourceDecoder> decoder = TextResourceDecoder::create("application/xml");
1539 // Don't stop on encoding errors, unlike it is done for other kinds
1540 // of XML resources. This matches the behavior of previous WebKit
1541 // versions, Firefox and Opera.
1542 decoder->useLenientXMLDecoding();
1544 return decoder.release();
1547 if (responseIsHTML())
1548 return TextResourceDecoder::create("text/html", "UTF-8");
1550 return TextResourceDecoder::create("text/plain", "UTF-8");
1553 void XMLHttpRequest::didReceiveData(const char* data, unsigned len)
1555 ScopedEventDispatchProtect protect(&m_eventDispatchRecursionLevel);
1556 if (m_error)
1557 return;
1559 if (m_state < HEADERS_RECEIVED)
1560 changeState(HEADERS_RECEIVED);
1562 // We need to check for |m_error| again, because |changeState| may trigger
1563 // readystatechange, and user javascript can cause |abort()|.
1564 if (m_error)
1565 return;
1567 if (!len)
1568 return;
1570 if (m_responseTypeCode == ResponseTypeDocument && responseIsHTML()) {
1571 parseDocumentChunk(data, len);
1572 } else if (m_responseTypeCode == ResponseTypeDefault || m_responseTypeCode == ResponseTypeText || m_responseTypeCode == ResponseTypeJSON || m_responseTypeCode == ResponseTypeDocument) {
1573 if (!m_decoder)
1574 m_decoder = createDecoder();
1576 auto text = m_decoder->decode(data, len);
1577 if (!text.isEmpty() && !m_responseTextOverflow) {
1578 m_responseText = m_responseText.concatenateWith(text);
1579 m_responseTextOverflow = m_responseText.isEmpty();
1581 } else if (m_responseTypeCode == ResponseTypeArrayBuffer || m_responseTypeCode == ResponseTypeBlob) {
1582 // Buffer binary data.
1583 if (!m_binaryResponseBuilder)
1584 m_binaryResponseBuilder = SharedBuffer::create();
1585 m_binaryResponseBuilder->append(data, len);
1586 } else if (m_responseTypeCode == ResponseTypeLegacyStream) {
1587 if (!m_responseLegacyStream)
1588 m_responseLegacyStream = Stream::create(executionContext(), responseType());
1589 m_responseLegacyStream->addData(data, len);
1592 if (m_blobLoader) {
1593 // In this case, the data is provided by m_blobLoader. As progress
1594 // events are already fired, we should return here.
1595 return;
1597 trackProgress(len);
1600 void XMLHttpRequest::didDownloadData(int dataLength)
1602 ScopedEventDispatchProtect protect(&m_eventDispatchRecursionLevel);
1603 if (m_error)
1604 return;
1606 ASSERT(m_downloadingToFile);
1608 if (m_state < HEADERS_RECEIVED)
1609 changeState(HEADERS_RECEIVED);
1611 if (!dataLength)
1612 return;
1614 // readystatechange event handler may do something to put this XHR in error
1615 // state. We need to check m_error again here.
1616 if (m_error)
1617 return;
1619 m_lengthDownloadedToFile += dataLength;
1621 trackProgress(dataLength);
1624 void XMLHttpRequest::handleDidTimeout()
1626 WTF_LOG(Network, "XMLHttpRequest %p handleDidTimeout()", this);
1628 // Response is cleared next, save needed progress event data.
1629 long long expectedLength = m_response.expectedContentLength();
1630 long long receivedLength = m_receivedLength;
1632 if (!internalAbort())
1633 return;
1635 handleRequestError(TimeoutError, EventTypeNames::timeout, receivedLength, expectedLength);
1638 void XMLHttpRequest::suspend()
1640 m_progressEventThrottle->suspend();
1643 void XMLHttpRequest::resume()
1645 m_progressEventThrottle->resume();
1648 void XMLHttpRequest::stop()
1650 InspectorInstrumentation::didFailXHRLoading(executionContext(), this, this, m_method, m_url);
1651 internalAbort();
1654 bool XMLHttpRequest::hasPendingActivity() const
1656 // Neither this object nor the JavaScript wrapper should be deleted while
1657 // a request is in progress because we need to keep the listeners alive,
1658 // and they are referenced by the JavaScript wrapper.
1659 // |m_loader| is non-null while request is active and ThreadableLoaderClient
1660 // callbacks may be called, and |m_responseDocumentParser| is non-null while
1661 // DocumentParserClient callbacks may be called.
1662 if (m_loader || m_responseDocumentParser)
1663 return true;
1664 return m_eventDispatchRecursionLevel > 0;
1667 void XMLHttpRequest::contextDestroyed()
1669 ASSERT(!m_loader);
1670 ActiveDOMObject::contextDestroyed();
1673 const AtomicString& XMLHttpRequest::interfaceName() const
1675 return EventTargetNames::XMLHttpRequest;
1678 ExecutionContext* XMLHttpRequest::executionContext() const
1680 return ActiveDOMObject::executionContext();
1683 DEFINE_TRACE(XMLHttpRequest)
1685 visitor->trace(m_responseBlob);
1686 visitor->trace(m_responseLegacyStream);
1687 visitor->trace(m_responseDocument);
1688 visitor->trace(m_responseDocumentParser);
1689 visitor->trace(m_progressEventThrottle);
1690 visitor->trace(m_upload);
1691 visitor->trace(m_blobLoader);
1692 XMLHttpRequestEventTarget::trace(visitor);
1693 DocumentParserClient::trace(visitor);
1694 ActiveDOMObject::trace(visitor);
1697 } // namespace blink