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