Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Source / core / 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 "core/xml/XMLHttpRequest.h"
25
26 #include "bindings/core/v8/ExceptionState.h"
27 #include "core/FetchInitiatorTypeNames.h"
28 #include "core/dom/ContextFeatures.h"
29 #include "core/dom/DOMException.h"
30 #include "core/dom/DOMImplementation.h"
31 #include "core/dom/DocumentParser.h"
32 #include "core/dom/ExceptionCode.h"
33 #include "core/dom/XMLDocument.h"
34 #include "core/editing/markup.h"
35 #include "core/events/Event.h"
36 #include "core/fetch/FetchUtils.h"
37 #include "core/fileapi/Blob.h"
38 #include "core/fileapi/File.h"
39 #include "core/frame/Settings.h"
40 #include "core/frame/UseCounter.h"
41 #include "core/frame/csp/ContentSecurityPolicy.h"
42 #include "core/html/DOMFormData.h"
43 #include "core/html/HTMLDocument.h"
44 #include "core/html/parser/TextResourceDecoder.h"
45 #include "core/inspector/ConsoleMessage.h"
46 #include "core/inspector/InspectorInstrumentation.h"
47 #include "core/inspector/InspectorTraceEvents.h"
48 #include "core/loader/ThreadableLoader.h"
49 #include "core/streams/ReadableStream.h"
50 #include "core/streams/ReadableStreamImpl.h"
51 #include "core/streams/Stream.h"
52 #include "core/streams/UnderlyingSource.h"
53 #include "core/xml/XMLHttpRequestProgressEvent.h"
54 #include "core/xml/XMLHttpRequestUpload.h"
55 #include "platform/Logging.h"
56 #include "platform/RuntimeEnabledFeatures.h"
57 #include "platform/SharedBuffer.h"
58 #include "platform/blob/BlobData.h"
59 #include "platform/network/HTTPParsers.h"
60 #include "platform/network/ParsedContentType.h"
61 #include "platform/network/ResourceError.h"
62 #include "platform/network/ResourceRequest.h"
63 #include "public/platform/WebURLRequest.h"
64 #include "wtf/ArrayBuffer.h"
65 #include "wtf/ArrayBufferView.h"
66 #include "wtf/Assertions.h"
67 #include "wtf/RefCountedLeakCounter.h"
68 #include "wtf/StdLibExtras.h"
69 #include "wtf/text/CString.h"
70
71 namespace blink {
72
73 DEFINE_DEBUG_ONLY_GLOBAL(WTF::RefCountedLeakCounter, xmlHttpRequestCounter, ("XMLHttpRequest"));
74
75 static bool isSetCookieHeader(const AtomicString& name)
76 {
77     return equalIgnoringCase(name, "set-cookie") || equalIgnoringCase(name, "set-cookie2");
78 }
79
80 static void replaceCharsetInMediaType(String& mediaType, const String& charsetValue)
81 {
82     unsigned pos = 0, len = 0;
83
84     findCharsetInMediaType(mediaType, pos, len);
85
86     if (!len) {
87         // When no charset found, do nothing.
88         return;
89     }
90
91     // Found at least one existing charset, replace all occurrences with new charset.
92     while (len) {
93         mediaType.replace(pos, len, charsetValue);
94         unsigned start = pos + charsetValue.length();
95         findCharsetInMediaType(mediaType, pos, len, start);
96     }
97 }
98
99 static void logConsoleError(ExecutionContext* context, const String& message)
100 {
101     if (!context)
102         return;
103     // FIXME: It's not good to report the bad usage without indicating what source line it came from.
104     // We should pass additional parameters so we can tell the console where the mistake occurred.
105     context->addConsoleMessage(ConsoleMessage::create(JSMessageSource, ErrorMessageLevel, message));
106 }
107
108 namespace {
109
110 class ReadableStreamSource : public GarbageCollectedFinalized<ReadableStreamSource>, public UnderlyingSource {
111     USING_GARBAGE_COLLECTED_MIXIN(ReadableStreamSource);
112 public:
113     ReadableStreamSource(XMLHttpRequest* owner) : m_owner(owner) { }
114     virtual ~ReadableStreamSource() { }
115     virtual void pullSource() OVERRIDE { }
116     virtual ScriptPromise cancelSource(ScriptState* scriptState, ScriptValue reason) OVERRIDE
117     {
118         m_owner->abort();
119         return ScriptPromise::cast(scriptState, v8::Undefined(scriptState->isolate()));
120     }
121     virtual void trace(Visitor* visitor) OVERRIDE
122     {
123         visitor->trace(m_owner);
124         UnderlyingSource::trace(visitor);
125     }
126
127 private:
128     // This is RawPtr in non-oilpan build to avoid the reference cycle. To
129     // avoid use-after free, the associated ReadableStream must be closed
130     // or errored when m_owner is gone.
131     RawPtrWillBeMember<XMLHttpRequest> m_owner;
132 };
133
134 } // namespace
135
136 PassRefPtrWillBeRawPtr<XMLHttpRequest> XMLHttpRequest::create(ExecutionContext* context, PassRefPtr<SecurityOrigin> securityOrigin)
137 {
138     RefPtrWillBeRawPtr<XMLHttpRequest> xmlHttpRequest = adoptRefWillBeNoop(new XMLHttpRequest(context, securityOrigin));
139     xmlHttpRequest->suspendIfNeeded();
140
141     return xmlHttpRequest.release();
142 }
143
144 XMLHttpRequest::XMLHttpRequest(ExecutionContext* context, PassRefPtr<SecurityOrigin> securityOrigin)
145     : ActiveDOMObject(context)
146     , m_timeoutMilliseconds(0)
147     , m_loaderIdentifier(0)
148     , m_state(UNSENT)
149     , m_lengthDownloadedToFile(0)
150     , m_receivedLength(0)
151     , m_lastSendLineNumber(0)
152     , m_exceptionCode(0)
153     , m_progressEventThrottle(this)
154     , m_responseTypeCode(ResponseTypeDefault)
155     , m_securityOrigin(securityOrigin)
156     , m_async(true)
157     , m_includeCredentials(false)
158     , m_parsedResponse(false)
159     , m_error(false)
160     , m_uploadEventsAllowed(true)
161     , m_uploadComplete(false)
162     , m_sameOriginRequest(true)
163     , m_downloadingToFile(false)
164 {
165 #ifndef NDEBUG
166     xmlHttpRequestCounter.increment();
167 #endif
168 }
169
170 XMLHttpRequest::~XMLHttpRequest()
171 {
172 #ifndef NDEBUG
173     xmlHttpRequestCounter.decrement();
174 #endif
175 }
176
177 Document* XMLHttpRequest::document() const
178 {
179     ASSERT(executionContext()->isDocument());
180     return toDocument(executionContext());
181 }
182
183 SecurityOrigin* XMLHttpRequest::securityOrigin() const
184 {
185     return m_securityOrigin ? m_securityOrigin.get() : executionContext()->securityOrigin();
186 }
187
188 XMLHttpRequest::State XMLHttpRequest::readyState() const
189 {
190     return m_state;
191 }
192
193 ScriptString XMLHttpRequest::responseText(ExceptionState& exceptionState)
194 {
195     if (m_responseTypeCode != ResponseTypeDefault && m_responseTypeCode != ResponseTypeText) {
196         exceptionState.throwDOMException(InvalidStateError, "The value is only accessible if the object's 'responseType' is '' or 'text' (was '" + responseType() + "').");
197         return ScriptString();
198     }
199     if (m_error || (m_state != LOADING && m_state != DONE))
200         return ScriptString();
201     return m_responseText;
202 }
203
204 ScriptString XMLHttpRequest::responseJSONSource()
205 {
206     ASSERT(m_responseTypeCode == ResponseTypeJSON);
207
208     if (m_error || m_state != DONE)
209         return ScriptString();
210     return m_responseText;
211 }
212
213 void XMLHttpRequest::initResponseDocument()
214 {
215     // The W3C spec requires the final MIME type to be some valid XML type, or text/html.
216     // If it is text/html, then the responseType of "document" must have been supplied explicitly.
217     bool isHTML = responseIsHTML();
218     if ((m_response.isHTTP() && !responseIsXML() && !isHTML)
219         || (isHTML && m_responseTypeCode == ResponseTypeDefault)
220         || executionContext()->isWorkerGlobalScope()) {
221         m_responseDocument = nullptr;
222         return;
223     }
224
225     DocumentInit init = DocumentInit::fromContext(document()->contextDocument(), m_url);
226     if (isHTML)
227         m_responseDocument = HTMLDocument::create(init);
228     else
229         m_responseDocument = XMLDocument::create(init);
230
231     // FIXME: Set Last-Modified.
232     m_responseDocument->setSecurityOrigin(securityOrigin());
233     m_responseDocument->setContextFeatures(document()->contextFeatures());
234     m_responseDocument->setMimeType(finalResponseMIMETypeWithFallback());
235 }
236
237 Document* XMLHttpRequest::responseXML(ExceptionState& exceptionState)
238 {
239     if (m_responseTypeCode != ResponseTypeDefault && m_responseTypeCode != ResponseTypeDocument) {
240         exceptionState.throwDOMException(InvalidStateError, "The value is only accessible if the object's 'responseType' is '' or 'document' (was '" + responseType() + "').");
241         return 0;
242     }
243
244     if (m_error || m_state != DONE)
245         return 0;
246
247     if (!m_parsedResponse) {
248         initResponseDocument();
249         if (!m_responseDocument)
250             return nullptr;
251
252         m_responseDocument->setContent(m_responseText.flattenToString());
253         if (!m_responseDocument->wellFormed())
254             m_responseDocument = nullptr;
255
256         m_parsedResponse = true;
257     }
258
259     return m_responseDocument.get();
260 }
261
262 Blob* XMLHttpRequest::responseBlob()
263 {
264     ASSERT(m_responseTypeCode == ResponseTypeBlob);
265
266     // We always return null before DONE.
267     if (m_error || m_state != DONE)
268         return 0;
269
270     if (!m_responseBlob) {
271         OwnPtr<BlobData> blobData = BlobData::create();
272         if (m_downloadingToFile) {
273             ASSERT(!m_binaryResponseBuilder.get());
274
275             // When responseType is set to "blob", we redirect the downloaded
276             // data to a file-handle directly in the browser process. We get
277             // the file-path from the ResourceResponse directly instead of
278             // copying the bytes between the browser and the renderer.
279             String filePath = m_response.downloadedFilePath();
280             // If we errored out or got no data, we still return a blob, just
281             // an empty one.
282             if (!filePath.isEmpty() && m_lengthDownloadedToFile) {
283                 blobData->appendFile(filePath);
284                 // FIXME: finalResponseMIMETypeWithFallback() defaults to
285                 // text/xml which may be incorrect. Replace it with
286                 // finalResponseMIMEType() after compatibility investigation.
287                 blobData->setContentType(finalResponseMIMETypeWithFallback());
288             }
289             m_responseBlob = Blob::create(BlobDataHandle::create(blobData.release(), m_lengthDownloadedToFile));
290         } else {
291             size_t size = 0;
292             if (m_binaryResponseBuilder.get() && m_binaryResponseBuilder->size()) {
293                 size = m_binaryResponseBuilder->size();
294                 blobData->appendBytes(m_binaryResponseBuilder->data(), size);
295                 blobData->setContentType(finalResponseMIMETypeWithFallback());
296                 m_binaryResponseBuilder.clear();
297             }
298             m_responseBlob = Blob::create(BlobDataHandle::create(blobData.release(), size));
299         }
300     }
301
302     return m_responseBlob.get();
303 }
304
305 ArrayBuffer* XMLHttpRequest::responseArrayBuffer()
306 {
307     ASSERT(m_responseTypeCode == ResponseTypeArrayBuffer);
308
309     if (m_error || m_state != DONE)
310         return 0;
311
312     if (!m_responseArrayBuffer.get()) {
313         if (m_binaryResponseBuilder.get() && m_binaryResponseBuilder->size() > 0) {
314             m_responseArrayBuffer = m_binaryResponseBuilder->getAsArrayBuffer();
315             if (!m_responseArrayBuffer) {
316                 // m_binaryResponseBuilder failed to allocate an ArrayBuffer.
317                 // We need to crash the renderer since there's no way defined in
318                 // the spec to tell this to the user.
319                 CRASH();
320             }
321             m_binaryResponseBuilder.clear();
322         } else {
323             m_responseArrayBuffer = ArrayBuffer::create(static_cast<void*>(0), 0);
324         }
325     }
326
327     return m_responseArrayBuffer.get();
328 }
329
330 Stream* XMLHttpRequest::responseLegacyStream()
331 {
332     ASSERT(m_responseTypeCode == ResponseTypeLegacyStream);
333
334     if (m_error || (m_state != LOADING && m_state != DONE))
335         return 0;
336
337     return m_responseLegacyStream.get();
338 }
339
340 ReadableStream* XMLHttpRequest::responseStream()
341 {
342     ASSERT(m_responseTypeCode == ResponseTypeStream);
343     if (m_error || (m_state != LOADING && m_state != DONE))
344         return 0;
345
346     return m_responseStream;
347 }
348
349 void XMLHttpRequest::setTimeout(unsigned long timeout, ExceptionState& exceptionState)
350 {
351     // FIXME: Need to trigger or update the timeout Timer here, if needed. http://webkit.org/b/98156
352     // 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."
353     if (executionContext()->isDocument() && !m_async) {
354         exceptionState.throwDOMException(InvalidAccessError, "Timeouts cannot be set for synchronous requests made from a document.");
355         return;
356     }
357
358     m_timeoutMilliseconds = timeout;
359
360     // From http://www.w3.org/TR/XMLHttpRequest/#the-timeout-attribute:
361     // Note: This implies that the timeout attribute can be set while fetching is in progress. If
362     // that occurs it will still be measured relative to the start of fetching.
363     //
364     // The timeout may be overridden after send.
365     if (m_loader)
366         m_loader->overrideTimeout(timeout);
367 }
368
369 void XMLHttpRequest::setResponseType(const String& responseType, ExceptionState& exceptionState)
370 {
371     if (m_state >= LOADING) {
372         exceptionState.throwDOMException(InvalidStateError, "The response type cannot be set if the object's state is LOADING or DONE.");
373         return;
374     }
375
376     // Newer functionality is not available to synchronous requests in window contexts, as a spec-mandated
377     // attempt to discourage synchronous XHR use. responseType is one such piece of functionality.
378     if (!m_async && executionContext()->isDocument()) {
379         exceptionState.throwDOMException(InvalidAccessError, "The response type cannot be changed for synchronous requests made from a document.");
380         return;
381     }
382
383     if (responseType == "") {
384         m_responseTypeCode = ResponseTypeDefault;
385     } else if (responseType == "text") {
386         m_responseTypeCode = ResponseTypeText;
387     } else if (responseType == "json") {
388         m_responseTypeCode = ResponseTypeJSON;
389     } else if (responseType == "document") {
390         m_responseTypeCode = ResponseTypeDocument;
391     } else if (responseType == "blob") {
392         m_responseTypeCode = ResponseTypeBlob;
393     } else if (responseType == "arraybuffer") {
394         m_responseTypeCode = ResponseTypeArrayBuffer;
395     } else if (responseType == "legacystream") {
396         if (RuntimeEnabledFeatures::streamEnabled())
397             m_responseTypeCode = ResponseTypeLegacyStream;
398         else
399             return;
400     } else if (responseType == "stream") {
401         if (RuntimeEnabledFeatures::streamEnabled())
402             m_responseTypeCode = ResponseTypeStream;
403         else
404             return;
405     } else {
406         ASSERT_NOT_REACHED();
407     }
408 }
409
410 String XMLHttpRequest::responseType()
411 {
412     switch (m_responseTypeCode) {
413     case ResponseTypeDefault:
414         return "";
415     case ResponseTypeText:
416         return "text";
417     case ResponseTypeJSON:
418         return "json";
419     case ResponseTypeDocument:
420         return "document";
421     case ResponseTypeBlob:
422         return "blob";
423     case ResponseTypeArrayBuffer:
424         return "arraybuffer";
425     case ResponseTypeLegacyStream:
426         return "legacystream";
427     case ResponseTypeStream:
428         return "stream";
429     }
430     return "";
431 }
432
433 String XMLHttpRequest::responseURL()
434 {
435     return m_response.url().string();
436 }
437
438 XMLHttpRequestUpload* XMLHttpRequest::upload()
439 {
440     if (!m_upload)
441         m_upload = XMLHttpRequestUpload::create(this);
442     return m_upload.get();
443 }
444
445 void XMLHttpRequest::trackProgress(int length)
446 {
447     m_receivedLength += length;
448
449     if (m_state != LOADING) {
450         changeState(LOADING);
451     } else {
452         // Dispatch a readystatechange event because many applications use
453         // it to track progress although this is not specified.
454         //
455         // FIXME: Stop dispatching this event for progress tracking.
456         dispatchReadyStateChangeEvent();
457     }
458     if (m_async)
459         dispatchProgressEventFromSnapshot(EventTypeNames::progress);
460 }
461
462 void XMLHttpRequest::changeState(State newState)
463 {
464     if (m_state != newState) {
465         m_state = newState;
466         dispatchReadyStateChangeEvent();
467     }
468 }
469
470 void XMLHttpRequest::dispatchReadyStateChangeEvent()
471 {
472     if (!executionContext())
473         return;
474
475     InspectorInstrumentationCookie cookie = InspectorInstrumentation::willDispatchXHRReadyStateChangeEvent(executionContext(), this);
476
477     if (m_async || (m_state <= OPENED || m_state == DONE)) {
478         TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("devtools.timeline"), "XHRReadyStateChange", "data", InspectorXhrReadyStateChangeEvent::data(executionContext(), this));
479         TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("devtools.timeline.stack"), "CallStack", "stack", InspectorCallStackEvent::currentCallStack());
480         XMLHttpRequestProgressEventThrottle::DeferredEventAction action = XMLHttpRequestProgressEventThrottle::Ignore;
481         if (m_state == DONE) {
482             if (m_error)
483                 action = XMLHttpRequestProgressEventThrottle::Clear;
484             else
485                 action = XMLHttpRequestProgressEventThrottle::Flush;
486         }
487         m_progressEventThrottle.dispatchReadyStateChangeEvent(Event::create(EventTypeNames::readystatechange), action);
488         TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("devtools.timeline"), "UpdateCounters", "data", InspectorUpdateCountersEvent::data());
489     }
490
491     InspectorInstrumentation::didDispatchXHRReadyStateChangeEvent(cookie);
492     if (m_state == DONE && !m_error) {
493         {
494             TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("devtools.timeline"), "XHRLoad", "data", InspectorXhrLoadEvent::data(executionContext(), this));
495             TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("devtools.timeline.stack"), "CallStack", "stack", InspectorCallStackEvent::currentCallStack());
496             InspectorInstrumentationCookie cookie = InspectorInstrumentation::willDispatchXHRLoadEvent(executionContext(), this);
497             dispatchProgressEventFromSnapshot(EventTypeNames::load);
498             InspectorInstrumentation::didDispatchXHRLoadEvent(cookie);
499         }
500         dispatchProgressEventFromSnapshot(EventTypeNames::loadend);
501         TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("devtools.timeline"), "UpdateCounters", "data", InspectorUpdateCountersEvent::data());
502     }
503 }
504
505 void XMLHttpRequest::setWithCredentials(bool value, ExceptionState& exceptionState)
506 {
507     if (m_state > OPENED || m_loader) {
508         exceptionState.throwDOMException(InvalidStateError,  "The value may only be set if the object's state is UNSENT or OPENED.");
509         return;
510     }
511
512     // FIXME: According to XMLHttpRequest Level 2 we should throw InvalidAccessError exception here.
513     // However for time being only print warning message to warn web developers.
514     if (!m_async)
515         UseCounter::countDeprecation(executionContext(), UseCounter::SyncXHRWithCredentials);
516
517     m_includeCredentials = value;
518 }
519
520 AtomicString XMLHttpRequest::uppercaseKnownHTTPMethod(const AtomicString& method)
521 {
522     // Valid methods per step-5 of http://xhr.spec.whatwg.org/#the-open()-method.
523     const char* const methods[] = {
524         "DELETE",
525         "GET",
526         "HEAD",
527         "OPTIONS",
528         "POST",
529         "PUT" };
530
531     for (unsigned i = 0; i < WTF_ARRAY_LENGTH(methods); ++i) {
532         if (equalIgnoringCase(method, methods[i])) {
533             // Don't bother allocating a new string if it's already all uppercase.
534             if (method == methods[i])
535                 return method;
536             return methods[i];
537         }
538     }
539     return method;
540 }
541
542 void XMLHttpRequest::open(const AtomicString& method, const KURL& url, ExceptionState& exceptionState)
543 {
544     open(method, url, true, exceptionState);
545 }
546
547 void XMLHttpRequest::open(const AtomicString& method, const KURL& url, bool async, ExceptionState& exceptionState)
548 {
549     WTF_LOG(Network, "XMLHttpRequest %p open('%s', '%s', %d)", this, method.utf8().data(), url.elidedString().utf8().data(), async);
550
551     if (!internalAbort())
552         return;
553
554     State previousState = m_state;
555     m_state = UNSENT;
556     m_error = false;
557     m_uploadComplete = false;
558
559     if (!isValidHTTPToken(method)) {
560         exceptionState.throwDOMException(SyntaxError, "'" + method + "' is not a valid HTTP method.");
561         return;
562     }
563
564     if (FetchUtils::isForbiddenMethod(method)) {
565         exceptionState.throwSecurityError("'" + method + "' HTTP method is unsupported.");
566         return;
567     }
568
569     if (!ContentSecurityPolicy::shouldBypassMainWorld(executionContext()) && !executionContext()->contentSecurityPolicy()->allowConnectToSource(url)) {
570         // We can safely expose the URL to JavaScript, as these checks happen synchronously before redirection. JavaScript receives no new information.
571         exceptionState.throwSecurityError("Refused to connect to '" + url.elidedString() + "' because it violates the document's Content Security Policy.");
572         return;
573     }
574
575     if (!async && executionContext()->isDocument()) {
576         if (document()->settings() && !document()->settings()->syncXHRInDocumentsEnabled()) {
577             exceptionState.throwDOMException(InvalidAccessError, "Synchronous requests are disabled for this page.");
578             return;
579         }
580
581         // Newer functionality is not available to synchronous requests in window contexts, as a spec-mandated
582         // attempt to discourage synchronous XHR use. responseType is one such piece of functionality.
583         if (m_responseTypeCode != ResponseTypeDefault) {
584             exceptionState.throwDOMException(InvalidAccessError, "Synchronous requests from a document must not set a response type.");
585             return;
586         }
587
588         // Similarly, timeouts are disabled for synchronous requests as well.
589         if (m_timeoutMilliseconds > 0) {
590             exceptionState.throwDOMException(InvalidAccessError, "Synchronous requests must not set a timeout.");
591             return;
592         }
593     }
594
595     m_method = uppercaseKnownHTTPMethod(method);
596
597     m_url = url;
598
599     m_async = async;
600
601     ASSERT(!m_loader);
602
603     // Check previous state to avoid dispatching readyState event
604     // when calling open several times in a row.
605     if (previousState != OPENED)
606         changeState(OPENED);
607     else
608         m_state = OPENED;
609 }
610
611 void XMLHttpRequest::open(const AtomicString& method, const KURL& url, bool async, const String& user, ExceptionState& exceptionState)
612 {
613     KURL urlWithCredentials(url);
614     urlWithCredentials.setUser(user);
615
616     open(method, urlWithCredentials, async, exceptionState);
617 }
618
619 void XMLHttpRequest::open(const AtomicString& method, const KURL& url, bool async, const String& user, const String& password, ExceptionState& exceptionState)
620 {
621     KURL urlWithCredentials(url);
622     urlWithCredentials.setUser(user);
623     urlWithCredentials.setPass(password);
624
625     open(method, urlWithCredentials, async, exceptionState);
626 }
627
628 bool XMLHttpRequest::initSend(ExceptionState& exceptionState)
629 {
630     if (!executionContext())
631         return false;
632
633     if (m_state != OPENED || m_loader) {
634         exceptionState.throwDOMException(InvalidStateError, "The object's state must be OPENED.");
635         return false;
636     }
637
638     m_error = false;
639     return true;
640 }
641
642 void XMLHttpRequest::send(ExceptionState& exceptionState)
643 {
644     send(String(), exceptionState);
645 }
646
647 bool XMLHttpRequest::areMethodAndURLValidForSend()
648 {
649     return m_method != "GET" && m_method != "HEAD" && m_url.protocolIsInHTTPFamily();
650 }
651
652 void XMLHttpRequest::send(Document* document, ExceptionState& exceptionState)
653 {
654     WTF_LOG(Network, "XMLHttpRequest %p send() Document %p", this, document);
655
656     ASSERT(document);
657
658     if (!initSend(exceptionState))
659         return;
660
661     RefPtr<FormData> httpBody;
662
663     if (areMethodAndURLValidForSend()) {
664         if (getRequestHeader("Content-Type").isEmpty()) {
665             // FIXME: this should include the charset used for encoding.
666             setRequestHeaderInternal("Content-Type", "application/xml");
667         }
668
669         // FIXME: According to XMLHttpRequest Level 2, this should use the Document.innerHTML algorithm
670         // from the HTML5 specification to serialize the document.
671         String body = createMarkup(document);
672
673         // FIXME: This should use value of document.inputEncoding to determine the encoding to use.
674         httpBody = FormData::create(UTF8Encoding().encode(body, WTF::EntitiesForUnencodables));
675         if (m_upload)
676             httpBody->setAlwaysStream(true);
677     }
678
679     createRequest(httpBody.release(), exceptionState);
680 }
681
682 void XMLHttpRequest::send(const String& body, ExceptionState& exceptionState)
683 {
684     WTF_LOG(Network, "XMLHttpRequest %p send() String '%s'", this, body.utf8().data());
685
686     if (!initSend(exceptionState))
687         return;
688
689     RefPtr<FormData> httpBody;
690
691     if (!body.isNull() && areMethodAndURLValidForSend()) {
692         String contentType = getRequestHeader("Content-Type");
693         if (contentType.isEmpty()) {
694             setRequestHeaderInternal("Content-Type", "text/plain;charset=UTF-8");
695         } else {
696             replaceCharsetInMediaType(contentType, "UTF-8");
697             m_requestHeaders.set("Content-Type", AtomicString(contentType));
698         }
699
700         httpBody = FormData::create(UTF8Encoding().encode(body, WTF::EntitiesForUnencodables));
701         if (m_upload)
702             httpBody->setAlwaysStream(true);
703     }
704
705     createRequest(httpBody.release(), exceptionState);
706 }
707
708 void XMLHttpRequest::send(Blob* body, ExceptionState& exceptionState)
709 {
710     WTF_LOG(Network, "XMLHttpRequest %p send() Blob '%s'", this, body->uuid().utf8().data());
711
712     if (!initSend(exceptionState))
713         return;
714
715     RefPtr<FormData> httpBody;
716
717     if (areMethodAndURLValidForSend()) {
718         if (getRequestHeader("Content-Type").isEmpty()) {
719             const String& blobType = body->type();
720             if (!blobType.isEmpty() && isValidContentType(blobType)) {
721                 setRequestHeaderInternal("Content-Type", AtomicString(blobType));
722             } else {
723                 // From FileAPI spec, whenever media type cannot be determined,
724                 // empty string must be returned.
725                 setRequestHeaderInternal("Content-Type", "");
726             }
727         }
728
729         // FIXME: add support for uploading bundles.
730         httpBody = FormData::create();
731         if (body->hasBackingFile()) {
732             File* file = toFile(body);
733             if (!file->path().isEmpty())
734                 httpBody->appendFile(file->path());
735             else if (!file->fileSystemURL().isEmpty())
736                 httpBody->appendFileSystemURL(file->fileSystemURL());
737             else
738                 ASSERT_NOT_REACHED();
739         } else {
740             httpBody->appendBlob(body->uuid(), body->blobDataHandle());
741         }
742     }
743
744     createRequest(httpBody.release(), exceptionState);
745 }
746
747 void XMLHttpRequest::send(DOMFormData* body, ExceptionState& exceptionState)
748 {
749     WTF_LOG(Network, "XMLHttpRequest %p send() DOMFormData %p", this, body);
750
751     if (!initSend(exceptionState))
752         return;
753
754     RefPtr<FormData> httpBody;
755
756     if (areMethodAndURLValidForSend()) {
757         httpBody = body->createMultiPartFormData();
758
759         if (getRequestHeader("Content-Type").isEmpty()) {
760             AtomicString contentType = AtomicString("multipart/form-data; boundary=", AtomicString::ConstructFromLiteral) + httpBody->boundary().data();
761             setRequestHeaderInternal("Content-Type", contentType);
762         }
763     }
764
765     createRequest(httpBody.release(), exceptionState);
766 }
767
768 void XMLHttpRequest::send(ArrayBuffer* body, ExceptionState& exceptionState)
769 {
770     WTF_LOG(Network, "XMLHttpRequest %p send() ArrayBuffer %p", this, body);
771
772     sendBytesData(body->data(), body->byteLength(), exceptionState);
773 }
774
775 void XMLHttpRequest::send(ArrayBufferView* body, ExceptionState& exceptionState)
776 {
777     WTF_LOG(Network, "XMLHttpRequest %p send() ArrayBufferView %p", this, body);
778
779     sendBytesData(body->baseAddress(), body->byteLength(), exceptionState);
780 }
781
782 void XMLHttpRequest::sendBytesData(const void* data, size_t length, ExceptionState& exceptionState)
783 {
784     if (!initSend(exceptionState))
785         return;
786
787     RefPtr<FormData> httpBody;
788
789     if (areMethodAndURLValidForSend()) {
790         httpBody = FormData::create(data, length);
791         if (m_upload)
792             httpBody->setAlwaysStream(true);
793     }
794
795     createRequest(httpBody.release(), exceptionState);
796 }
797
798 void XMLHttpRequest::sendForInspectorXHRReplay(PassRefPtr<FormData> formData, ExceptionState& exceptionState)
799 {
800     createRequest(formData ? formData->deepCopy() : nullptr, exceptionState);
801     m_exceptionCode = exceptionState.code();
802 }
803
804 void XMLHttpRequest::createRequest(PassRefPtr<FormData> httpBody, ExceptionState& exceptionState)
805 {
806     // Only GET request is supported for blob URL.
807     if (m_url.protocolIs("blob") && m_method != "GET") {
808         exceptionState.throwDOMException(NetworkError, "'GET' is the only method allowed for 'blob:' URLs.");
809         return;
810     }
811
812     // The presence of upload event listeners forces us to use preflighting because POSTing to an URL that does not
813     // permit cross origin requests should look exactly like POSTing to an URL that does not respond at all.
814     // Also, only async requests support upload progress events.
815     bool uploadEvents = false;
816     if (m_async) {
817         dispatchProgressEvent(EventTypeNames::loadstart, 0, 0);
818         if (httpBody && m_upload) {
819             uploadEvents = m_upload->hasEventListeners();
820             m_upload->dispatchEvent(XMLHttpRequestProgressEvent::create(EventTypeNames::loadstart));
821         }
822     }
823
824     m_sameOriginRequest = securityOrigin()->canRequest(m_url);
825
826     // We also remember whether upload events should be allowed for this request in case the upload listeners are
827     // added after the request is started.
828     m_uploadEventsAllowed = m_sameOriginRequest || uploadEvents || !FetchUtils::isSimpleRequest(m_method, m_requestHeaders);
829
830     ASSERT(executionContext());
831     ExecutionContext& executionContext = *this->executionContext();
832
833     ResourceRequest request(m_url);
834     request.setHTTPMethod(m_method);
835     request.setRequestContext(blink::WebURLRequest::RequestContextXMLHttpRequest);
836
837     InspectorInstrumentation::willLoadXHR(&executionContext, this, this, m_method, m_url, m_async, httpBody ? httpBody->deepCopy() : nullptr, m_requestHeaders, m_includeCredentials);
838
839     if (httpBody) {
840         ASSERT(m_method != "GET");
841         ASSERT(m_method != "HEAD");
842         request.setHTTPBody(httpBody);
843     }
844
845     if (m_requestHeaders.size() > 0)
846         request.addHTTPHeaderFields(m_requestHeaders);
847
848     ThreadableLoaderOptions options;
849     options.preflightPolicy = uploadEvents ? ForcePreflight : ConsiderPreflight;
850     options.crossOriginRequestPolicy = UseAccessControl;
851     options.initiator = FetchInitiatorTypeNames::xmlhttprequest;
852     options.contentSecurityPolicyEnforcement = ContentSecurityPolicy::shouldBypassMainWorld(&executionContext) ? DoNotEnforceContentSecurityPolicy : EnforceConnectSrcDirective;
853     options.timeoutMilliseconds = m_timeoutMilliseconds;
854
855     ResourceLoaderOptions resourceLoaderOptions;
856     resourceLoaderOptions.allowCredentials = (m_sameOriginRequest || m_includeCredentials) ? AllowStoredCredentials : DoNotAllowStoredCredentials;
857     resourceLoaderOptions.credentialsRequested = m_includeCredentials ? ClientRequestedCredentials : ClientDidNotRequestCredentials;
858     resourceLoaderOptions.securityOrigin = securityOrigin();
859     resourceLoaderOptions.mixedContentBlockingTreatment = RuntimeEnabledFeatures::laxMixedContentCheckingEnabled() ? TreatAsPassiveContent : TreatAsActiveContent;
860
861     // When responseType is set to "blob", we redirect the downloaded data to a
862     // file-handle directly.
863     m_downloadingToFile = responseTypeCode() == ResponseTypeBlob;
864     if (m_downloadingToFile) {
865         request.setDownloadToFile(true);
866         resourceLoaderOptions.dataBufferingPolicy = DoNotBufferData;
867     }
868
869     m_exceptionCode = 0;
870     m_error = false;
871
872     if (m_async) {
873         if (m_upload)
874             request.setReportUploadProgress(true);
875
876         // ThreadableLoader::create can return null here, for example if we're no longer attached to a page.
877         // This is true while running onunload handlers.
878         // FIXME: Maybe we need to be able to send XMLHttpRequests from onunload, <http://bugs.webkit.org/show_bug.cgi?id=10904>.
879         // FIXME: Maybe create() can return null for other reasons too?
880         ASSERT(!m_loader);
881         m_loader = ThreadableLoader::create(executionContext, this, request, options, resourceLoaderOptions);
882     } else {
883         // Use count for XHR synchronous requests.
884         UseCounter::count(&executionContext, UseCounter::XMLHttpRequestSynchronous);
885         ThreadableLoader::loadResourceSynchronously(executionContext, request, *this, options, resourceLoaderOptions);
886     }
887
888     if (!m_exceptionCode && m_error)
889         m_exceptionCode = NetworkError;
890     if (m_exceptionCode)
891         exceptionState.throwDOMException(m_exceptionCode, "Failed to load '" + m_url.elidedString() + "'.");
892 }
893
894 void XMLHttpRequest::abort()
895 {
896     WTF_LOG(Network, "XMLHttpRequest %p abort()", this);
897
898     // internalAbort() clears |m_loader|. Compute |sendFlag| now.
899     //
900     // |sendFlag| corresponds to "the send() flag" defined in the XHR spec.
901     //
902     // |sendFlag| is only set when we have an active, asynchronous loader.
903     // Don't use it as "the send() flag" when the XHR is in sync mode.
904     bool sendFlag = m_loader;
905
906     // internalAbort() clears the response. Save the data needed for
907     // dispatching ProgressEvents.
908     long long expectedLength = m_response.expectedContentLength();
909     long long receivedLength = m_receivedLength;
910
911     if (!internalAbort())
912         return;
913
914     // The script never gets any chance to call abort() on a sync XHR between
915     // send() call and transition to the DONE state. It's because a sync XHR
916     // doesn't dispatch any event between them. So, if |m_async| is false, we
917     // can skip the "request error steps" (defined in the XHR spec) without any
918     // state check.
919     //
920     // FIXME: It's possible open() is invoked in internalAbort() and |m_async|
921     // becomes true by that. We should implement more reliable treatment for
922     // nested method invocations at some point.
923     if (m_async) {
924         if ((m_state == OPENED && sendFlag) || m_state == HEADERS_RECEIVED || m_state == LOADING) {
925             ASSERT(!m_loader);
926             handleRequestError(0, EventTypeNames::abort, receivedLength, expectedLength);
927         }
928     }
929     m_state = UNSENT;
930 }
931
932 void XMLHttpRequest::clearVariablesForLoading()
933 {
934     m_decoder.clear();
935
936     if (m_responseDocumentParser) {
937         m_responseDocumentParser->removeClient(this);
938 #if !ENABLE(OILPAN)
939         m_responseDocumentParser->detach();
940 #endif
941         m_responseDocumentParser = nullptr;
942     }
943
944     m_finalResponseCharset = String();
945 }
946
947 bool XMLHttpRequest::internalAbort()
948 {
949     m_error = true;
950
951     if (m_responseDocumentParser && !m_responseDocumentParser->isStopped())
952         m_responseDocumentParser->stopParsing();
953
954     clearVariablesForLoading();
955
956     InspectorInstrumentation::didFailXHRLoading(executionContext(), this, this);
957
958     if (m_responseLegacyStream && m_state != DONE)
959         m_responseLegacyStream->abort();
960
961     if (m_responseStream) {
962         // When the stream is already closed (including canceled from the
963         // user), |error| does nothing.
964         // FIXME: Create a more specific error.
965         m_responseStream->error(DOMException::create(!m_async && m_exceptionCode ? m_exceptionCode : AbortError, "XMLHttpRequest::abort"));
966     }
967
968     clearResponse();
969     clearRequest();
970
971     if (!m_loader)
972         return true;
973
974     // Cancelling the ThreadableLoader m_loader may result in calling
975     // window.onload synchronously. If such an onload handler contains open()
976     // call on the same XMLHttpRequest object, reentry happens.
977     //
978     // If, window.onload contains open() and send(), m_loader will be set to
979     // non 0 value. So, we cannot continue the outer open(). In such case,
980     // just abort the outer open() by returning false.
981     RefPtrWillBeRawPtr<XMLHttpRequest> protect(this);
982     RefPtr<ThreadableLoader> loader = m_loader.release();
983     loader->cancel();
984
985     // If abort() called internalAbort() and a nested open() ended up
986     // clearing the error flag, but didn't send(), make sure the error
987     // flag is still set.
988     bool newLoadStarted = hasPendingActivity();
989     if (!newLoadStarted)
990         m_error = true;
991
992     return !newLoadStarted;
993 }
994
995 void XMLHttpRequest::clearResponse()
996 {
997     // FIXME: when we add the support for multi-part XHR, we will have to
998     // be careful with this initialization.
999     m_receivedLength = 0;
1000
1001     m_response = ResourceResponse();
1002
1003     m_responseText.clear();
1004
1005     m_parsedResponse = false;
1006     m_responseDocument = nullptr;
1007
1008     m_responseBlob = nullptr;
1009
1010     m_downloadingToFile = false;
1011     m_lengthDownloadedToFile = 0;
1012
1013     m_responseLegacyStream = nullptr;
1014     m_responseStream = nullptr;
1015
1016     // These variables may referred by the response accessors. So, we can clear
1017     // this only when we clear the response holder variables above.
1018     m_binaryResponseBuilder.clear();
1019     m_responseArrayBuffer.clear();
1020 }
1021
1022 void XMLHttpRequest::clearRequest()
1023 {
1024     m_requestHeaders.clear();
1025 }
1026
1027 void XMLHttpRequest::dispatchProgressEvent(const AtomicString& type, long long receivedLength, long long expectedLength)
1028 {
1029     bool lengthComputable = expectedLength > 0 && receivedLength <= expectedLength;
1030     unsigned long long loaded = receivedLength >= 0 ? static_cast<unsigned long long>(receivedLength) : 0;
1031     unsigned long long total = lengthComputable ? static_cast<unsigned long long>(expectedLength) : 0;
1032
1033     m_progressEventThrottle.dispatchProgressEvent(type, lengthComputable, loaded, total);
1034
1035     if (type == EventTypeNames::loadend)
1036         InspectorInstrumentation::didDispatchXHRLoadendEvent(executionContext(), this);
1037 }
1038
1039 void XMLHttpRequest::dispatchProgressEventFromSnapshot(const AtomicString& type)
1040 {
1041     dispatchProgressEvent(type, m_receivedLength, m_response.expectedContentLength());
1042 }
1043
1044 void XMLHttpRequest::handleNetworkError()
1045 {
1046     WTF_LOG(Network, "XMLHttpRequest %p handleNetworkError()", this);
1047
1048     // Response is cleared next, save needed progress event data.
1049     long long expectedLength = m_response.expectedContentLength();
1050     long long receivedLength = m_receivedLength;
1051
1052     if (!internalAbort())
1053         return;
1054
1055     handleRequestError(NetworkError, EventTypeNames::error, receivedLength, expectedLength);
1056 }
1057
1058 void XMLHttpRequest::handleDidCancel()
1059 {
1060     WTF_LOG(Network, "XMLHttpRequest %p handleDidCancel()", this);
1061
1062     // Response is cleared next, save needed progress event data.
1063     long long expectedLength = m_response.expectedContentLength();
1064     long long receivedLength = m_receivedLength;
1065
1066     if (!internalAbort())
1067         return;
1068
1069     handleRequestError(AbortError, EventTypeNames::abort, receivedLength, expectedLength);
1070 }
1071
1072 void XMLHttpRequest::handleRequestError(ExceptionCode exceptionCode, const AtomicString& type, long long receivedLength, long long expectedLength)
1073 {
1074     WTF_LOG(Network, "XMLHttpRequest %p handleRequestError()", this);
1075
1076     // The request error steps for event 'type' and exception 'exceptionCode'.
1077
1078     if (!m_async && exceptionCode) {
1079         m_state = DONE;
1080         m_exceptionCode = exceptionCode;
1081         return;
1082     }
1083     // With m_error set, the state change steps are minimal: any pending
1084     // progress event is flushed + a readystatechange is dispatched.
1085     // No new progress events dispatched; as required, that happens at
1086     // the end here.
1087     ASSERT(m_error);
1088     changeState(DONE);
1089
1090     if (!m_uploadComplete) {
1091         m_uploadComplete = true;
1092         if (m_upload && m_uploadEventsAllowed)
1093             m_upload->handleRequestError(type);
1094     }
1095
1096     // Note: The below event dispatch may be called while |hasPendingActivity() == false|,
1097     // when |handleRequestError| is called after |internalAbort()|.
1098     // This is safe, however, as |this| will be kept alive from a strong ref |Event::m_target|.
1099     dispatchProgressEvent(EventTypeNames::progress, receivedLength, expectedLength);
1100     dispatchProgressEvent(type, receivedLength, expectedLength);
1101     dispatchProgressEvent(EventTypeNames::loadend, receivedLength, expectedLength);
1102 }
1103
1104 void XMLHttpRequest::overrideMimeType(const AtomicString& mimeType, ExceptionState& exceptionState)
1105 {
1106     if (m_state == LOADING || m_state == DONE) {
1107         exceptionState.throwDOMException(InvalidStateError, "MimeType cannot be overridden when the state is LOADING or DONE.");
1108         return;
1109     }
1110
1111     m_mimeTypeOverride = mimeType;
1112 }
1113
1114 void XMLHttpRequest::setRequestHeader(const AtomicString& name, const AtomicString& value, ExceptionState& exceptionState)
1115 {
1116     if (m_state != OPENED || m_loader) {
1117         exceptionState.throwDOMException(InvalidStateError, "The object's state must be OPENED.");
1118         return;
1119     }
1120
1121     if (!isValidHTTPToken(name)) {
1122         exceptionState.throwDOMException(SyntaxError, "'" + name + "' is not a valid HTTP header field name.");
1123         return;
1124     }
1125
1126     if (!isValidHTTPHeaderValue(value)) {
1127         exceptionState.throwDOMException(SyntaxError, "'" + value + "' is not a valid HTTP header field value.");
1128         return;
1129     }
1130
1131     // No script (privileged or not) can set unsafe headers.
1132     if (FetchUtils::isForbiddenHeaderName(name)) {
1133         logConsoleError(executionContext(), "Refused to set unsafe header \"" + name + "\"");
1134         return;
1135     }
1136
1137     setRequestHeaderInternal(name, value);
1138 }
1139
1140 void XMLHttpRequest::setRequestHeaderInternal(const AtomicString& name, const AtomicString& value)
1141 {
1142     HTTPHeaderMap::AddResult result = m_requestHeaders.add(name, value);
1143     if (!result.isNewEntry)
1144         result.storedValue->value = result.storedValue->value + ", " + value;
1145 }
1146
1147 const AtomicString& XMLHttpRequest::getRequestHeader(const AtomicString& name) const
1148 {
1149     return m_requestHeaders.get(name);
1150 }
1151
1152 String XMLHttpRequest::getAllResponseHeaders() const
1153 {
1154     if (m_state < HEADERS_RECEIVED || m_error)
1155         return "";
1156
1157     StringBuilder stringBuilder;
1158
1159     HTTPHeaderSet accessControlExposeHeaderSet;
1160     parseAccessControlExposeHeadersAllowList(m_response.httpHeaderField("Access-Control-Expose-Headers"), accessControlExposeHeaderSet);
1161     HTTPHeaderMap::const_iterator end = m_response.httpHeaderFields().end();
1162     for (HTTPHeaderMap::const_iterator it = m_response.httpHeaderFields().begin(); it!= end; ++it) {
1163         // Hide Set-Cookie header fields from the XMLHttpRequest client for these reasons:
1164         //     1) If the client did have access to the fields, then it could read HTTP-only
1165         //        cookies; those cookies are supposed to be hidden from scripts.
1166         //     2) There's no known harm in hiding Set-Cookie header fields entirely; we don't
1167         //        know any widely used technique that requires access to them.
1168         //     3) Firefox has implemented this policy.
1169         if (isSetCookieHeader(it->key) && !securityOrigin()->canLoadLocalResources())
1170             continue;
1171
1172         if (!m_sameOriginRequest && !isOnAccessControlResponseHeaderWhitelist(it->key) && !accessControlExposeHeaderSet.contains(it->key))
1173             continue;
1174
1175         stringBuilder.append(it->key);
1176         stringBuilder.append(':');
1177         stringBuilder.append(' ');
1178         stringBuilder.append(it->value);
1179         stringBuilder.append('\r');
1180         stringBuilder.append('\n');
1181     }
1182
1183     return stringBuilder.toString();
1184 }
1185
1186 const AtomicString& XMLHttpRequest::getResponseHeader(const AtomicString& name) const
1187 {
1188     if (m_state < HEADERS_RECEIVED || m_error)
1189         return nullAtom;
1190
1191     // See comment in getAllResponseHeaders above.
1192     if (isSetCookieHeader(name) && !securityOrigin()->canLoadLocalResources()) {
1193         logConsoleError(executionContext(), "Refused to get unsafe header \"" + name + "\"");
1194         return nullAtom;
1195     }
1196
1197     HTTPHeaderSet accessControlExposeHeaderSet;
1198     parseAccessControlExposeHeadersAllowList(m_response.httpHeaderField("Access-Control-Expose-Headers"), accessControlExposeHeaderSet);
1199
1200     if (!m_sameOriginRequest && !isOnAccessControlResponseHeaderWhitelist(name) && !accessControlExposeHeaderSet.contains(name)) {
1201         logConsoleError(executionContext(), "Refused to get unsafe header \"" + name + "\"");
1202         return nullAtom;
1203     }
1204     return m_response.httpHeaderField(name);
1205 }
1206
1207 AtomicString XMLHttpRequest::finalResponseMIMEType() const
1208 {
1209     AtomicString overriddenType = extractMIMETypeFromMediaType(m_mimeTypeOverride);
1210     if (!overriddenType.isEmpty())
1211         return overriddenType;
1212
1213     if (m_response.isHTTP())
1214         return extractMIMETypeFromMediaType(m_response.httpHeaderField("Content-Type"));
1215
1216     return m_response.mimeType();
1217 }
1218
1219 AtomicString XMLHttpRequest::finalResponseMIMETypeWithFallback() const
1220 {
1221     AtomicString finalType = finalResponseMIMEType();
1222     if (!finalType.isEmpty())
1223         return finalType;
1224
1225     // FIXME: This fallback is not specified in the final MIME type algorithm
1226     // of the XHR spec. Move this to more appropriate place.
1227     return AtomicString("text/xml", AtomicString::ConstructFromLiteral);
1228 }
1229
1230 bool XMLHttpRequest::responseIsXML() const
1231 {
1232     return DOMImplementation::isXMLMIMEType(finalResponseMIMETypeWithFallback());
1233 }
1234
1235 bool XMLHttpRequest::responseIsHTML() const
1236 {
1237     return equalIgnoringCase(finalResponseMIMEType(), "text/html");
1238 }
1239
1240 int XMLHttpRequest::status() const
1241 {
1242     if (m_state == UNSENT || m_state == OPENED || m_error)
1243         return 0;
1244
1245     if (m_response.httpStatusCode())
1246         return m_response.httpStatusCode();
1247
1248     return 0;
1249 }
1250
1251 String XMLHttpRequest::statusText() const
1252 {
1253     if (m_state == UNSENT || m_state == OPENED || m_error)
1254         return String();
1255
1256     if (!m_response.httpStatusText().isNull())
1257         return m_response.httpStatusText();
1258
1259     return String();
1260 }
1261
1262 void XMLHttpRequest::didFail(const ResourceError& error)
1263 {
1264     WTF_LOG(Network, "XMLHttpRequest %p didFail()", this);
1265
1266     // If we are already in an error state, for instance we called abort(), bail out early.
1267     if (m_error)
1268         return;
1269
1270     if (error.isCancellation()) {
1271         handleDidCancel();
1272         return;
1273     }
1274
1275     if (error.isTimeout()) {
1276         handleDidTimeout();
1277         return;
1278     }
1279
1280     // Network failures are already reported to Web Inspector by ResourceLoader.
1281     if (error.domain() == errorDomainBlinkInternal)
1282         logConsoleError(executionContext(), "XMLHttpRequest cannot load " + error.failingURL() + ". " + error.localizedDescription());
1283
1284     handleNetworkError();
1285 }
1286
1287 void XMLHttpRequest::didFailRedirectCheck()
1288 {
1289     WTF_LOG(Network, "XMLHttpRequest %p didFailRedirectCheck()", this);
1290
1291     handleNetworkError();
1292 }
1293
1294 void XMLHttpRequest::didFinishLoading(unsigned long identifier, double)
1295 {
1296     WTF_LOG(Network, "XMLHttpRequest %p didFinishLoading(%lu)", this, identifier);
1297
1298     if (m_error)
1299         return;
1300
1301     if (m_state < HEADERS_RECEIVED)
1302         changeState(HEADERS_RECEIVED);
1303
1304     m_loaderIdentifier = identifier;
1305
1306     if (m_responseDocumentParser) {
1307         // |DocumentParser::finish()| tells the parser that we have reached end of the data.
1308         // When using |HTMLDocumentParser|, which works asynchronously, we do not have the
1309         // complete document just after the |DocumentParser::finish()| call.
1310         // Wait for the parser to call us back in |notifyParserStopped| to progress state.
1311         m_responseDocumentParser->finish();
1312         ASSERT(m_responseDocument);
1313         return;
1314     }
1315
1316     if (m_decoder)
1317         m_responseText = m_responseText.concatenateWith(m_decoder->flush());
1318
1319     if (m_responseLegacyStream)
1320         m_responseLegacyStream->finalize();
1321
1322     if (m_responseStream)
1323         m_responseStream->close();
1324
1325     clearVariablesForLoading();
1326     endLoading();
1327 }
1328
1329 void XMLHttpRequest::notifyParserStopped()
1330 {
1331     // This should only be called when response document is parsed asynchronously.
1332     ASSERT(m_responseDocumentParser);
1333     ASSERT(!m_responseDocumentParser->isParsing());
1334     ASSERT(!m_responseLegacyStream);
1335     ASSERT(!m_responseStream);
1336
1337     // Do nothing if we are called from |internalAbort()|.
1338     if (m_error)
1339         return;
1340
1341     clearVariablesForLoading();
1342
1343     m_responseDocument->implicitClose();
1344
1345     if (!m_responseDocument->wellFormed())
1346         m_responseDocument = nullptr;
1347
1348     m_parsedResponse = true;
1349
1350     endLoading();
1351 }
1352
1353 void XMLHttpRequest::endLoading()
1354 {
1355     InspectorInstrumentation::didFinishXHRLoading(executionContext(), this, this, m_loaderIdentifier, m_responseText, m_method, m_url, m_lastSendURL, m_lastSendLineNumber);
1356
1357     if (m_loader)
1358         m_loader = nullptr;
1359     m_loaderIdentifier = 0;
1360
1361     changeState(DONE);
1362 }
1363
1364 void XMLHttpRequest::didSendData(unsigned long long bytesSent, unsigned long long totalBytesToBeSent)
1365 {
1366     WTF_LOG(Network, "XMLHttpRequest %p didSendData(%llu, %llu)", this, bytesSent, totalBytesToBeSent);
1367
1368     if (!m_upload)
1369         return;
1370
1371     if (m_uploadEventsAllowed)
1372         m_upload->dispatchProgressEvent(bytesSent, totalBytesToBeSent);
1373
1374     if (bytesSent == totalBytesToBeSent && !m_uploadComplete) {
1375         m_uploadComplete = true;
1376         if (m_uploadEventsAllowed)
1377             m_upload->dispatchEventAndLoadEnd(EventTypeNames::load, true, bytesSent, totalBytesToBeSent);
1378     }
1379 }
1380
1381 void XMLHttpRequest::didReceiveResponse(unsigned long identifier, const ResourceResponse& response)
1382 {
1383     WTF_LOG(Network, "XMLHttpRequest %p didReceiveResponse(%lu)", this, identifier);
1384
1385     m_response = response;
1386     if (!m_mimeTypeOverride.isEmpty()) {
1387         m_response.setHTTPHeaderField("Content-Type", m_mimeTypeOverride);
1388         m_finalResponseCharset = extractCharsetFromMediaType(m_mimeTypeOverride);
1389     }
1390
1391     if (m_finalResponseCharset.isEmpty())
1392         m_finalResponseCharset = response.textEncodingName();
1393 }
1394
1395 void XMLHttpRequest::parseDocumentChunk(const char* data, int len)
1396 {
1397     if (!m_responseDocumentParser) {
1398         ASSERT(!m_responseDocument);
1399         initResponseDocument();
1400         if (!m_responseDocument)
1401             return;
1402
1403         m_responseDocumentParser = m_responseDocument->implicitOpen();
1404         m_responseDocumentParser->addClient(this);
1405     }
1406     ASSERT(m_responseDocumentParser);
1407
1408     if (m_responseDocumentParser->needsDecoder())
1409         m_responseDocumentParser->setDecoder(createDecoder());
1410
1411     m_responseDocumentParser->appendBytes(data, len);
1412 }
1413
1414 PassOwnPtr<TextResourceDecoder> XMLHttpRequest::createDecoder() const
1415 {
1416     if (m_responseTypeCode == ResponseTypeJSON)
1417         return TextResourceDecoder::create("application/json", "UTF-8");
1418
1419     if (!m_finalResponseCharset.isEmpty())
1420         return TextResourceDecoder::create("text/plain", m_finalResponseCharset);
1421
1422     // allow TextResourceDecoder to look inside the m_response if it's XML or HTML
1423     if (responseIsXML()) {
1424         OwnPtr<TextResourceDecoder> decoder = TextResourceDecoder::create("application/xml");
1425         // Don't stop on encoding errors, unlike it is done for other kinds
1426         // of XML resources. This matches the behavior of previous WebKit
1427         // versions, Firefox and Opera.
1428         decoder->useLenientXMLDecoding();
1429
1430         return decoder.release();
1431     }
1432
1433     if (responseIsHTML())
1434         return TextResourceDecoder::create("text/html", "UTF-8");
1435
1436     return TextResourceDecoder::create("text/plain", "UTF-8");
1437 }
1438
1439 void XMLHttpRequest::didReceiveData(const char* data, int len)
1440 {
1441     ASSERT(!m_downloadingToFile);
1442
1443     if (m_error)
1444         return;
1445
1446     if (m_state < HEADERS_RECEIVED)
1447         changeState(HEADERS_RECEIVED);
1448
1449     // We need to check for |m_error| again, because |changeState| may trigger
1450     // readystatechange, and user javascript can cause |abort()|.
1451     if (m_error)
1452         return;
1453
1454     if (!len)
1455         return;
1456
1457     if (len == -1)
1458         len = strlen(data);
1459
1460     if (m_responseTypeCode == ResponseTypeDocument && responseIsHTML()) {
1461         parseDocumentChunk(data, len);
1462     } else if (m_responseTypeCode == ResponseTypeDefault || m_responseTypeCode == ResponseTypeText || m_responseTypeCode == ResponseTypeJSON || m_responseTypeCode == ResponseTypeDocument) {
1463         if (!m_decoder)
1464             m_decoder = createDecoder();
1465
1466         m_responseText = m_responseText.concatenateWith(m_decoder->decode(data, len));
1467     } else if (m_responseTypeCode == ResponseTypeArrayBuffer || m_responseTypeCode == ResponseTypeBlob) {
1468         // Buffer binary data.
1469         if (!m_binaryResponseBuilder)
1470             m_binaryResponseBuilder = SharedBuffer::create();
1471         m_binaryResponseBuilder->append(data, len);
1472     } else if (m_responseTypeCode == ResponseTypeLegacyStream) {
1473         if (!m_responseLegacyStream)
1474             m_responseLegacyStream = Stream::create(executionContext(), responseType());
1475         m_responseLegacyStream->addData(data, len);
1476     } else if (m_responseTypeCode == ResponseTypeStream) {
1477         if (!m_responseStream) {
1478             m_responseStream = new ReadableStreamImpl<ReadableStreamChunkTypeTraits<ArrayBuffer> >(executionContext(), new ReadableStreamSource(this));
1479             m_responseStream->didSourceStart();
1480         }
1481         m_responseStream->enqueue(ArrayBuffer::create(data, len));
1482     }
1483
1484     trackProgress(len);
1485 }
1486
1487 void XMLHttpRequest::didDownloadData(int dataLength)
1488 {
1489     if (m_error)
1490         return;
1491
1492     ASSERT(m_downloadingToFile);
1493
1494     if (m_state < HEADERS_RECEIVED)
1495         changeState(HEADERS_RECEIVED);
1496
1497     if (!dataLength)
1498         return;
1499
1500     // readystatechange event handler may do something to put this XHR in error
1501     // state. We need to check m_error again here.
1502     if (m_error)
1503         return;
1504
1505     m_lengthDownloadedToFile += dataLength;
1506
1507     trackProgress(dataLength);
1508 }
1509
1510 void XMLHttpRequest::handleDidTimeout()
1511 {
1512     WTF_LOG(Network, "XMLHttpRequest %p handleDidTimeout()", this);
1513
1514     // Response is cleared next, save needed progress event data.
1515     long long expectedLength = m_response.expectedContentLength();
1516     long long receivedLength = m_receivedLength;
1517
1518     if (!internalAbort())
1519         return;
1520
1521     handleRequestError(TimeoutError, EventTypeNames::timeout, receivedLength, expectedLength);
1522 }
1523
1524 void XMLHttpRequest::suspend()
1525 {
1526     m_progressEventThrottle.suspend();
1527 }
1528
1529 void XMLHttpRequest::resume()
1530 {
1531     m_progressEventThrottle.resume();
1532 }
1533
1534 void XMLHttpRequest::stop()
1535 {
1536     internalAbort();
1537 }
1538
1539 bool XMLHttpRequest::hasPendingActivity() const
1540 {
1541     // Neither this object nor the JavaScript wrapper should be deleted while
1542     // a request is in progress because we need to keep the listeners alive,
1543     // and they are referenced by the JavaScript wrapper.
1544     // |m_loader| is non-null while request is active and ThreadableLoaderClient
1545     // callbacks may be called, and |m_responseDocumentParser| is non-null while
1546     // DocumentParserClient callbacks may be called.
1547     return m_loader || m_responseDocumentParser;
1548 }
1549
1550 void XMLHttpRequest::contextDestroyed()
1551 {
1552     ASSERT(!m_loader);
1553     ActiveDOMObject::contextDestroyed();
1554 }
1555
1556 const AtomicString& XMLHttpRequest::interfaceName() const
1557 {
1558     return EventTargetNames::XMLHttpRequest;
1559 }
1560
1561 ExecutionContext* XMLHttpRequest::executionContext() const
1562 {
1563     return ActiveDOMObject::executionContext();
1564 }
1565
1566 void XMLHttpRequest::trace(Visitor* visitor)
1567 {
1568     visitor->trace(m_responseBlob);
1569     visitor->trace(m_responseLegacyStream);
1570     visitor->trace(m_responseStream);
1571     visitor->trace(m_streamSource);
1572     visitor->trace(m_responseDocument);
1573     visitor->trace(m_responseDocumentParser);
1574     visitor->trace(m_progressEventThrottle);
1575     visitor->trace(m_upload);
1576     XMLHttpRequestEventTarget::trace(visitor);
1577 }
1578
1579 } // namespace blink