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