Add WTF::move()
[WebKit-https.git] / Source / WebCore / xml / XMLHttpRequest.cpp
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
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 "ContentSecurityPolicy.h"
28 #include "CrossOriginAccessControl.h"
29 #include "DOMFormData.h"
30 #include "DOMImplementation.h"
31 #include "Event.h"
32 #include "EventException.h"
33 #include "ExceptionCode.h"
34 #include "File.h"
35 #include "HTMLDocument.h"
36 #include "HTTPHeaderNames.h"
37 #include "HTTPParsers.h"
38 #include "InspectorInstrumentation.h"
39 #include "JSDOMBinding.h"
40 #include "JSDOMWindow.h"
41 #include "MemoryCache.h"
42 #include "ParsedContentType.h"
43 #include "ResourceError.h"
44 #include "ResourceRequest.h"
45 #include "ScriptController.h"
46 #include "Settings.h"
47 #include "SharedBuffer.h"
48 #include "TextResourceDecoder.h"
49 #include "ThreadableLoader.h"
50 #include "XMLHttpRequestException.h"
51 #include "XMLHttpRequestProgressEvent.h"
52 #include "XMLHttpRequestUpload.h"
53 #include "markup.h"
54 #include <heap/Strong.h>
55 #include <mutex>
56 #include <runtime/ArrayBuffer.h>
57 #include <runtime/ArrayBufferView.h>
58 #include <runtime/JSCInlines.h>
59 #include <runtime/JSLock.h>
60 #include <wtf/NeverDestroyed.h>
61 #include <wtf/Ref.h>
62 #include <wtf/RefCountedLeakCounter.h>
63 #include <wtf/StdLibExtras.h>
64 #include <wtf/text/CString.h>
65
66 #if ENABLE(RESOURCE_TIMING)
67 #include "CachedResourceRequestInitiators.h"
68 #endif
69
70 namespace WebCore {
71
72 DEFINE_DEBUG_ONLY_GLOBAL(WTF::RefCountedLeakCounter, xmlHttpRequestCounter, ("XMLHttpRequest"));
73
74 // Histogram enum to see when we can deprecate xhr.send(ArrayBuffer).
75 enum XMLHttpRequestSendArrayBufferOrView {
76     XMLHttpRequestSendArrayBuffer,
77     XMLHttpRequestSendArrayBufferView,
78     XMLHttpRequestSendArrayBufferOrViewMax,
79 };
80
81 static bool isSetCookieHeader(const String& name)
82 {
83     return equalIgnoringCase(name, "set-cookie") || equalIgnoringCase(name, "set-cookie2");
84 }
85
86 static void replaceCharsetInMediaType(String& mediaType, const String& charsetValue)
87 {
88     unsigned int pos = 0, len = 0;
89
90     findCharsetInMediaType(mediaType, pos, len);
91
92     if (!len) {
93         // When no charset found, do nothing.
94         return;
95     }
96
97     // Found at least one existing charset, replace all occurrences with new charset.
98     while (len) {
99         mediaType.replace(pos, len, charsetValue);
100         unsigned int start = pos + charsetValue.length();
101         findCharsetInMediaType(mediaType, pos, len, start);
102     }
103 }
104
105 static void logConsoleError(ScriptExecutionContext* context, const String& message)
106 {
107     if (!context)
108         return;
109     // FIXME: It's not good to report the bad usage without indicating what source line it came from.
110     // We should pass additional parameters so we can tell the console where the mistake occurred.
111     context->addConsoleMessage(MessageSource::JS, MessageLevel::Error, message);
112 }
113
114 PassRefPtr<XMLHttpRequest> XMLHttpRequest::create(ScriptExecutionContext& context)
115 {
116     RefPtr<XMLHttpRequest> xmlHttpRequest(adoptRef(new XMLHttpRequest(context)));
117     xmlHttpRequest->suspendIfNeeded();
118
119     return xmlHttpRequest.release();
120 }
121
122 XMLHttpRequest::XMLHttpRequest(ScriptExecutionContext& context)
123     : ActiveDOMObject(&context)
124     , m_async(true)
125     , m_includeCredentials(false)
126 #if ENABLE(XHR_TIMEOUT)
127     , m_timeoutMilliseconds(0)
128 #endif
129     , m_state(UNSENT)
130     , m_createdDocument(false)
131     , m_error(false)
132     , m_uploadEventsAllowed(true)
133     , m_uploadComplete(false)
134     , m_sameOriginRequest(true)
135     , m_receivedLength(0)
136     , m_lastSendLineNumber(0)
137     , m_lastSendColumnNumber(0)
138     , m_exceptionCode(0)
139     , m_progressEventThrottle(this)
140     , m_responseTypeCode(ResponseTypeDefault)
141     , m_responseCacheIsValid(false)
142 {
143 #ifndef NDEBUG
144     xmlHttpRequestCounter.increment();
145 #endif
146 }
147
148 XMLHttpRequest::~XMLHttpRequest()
149 {
150 #ifndef NDEBUG
151     xmlHttpRequestCounter.decrement();
152 #endif
153 }
154
155 Document* XMLHttpRequest::document() const
156 {
157     ASSERT_WITH_SECURITY_IMPLICATION(scriptExecutionContext()->isDocument());
158     return static_cast<Document*>(scriptExecutionContext());
159 }
160
161 SecurityOrigin* XMLHttpRequest::securityOrigin() const
162 {
163     return scriptExecutionContext()->securityOrigin();
164 }
165
166 #if ENABLE(DASHBOARD_SUPPORT)
167 bool XMLHttpRequest::usesDashboardBackwardCompatibilityMode() const
168 {
169     if (scriptExecutionContext()->isWorkerGlobalScope())
170         return false;
171     Settings* settings = document()->settings();
172     return settings && settings->usesDashboardBackwardCompatibilityMode();
173 }
174 #endif
175
176 XMLHttpRequest::State XMLHttpRequest::readyState() const
177 {
178     return m_state;
179 }
180
181 String XMLHttpRequest::responseText(ExceptionCode& ec)
182 {
183     if (m_responseTypeCode != ResponseTypeDefault && m_responseTypeCode != ResponseTypeText) {
184         ec = INVALID_STATE_ERR;
185         return "";
186     }
187     return responseTextIgnoringResponseType();
188 }
189
190 void XMLHttpRequest::didCacheResponseJSON()
191 {
192     ASSERT(m_responseTypeCode == ResponseTypeJSON);
193     ASSERT(doneWithoutErrors());
194     m_responseCacheIsValid = true;
195     m_responseBuilder.clear();
196 }
197
198 Document* XMLHttpRequest::responseXML(ExceptionCode& ec)
199 {
200     if (m_responseTypeCode != ResponseTypeDefault && m_responseTypeCode != ResponseTypeDocument) {
201         ec = INVALID_STATE_ERR;
202         return nullptr;
203     }
204
205     if (!doneWithoutErrors())
206         return nullptr;
207
208     if (!m_createdDocument) {
209         bool isHTML = equalIgnoringCase(responseMIMEType(), "text/html");
210
211         // The W3C spec requires the final MIME type to be some valid XML type, or text/html.
212         // If it is text/html, then the responseType of "document" must have been supplied explicitly.
213         if ((m_response.isHTTP() && !responseIsXML() && !isHTML)
214             || (isHTML && m_responseTypeCode == ResponseTypeDefault)
215             || scriptExecutionContext()->isWorkerGlobalScope()) {
216             m_responseDocument = 0;
217         } else {
218             if (isHTML)
219                 m_responseDocument = HTMLDocument::create(0, m_url);
220             else
221                 m_responseDocument = Document::create(0, m_url);
222             // FIXME: Set Last-Modified.
223             m_responseDocument->setContent(m_responseBuilder.toStringPreserveCapacity());
224             m_responseDocument->setSecurityOrigin(securityOrigin());
225             if (!m_responseDocument->wellFormed())
226                 m_responseDocument = 0;
227         }
228         m_createdDocument = true;
229     }
230
231     return m_responseDocument.get();
232 }
233
234 Blob* XMLHttpRequest::responseBlob()
235 {
236     ASSERT(m_responseTypeCode == ResponseTypeBlob);
237     ASSERT(doneWithoutErrors());
238
239     if (!m_responseBlob) {
240         if (m_binaryResponseBuilder) {
241             // FIXME: We just received the data from NetworkProcess, and are sending it back. This is inefficient.
242             Vector<char> data;
243             data.append(m_binaryResponseBuilder->data(), m_binaryResponseBuilder->size());
244             String normalizedContentType = Blob::normalizedContentType(responseMIMEType()); // responseMIMEType defaults to text/xml which may be incorrect.
245             m_responseBlob = Blob::create(WTF::move(data), normalizedContentType);
246             m_binaryResponseBuilder.clear();
247         } else {
248             // If we errored out or got no data, we still return a blob, just an empty one.
249             m_responseBlob = Blob::create();
250         }
251     }
252
253     return m_responseBlob.get();
254 }
255
256 ArrayBuffer* XMLHttpRequest::responseArrayBuffer()
257 {
258     ASSERT(m_responseTypeCode == ResponseTypeArrayBuffer);
259     ASSERT(doneWithoutErrors());
260
261     if (!m_responseArrayBuffer) {
262         if (m_binaryResponseBuilder)
263             m_responseArrayBuffer = m_binaryResponseBuilder->createArrayBuffer();
264         else
265             m_responseArrayBuffer = ArrayBuffer::create(nullptr, 0);
266         m_binaryResponseBuilder.clear();
267     }
268
269     return m_responseArrayBuffer.get();
270 }
271
272 #if ENABLE(XHR_TIMEOUT)
273 void XMLHttpRequest::setTimeout(unsigned long timeout, ExceptionCode& ec)
274 {
275     // FIXME: Need to trigger or update the timeout Timer here, if needed. http://webkit.org/b/98156
276     // 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."
277     if (scriptExecutionContext()->isDocument() && !m_async) {
278         logConsoleError(scriptExecutionContext(), "XMLHttpRequest.timeout cannot be set for synchronous HTTP(S) requests made from the window context.");
279         ec = INVALID_ACCESS_ERR;
280         return;
281     }
282     m_timeoutMilliseconds = timeout;
283 }
284 #endif
285
286 void XMLHttpRequest::setResponseType(const String& responseType, ExceptionCode& ec)
287 {
288     if (m_state >= LOADING) {
289         ec = INVALID_STATE_ERR;
290         return;
291     }
292
293     // Newer functionality is not available to synchronous requests in window contexts, as a spec-mandated
294     // attempt to discourage synchronous XHR use. responseType is one such piece of functionality.
295     // We'll only disable this functionality for HTTP(S) requests since sync requests for local protocols
296     // such as file: and data: still make sense to allow.
297     if (!m_async && scriptExecutionContext()->isDocument() && m_url.protocolIsInHTTPFamily()) {
298         logConsoleError(scriptExecutionContext(), "XMLHttpRequest.responseType cannot be changed for synchronous HTTP(S) requests made from the window context.");
299         ec = INVALID_ACCESS_ERR;
300         return;
301     }
302
303     if (responseType == "")
304         m_responseTypeCode = ResponseTypeDefault;
305     else if (responseType == "text")
306         m_responseTypeCode = ResponseTypeText;
307     else if (responseType == "json")
308         m_responseTypeCode = ResponseTypeJSON;
309     else if (responseType == "document")
310         m_responseTypeCode = ResponseTypeDocument;
311     else if (responseType == "blob")
312         m_responseTypeCode = ResponseTypeBlob;
313     else if (responseType == "arraybuffer")
314         m_responseTypeCode = ResponseTypeArrayBuffer;
315     else
316         ASSERT_NOT_REACHED();
317 }
318
319 String XMLHttpRequest::responseType()
320 {
321     switch (m_responseTypeCode) {
322     case ResponseTypeDefault:
323         return "";
324     case ResponseTypeText:
325         return "text";
326     case ResponseTypeJSON:
327         return "json";
328     case ResponseTypeDocument:
329         return "document";
330     case ResponseTypeBlob:
331         return "blob";
332     case ResponseTypeArrayBuffer:
333         return "arraybuffer";
334     }
335     return "";
336 }
337
338 void XMLHttpRequest::setLastSendLineAndColumnNumber(unsigned lineNumber, unsigned columnNumber)
339 {
340     m_lastSendLineNumber = lineNumber;
341     m_lastSendColumnNumber = columnNumber;
342 }
343
344 XMLHttpRequestUpload* XMLHttpRequest::upload()
345 {
346     if (!m_upload)
347         m_upload = std::make_unique<XMLHttpRequestUpload>(this);
348     return m_upload.get();
349 }
350
351 void XMLHttpRequest::changeState(State newState)
352 {
353     if (m_state != newState) {
354         m_state = newState;
355         callReadyStateChangeListener();
356     }
357 }
358
359 void XMLHttpRequest::callReadyStateChangeListener()
360 {
361     if (!scriptExecutionContext())
362         return;
363
364     InspectorInstrumentationCookie cookie = InspectorInstrumentation::willDispatchXHRReadyStateChangeEvent(scriptExecutionContext(), this);
365
366     if (m_async || (m_state <= OPENED || m_state == DONE))
367         m_progressEventThrottle.dispatchReadyStateChangeEvent(Event::create(eventNames().readystatechangeEvent, false, false), m_state == DONE ? FlushProgressEvent : DoNotFlushProgressEvent);
368
369     InspectorInstrumentation::didDispatchXHRReadyStateChangeEvent(cookie);
370     if (m_state == DONE && !m_error) {
371         InspectorInstrumentationCookie cookie = InspectorInstrumentation::willDispatchXHRLoadEvent(scriptExecutionContext(), this);
372         m_progressEventThrottle.dispatchProgressEvent(eventNames().loadEvent);
373         InspectorInstrumentation::didDispatchXHRLoadEvent(cookie);
374         m_progressEventThrottle.dispatchProgressEvent(eventNames().loadendEvent);
375     }
376 }
377
378 void XMLHttpRequest::setWithCredentials(bool value, ExceptionCode& ec)
379 {
380     if (m_state > OPENED || m_loader) {
381         ec = INVALID_STATE_ERR;
382         return;
383     }
384
385     m_includeCredentials = value;
386 }
387
388 bool XMLHttpRequest::isAllowedHTTPMethod(const String& method)
389 {
390     return !equalIgnoringCase(method, "TRACE")
391         && !equalIgnoringCase(method, "TRACK")
392         && !equalIgnoringCase(method, "CONNECT");
393 }
394
395 String XMLHttpRequest::uppercaseKnownHTTPMethod(const String& method)
396 {
397     const char* const methods[] = { "DELETE", "GET", "HEAD", "OPTIONS", "POST", "PUT" };
398     for (unsigned i = 0; i < WTF_ARRAY_LENGTH(methods); ++i) {
399         if (equalIgnoringCase(method, methods[i])) {
400             // Don't bother allocating a new string if it's already all uppercase.
401             if (method == methods[i])
402                 break;
403             return ASCIILiteral(methods[i]);
404         }
405     }
406     return method;
407 }
408
409 static bool isForbiddenRequestHeader(const String& name)
410 {
411     HTTPHeaderName headerName;
412     if (!findHTTPHeaderName(name, headerName))
413         return false;
414
415     switch (headerName) {
416     case HTTPHeaderName::AcceptCharset:
417     case HTTPHeaderName::AcceptEncoding:
418     case HTTPHeaderName::AccessControlRequestHeaders:
419     case HTTPHeaderName::AccessControlRequestMethod:
420     case HTTPHeaderName::Connection:
421     case HTTPHeaderName::ContentLength:
422     case HTTPHeaderName::ContentTransferEncoding:
423     case HTTPHeaderName::Cookie:
424     case HTTPHeaderName::Cookie2:
425     case HTTPHeaderName::Date:
426     case HTTPHeaderName::DNT:
427     case HTTPHeaderName::Expect:
428     case HTTPHeaderName::Host:
429     case HTTPHeaderName::KeepAlive:
430     case HTTPHeaderName::Origin:
431     case HTTPHeaderName::Referer:
432     case HTTPHeaderName::TE:
433     case HTTPHeaderName::Trailer:
434     case HTTPHeaderName::TransferEncoding:
435     case HTTPHeaderName::Upgrade:
436     case HTTPHeaderName::UserAgent:
437     case HTTPHeaderName::Via:
438         return true;
439
440     default:
441         return false;
442     }
443 }
444
445 bool XMLHttpRequest::isAllowedHTTPHeader(const String& name)
446 {
447     if (isForbiddenRequestHeader(name))
448         return false;
449
450     if (name.startsWith("proxy-", false))
451         return false;
452
453     if (name.startsWith("sec-", false))
454         return false;
455
456     return true;
457 }
458
459 void XMLHttpRequest::open(const String& method, const URL& url, ExceptionCode& ec)
460 {
461     open(method, url, true, ec);
462 }
463
464 void XMLHttpRequest::open(const String& method, const URL& url, bool async, ExceptionCode& ec)
465 {
466     internalAbort();
467     State previousState = m_state;
468     m_state = UNSENT;
469     m_error = false;
470     m_uploadComplete = false;
471
472     // clear stuff from possible previous load
473     clearResponse();
474     clearRequest();
475
476     ASSERT(m_state == UNSENT);
477
478     if (!isValidHTTPToken(method)) {
479         ec = SYNTAX_ERR;
480         return;
481     }
482
483     if (!isAllowedHTTPMethod(method)) {
484         ec = SECURITY_ERR;
485         return;
486     }
487
488     // FIXME: Convert this to check the isolated world's Content Security Policy once webkit.org/b/104520 is solved.
489     bool shouldBypassMainWorldContentSecurityPolicy = false;
490     if (scriptExecutionContext()->isDocument()) {
491         Document* document = static_cast<Document*>(scriptExecutionContext());
492         if (document->frame())
493             shouldBypassMainWorldContentSecurityPolicy = document->frame()->script().shouldBypassMainWorldContentSecurityPolicy();
494     }
495     if (!shouldBypassMainWorldContentSecurityPolicy && !scriptExecutionContext()->contentSecurityPolicy()->allowConnectToSource(url)) {
496         // FIXME: Should this be throwing an exception?
497         ec = SECURITY_ERR;
498         return;
499     }
500
501     if (!async && scriptExecutionContext()->isDocument()) {
502         if (document()->settings() && !document()->settings()->syncXHRInDocumentsEnabled()) {
503             logConsoleError(scriptExecutionContext(), "Synchronous XMLHttpRequests are disabled for this page.");
504             ec = INVALID_ACCESS_ERR;
505             return;
506         }
507
508         // Newer functionality is not available to synchronous requests in window contexts, as a spec-mandated
509         // attempt to discourage synchronous XHR use. responseType is one such piece of functionality.
510         // We'll only disable this functionality for HTTP(S) requests since sync requests for local protocols
511         // such as file: and data: still make sense to allow.
512         if (url.protocolIsInHTTPFamily() && m_responseTypeCode != ResponseTypeDefault) {
513             logConsoleError(scriptExecutionContext(), "Synchronous HTTP(S) requests made from the window context cannot have XMLHttpRequest.responseType set.");
514             ec = INVALID_ACCESS_ERR;
515             return;
516         }
517
518 #if ENABLE(XHR_TIMEOUT)
519         // Similarly, timeouts are disabled for synchronous requests as well.
520         if (m_timeoutMilliseconds > 0) {
521             logConsoleError(scriptExecutionContext(), "Synchronous XMLHttpRequests must not have a timeout value set.");
522             ec = INVALID_ACCESS_ERR;
523             return;
524         }
525 #endif
526     }
527
528     m_method = uppercaseKnownHTTPMethod(method);
529
530     m_url = url;
531
532     m_async = async;
533
534     ASSERT(!m_loader);
535
536     // Check previous state to avoid dispatching readyState event
537     // when calling open several times in a row.
538     if (previousState != OPENED)
539         changeState(OPENED);
540     else
541         m_state = OPENED;
542 }
543
544 void XMLHttpRequest::open(const String& method, const URL& url, bool async, const String& user, ExceptionCode& ec)
545 {
546     URL urlWithCredentials(url);
547     urlWithCredentials.setUser(user);
548
549     open(method, urlWithCredentials, async, ec);
550 }
551
552 void XMLHttpRequest::open(const String& method, const URL& url, bool async, const String& user, const String& password, ExceptionCode& ec)
553 {
554     URL urlWithCredentials(url);
555     urlWithCredentials.setUser(user);
556     urlWithCredentials.setPass(password);
557
558     open(method, urlWithCredentials, async, ec);
559 }
560
561 bool XMLHttpRequest::initSend(ExceptionCode& ec)
562 {
563     if (!scriptExecutionContext())
564         return false;
565
566     if (m_state != OPENED || m_loader) {
567         ec = INVALID_STATE_ERR;
568         return false;
569     }
570
571     m_error = false;
572     return true;
573 }
574
575 void XMLHttpRequest::send(ExceptionCode& ec)
576 {
577     send(String(), ec);
578 }
579
580 void XMLHttpRequest::send(Document* document, ExceptionCode& ec)
581 {
582     ASSERT(document);
583
584     if (!initSend(ec))
585         return;
586
587     if (m_method != "GET" && m_method != "HEAD" && m_url.protocolIsInHTTPFamily()) {
588         String contentType = getRequestHeader("Content-Type");
589         if (contentType.isEmpty()) {
590 #if ENABLE(DASHBOARD_SUPPORT)
591             if (usesDashboardBackwardCompatibilityMode())
592                 setRequestHeaderInternal("Content-Type", "application/x-www-form-urlencoded");
593             else
594 #endif
595                 // FIXME: this should include the charset used for encoding.
596                 setRequestHeaderInternal("Content-Type", "application/xml");
597         }
598
599         // FIXME: According to XMLHttpRequest Level 2, this should use the Document.innerHTML algorithm
600         // from the HTML5 specification to serialize the document.
601         String body = createMarkup(*document);
602
603         // FIXME: this should use value of document.inputEncoding to determine the encoding to use.
604         TextEncoding encoding = UTF8Encoding();
605         m_requestEntityBody = FormData::create(encoding.encode(body, EntitiesForUnencodables));
606         if (m_upload)
607             m_requestEntityBody->setAlwaysStream(true);
608     }
609
610     createRequest(ec);
611 }
612
613 void XMLHttpRequest::send(const String& body, ExceptionCode& ec)
614 {
615     if (!initSend(ec))
616         return;
617
618     if (!body.isNull() && m_method != "GET" && m_method != "HEAD" && m_url.protocolIsInHTTPFamily()) {
619         String contentType = getRequestHeader("Content-Type");
620         if (contentType.isEmpty()) {
621 #if ENABLE(DASHBOARD_SUPPORT)
622             if (usesDashboardBackwardCompatibilityMode())
623                 setRequestHeaderInternal("Content-Type", "application/x-www-form-urlencoded");
624             else
625 #endif
626                 setRequestHeaderInternal("Content-Type", "application/xml");
627         } else {
628             replaceCharsetInMediaType(contentType, "UTF-8");
629             m_requestHeaders.set(HTTPHeaderName::ContentType, contentType);
630         }
631
632         m_requestEntityBody = FormData::create(UTF8Encoding().encode(body, EntitiesForUnencodables));
633         if (m_upload)
634             m_requestEntityBody->setAlwaysStream(true);
635     }
636
637     createRequest(ec);
638 }
639
640 void XMLHttpRequest::send(Blob* body, ExceptionCode& ec)
641 {
642     if (!initSend(ec))
643         return;
644
645     if (m_method != "GET" && m_method != "HEAD" && m_url.protocolIsInHTTPFamily()) {
646         const String& contentType = getRequestHeader("Content-Type");
647         if (contentType.isEmpty()) {
648             const String& blobType = body->type();
649             if (!blobType.isEmpty() && isValidContentType(blobType))
650                 setRequestHeaderInternal("Content-Type", blobType);
651             else {
652                 // From FileAPI spec, whenever media type cannot be determined, empty string must be returned.
653                 setRequestHeaderInternal("Content-Type", "");
654             }
655         }
656
657         m_requestEntityBody = FormData::create();
658         m_requestEntityBody->appendBlob(body->url());
659     }
660
661     createRequest(ec);
662 }
663
664 void XMLHttpRequest::send(DOMFormData* body, ExceptionCode& ec)
665 {
666     if (!initSend(ec))
667         return;
668
669     if (m_method != "GET" && m_method != "HEAD" && m_url.protocolIsInHTTPFamily()) {
670         m_requestEntityBody = FormData::createMultiPart(*(static_cast<FormDataList*>(body)), body->encoding(), document());
671
672         m_requestEntityBody->generateFiles(document());
673
674         String contentType = getRequestHeader("Content-Type");
675         if (contentType.isEmpty()) {
676             contentType = makeString("multipart/form-data; boundary=", m_requestEntityBody->boundary().data());
677             setRequestHeaderInternal("Content-Type", contentType);
678         }
679     }
680
681     createRequest(ec);
682 }
683
684 void XMLHttpRequest::send(ArrayBuffer* body, ExceptionCode& ec)
685 {
686     String consoleMessage("ArrayBuffer is deprecated in XMLHttpRequest.send(). Use ArrayBufferView instead.");
687     scriptExecutionContext()->addConsoleMessage(MessageSource::JS, MessageLevel::Warning, consoleMessage);
688
689     sendBytesData(body->data(), body->byteLength(), ec);
690 }
691
692 void XMLHttpRequest::send(ArrayBufferView* body, ExceptionCode& ec)
693 {
694     sendBytesData(body->baseAddress(), body->byteLength(), ec);
695 }
696
697 void XMLHttpRequest::sendBytesData(const void* data, size_t length, ExceptionCode& ec)
698 {
699     if (!initSend(ec))
700         return;
701
702     if (m_method != "GET" && m_method != "HEAD" && m_url.protocolIsInHTTPFamily()) {
703         m_requestEntityBody = FormData::create(data, length);
704         if (m_upload)
705             m_requestEntityBody->setAlwaysStream(true);
706     }
707
708     createRequest(ec);
709 }
710
711 void XMLHttpRequest::sendForInspectorXHRReplay(PassRefPtr<FormData> formData, ExceptionCode& ec)
712 {
713     m_requestEntityBody = formData ? formData->deepCopy() : 0;
714     createRequest(ec);
715     m_exceptionCode = ec;
716 }
717
718 void XMLHttpRequest::createRequest(ExceptionCode& ec)
719 {
720     // Only GET request is supported for blob URL.
721     if (m_url.protocolIs("blob") && m_method != "GET") {
722         ec = XMLHttpRequestException::NETWORK_ERR;
723         return;
724     }
725
726     // The presence of upload event listeners forces us to use preflighting because POSTing to an URL that does not
727     // permit cross origin requests should look exactly like POSTing to an URL that does not respond at all.
728     // Also, only async requests support upload progress events.
729     bool uploadEvents = false;
730     if (m_async) {
731         m_progressEventThrottle.dispatchProgressEvent(eventNames().loadstartEvent);
732         if (m_requestEntityBody && m_upload) {
733             uploadEvents = m_upload->hasEventListeners();
734             m_upload->dispatchProgressEvent(eventNames().loadstartEvent);
735         }
736     }
737
738     m_sameOriginRequest = securityOrigin()->canRequest(m_url);
739
740     // We also remember whether upload events should be allowed for this request in case the upload listeners are
741     // added after the request is started.
742     m_uploadEventsAllowed = m_sameOriginRequest || uploadEvents || !isSimpleCrossOriginAccessRequest(m_method, m_requestHeaders);
743
744     ResourceRequest request(m_url);
745     request.setHTTPMethod(m_method);
746
747     InspectorInstrumentation::willLoadXHR(scriptExecutionContext(), this, m_method, m_url, m_async, m_requestEntityBody ? m_requestEntityBody->deepCopy() : 0, m_requestHeaders, m_includeCredentials);
748
749     if (m_requestEntityBody) {
750         ASSERT(m_method != "GET");
751         ASSERT(m_method != "HEAD");
752         request.setHTTPBody(m_requestEntityBody.release());
753     }
754
755     if (!m_requestHeaders.isEmpty())
756         request.setHTTPHeaderFields(m_requestHeaders);
757
758     ThreadableLoaderOptions options;
759     options.setSendLoadCallbacks(SendCallbacks);
760     options.setSniffContent(DoNotSniffContent);
761     options.preflightPolicy = uploadEvents ? ForcePreflight : ConsiderPreflight;
762     options.setAllowCredentials((m_sameOriginRequest || m_includeCredentials) ? AllowStoredCredentials : DoNotAllowStoredCredentials);
763     options.crossOriginRequestPolicy = UseAccessControl;
764     options.securityOrigin = securityOrigin();
765 #if ENABLE(RESOURCE_TIMING)
766     options.initiator = cachedResourceRequestInitiators().xmlhttprequest;
767 #endif
768
769 #if ENABLE(XHR_TIMEOUT)
770     if (m_timeoutMilliseconds)
771         request.setTimeoutInterval(m_timeoutMilliseconds / 1000.0);
772 #endif
773
774     m_exceptionCode = 0;
775     m_error = false;
776
777     if (m_async) {
778         if (m_upload)
779             request.setReportUploadProgress(true);
780
781         // ThreadableLoader::create can return null here, for example if we're no longer attached to a page.
782         // This is true while running onunload handlers.
783         // FIXME: Maybe we need to be able to send XMLHttpRequests from onunload, <http://bugs.webkit.org/show_bug.cgi?id=10904>.
784         // FIXME: Maybe create() can return null for other reasons too?
785         m_loader = ThreadableLoader::create(scriptExecutionContext(), this, request, options);
786         if (m_loader) {
787             // Neither this object nor the JavaScript wrapper should be deleted while
788             // a request is in progress because we need to keep the listeners alive,
789             // and they are referenced by the JavaScript wrapper.
790             setPendingActivity(this);
791         }
792     } else {
793         InspectorInstrumentation::willLoadXHRSynchronously(scriptExecutionContext());
794         ThreadableLoader::loadResourceSynchronously(scriptExecutionContext(), request, *this, options);
795         InspectorInstrumentation::didLoadXHRSynchronously(scriptExecutionContext());
796     }
797
798     if (!m_exceptionCode && m_error)
799         m_exceptionCode = XMLHttpRequestException::NETWORK_ERR;
800     ec = m_exceptionCode;
801 }
802
803 void XMLHttpRequest::abort()
804 {
805     // internalAbort() calls dropProtection(), which may release the last reference.
806     Ref<XMLHttpRequest> protect(*this);
807
808     bool sendFlag = m_loader;
809
810     internalAbort();
811
812     clearResponseBuffers();
813
814     // Clear headers as required by the spec
815     m_requestHeaders.clear();
816
817     if ((m_state <= OPENED && !sendFlag) || m_state == DONE)
818         m_state = UNSENT;
819     else {
820         ASSERT(!m_loader);
821         changeState(DONE);
822         m_state = UNSENT;
823     }
824
825     dispatchErrorEvents(eventNames().abortEvent);
826 }
827
828 void XMLHttpRequest::internalAbort()
829 {
830     bool hadLoader = m_loader;
831
832     m_error = true;
833
834     // FIXME: when we add the support for multi-part XHR, we will have to think be careful with this initialization.
835     m_receivedLength = 0;
836
837     if (hadLoader) {
838         m_loader->cancel();
839         m_loader = 0;
840     }
841
842     m_decoder = 0;
843
844     InspectorInstrumentation::didFailXHRLoading(scriptExecutionContext(), this);
845
846     if (hadLoader)
847         dropProtection();
848 }
849
850 void XMLHttpRequest::clearResponse()
851 {
852     m_response = ResourceResponse();
853     clearResponseBuffers();
854 }
855
856 void XMLHttpRequest::clearResponseBuffers()
857 {
858     m_responseBuilder.clear();
859     m_responseEncoding = String();
860     m_createdDocument = false;
861     m_responseDocument = 0;
862     m_responseBlob = 0;
863     m_binaryResponseBuilder.clear();
864     m_responseArrayBuffer.clear();
865     m_responseCacheIsValid = false;
866 }
867
868 void XMLHttpRequest::clearRequest()
869 {
870     m_requestHeaders.clear();
871     m_requestEntityBody = 0;
872 }
873
874 void XMLHttpRequest::genericError()
875 {
876     clearResponse();
877     clearRequest();
878     m_error = true;
879
880     changeState(DONE);
881 }
882
883 void XMLHttpRequest::networkError()
884 {
885     genericError();
886     dispatchErrorEvents(eventNames().errorEvent);
887     internalAbort();
888 }
889
890 void XMLHttpRequest::abortError()
891 {
892     genericError();
893     dispatchErrorEvents(eventNames().abortEvent);
894 }
895
896 void XMLHttpRequest::dropProtection()
897 {
898     // The XHR object itself holds on to the responseText, and
899     // thus has extra cost even independent of any
900     // responseText or responseXML objects it has handed
901     // out. But it is protected from GC while loading, so this
902     // can't be recouped until the load is done, so only
903     // report the extra cost at that point.
904     JSC::VM& vm = scriptExecutionContext()->vm();
905     JSC::JSLockHolder lock(vm);
906     vm.heap.reportExtraMemoryCost(m_responseBuilder.length() * 2);
907
908     unsetPendingActivity(this);
909 }
910
911 void XMLHttpRequest::overrideMimeType(const String& override)
912 {
913     m_mimeTypeOverride = override;
914 }
915
916 void XMLHttpRequest::setRequestHeader(const String& name, const String& value, ExceptionCode& ec)
917 {
918     if (m_state != OPENED || m_loader) {
919 #if ENABLE(DASHBOARD_SUPPORT)
920         if (usesDashboardBackwardCompatibilityMode())
921             return;
922 #endif
923
924         ec = INVALID_STATE_ERR;
925         return;
926     }
927
928     if (!isValidHTTPToken(name) || !isValidHTTPHeaderValue(value)) {
929         ec = SYNTAX_ERR;
930         return;
931     }
932
933     // A privileged script (e.g. a Dashboard widget) can set any headers.
934     if (!securityOrigin()->canLoadLocalResources() && !isAllowedHTTPHeader(name)) {
935         logConsoleError(scriptExecutionContext(), "Refused to set unsafe header \"" + name + "\"");
936         return;
937     }
938
939     setRequestHeaderInternal(name, value);
940 }
941
942 void XMLHttpRequest::setRequestHeaderInternal(const String& name, const String& value)
943 {
944     m_requestHeaders.add(name, value);
945 }
946
947 String XMLHttpRequest::getRequestHeader(const String& name) const
948 {
949     return m_requestHeaders.get(name);
950 }
951
952 String XMLHttpRequest::getAllResponseHeaders() const
953 {
954     if (m_state < HEADERS_RECEIVED || m_error)
955         return "";
956
957     StringBuilder stringBuilder;
958
959     HTTPHeaderSet accessControlExposeHeaderSet;
960     parseAccessControlExposeHeadersAllowList(m_response.httpHeaderField(HTTPHeaderName::AccessControlExposeHeaders), accessControlExposeHeaderSet);
961     
962     for (const auto& header : m_response.httpHeaderFields()) {
963         // Hide Set-Cookie header fields from the XMLHttpRequest client for these reasons:
964         //     1) If the client did have access to the fields, then it could read HTTP-only
965         //        cookies; those cookies are supposed to be hidden from scripts.
966         //     2) There's no known harm in hiding Set-Cookie header fields entirely; we don't
967         //        know any widely used technique that requires access to them.
968         //     3) Firefox has implemented this policy.
969         if (isSetCookieHeader(header.key) && !securityOrigin()->canLoadLocalResources())
970             continue;
971
972         if (!m_sameOriginRequest && !isOnAccessControlResponseHeaderWhitelist(header.key) && !accessControlExposeHeaderSet.contains(header.key))
973             continue;
974
975         stringBuilder.append(header.key);
976         stringBuilder.append(':');
977         stringBuilder.append(' ');
978         stringBuilder.append(header.value);
979         stringBuilder.append('\r');
980         stringBuilder.append('\n');
981     }
982
983     return stringBuilder.toString();
984 }
985
986 String XMLHttpRequest::getResponseHeader(const String& name) const
987 {
988     if (m_state < HEADERS_RECEIVED || m_error)
989         return String();
990
991     // See comment in getAllResponseHeaders above.
992     if (isSetCookieHeader(name) && !securityOrigin()->canLoadLocalResources()) {
993         logConsoleError(scriptExecutionContext(), "Refused to get unsafe header \"" + name + "\"");
994         return String();
995     }
996
997     HTTPHeaderSet accessControlExposeHeaderSet;
998     parseAccessControlExposeHeadersAllowList(m_response.httpHeaderField(HTTPHeaderName::AccessControlExposeHeaders), accessControlExposeHeaderSet);
999
1000     if (!m_sameOriginRequest && !isOnAccessControlResponseHeaderWhitelist(name) && !accessControlExposeHeaderSet.contains(name)) {
1001         logConsoleError(scriptExecutionContext(), "Refused to get unsafe header \"" + name + "\"");
1002         return String();
1003     }
1004     return m_response.httpHeaderField(name);
1005 }
1006
1007 String XMLHttpRequest::responseMIMEType() const
1008 {
1009     String mimeType = extractMIMETypeFromMediaType(m_mimeTypeOverride);
1010     if (mimeType.isEmpty()) {
1011         if (m_response.isHTTP())
1012             mimeType = extractMIMETypeFromMediaType(m_response.httpHeaderField(HTTPHeaderName::ContentType));
1013         else
1014             mimeType = m_response.mimeType();
1015     }
1016     if (mimeType.isEmpty())
1017         mimeType = "text/xml";
1018
1019     return mimeType;
1020 }
1021
1022 bool XMLHttpRequest::responseIsXML() const
1023 {
1024     // FIXME: Remove the lower() call when DOMImplementation.isXMLMIMEType() is modified
1025     //        to do case insensitive MIME type matching.
1026     return DOMImplementation::isXMLMIMEType(responseMIMEType().lower());
1027 }
1028
1029 int XMLHttpRequest::status() const
1030 {
1031     if (m_state == UNSENT || m_state == OPENED || m_error)
1032         return 0;
1033
1034     if (m_response.httpStatusCode())
1035         return m_response.httpStatusCode();
1036
1037     return 0;
1038 }
1039
1040 String XMLHttpRequest::statusText() const
1041 {
1042     if (m_state == UNSENT || m_state == OPENED || m_error)
1043         return String();
1044
1045     if (!m_response.httpStatusText().isNull())
1046         return m_response.httpStatusText();
1047
1048     return String();
1049 }
1050
1051 void XMLHttpRequest::didFail(const ResourceError& error)
1052 {
1053
1054     // If we are already in an error state, for instance we called abort(), bail out early.
1055     if (m_error)
1056         return;
1057
1058     if (error.isCancellation()) {
1059         m_exceptionCode = XMLHttpRequestException::ABORT_ERR;
1060         abortError();
1061         return;
1062     }
1063
1064 #if ENABLE(XHR_TIMEOUT)
1065     if (error.isTimeout()) {
1066         didTimeout();
1067         return;
1068     }
1069 #endif
1070
1071     // Network failures are already reported to Web Inspector by ResourceLoader.
1072     if (error.domain() == errorDomainWebKitInternal)
1073         logConsoleError(scriptExecutionContext(), "XMLHttpRequest cannot load " + error.failingURL() + ". " + error.localizedDescription());
1074
1075     m_exceptionCode = XMLHttpRequestException::NETWORK_ERR;
1076     networkError();
1077 }
1078
1079 void XMLHttpRequest::didFailRedirectCheck()
1080 {
1081     networkError();
1082 }
1083
1084 void XMLHttpRequest::didFinishLoading(unsigned long identifier, double)
1085 {
1086     if (m_error)
1087         return;
1088
1089     if (m_state < HEADERS_RECEIVED)
1090         changeState(HEADERS_RECEIVED);
1091
1092     if (m_decoder)
1093         m_responseBuilder.append(m_decoder->flush());
1094
1095     m_responseBuilder.shrinkToFit();
1096
1097     InspectorInstrumentation::didFinishXHRLoading(scriptExecutionContext(), this, identifier, m_responseBuilder.toStringPreserveCapacity(), m_url, m_lastSendURL, m_lastSendLineNumber, m_lastSendColumnNumber);
1098
1099     bool hadLoader = m_loader;
1100     m_loader = 0;
1101
1102     changeState(DONE);
1103     m_responseEncoding = String();
1104     m_decoder = 0;
1105
1106     if (hadLoader)
1107         dropProtection();
1108 }
1109
1110 void XMLHttpRequest::didSendData(unsigned long long bytesSent, unsigned long long totalBytesToBeSent)
1111 {
1112     if (!m_upload)
1113         return;
1114
1115     if (m_uploadEventsAllowed)
1116         m_upload->dispatchThrottledProgressEvent(true, bytesSent, totalBytesToBeSent);
1117     if (bytesSent == totalBytesToBeSent && !m_uploadComplete) {
1118         m_uploadComplete = true;
1119         if (m_uploadEventsAllowed) {
1120             m_upload->dispatchProgressEvent(eventNames().loadEvent);
1121             m_upload->dispatchProgressEvent(eventNames().loadendEvent);
1122         }
1123     }
1124 }
1125
1126 void XMLHttpRequest::didReceiveResponse(unsigned long identifier, const ResourceResponse& response)
1127 {
1128     InspectorInstrumentation::didReceiveXHRResponse(scriptExecutionContext(), identifier);
1129
1130     m_response = response;
1131     if (!m_mimeTypeOverride.isEmpty()) {
1132         m_response.setHTTPHeaderField(HTTPHeaderName::ContentType, m_mimeTypeOverride);
1133         m_responseEncoding = extractCharsetFromMediaType(m_mimeTypeOverride);
1134     }
1135
1136     if (m_responseEncoding.isEmpty())
1137         m_responseEncoding = response.textEncodingName();
1138 }
1139
1140 void XMLHttpRequest::didReceiveData(const char* data, int len)
1141 {
1142     if (m_error)
1143         return;
1144
1145     if (m_state < HEADERS_RECEIVED)
1146         changeState(HEADERS_RECEIVED);
1147
1148     bool useDecoder = shouldDecodeResponse();
1149
1150     if (useDecoder && !m_decoder) {
1151         if (!m_responseEncoding.isEmpty())
1152             m_decoder = TextResourceDecoder::create("text/plain", m_responseEncoding);
1153         // allow TextResourceDecoder to look inside the m_response if it's XML or HTML
1154         else if (responseIsXML()) {
1155             m_decoder = TextResourceDecoder::create("application/xml");
1156             // 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.
1157             m_decoder->useLenientXMLDecoding();
1158         } else if (equalIgnoringCase(responseMIMEType(), "text/html"))
1159             m_decoder = TextResourceDecoder::create("text/html", "UTF-8");
1160         else
1161             m_decoder = TextResourceDecoder::create("text/plain", "UTF-8");
1162     }
1163
1164     if (!len)
1165         return;
1166
1167     if (len == -1)
1168         len = strlen(data);
1169
1170     if (useDecoder)
1171         m_responseBuilder.append(m_decoder->decode(data, len));
1172     else if (m_responseTypeCode == ResponseTypeArrayBuffer || m_responseTypeCode == ResponseTypeBlob) {
1173         // Buffer binary data.
1174         if (!m_binaryResponseBuilder)
1175             m_binaryResponseBuilder = SharedBuffer::create();
1176         m_binaryResponseBuilder->append(data, len);
1177     }
1178
1179     if (!m_error) {
1180         m_receivedLength += len;
1181
1182         if (m_async) {
1183             long long expectedLength = m_response.expectedContentLength();
1184             bool lengthComputable = expectedLength > 0 && m_receivedLength <= expectedLength;
1185             unsigned long long total = lengthComputable ? expectedLength : 0;
1186             m_progressEventThrottle.dispatchThrottledProgressEvent(lengthComputable, m_receivedLength, total);
1187         }
1188
1189         if (m_state != LOADING)
1190             changeState(LOADING);
1191         else
1192             // Firefox calls readyStateChanged every time it receives data, 4449442
1193             callReadyStateChangeListener();
1194     }
1195 }
1196
1197 void XMLHttpRequest::dispatchErrorEvents(const AtomicString& type)
1198 {
1199     if (!m_uploadComplete) {
1200         m_uploadComplete = true;
1201         if (m_upload && m_uploadEventsAllowed) {
1202             m_upload->dispatchProgressEvent(eventNames().progressEvent);
1203             m_upload->dispatchProgressEvent(type);
1204             m_upload->dispatchProgressEvent(eventNames().loadendEvent);
1205         }
1206     }
1207     m_progressEventThrottle.dispatchProgressEvent(eventNames().progressEvent);
1208     m_progressEventThrottle.dispatchProgressEvent(type);
1209     m_progressEventThrottle.dispatchProgressEvent(eventNames().loadendEvent);
1210 }
1211
1212 #if ENABLE(XHR_TIMEOUT)
1213 void XMLHttpRequest::didTimeout()
1214 {
1215     // internalAbort() calls dropProtection(), which may release the last reference.
1216     Ref<XMLHttpRequest> protect(*this);
1217     internalAbort();
1218
1219     clearResponse();
1220     clearRequest();
1221
1222     m_error = true;
1223     m_exceptionCode = XMLHttpRequestException::TIMEOUT_ERR;
1224
1225     if (!m_async) {
1226         m_state = DONE;
1227         m_exceptionCode = TIMEOUT_ERR;
1228         return;
1229     }
1230
1231     changeState(DONE);
1232
1233     dispatchErrorEvents(eventNames().timeoutEvent);
1234 }
1235 #endif
1236
1237 bool XMLHttpRequest::canSuspend() const
1238 {
1239     return !m_loader;
1240 }
1241
1242 void XMLHttpRequest::suspend(ReasonForSuspension)
1243 {
1244     m_progressEventThrottle.suspend();
1245 }
1246
1247 void XMLHttpRequest::resume()
1248 {
1249     m_progressEventThrottle.resume();
1250 }
1251
1252 void XMLHttpRequest::stop()
1253 {
1254     internalAbort();
1255 }
1256
1257 void XMLHttpRequest::contextDestroyed()
1258 {
1259     ASSERT(!m_loader);
1260     ActiveDOMObject::contextDestroyed();
1261 }
1262
1263 } // namespace WebCore