Unreviewed, rolling out r243551.
[WebKit-https.git] / Source / WebCore / xml / XMLHttpRequest.cpp
1 /*
2  *  Copyright (C) 2004-2016 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
7  *
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.
12  *
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.
17  *
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
21  */
22
23 #include "config.h"
24 #include "XMLHttpRequest.h"
25
26 #include "Blob.h"
27 #include "CachedResourceRequestInitiators.h"
28 #include "ContentSecurityPolicy.h"
29 #include "CrossOriginAccessControl.h"
30 #include "DOMFormData.h"
31 #include "DOMWindow.h"
32 #include "Event.h"
33 #include "EventNames.h"
34 #include "File.h"
35 #include "HTMLDocument.h"
36 #include "HTTPHeaderNames.h"
37 #include "HTTPHeaderValues.h"
38 #include "HTTPParsers.h"
39 #include "InspectorInstrumentation.h"
40 #include "JSDOMBinding.h"
41 #include "JSDOMWindow.h"
42 #include "MIMETypeRegistry.h"
43 #include "MemoryCache.h"
44 #include "ParsedContentType.h"
45 #include "ResourceError.h"
46 #include "ResourceRequest.h"
47 #include "RuntimeApplicationChecks.h"
48 #include "SecurityOriginPolicy.h"
49 #include "Settings.h"
50 #include "SharedBuffer.h"
51 #include "StringAdaptors.h"
52 #include "TextResourceDecoder.h"
53 #include "ThreadableLoader.h"
54 #include "XMLDocument.h"
55 #include "XMLHttpRequestProgressEvent.h"
56 #include "XMLHttpRequestUpload.h"
57 #include "markup.h"
58 #include <JavaScriptCore/ArrayBuffer.h>
59 #include <JavaScriptCore/ArrayBufferView.h>
60 #include <JavaScriptCore/JSCInlines.h>
61 #include <JavaScriptCore/JSLock.h>
62 #include <wtf/RefCountedLeakCounter.h>
63 #include <wtf/StdLibExtras.h>
64 #include <wtf/text/CString.h>
65
66 namespace WebCore {
67
68 DEFINE_DEBUG_ONLY_GLOBAL(WTF::RefCountedLeakCounter, xmlHttpRequestCounter, ("XMLHttpRequest"));
69
70 // Histogram enum to see when we can deprecate xhr.send(ArrayBuffer).
71 enum XMLHttpRequestSendArrayBufferOrView {
72     XMLHttpRequestSendArrayBuffer,
73     XMLHttpRequestSendArrayBufferView,
74     XMLHttpRequestSendArrayBufferOrViewMax,
75 };
76
77 static void replaceCharsetInMediaTypeIfNeeded(String& mediaType)
78 {
79     auto parsedContentType = ParsedContentType::create(mediaType);
80     if (!parsedContentType || parsedContentType->charset().isEmpty() || equalIgnoringASCIICase(parsedContentType->charset(), "UTF-8"))
81         return;
82
83     parsedContentType->setCharset("UTF-8");
84     mediaType = parsedContentType->serialize();
85 }
86
87 static void logConsoleError(ScriptExecutionContext* context, const String& message)
88 {
89     if (!context)
90         return;
91     // FIXME: It's not good to report the bad usage without indicating what source line it came from.
92     // We should pass additional parameters so we can tell the console where the mistake occurred.
93     context->addConsoleMessage(MessageSource::JS, MessageLevel::Error, message);
94 }
95
96 Ref<XMLHttpRequest> XMLHttpRequest::create(ScriptExecutionContext& context)
97 {
98     auto xmlHttpRequest = adoptRef(*new XMLHttpRequest(context));
99     xmlHttpRequest->suspendIfNeeded();
100     return xmlHttpRequest;
101 }
102
103 XMLHttpRequest::XMLHttpRequest(ScriptExecutionContext& context)
104     : ActiveDOMObject(&context)
105     , m_async(true)
106     , m_includeCredentials(false)
107     , m_sendFlag(false)
108     , m_createdDocument(false)
109     , m_error(false)
110     , m_uploadListenerFlag(false)
111     , m_uploadComplete(false)
112     , m_wasAbortedByClient(false)
113     , m_responseCacheIsValid(false)
114     , m_dispatchErrorOnResuming(false)
115     , m_readyState(static_cast<unsigned>(UNSENT))
116     , m_responseType(static_cast<unsigned>(ResponseType::EmptyString))
117     , m_progressEventThrottle(this)
118     , m_resumeTimer(*this, &XMLHttpRequest::resumeTimerFired)
119     , m_networkErrorTimer(*this, &XMLHttpRequest::networkErrorTimerFired)
120     , m_timeoutTimer(*this, &XMLHttpRequest::didReachTimeout)
121 {
122 #ifndef NDEBUG
123     xmlHttpRequestCounter.increment();
124 #endif
125 }
126
127 XMLHttpRequest::~XMLHttpRequest()
128 {
129 #ifndef NDEBUG
130     xmlHttpRequestCounter.decrement();
131 #endif
132 }
133
134 Document* XMLHttpRequest::document() const
135 {
136     ASSERT(scriptExecutionContext());
137     return downcast<Document>(scriptExecutionContext());
138 }
139
140 SecurityOrigin* XMLHttpRequest::securityOrigin() const
141 {
142     return scriptExecutionContext()->securityOrigin();
143 }
144
145 #if ENABLE(DASHBOARD_SUPPORT)
146
147 bool XMLHttpRequest::usesDashboardBackwardCompatibilityMode() const
148 {
149     if (scriptExecutionContext()->isWorkerGlobalScope())
150         return false;
151     return document()->settings().usesDashboardBackwardCompatibilityMode();
152 }
153
154 #endif
155
156 ExceptionOr<OwnedString> XMLHttpRequest::responseText()
157 {
158     if (responseType() != ResponseType::EmptyString && responseType() != ResponseType::Text)
159         return Exception { InvalidStateError };
160     return OwnedString { responseTextIgnoringResponseType() };
161 }
162
163 void XMLHttpRequest::didCacheResponse()
164 {
165     ASSERT(doneWithoutErrors());
166     m_responseCacheIsValid = true;
167     m_responseBuilder.clear();
168 }
169
170 ExceptionOr<Document*> XMLHttpRequest::responseXML()
171 {
172     ASSERT(scriptExecutionContext()->isDocument());
173     
174     if (responseType() != ResponseType::EmptyString && responseType() != ResponseType::Document)
175         return Exception { InvalidStateError };
176
177     if (!doneWithoutErrors())
178         return nullptr;
179
180     if (!m_createdDocument) {
181         String mimeType = responseMIMEType();
182         bool isHTML = equalLettersIgnoringASCIICase(mimeType, "text/html");
183
184         // The W3C spec requires the final MIME type to be some valid XML type, or text/html.
185         // If it is text/html, then the responseType of "document" must have been supplied explicitly.
186         if ((m_response.isHTTP() && !responseIsXML() && !isHTML)
187             || (isHTML && responseType() == ResponseType::EmptyString)) {
188             m_responseDocument = nullptr;
189         } else {
190             if (isHTML)
191                 m_responseDocument = HTMLDocument::create(nullptr, m_url);
192             else
193                 m_responseDocument = XMLDocument::create(nullptr, m_url);
194             m_responseDocument->overrideLastModified(m_response.lastModified());
195             m_responseDocument->setContent(m_responseBuilder.toStringPreserveCapacity());
196             m_responseDocument->setContextDocument(downcast<Document>(*scriptExecutionContext()));
197             m_responseDocument->setSecurityOriginPolicy(scriptExecutionContext()->securityOriginPolicy());
198             m_responseDocument->overrideMIMEType(mimeType);
199
200             if (!m_responseDocument->wellFormed())
201                 m_responseDocument = nullptr;
202         }
203         m_createdDocument = true;
204     }
205
206     return m_responseDocument.get();
207 }
208
209 Ref<Blob> XMLHttpRequest::createResponseBlob()
210 {
211     ASSERT(responseType() == ResponseType::Blob);
212     ASSERT(doneWithoutErrors());
213
214     // FIXME: We just received the data from NetworkProcess, and are sending it back. This is inefficient.
215     Vector<uint8_t> data;
216     if (m_binaryResponseBuilder)
217         data.append(m_binaryResponseBuilder->data(), m_binaryResponseBuilder->size());
218     m_binaryResponseBuilder = nullptr;
219     String normalizedContentType = Blob::normalizedContentType(responseMIMEType()); // responseMIMEType defaults to text/xml which may be incorrect.
220     return Blob::create(WTFMove(data), normalizedContentType);
221 }
222
223 RefPtr<ArrayBuffer> XMLHttpRequest::createResponseArrayBuffer()
224 {
225     ASSERT(responseType() == ResponseType::Arraybuffer);
226     ASSERT(doneWithoutErrors());
227
228     auto result = m_binaryResponseBuilder ? m_binaryResponseBuilder->tryCreateArrayBuffer() : ArrayBuffer::create(nullptr, 0);
229     m_binaryResponseBuilder = nullptr;
230     return result;
231 }
232
233 ExceptionOr<void> XMLHttpRequest::setTimeout(unsigned timeout)
234 {
235     if (scriptExecutionContext()->isDocument() && !m_async) {
236         logConsoleError(scriptExecutionContext(), "XMLHttpRequest.timeout cannot be set for synchronous HTTP(S) requests made from the window context.");
237         return Exception { InvalidAccessError };
238     }
239     m_timeoutMilliseconds = timeout;
240     if (!m_timeoutTimer.isActive())
241         return { };
242
243     // If timeout is zero, we should use the default network timeout. But we disabled it so let's mimic it with a 60 seconds timeout value.
244     Seconds interval = Seconds { m_timeoutMilliseconds ? m_timeoutMilliseconds / 1000. : 60. } - (MonotonicTime::now() - m_sendingTime);
245     m_timeoutTimer.startOneShot(std::max(interval, 0_s));
246     return { };
247 }
248
249 ExceptionOr<void> XMLHttpRequest::setResponseType(ResponseType type)
250 {
251     if (!scriptExecutionContext()->isDocument() && type == ResponseType::Document)
252         return { };
253
254     if (readyState() >= LOADING)
255         return Exception { InvalidStateError };
256
257     // Newer functionality is not available to synchronous requests in window contexts, as a spec-mandated
258     // attempt to discourage synchronous XHR use. responseType is one such piece of functionality.
259     // We'll only disable this functionality for HTTP(S) requests since sync requests for local protocols
260     // such as file: and data: still make sense to allow.
261     if (!m_async && scriptExecutionContext()->isDocument() && m_url.protocolIsInHTTPFamily()) {
262         logConsoleError(scriptExecutionContext(), "XMLHttpRequest.responseType cannot be changed for synchronous HTTP(S) requests made from the window context.");
263         return Exception { InvalidAccessError };
264     }
265
266     m_responseType = static_cast<unsigned>(type);
267     return { };
268 }
269
270 String XMLHttpRequest::responseURL() const
271 {
272     URL responseURL(m_response.url());
273     responseURL.removeFragmentIdentifier();
274
275     return responseURL.string();
276 }
277
278 XMLHttpRequestUpload& XMLHttpRequest::upload()
279 {
280     if (!m_upload)
281         m_upload = std::make_unique<XMLHttpRequestUpload>(*this);
282     return *m_upload;
283 }
284
285 void XMLHttpRequest::changeState(State newState)
286 {
287     if (readyState() != newState) {
288         m_readyState = static_cast<State>(newState);
289         if (readyState() == DONE) {
290             // The XHR object itself holds on to the responseText, and
291             // thus has extra cost even independent of any
292             // responseText or responseXML objects it has handed
293             // out. But it is protected from GC while loading, so this
294             // can't be recouped until the load is done, so only
295             // report the extra cost at that point.
296             if (auto* context = scriptExecutionContext()) {
297                 JSC::VM& vm = context->vm();
298                 JSC::JSLockHolder lock(vm);
299                 vm.heap.reportExtraMemoryAllocated(memoryCost());
300             }
301         }
302         callReadyStateChangeListener();
303     }
304 }
305
306 void XMLHttpRequest::callReadyStateChangeListener()
307 {
308     if (!scriptExecutionContext())
309         return;
310
311     // Check whether sending load and loadend events before sending readystatechange event, as it may change m_error/m_readyState values.
312     bool shouldSendLoadEvent = (readyState() == DONE && !m_error);
313
314     if (m_async || (readyState() <= OPENED || readyState() == DONE)) {
315         m_progressEventThrottle.dispatchReadyStateChangeEvent(Event::create(eventNames().readystatechangeEvent, Event::CanBubble::No, Event::IsCancelable::No),
316             readyState() == DONE ? FlushProgressEvent : DoNotFlushProgressEvent);
317     }
318
319     if (shouldSendLoadEvent) {
320         m_progressEventThrottle.dispatchProgressEvent(eventNames().loadEvent);
321         m_progressEventThrottle.dispatchProgressEvent(eventNames().loadendEvent);
322     }
323 }
324
325 ExceptionOr<void> XMLHttpRequest::setWithCredentials(bool value)
326 {
327     if (readyState() > OPENED || m_sendFlag)
328         return Exception { InvalidStateError };
329
330     m_includeCredentials = value;
331     return { };
332 }
333
334 ExceptionOr<void> XMLHttpRequest::open(const String& method, const String& url)
335 {
336     // If the async argument is omitted, set async to true.
337     return open(method, scriptExecutionContext()->completeURL(url), true);
338 }
339
340 ExceptionOr<void> XMLHttpRequest::open(const String& method, const URL& url, bool async)
341 {
342     if (!isValidHTTPToken(method))
343         return Exception { SyntaxError };
344
345     if (isForbiddenMethod(method))
346         return Exception { SecurityError };
347
348     if (!url.isValid())
349         return Exception { SyntaxError };
350
351     if (!async && scriptExecutionContext()->isDocument()) {
352         // Newer functionality is not available to synchronous requests in window contexts, as a spec-mandated
353         // attempt to discourage synchronous XHR use. responseType is one such piece of functionality.
354         // We'll only disable this functionality for HTTP(S) requests since sync requests for local protocols
355         // such as file: and data: still make sense to allow.
356         if (url.protocolIsInHTTPFamily() && responseType() != ResponseType::EmptyString) {
357             logConsoleError(scriptExecutionContext(), "Synchronous HTTP(S) requests made from the window context cannot have XMLHttpRequest.responseType set.");
358             return Exception { InvalidAccessError };
359         }
360
361         // Similarly, timeouts are disabled for synchronous requests as well.
362         if (m_timeoutMilliseconds > 0) {
363             logConsoleError(scriptExecutionContext(), "Synchronous XMLHttpRequests must not have a timeout value set.");
364             return Exception { InvalidAccessError };
365         }
366     }
367
368     if (!internalAbort())
369         return { };
370
371     m_sendFlag = false;
372     m_uploadListenerFlag = false;
373     m_method = normalizeHTTPMethod(method);
374     m_error = false;
375     m_uploadComplete = false;
376     m_wasAbortedByClient = false;
377
378     // clear stuff from possible previous load
379     clearResponse();
380     clearRequest();
381
382     m_url = url;
383     scriptExecutionContext()->contentSecurityPolicy()->upgradeInsecureRequestIfNeeded(m_url, ContentSecurityPolicy::InsecureRequestType::Load);
384
385     m_async = async;
386
387     ASSERT(!m_loader);
388
389     changeState(OPENED);
390
391     return { };
392 }
393
394 ExceptionOr<void> XMLHttpRequest::open(const String& method, const String& url, bool async, const String& user, const String& password)
395 {
396     URL urlWithCredentials = scriptExecutionContext()->completeURL(url);
397     if (!user.isNull())
398         urlWithCredentials.setUser(user);
399     if (!password.isNull())
400         urlWithCredentials.setPass(password);
401
402     return open(method, urlWithCredentials, async);
403 }
404
405 Optional<ExceptionOr<void>> XMLHttpRequest::prepareToSend()
406 {
407     // A return value other than WTF::nullopt means we should not try to send, and we should return that value to the caller.
408     // WTF::nullopt means we are ready to send and should continue with the send algorithm.
409
410     if (!scriptExecutionContext())
411         return ExceptionOr<void> { };
412
413     auto& context = *scriptExecutionContext();
414
415     if (readyState() != OPENED || m_sendFlag)
416         return ExceptionOr<void> { Exception { InvalidStateError } };
417     ASSERT(!m_loader);
418
419     // FIXME: Convert this to check the isolated world's Content Security Policy once webkit.org/b/104520 is solved.
420     if (!context.shouldBypassMainWorldContentSecurityPolicy() && !context.contentSecurityPolicy()->allowConnectToSource(m_url)) {
421         if (!m_async)
422             return ExceptionOr<void> { Exception { NetworkError } };
423         setPendingActivity(*this);
424         m_timeoutTimer.stop();
425         m_networkErrorTimer.startOneShot(0_s);
426         return ExceptionOr<void> { };
427     }
428
429     m_error = false;
430     return WTF::nullopt;
431 }
432
433 ExceptionOr<void> XMLHttpRequest::send(Optional<SendTypes>&& sendType)
434 {
435     InspectorInstrumentation::willSendXMLHttpRequest(scriptExecutionContext(), url());
436
437     ExceptionOr<void> result;
438     if (!sendType)
439         result = send();
440     else {
441         result = WTF::switchOn(sendType.value(),
442             [this] (const RefPtr<Document>& document) -> ExceptionOr<void> { return send(*document); },
443             [this] (const RefPtr<Blob>& blob) -> ExceptionOr<void> { return send(*blob); },
444             [this] (const RefPtr<JSC::ArrayBufferView>& arrayBufferView) -> ExceptionOr<void> { return send(*arrayBufferView); },
445             [this] (const RefPtr<JSC::ArrayBuffer>& arrayBuffer) -> ExceptionOr<void> { return send(*arrayBuffer); },
446             [this] (const RefPtr<DOMFormData>& formData) -> ExceptionOr<void> { return send(*formData); },
447             [this] (const String& string) -> ExceptionOr<void> { return send(string); }
448         );
449     }
450
451     return result;
452 }
453
454 ExceptionOr<void> XMLHttpRequest::send(Document& document)
455 {
456     if (auto result = prepareToSend())
457         return WTFMove(result.value());
458
459     if (m_method != "GET" && m_method != "HEAD" && m_url.protocolIsInHTTPFamily()) {
460         if (!m_requestHeaders.contains(HTTPHeaderName::ContentType)) {
461 #if ENABLE(DASHBOARD_SUPPORT)
462             if (usesDashboardBackwardCompatibilityMode())
463                 m_requestHeaders.set(HTTPHeaderName::ContentType, "application/x-www-form-urlencoded"_s);
464             else
465 #endif
466                 // FIXME: this should include the charset used for encoding.
467                 m_requestHeaders.set(HTTPHeaderName::ContentType, document.isHTMLDocument() ? "text/html;charset=UTF-8"_s : "application/xml;charset=UTF-8"_s);
468         } else {
469             String contentType = m_requestHeaders.get(HTTPHeaderName::ContentType);
470             replaceCharsetInMediaTypeIfNeeded(contentType);
471             m_requestHeaders.set(HTTPHeaderName::ContentType, contentType);
472         }
473
474         // FIXME: According to XMLHttpRequest Level 2, this should use the Document.innerHTML algorithm
475         // from the HTML5 specification to serialize the document.
476         m_requestEntityBody = FormData::create(UTF8Encoding().encode(serializeFragment(document, SerializedNodes::SubtreeIncludingNode), UnencodableHandling::Entities));
477         if (m_upload)
478             m_requestEntityBody->setAlwaysStream(true);
479     }
480
481     return createRequest();
482 }
483
484 ExceptionOr<void> XMLHttpRequest::send(const String& body)
485 {
486     if (auto result = prepareToSend())
487         return WTFMove(result.value());
488
489     if (!body.isNull() && m_method != "GET" && m_method != "HEAD" && m_url.protocolIsInHTTPFamily()) {
490         String contentType = m_requestHeaders.get(HTTPHeaderName::ContentType);
491         if (contentType.isNull()) {
492 #if ENABLE(DASHBOARD_SUPPORT)
493             if (usesDashboardBackwardCompatibilityMode())
494                 m_requestHeaders.set(HTTPHeaderName::ContentType, "application/x-www-form-urlencoded"_s);
495             else
496 #endif
497                 m_requestHeaders.set(HTTPHeaderName::ContentType, HTTPHeaderValues::textPlainContentType());
498         } else {
499             replaceCharsetInMediaTypeIfNeeded(contentType);
500             m_requestHeaders.set(HTTPHeaderName::ContentType, contentType);
501         }
502
503         m_requestEntityBody = FormData::create(UTF8Encoding().encode(body, UnencodableHandling::Entities));
504         if (m_upload)
505             m_requestEntityBody->setAlwaysStream(true);
506     }
507
508     return createRequest();
509 }
510
511 ExceptionOr<void> XMLHttpRequest::send(Blob& body)
512 {
513     if (auto result = prepareToSend())
514         return WTFMove(result.value());
515
516     if (m_method != "GET" && m_method != "HEAD" && m_url.protocolIsInHTTPFamily()) {
517         if (!m_requestHeaders.contains(HTTPHeaderName::ContentType)) {
518             const String& blobType = body.type();
519             if (!blobType.isEmpty() && isValidContentType(blobType))
520                 m_requestHeaders.set(HTTPHeaderName::ContentType, blobType);
521             else {
522                 // From FileAPI spec, whenever media type cannot be determined, empty string must be returned.
523                 m_requestHeaders.set(HTTPHeaderName::ContentType, emptyString());
524             }
525         }
526
527         m_requestEntityBody = FormData::create();
528         m_requestEntityBody->appendBlob(body.url());
529     }
530
531     return createRequest();
532 }
533
534 ExceptionOr<void> XMLHttpRequest::send(DOMFormData& body)
535 {
536     if (auto result = prepareToSend())
537         return WTFMove(result.value());
538
539     if (m_method != "GET" && m_method != "HEAD" && m_url.protocolIsInHTTPFamily()) {
540         m_requestEntityBody = FormData::createMultiPart(body, document());
541         m_requestEntityBody->generateFiles(document());
542         if (!m_requestHeaders.contains(HTTPHeaderName::ContentType))
543             m_requestHeaders.set(HTTPHeaderName::ContentType, makeString("multipart/form-data; boundary=", m_requestEntityBody->boundary().data()));
544     }
545
546     return createRequest();
547 }
548
549 ExceptionOr<void> XMLHttpRequest::send(ArrayBuffer& body)
550 {
551     ASCIILiteral consoleMessage { "ArrayBuffer is deprecated in XMLHttpRequest.send(). Use ArrayBufferView instead."_s };
552     scriptExecutionContext()->addConsoleMessage(MessageSource::JS, MessageLevel::Warning, consoleMessage);
553     return sendBytesData(body.data(), body.byteLength());
554 }
555
556 ExceptionOr<void> XMLHttpRequest::send(ArrayBufferView& body)
557 {
558     return sendBytesData(body.baseAddress(), body.byteLength());
559 }
560
561 ExceptionOr<void> XMLHttpRequest::sendBytesData(const void* data, size_t length)
562 {
563     if (auto result = prepareToSend())
564         return WTFMove(result.value());
565
566     if (m_method != "GET" && m_method != "HEAD" && m_url.protocolIsInHTTPFamily()) {
567         m_requestEntityBody = FormData::create(data, length);
568         if (m_upload)
569             m_requestEntityBody->setAlwaysStream(true);
570     }
571
572     return createRequest();
573 }
574
575 ExceptionOr<void> XMLHttpRequest::createRequest()
576 {
577     // Only GET request is supported for blob URL.
578     if (!m_async && m_url.protocolIsBlob() && m_method != "GET")
579         return Exception { NetworkError };
580
581     if (m_async && m_upload && m_upload->hasEventListeners())
582         m_uploadListenerFlag = true;
583
584     ResourceRequest request(m_url);
585     request.setRequester(ResourceRequest::Requester::XHR);
586     request.setInitiatorIdentifier(scriptExecutionContext()->resourceRequestIdentifier());
587     request.setHTTPMethod(m_method);
588
589     if (m_requestEntityBody) {
590         ASSERT(m_method != "GET");
591         ASSERT(m_method != "HEAD");
592         request.setHTTPBody(WTFMove(m_requestEntityBody));
593     }
594
595     if (!m_requestHeaders.isEmpty())
596         request.setHTTPHeaderFields(m_requestHeaders);
597
598     ThreadableLoaderOptions options;
599     options.sendLoadCallbacks = SendCallbackPolicy::SendCallbacks;
600     // The presence of upload event listeners forces us to use preflighting because POSTing to an URL that does not
601     // permit cross origin requests should look exactly like POSTing to an URL that does not respond at all.
602     options.preflightPolicy = m_uploadListenerFlag ? PreflightPolicy::Force : PreflightPolicy::Consider;
603     options.credentials = m_includeCredentials ? FetchOptions::Credentials::Include : FetchOptions::Credentials::SameOrigin;
604     options.mode = FetchOptions::Mode::Cors;
605     options.contentSecurityPolicyEnforcement = scriptExecutionContext()->shouldBypassMainWorldContentSecurityPolicy() ? ContentSecurityPolicyEnforcement::DoNotEnforce : ContentSecurityPolicyEnforcement::EnforceConnectSrcDirective;
606     options.initiator = cachedResourceRequestInitiators().xmlhttprequest;
607     options.sameOriginDataURLFlag = SameOriginDataURLFlag::Set;
608     options.filteringPolicy = ResponseFilteringPolicy::Enable;
609     options.sniffContentEncoding = ContentEncodingSniffingPolicy::DoNotSniff;
610
611     if (m_timeoutMilliseconds) {
612         if (!m_async)
613             request.setTimeoutInterval(m_timeoutMilliseconds / 1000.0);
614         else {
615             request.setTimeoutInterval(std::numeric_limits<double>::infinity());
616             m_sendingTime = MonotonicTime::now();
617             m_timeoutTimer.startOneShot(1_ms * m_timeoutMilliseconds);
618         }
619     }
620
621     m_exceptionCode = WTF::nullopt;
622     m_error = false;
623     m_uploadComplete = !request.httpBody();
624     m_sendFlag = true;
625
626     if (m_async) {
627         m_progressEventThrottle.dispatchProgressEvent(eventNames().loadstartEvent);
628         if (!m_uploadComplete && m_uploadListenerFlag)
629             m_upload->dispatchProgressEvent(eventNames().loadstartEvent);
630
631         if (readyState() != OPENED || !m_sendFlag || m_loader)
632             return { };
633
634         // ThreadableLoader::create can return null here, for example if we're no longer attached to a page or if a content blocker blocks the load.
635         // This is true while running onunload handlers.
636         // FIXME: Maybe we need to be able to send XMLHttpRequests from onunload, <http://bugs.webkit.org/show_bug.cgi?id=10904>.
637         m_loader = ThreadableLoader::create(*scriptExecutionContext(), *this, WTFMove(request), options);
638
639         // Either loader is null or some error was synchronously sent to us.
640         ASSERT(m_loader || !m_sendFlag);
641
642         // Neither this object nor the JavaScript wrapper should be deleted while
643         // a request is in progress because we need to keep the listeners alive,
644         // and they are referenced by the JavaScript wrapper.
645         if (m_loader)
646             setPendingActivity(*this);
647     } else {
648         request.setDomainForCachePartition(scriptExecutionContext()->domainForCachePartition());
649         InspectorInstrumentation::willLoadXHRSynchronously(scriptExecutionContext());
650         ThreadableLoader::loadResourceSynchronously(*scriptExecutionContext(), WTFMove(request), *this, options);
651         InspectorInstrumentation::didLoadXHRSynchronously(scriptExecutionContext());
652     }
653
654     if (m_exceptionCode)
655         return Exception { m_exceptionCode.value() };
656     if (m_error)
657         return Exception { NetworkError };
658     return { };
659 }
660
661 void XMLHttpRequest::abort()
662 {
663     // internalAbort() calls unsetPendingActivity(this), which may release the last reference.
664     Ref<XMLHttpRequest> protectedThis(*this);
665
666     m_wasAbortedByClient = true;
667     if (!internalAbort())
668         return;
669
670     clearResponseBuffers();
671
672     m_requestHeaders.clear();
673     if ((readyState() == OPENED && m_sendFlag) || readyState() == HEADERS_RECEIVED || readyState() == LOADING) {
674         ASSERT(!m_loader);
675         m_sendFlag = false;
676         changeState(DONE);
677         dispatchErrorEvents(eventNames().abortEvent);
678     }
679     if (readyState() == DONE)
680         m_readyState = static_cast<State>(UNSENT);
681 }
682
683 bool XMLHttpRequest::internalAbort()
684 {
685     m_error = true;
686
687     // FIXME: when we add the support for multi-part XHR, we will have to think be careful with this initialization.
688     m_receivedLength = 0;
689
690     m_decoder = nullptr;
691
692     m_timeoutTimer.stop();
693
694     if (!m_loader)
695         return true;
696
697     // Cancelling m_loader may trigger a window.onload callback which can call open() on the same xhr.
698     // This would create internalAbort reentrant call.
699     // m_loader is set to null before being cancelled to exit early in any reentrant internalAbort() call.
700     auto loader = WTFMove(m_loader);
701     loader->cancel();
702
703     // If window.onload callback calls open() and send() on the same xhr, m_loader is now set to a new value.
704     // The function calling internalAbort() should abort to let the open() and send() calls continue properly.
705     // We ask the function calling internalAbort() to exit by returning false.
706     // Save this information to a local variable since we are going to drop protection.
707     bool newLoadStarted = m_loader;
708
709     unsetPendingActivity(*this);
710
711     return !newLoadStarted;
712 }
713
714 void XMLHttpRequest::clearResponse()
715 {
716     m_response = ResourceResponse();
717     clearResponseBuffers();
718 }
719
720 void XMLHttpRequest::clearResponseBuffers()
721 {
722     m_responseBuilder.clear();
723     m_responseEncoding = String();
724     m_createdDocument = false;
725     m_responseDocument = nullptr;
726     m_binaryResponseBuilder = nullptr;
727     m_responseCacheIsValid = false;
728 }
729
730 void XMLHttpRequest::clearRequest()
731 {
732     m_requestHeaders.clear();
733     m_requestEntityBody = nullptr;
734 }
735
736 void XMLHttpRequest::genericError()
737 {
738     clearResponse();
739     clearRequest();
740     m_sendFlag = false;
741     m_error = true;
742
743     changeState(DONE);
744 }
745
746 void XMLHttpRequest::networkError()
747 {
748     genericError();
749     dispatchErrorEvents(eventNames().errorEvent);
750     internalAbort();
751 }
752
753 void XMLHttpRequest::networkErrorTimerFired()
754 {
755     networkError();
756     unsetPendingActivity(*this);
757 }
758     
759 void XMLHttpRequest::abortError()
760 {
761     ASSERT(m_wasAbortedByClient);
762     genericError();
763     dispatchErrorEvents(eventNames().abortEvent);
764 }
765
766 size_t XMLHttpRequest::memoryCost() const
767 {
768     if (readyState() == DONE)
769         return m_responseBuilder.length() * 2;
770     return 0;
771 }
772
773 ExceptionOr<void> XMLHttpRequest::overrideMimeType(const String& mimeType)
774 {
775     if (readyState() == LOADING || readyState() == DONE)
776         return Exception { InvalidStateError };
777
778     m_mimeTypeOverride = "application/octet-stream"_s;
779     if (isValidContentType(mimeType))
780         m_mimeTypeOverride = mimeType;
781
782     return { };
783 }
784
785 ExceptionOr<void> XMLHttpRequest::setRequestHeader(const String& name, const String& value)
786 {
787     if (readyState() != OPENED || m_sendFlag) {
788 #if ENABLE(DASHBOARD_SUPPORT)
789         if (usesDashboardBackwardCompatibilityMode())
790             return { };
791 #endif
792         return Exception { InvalidStateError };
793     }
794
795     String normalizedValue = stripLeadingAndTrailingHTTPSpaces(value);
796     if (!isValidHTTPToken(name) || !isValidHTTPHeaderValue(normalizedValue))
797         return Exception { SyntaxError };
798
799     bool allowUnsafeHeaderField = false;
800 #if ENABLE(DASHBOARD_SUPPORT)
801     allowUnsafeHeaderField = usesDashboardBackwardCompatibilityMode();
802 #endif
803     if (securityOrigin()->canLoadLocalResources() && document()->settings().allowSettingAnyXHRHeaderFromFileURLs())
804         allowUnsafeHeaderField = true;
805     if (!allowUnsafeHeaderField && isForbiddenHeaderName(name)) {
806         logConsoleError(scriptExecutionContext(), "Refused to set unsafe header \"" + name + "\"");
807         return { };
808     }
809
810     m_requestHeaders.add(name, normalizedValue);
811     return { };
812 }
813
814 String XMLHttpRequest::getAllResponseHeaders() const
815 {
816     if (readyState() < HEADERS_RECEIVED || m_error)
817         return emptyString();
818
819     if (!m_allResponseHeaders) {
820         Vector<String> headers;
821         headers.reserveInitialCapacity(m_response.httpHeaderFields().size());
822
823         for (auto& header : m_response.httpHeaderFields()) {
824             StringBuilder stringBuilder;
825             stringBuilder.append(header.key.convertToASCIILowercase());
826             stringBuilder.appendLiteral(": ");
827             stringBuilder.append(header.value);
828             stringBuilder.appendLiteral("\r\n");
829             headers.uncheckedAppend(stringBuilder.toString());
830         }
831         std::sort(headers.begin(), headers.end(), WTF::codePointCompareLessThan);
832
833         StringBuilder stringBuilder;
834         for (auto& header : headers)
835             stringBuilder.append(header);
836         m_allResponseHeaders = stringBuilder.toString();
837     }
838
839     return m_allResponseHeaders;
840 }
841
842 String XMLHttpRequest::getResponseHeader(const String& name) const
843 {
844     if (readyState() < HEADERS_RECEIVED || m_error)
845         return String();
846
847     return m_response.httpHeaderField(name);
848 }
849
850 String XMLHttpRequest::responseMIMEType() const
851 {
852     String mimeType = extractMIMETypeFromMediaType(m_mimeTypeOverride);
853     if (mimeType.isEmpty()) {
854         if (m_response.isHTTP())
855             mimeType = extractMIMETypeFromMediaType(m_response.httpHeaderField(HTTPHeaderName::ContentType));
856         else
857             mimeType = m_response.mimeType();
858         if (mimeType.isEmpty())
859             mimeType = "text/xml"_s;
860     }
861     return mimeType;
862 }
863
864 bool XMLHttpRequest::responseIsXML() const
865 {
866     return MIMETypeRegistry::isXMLMIMEType(responseMIMEType());
867 }
868
869 int XMLHttpRequest::status() const
870 {
871     if (readyState() == UNSENT || readyState() == OPENED || m_error)
872         return 0;
873
874     return m_response.httpStatusCode();
875 }
876
877 String XMLHttpRequest::statusText() const
878 {
879     if (readyState() == UNSENT || readyState() == OPENED || m_error)
880         return String();
881
882     return m_response.httpStatusText();
883 }
884
885 void XMLHttpRequest::didFail(const ResourceError& error)
886 {
887     // If we are already in an error state, for instance we called abort(), bail out early.
888     if (m_error)
889         return;
890
891     // The XHR specification says we should only fire an abort event if the cancelation was requested by the client.
892     if (m_wasAbortedByClient && error.isCancellation()) {
893         m_exceptionCode = AbortError;
894         abortError();
895         return;
896     }
897
898     // In case of worker sync timeouts.
899     if (error.isTimeout()) {
900         didReachTimeout();
901         return;
902     }
903
904     // In case didFail is called synchronously on an asynchronous XHR call, let's dispatch network error asynchronously
905     if (m_async && m_sendFlag && !m_loader) {
906         m_sendFlag = false;
907         setPendingActivity(*this);
908         m_timeoutTimer.stop();
909         m_networkErrorTimer.startOneShot(0_s);
910         return;
911     }
912     m_exceptionCode = NetworkError;
913     networkError();
914 }
915
916 void XMLHttpRequest::didFinishLoading(unsigned long)
917 {
918     if (m_error)
919         return;
920
921     if (readyState() < HEADERS_RECEIVED)
922         changeState(HEADERS_RECEIVED);
923
924     if (m_decoder)
925         m_responseBuilder.append(m_decoder->flush());
926
927     m_responseBuilder.shrinkToFit();
928
929     bool hadLoader = m_loader;
930     m_loader = nullptr;
931
932     m_sendFlag = false;
933     changeState(DONE);
934     m_responseEncoding = String();
935     m_decoder = nullptr;
936
937     m_timeoutTimer.stop();
938
939     if (hadLoader)
940         unsetPendingActivity(*this);
941 }
942
943 void XMLHttpRequest::didSendData(unsigned long long bytesSent, unsigned long long totalBytesToBeSent)
944 {
945     if (!m_upload)
946         return;
947
948     if (m_uploadListenerFlag)
949         m_upload->dispatchThrottledProgressEvent(true, bytesSent, totalBytesToBeSent);
950
951     if (bytesSent == totalBytesToBeSent && !m_uploadComplete) {
952         m_uploadComplete = true;
953         if (m_uploadListenerFlag) {
954             m_upload->dispatchProgressEvent(eventNames().loadEvent);
955             m_upload->dispatchProgressEvent(eventNames().loadendEvent);
956         }
957     }
958 }
959
960 void XMLHttpRequest::didReceiveResponse(unsigned long, const ResourceResponse& response)
961 {
962     m_response = response;
963 }
964
965 static inline bool shouldDecodeResponse(XMLHttpRequest::ResponseType type)
966 {
967     switch (type) {
968     case XMLHttpRequest::ResponseType::EmptyString:
969     case XMLHttpRequest::ResponseType::Document:
970     case XMLHttpRequest::ResponseType::Json:
971     case XMLHttpRequest::ResponseType::Text:
972         return true;
973     case XMLHttpRequest::ResponseType::Arraybuffer:
974     case XMLHttpRequest::ResponseType::Blob:
975         return false;
976     }
977     ASSERT_NOT_REACHED();
978     return true;
979 }
980
981 Ref<TextResourceDecoder> XMLHttpRequest::createDecoder() const
982 {
983     if (!m_responseEncoding.isEmpty())
984         return TextResourceDecoder::create("text/plain", m_responseEncoding);
985
986     switch (responseType()) {
987     case ResponseType::EmptyString:
988         if (responseIsXML()) {
989             auto decoder = TextResourceDecoder::create("application/xml");
990             // Don't stop on encoding errors, unlike it is done for other kinds of XML resources. This matches the behavior of previous WebKit versions, Firefox and Opera.
991             decoder->useLenientXMLDecoding();
992             return decoder;
993         }
994         FALLTHROUGH;
995     case ResponseType::Text:
996     case ResponseType::Json:
997         return TextResourceDecoder::create("text/plain", "UTF-8");
998     case ResponseType::Document: {
999         if (equalLettersIgnoringASCIICase(responseMIMEType(), "text/html"))
1000             return TextResourceDecoder::create("text/html", "UTF-8");
1001         auto decoder = TextResourceDecoder::create("application/xml");
1002         // Don't stop on encoding errors, unlike it is done for other kinds of XML resources. This matches the behavior of previous WebKit versions, Firefox and Opera.
1003         decoder->useLenientXMLDecoding();
1004         return decoder;
1005     }
1006     case ResponseType::Arraybuffer:
1007     case ResponseType::Blob:
1008         ASSERT_NOT_REACHED();
1009         break;
1010     }
1011     return TextResourceDecoder::create("text/plain", "UTF-8");
1012 }
1013
1014 void XMLHttpRequest::didReceiveData(const char* data, int len)
1015 {
1016     if (m_error)
1017         return;
1018
1019     if (readyState() < HEADERS_RECEIVED)
1020         changeState(HEADERS_RECEIVED);
1021
1022     if (!m_mimeTypeOverride.isEmpty())
1023         m_responseEncoding = extractCharsetFromMediaType(m_mimeTypeOverride);
1024     if (m_responseEncoding.isEmpty())
1025         m_responseEncoding = m_response.textEncodingName();
1026
1027     bool useDecoder = shouldDecodeResponse(responseType());
1028
1029     if (useDecoder && !m_decoder)
1030         m_decoder = createDecoder();
1031
1032     if (!len)
1033         return;
1034
1035     if (len == -1)
1036         len = strlen(data);
1037
1038     if (useDecoder)
1039         m_responseBuilder.append(m_decoder->decode(data, len));
1040     else {
1041         // Buffer binary data.
1042         if (!m_binaryResponseBuilder)
1043             m_binaryResponseBuilder = SharedBuffer::create();
1044         m_binaryResponseBuilder->append(data, len);
1045     }
1046
1047     if (!m_error) {
1048         m_receivedLength += len;
1049
1050         if (m_async) {
1051             long long expectedLength = m_response.expectedContentLength();
1052             bool lengthComputable = expectedLength > 0 && m_receivedLength <= expectedLength;
1053             unsigned long long total = lengthComputable ? expectedLength : 0;
1054             m_progressEventThrottle.dispatchThrottledProgressEvent(lengthComputable, m_receivedLength, total);
1055         }
1056
1057         if (readyState() != LOADING)
1058             changeState(LOADING);
1059         else
1060             // Firefox calls readyStateChanged every time it receives data, 4449442
1061             callReadyStateChangeListener();
1062     }
1063 }
1064
1065 void XMLHttpRequest::dispatchErrorEvents(const AtomicString& type)
1066 {
1067     if (!m_uploadComplete) {
1068         m_uploadComplete = true;
1069         if (m_upload && m_uploadListenerFlag) {
1070             m_upload->dispatchProgressEvent(type);
1071             m_upload->dispatchProgressEvent(eventNames().loadendEvent);
1072         }
1073     }
1074     m_progressEventThrottle.dispatchProgressEvent(type);
1075     m_progressEventThrottle.dispatchProgressEvent(eventNames().loadendEvent);
1076 }
1077
1078 void XMLHttpRequest::didReachTimeout()
1079 {
1080     // internalAbort() calls unsetPendingActivity(this), which may release the last reference.
1081     Ref<XMLHttpRequest> protectedThis(*this);
1082     if (!internalAbort())
1083         return;
1084
1085     clearResponse();
1086     clearRequest();
1087
1088     m_sendFlag = false;
1089     m_error = true;
1090     m_exceptionCode = TimeoutError;
1091
1092     if (!m_async) {
1093         m_readyState = static_cast<State>(DONE);
1094         m_exceptionCode = TimeoutError;
1095         return;
1096     }
1097
1098     changeState(DONE);
1099
1100     dispatchErrorEvents(eventNames().timeoutEvent);
1101 }
1102
1103 bool XMLHttpRequest::canSuspendForDocumentSuspension() const
1104 {
1105     // If the load event has not fired yet, cancelling the load in suspend() may cause
1106     // the load event to be fired and arbitrary JS execution, which would be unsafe.
1107     // Therefore, we prevent suspending in this case.
1108     return document()->loadEventFinished();
1109 }
1110
1111 const char* XMLHttpRequest::activeDOMObjectName() const
1112 {
1113     return "XMLHttpRequest";
1114 }
1115
1116 void XMLHttpRequest::suspend(ReasonForSuspension reason)
1117 {
1118     m_progressEventThrottle.suspend();
1119
1120     if (m_resumeTimer.isActive()) {
1121         m_resumeTimer.stop();
1122         m_dispatchErrorOnResuming = true;
1123     }
1124
1125     if (reason == ReasonForSuspension::PageCache && m_loader) {
1126         // Going into PageCache, abort the request and dispatch a network error on resuming.
1127         genericError();
1128         m_dispatchErrorOnResuming = true;
1129         bool aborted = internalAbort();
1130         // It should not be possible to restart the load when aborting in suspend() because
1131         // we are not allowed to execute in JS in suspend().
1132         ASSERT_UNUSED(aborted, aborted);
1133     }
1134 }
1135
1136 void XMLHttpRequest::resume()
1137 {
1138     m_progressEventThrottle.resume();
1139
1140     // We are not allowed to execute arbitrary JS in resume() so dispatch
1141     // the error event in a timer.
1142     if (m_dispatchErrorOnResuming && !m_resumeTimer.isActive())
1143         m_resumeTimer.startOneShot(0_s);
1144 }
1145
1146 void XMLHttpRequest::resumeTimerFired()
1147 {
1148     ASSERT(m_dispatchErrorOnResuming);
1149     m_dispatchErrorOnResuming = false;
1150     dispatchErrorEvents(eventNames().errorEvent);
1151 }
1152
1153 void XMLHttpRequest::stop()
1154 {
1155     internalAbort();
1156 }
1157
1158 void XMLHttpRequest::contextDestroyed()
1159 {
1160     ASSERT(!m_loader);
1161     ActiveDOMObject::contextDestroyed();
1162 }
1163
1164 } // namespace WebCore