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