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