XMLHttpRequestMainThread.h (28183B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */ 3 /* This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #ifndef mozilla_dom_XMLHttpRequestMainThread_h 8 #define mozilla_dom_XMLHttpRequestMainThread_h 9 10 #include <bitset> 11 12 #include "mozilla/Assertions.h" 13 #include "mozilla/Attributes.h" 14 #include "mozilla/DOMEventTargetHelper.h" 15 #include "mozilla/Encoding.h" 16 #include "mozilla/Maybe.h" 17 #include "mozilla/MemoryReporting.h" 18 #include "mozilla/NotNull.h" 19 #include "mozilla/dom/BodyExtractor.h" 20 #include "mozilla/dom/ClientInfo.h" 21 #include "mozilla/dom/Document.h" 22 #include "mozilla/dom/File.h" 23 #include "mozilla/dom/FormData.h" 24 #include "mozilla/dom/MimeType.h" 25 #include "mozilla/dom/MutableBlobStorage.h" 26 #include "mozilla/dom/PerformanceStorage.h" 27 #include "mozilla/dom/ServiceWorkerDescriptor.h" 28 #include "mozilla/dom/TypedArray.h" 29 #include "mozilla/dom/URLSearchParams.h" 30 #include "mozilla/dom/WorkerRef.h" 31 #include "mozilla/dom/XMLHttpRequest.h" 32 #include "mozilla/dom/XMLHttpRequestBinding.h" 33 #include "mozilla/dom/XMLHttpRequestEventTarget.h" 34 #include "mozilla/dom/XMLHttpRequestString.h" 35 #include "nsIAsyncVerifyRedirectCallback.h" 36 #include "nsIChannelEventSink.h" 37 #include "nsIDOMEventListener.h" 38 #include "nsIHttpHeaderVisitor.h" 39 #include "nsIInputStream.h" 40 #include "nsIInterfaceRequestor.h" 41 #include "nsIPrincipal.h" 42 #include "nsIProgressEventSink.h" 43 #include "nsIScriptObjectPrincipal.h" 44 #include "nsISizeOfEventTarget.h" 45 #include "nsIStreamListener.h" 46 #include "nsISupportsUtils.h" 47 #include "nsITimer.h" 48 #include "nsIURI.h" 49 #include "nsJSUtils.h" 50 #include "nsTArray.h" 51 52 #ifdef Status 53 /* Xlib headers insist on this for some reason... Nuke it because 54 it'll override our member name */ 55 typedef Status __StatusTmp; 56 # undef Status 57 typedef __StatusTmp Status; 58 #endif 59 60 class nsIHttpChannel; 61 class nsIJARChannel; 62 class nsILoadGroup; 63 64 namespace mozilla { 65 class ProfileChunkedBuffer; 66 67 namespace net { 68 class ContentRange; 69 } 70 71 namespace dom { 72 73 class DOMString; 74 class XMLHttpRequestUpload; 75 class SerializedStackHolder; 76 struct OriginAttributesDictionary; 77 78 // A helper for building up an ArrayBuffer object's data 79 // before creating the ArrayBuffer itself. Will do doubling 80 // based reallocation, up to an optional maximum growth given. 81 // 82 // When all the data has been appended, call GetArrayBuffer, 83 // passing in the JSContext* for which the ArrayBuffer object 84 // is to be created. This also implicitly resets the builder. 85 class ArrayBufferBuilder { 86 public: 87 NS_INLINE_DECL_THREADSAFE_REFCOUNTING(ArrayBufferBuilder); 88 89 ArrayBufferBuilder(); 90 91 // Will truncate if aNewCap is < Length(). 92 bool SetCapacity(uint32_t aNewCap); 93 94 // Append aDataLen bytes from data to the current buffer. If we 95 // need to grow the buffer, grow by doubling the size up to a 96 // maximum of aMaxGrowth (if given). If aDataLen is greater than 97 // what the new capacity would end up as, then grow by aDataLen. 98 // 99 // The data parameter must not overlap with anything beyond the 100 // builder's current valid contents [0..length) 101 bool Append(const uint8_t* aNewData, uint32_t aDataLen, 102 uint32_t aMaxGrowth = 0); 103 104 uint32_t Length(); 105 uint32_t Capacity(); 106 107 JSObject* TakeArrayBuffer(JSContext* aCx); 108 109 // Memory mapping to starting position of file(aFile) in the zip 110 // package(aJarFile). 111 // 112 // The file in the zip package has to be uncompressed and the starting 113 // position of the file must be aligned according to array buffer settings 114 // in JS engine. 115 nsresult MapToFileInPackage(const nsCString& aFile, nsIFile* aJarFile); 116 117 private: 118 ~ArrayBufferBuilder(); 119 120 ArrayBufferBuilder(const ArrayBufferBuilder&) = delete; 121 ArrayBufferBuilder& operator=(const ArrayBufferBuilder&) = delete; 122 ArrayBufferBuilder& operator=(const ArrayBufferBuilder&&) = delete; 123 124 bool SetCapacityInternal(uint32_t aNewCap, const MutexAutoLock& aProofOfLock) 125 MOZ_REQUIRES(mMutex); 126 127 static bool AreOverlappingRegions(const uint8_t* aStart1, uint32_t aLength1, 128 const uint8_t* aStart2, uint32_t aLength2); 129 130 Mutex mMutex; 131 132 // All of these are protected by mMutex. 133 uint8_t* mDataPtr MOZ_GUARDED_BY(mMutex); 134 uint32_t mCapacity MOZ_GUARDED_BY(mMutex); 135 uint32_t mLength MOZ_GUARDED_BY(mMutex); 136 void* mMapPtr MOZ_GUARDED_BY(mMutex); 137 138 // This is used in assertions only. 139 bool mNeutered; 140 }; 141 142 class nsXMLHttpRequestXPCOMifier; 143 144 class RequestHeaders { 145 struct RequestHeader { 146 nsCString mName; 147 nsCString mValue; 148 }; 149 nsTArray<RequestHeader> mHeaders; 150 RequestHeader* Find(const nsACString& aName); 151 152 public: 153 class CharsetIterator { 154 bool mValid; 155 int32_t mCurPos, mCurLen, mCutoff; 156 nsACString& mSource; 157 158 public: 159 explicit CharsetIterator(nsACString& aSource); 160 bool Equals(const nsACString& aOther, 161 const nsCStringComparator& aCmp) const; 162 void Replace(const nsACString& aReplacement); 163 bool Next(); 164 }; 165 166 bool IsEmpty() const; 167 bool Has(const char* aName); 168 bool Has(const nsACString& aName); 169 void Get(const char* aName, nsACString& aValue); 170 void Get(const nsACString& aName, nsACString& aValue); 171 void Set(const char* aName, const nsACString& aValue); 172 void Set(const nsACString& aName, const nsACString& aValue); 173 void MergeOrSet(const char* aName, const nsACString& aValue); 174 void MergeOrSet(const nsACString& aName, const nsACString& aValue); 175 void Clear(); 176 void ApplyToChannel(nsIHttpChannel* aChannel, bool aStripRequestBodyHeader, 177 bool aStripAuth) const; 178 void GetCORSUnsafeHeaders(nsTArray<nsCString>& aArray) const; 179 }; 180 181 class nsXHRParseEndListener; 182 class XMLHttpRequestDoneNotifier; 183 184 // Make sure that any non-DOM interfaces added here are also added to 185 // nsXMLHttpRequestXPCOMifier. 186 class XMLHttpRequestMainThread final : public XMLHttpRequest, 187 public nsIStreamListener, 188 public nsIChannelEventSink, 189 public nsIProgressEventSink, 190 public nsIInterfaceRequestor, 191 public nsITimerCallback, 192 public nsISizeOfEventTarget, 193 public nsINamed, 194 public MutableBlobStorageCallback { 195 friend class nsXHRParseEndListener; 196 friend class nsXMLHttpRequestXPCOMifier; 197 friend class XMLHttpRequestDoneNotifier; 198 199 public: 200 // Make sure that any additions done to ErrorType enum are also mirrored in 201 // XHR_ERROR_TYPE enum of TelemetrySend.sys.mjs. 202 enum class ErrorType : uint16_t { 203 eOK, 204 eRequest, 205 eUnreachable, 206 eChannelOpen, 207 eRedirect, 208 eTerminated, 209 ENUM_MAX 210 }; 211 212 explicit XMLHttpRequestMainThread(nsIGlobalObject* aGlobalObject); 213 214 void Construct(nsIPrincipal* aPrincipal, 215 nsICookieJarSettings* aCookieJarSettings, bool aForWorker, 216 nsIURI* aBaseURI = nullptr, nsILoadGroup* aLoadGroup = nullptr, 217 PerformanceStorage* aPerformanceStorage = nullptr, 218 nsICSPEventListener* aCSPEventListener = nullptr); 219 220 void InitParameters(bool aAnon, bool aSystem); 221 222 void SetParameters(bool aAnon, bool aSystem) { 223 mIsAnon = aAnon || aSystem; 224 mIsSystem = aSystem; 225 } 226 227 void SetClientInfoAndController( 228 const ClientInfo& aClientInfo, 229 const Maybe<ServiceWorkerDescriptor>& aController); 230 231 NS_DECL_ISUPPORTS_INHERITED 232 233 // nsIStreamListener 234 NS_DECL_NSISTREAMLISTENER 235 236 // nsIRequestObserver 237 NS_DECL_NSIREQUESTOBSERVER 238 239 // nsIChannelEventSink 240 NS_DECL_NSICHANNELEVENTSINK 241 242 // nsIProgressEventSink 243 NS_DECL_NSIPROGRESSEVENTSINK 244 245 // nsIInterfaceRequestor 246 NS_DECL_NSIINTERFACEREQUESTOR 247 248 // nsITimerCallback 249 NS_DECL_NSITIMERCALLBACK 250 251 // nsINamed 252 NS_DECL_NSINAMED 253 254 // nsISizeOfEventTarget 255 virtual size_t SizeOfEventTargetIncludingThis( 256 MallocSizeOf aMallocSizeOf) const override; 257 258 // states 259 virtual uint16_t ReadyState() const override; 260 261 // request 262 nsresult CreateChannel(); 263 nsresult InitiateFetch(already_AddRefed<nsIInputStream> aUploadStream, 264 int64_t aUploadLength, nsACString& aUploadContentType); 265 266 virtual void Open(const nsACString& aMethod, const nsACString& aUrl, 267 ErrorResult& aRv) override; 268 269 virtual void Open(const nsACString& aMethod, const nsACString& aUrl, 270 bool aAsync, const nsACString& aUsername, 271 const nsACString& aPassword, ErrorResult& aRv) override; 272 273 virtual void SetRequestHeader(const nsACString& aName, 274 const nsACString& aValue, 275 ErrorResult& aRv) override; 276 277 virtual uint32_t Timeout() const override { return mTimeoutMilliseconds; } 278 279 virtual void SetTimeout(uint32_t aTimeout, ErrorResult& aRv) override; 280 281 virtual bool WithCredentials() const override; 282 283 virtual void SetWithCredentials(bool aWithCredentials, 284 ErrorResult& aRv) override; 285 286 virtual XMLHttpRequestUpload* GetUpload(ErrorResult& aRv) override; 287 288 private: 289 virtual ~XMLHttpRequestMainThread(); 290 291 nsresult MaybeSilentSendFailure(nsresult aRv); 292 void SendInternal(const BodyExtractorBase* aBody, 293 bool aBodyIsDocumentOrString, ErrorResult& aRv); 294 295 bool IsCrossSiteCORSRequest() const; 296 bool IsDeniedCrossSiteCORSRequest(); 297 298 void ResumeTimeout(); 299 300 void MaybeLowerChannelPriority(); 301 302 public: 303 bool CanSend(ErrorResult& aRv); 304 305 virtual void Send( 306 const Nullable< 307 DocumentOrBlobOrArrayBufferViewOrArrayBufferOrFormDataOrURLSearchParamsOrUSVString>& 308 aData, 309 ErrorResult& aRv) override; 310 311 virtual void SendInputStream(nsIInputStream* aInputStream, 312 ErrorResult& aRv) override { 313 if (!CanSend(aRv)) { 314 return; 315 } 316 BodyExtractor<nsIInputStream> body(aInputStream); 317 SendInternal(&body, false, aRv); 318 } 319 320 void RequestErrorSteps(const ProgressEventType aEventType, 321 const nsresult aOptionalException, ErrorResult& aRv); 322 323 void Abort() { 324 IgnoredErrorResult rv; 325 AbortInternal(rv); 326 MOZ_ASSERT(!rv.Failed() || rv.ErrorCodeIs(NS_ERROR_DOM_ABORT_ERR)); 327 } 328 329 virtual void Abort(ErrorResult& aRv) override; 330 331 // response 332 virtual void GetResponseURL(nsACString& aUrl) override; 333 334 virtual uint32_t GetStatus(ErrorResult& aRv) override; 335 336 virtual void GetStatusText(nsACString& aStatusText, 337 ErrorResult& aRv) override; 338 339 virtual void GetResponseHeader(const nsACString& aHeader, nsACString& aResult, 340 ErrorResult& aRv) override; 341 342 virtual void GetAllResponseHeaders(nsACString& aResponseHeaders, 343 ErrorResult& aRv) override; 344 345 bool IsSafeHeader(const nsACString& aHeaderName, 346 NotNull<nsIHttpChannel*> aHttpChannel) const; 347 348 virtual void OverrideMimeType(const nsAString& aMimeType, 349 ErrorResult& aRv) override; 350 351 virtual XMLHttpRequestResponseType ResponseType() const override { 352 return XMLHttpRequestResponseType(mResponseType); 353 } 354 355 virtual void SetResponseType(XMLHttpRequestResponseType aType, 356 ErrorResult& aRv) override; 357 358 void SetResponseTypeRaw(XMLHttpRequestResponseType aType) { 359 mResponseType = aType; 360 } 361 362 virtual void GetResponse(JSContext* aCx, 363 JS::MutableHandle<JS::Value> aResponse, 364 ErrorResult& aRv) override; 365 366 virtual void GetResponseText(DOMString& aResponseText, 367 ErrorResult& aRv) override; 368 369 // GetResponse* for workers: 370 already_AddRefed<BlobImpl> GetResponseBlobImpl(); 371 already_AddRefed<ArrayBufferBuilder> GetResponseArrayBufferBuilder(); 372 nsresult GetResponseTextForJSON(nsAString& aString); 373 void GetResponseText(XMLHttpRequestStringSnapshot& aSnapshot, 374 ErrorResult& aRv); 375 376 virtual Document* GetResponseXML(ErrorResult& aRv) override; 377 378 virtual bool MozBackgroundRequest() const override; 379 380 void SetMozBackgroundRequestExternal(bool aMozBackgroundRequest, 381 ErrorResult& aRv); 382 383 virtual void SetMozBackgroundRequest(bool aMozBackgroundRequest, 384 ErrorResult& aRv) override; 385 386 void SetOriginStack(UniquePtr<SerializedStackHolder> aOriginStack); 387 388 void SetSource(UniquePtr<ProfileChunkedBuffer> aSource); 389 390 nsresult ErrorDetail() const { return mErrorLoadDetail; } 391 392 virtual uint16_t ErrorCode() const override { 393 return static_cast<uint16_t>(mErrorLoad); 394 } 395 396 virtual bool MozAnon() const override; 397 398 virtual bool MozSystem() const override; 399 400 virtual nsIChannel* GetChannel() const override { return mChannel; } 401 402 // We need a GetInterface callable from JS for chrome JS 403 virtual void GetInterface(JSContext* aCx, JS::Handle<JS::Value> aIID, 404 JS::MutableHandle<JS::Value> aRetval, 405 ErrorResult& aRv) override; 406 407 // This fires a trusted readystatechange event, which is not cancelable and 408 // doesn't bubble. 409 nsresult FireReadystatechangeEvent(); 410 void DispatchProgressEvent(DOMEventTargetHelper* aTarget, 411 const ProgressEventType& aType, int64_t aLoaded, 412 int64_t aTotal); 413 414 NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED( 415 XMLHttpRequestMainThread, XMLHttpRequest) 416 virtual bool IsCertainlyAliveForCC() const override; 417 418 bool AllowUploadProgress(); 419 420 virtual void DisconnectFromOwner() override; 421 422 static void SetDontWarnAboutSyncXHR(bool aVal) { 423 sDontWarnAboutSyncXHR = aVal; 424 } 425 static bool DontWarnAboutSyncXHR() { return sDontWarnAboutSyncXHR; } 426 427 virtual void SetOriginAttributes( 428 const mozilla::dom::OriginAttributesDictionary& aAttrs) override; 429 430 void BlobStoreCompleted(MutableBlobStorage* aBlobStorage, BlobImpl* aBlobImpl, 431 nsresult aResult) override; 432 433 void LocalFileToBlobCompleted(BlobImpl* aBlobImpl); 434 435 #ifdef DEBUG 436 // For logging when there's trouble 437 RefPtr<ThreadSafeWorkerRef> mTSWorkerRef MOZ_GUARDED_BY(mTSWorkerRefMutex); 438 Mutex mTSWorkerRefMutex; 439 #endif 440 441 protected: 442 nsresult DetectCharset(); 443 nsresult AppendToResponseText(Span<const uint8_t> aBuffer, 444 bool aLast = false); 445 static nsresult StreamReaderFunc(nsIInputStream* in, void* closure, 446 const char* fromRawSegment, 447 uint32_t toOffset, uint32_t count, 448 uint32_t* writeCount); 449 nsresult CreateResponseParsedJSON(JSContext* aCx); 450 // Change the state of the object with this. The broadcast argument 451 // determines if the onreadystatechange listener should be called. 452 nsresult ChangeState(uint16_t aState, bool aBroadcast = true); 453 already_AddRefed<nsILoadGroup> GetLoadGroup() const; 454 455 // Finds a preload for this XHR. If it is found it's removed from the preload 456 // table of the document and marked as used. The called doesn't need to do 457 // any more comparative checks. 458 already_AddRefed<PreloaderBase> FindPreload(); 459 // If no or unknown mime type is set on the channel this method ensures it's 460 // set to "text/xml". 461 void EnsureChannelContentType(); 462 463 // Gets the value of the final content-type header from the channel. 464 bool GetContentType(nsACString& aValue) const; 465 466 already_AddRefed<nsIHttpChannel> GetCurrentHttpChannel(); 467 already_AddRefed<nsIJARChannel> GetCurrentJARChannel(); 468 469 void TruncateResponseText(); 470 471 bool IsSystemXHR() const; 472 bool InUploadPhase() const; 473 474 void OnBodyParseEnd(); 475 void ChangeStateToDone(bool aWasSync); 476 void ChangeStateToDoneInternal(); 477 478 void StartProgressEventTimer(); 479 void StopProgressEventTimer(); 480 481 void MaybeCreateBlobStorage(); 482 483 nsresult OnRedirectVerifyCallback(nsresult result, bool stripAuth = false); 484 485 nsIEventTarget* GetTimerEventTarget(); 486 487 nsresult DispatchToMainThread(already_AddRefed<nsIRunnable> aRunnable); 488 489 void DispatchOrStoreEvent(DOMEventTargetHelper* aTarget, Event* aEvent); 490 491 already_AddRefed<nsXMLHttpRequestXPCOMifier> EnsureXPCOMifier(); 492 493 void SuspendEventDispatching(); 494 void ResumeEventDispatching(); 495 496 void AbortInternal(ErrorResult& aRv); 497 498 bool BadContentRangeRequested(); 499 RefPtr<mozilla::net::ContentRange> GetRequestedContentRange() const; 500 void GetContentRangeHeader(nsACString&) const; 501 502 struct PendingEvent { 503 RefPtr<DOMEventTargetHelper> mTarget; 504 RefPtr<Event> mEvent; 505 }; 506 507 nsTArray<PendingEvent> mPendingEvents; 508 509 nsCOMPtr<nsIPrincipal> mPrincipal; 510 nsCOMPtr<nsIChannel> mChannel; 511 nsCString mRequestMethod; 512 nsCOMPtr<nsIURI> mRequestURL; 513 RefPtr<Document> mResponseXML; 514 515 nsCOMPtr<nsIStreamListener> mXMLParserStreamListener; 516 517 nsCOMPtr<nsICookieJarSettings> mCookieJarSettings; 518 519 RefPtr<PerformanceStorage> mPerformanceStorage; 520 nsCOMPtr<nsICSPEventListener> mCSPEventListener; 521 522 // used to implement getAllResponseHeaders() 523 class nsHeaderVisitor : public nsIHttpHeaderVisitor { 524 struct HeaderEntry final { 525 nsCString mName; 526 nsCString mValue; 527 528 HeaderEntry(const nsACString& aName, const nsACString& aValue) 529 : mName(aName), mValue(aValue) {} 530 531 bool operator==(const HeaderEntry& aOther) const { 532 return mName == aOther.mName; 533 } 534 535 bool operator<(const HeaderEntry& aOther) const { 536 uint32_t selfLen = mName.Length(); 537 uint32_t otherLen = aOther.mName.Length(); 538 uint32_t min = std::min(selfLen, otherLen); 539 for (uint32_t i = 0; i < min; ++i) { 540 unsigned char self = mName[i]; 541 unsigned char other = aOther.mName[i]; 542 MOZ_ASSERT(!(self >= 'A' && self <= 'Z')); 543 MOZ_ASSERT(!(other >= 'A' && other <= 'Z')); 544 if (self == other) { 545 continue; 546 } 547 if (self >= 'a' && self <= 'z') { 548 self -= 0x20; 549 } 550 if (other >= 'a' && other <= 'z') { 551 other -= 0x20; 552 } 553 return self < other; 554 } 555 return selfLen < otherLen; 556 } 557 }; 558 559 public: 560 NS_DECL_ISUPPORTS 561 NS_DECL_NSIHTTPHEADERVISITOR 562 nsHeaderVisitor(const XMLHttpRequestMainThread& aXMLHttpRequest, 563 NotNull<nsIHttpChannel*> aHttpChannel); 564 const nsACString& Headers() { 565 for (uint32_t i = 0; i < mHeaderList.Length(); i++) { 566 HeaderEntry& header = mHeaderList.ElementAt(i); 567 568 mHeaders.Append(header.mName); 569 mHeaders.AppendLiteral(": "); 570 mHeaders.Append(header.mValue); 571 mHeaders.AppendLiteral("\r\n"); 572 } 573 return mHeaders; 574 } 575 576 private: 577 virtual ~nsHeaderVisitor(); 578 579 nsTArray<HeaderEntry> mHeaderList; 580 nsCString mHeaders; 581 const XMLHttpRequestMainThread& mXHR; 582 NotNull<nsCOMPtr<nsIHttpChannel>> mHttpChannel; 583 }; 584 585 // The bytes of our response body. Only used for DEFAULT, ARRAYBUFFER and 586 // BLOB responseTypes 587 nsCString mResponseBody; 588 589 // The text version of our response body. This is incrementally decoded into 590 // as we receive network data. However for the DEFAULT responseType we 591 // lazily decode into this from mResponseBody only when .responseText is 592 // accessed. 593 // Only used for DEFAULT and TEXT responseTypes. 594 XMLHttpRequestString mResponseText; 595 596 // For DEFAULT responseType we use this to keep track of how far we've 597 // lazily decoded from mResponseBody to mResponseText 598 uint32_t mResponseBodyDecodedPos; 599 600 // Decoder used for decoding into mResponseText 601 // Only used for DEFAULT, TEXT and JSON responseTypes. 602 // In cases where we've only received half a surrogate, the decoder itself 603 // carries the state to remember this. Next time we receive more data we 604 // simply feed the new data into the decoder which will handle the second 605 // part of the surrogate. 606 mozilla::UniquePtr<mozilla::Decoder> mDecoder; 607 608 void MatchCharsetAndDecoderToResponseDocument(); 609 610 XMLHttpRequestResponseType mResponseType; 611 612 RefPtr<BlobImpl> mResponseBlobImpl; 613 614 // This is the cached blob-response, created only at the first GetResponse() 615 // call. 616 RefPtr<Blob> mResponseBlob; 617 618 // We stream data to mBlobStorage when response type is "blob". 619 RefPtr<MutableBlobStorage> mBlobStorage; 620 621 nsString mOverrideMimeType; 622 623 /** 624 * The notification callbacks the channel had when Send() was 625 * called. We want to forward things here as needed. 626 */ 627 nsCOMPtr<nsIInterfaceRequestor> mNotificationCallbacks; 628 /** 629 * Sink interfaces that we implement that mNotificationCallbacks may 630 * want to also be notified for. These are inited lazily if we're 631 * asked for the relevant interface. 632 */ 633 nsCOMPtr<nsIChannelEventSink> mChannelEventSink; 634 nsCOMPtr<nsIProgressEventSink> mProgressEventSink; 635 636 nsCOMPtr<nsIURI> mBaseURI; 637 nsCOMPtr<nsILoadGroup> mLoadGroup; 638 639 Maybe<ClientInfo> mClientInfo; 640 Maybe<ServiceWorkerDescriptor> mController; 641 642 uint16_t mState; 643 644 // If true, this object is used by the worker's XMLHttpRequest. 645 bool mForWorker; 646 647 bool mFlagSynchronous; 648 bool mFlagAborted; 649 bool mFlagParseBody; 650 bool mFlagSyncLooping; 651 bool mFlagBackgroundRequest; 652 bool mFlagHadUploadListenersOnSend; 653 bool mFlagACwithCredentials; 654 bool mFlagTimedOut; 655 bool mFlagDeleted; 656 657 // The XHR2 spec's send() flag. Set when the XHR begins uploading, until it 658 // finishes downloading (or an error/abort has occurred during either phase). 659 // Used to guard against the user trying to alter headers/etc when it's too 660 // late, and ensure the XHR only handles one in-flight request at once. 661 bool mFlagSend; 662 663 RefPtr<XMLHttpRequestUpload> mUpload; 664 int64_t mUploadTransferred; 665 int64_t mUploadTotal; 666 bool mUploadComplete; 667 bool mProgressSinceLastProgressEvent; 668 669 // Timeout support 670 PRTime mRequestSentTime; 671 uint32_t mTimeoutMilliseconds; 672 nsCOMPtr<nsITimer> mTimeoutTimer; 673 void StartTimeoutTimer(); 674 void HandleTimeoutCallback(); 675 void CancelTimeoutTimer(); 676 677 nsCOMPtr<nsIRunnable> mResumeTimeoutRunnable; 678 679 nsCOMPtr<nsITimer> mSyncTimeoutTimer; 680 681 enum SyncTimeoutType { eErrorOrExpired, eTimerStarted, eNoTimerNeeded }; 682 683 SyncTimeoutType MaybeStartSyncTimeoutTimer(); 684 void HandleSyncTimeoutTimer(); 685 void CancelSyncTimeoutTimer(); 686 687 ErrorType mErrorLoad; 688 nsresult mErrorLoadDetail; 689 bool mErrorParsingXML; 690 bool mWaitingForOnStopRequest; 691 bool mProgressTimerIsActive; 692 bool mIsHtml; 693 bool mWarnAboutSyncHtml; 694 int64_t mLoadTotal; // -1 if not known. 695 // Number of HTTP message body bytes received so far. This quantity is 696 // in the same units as Content-Length and mLoadTotal, and hence counts 697 // compressed bytes when the channel has gzip Content-Encoding. If the 698 // channel does not have Content-Encoding, this will be the same as 699 // mDataReceived except between the OnProgress that changes mLoadTransferred 700 // and the corresponding OnDataAvailable (which changes mDataReceived). 701 // Ordering of OnProgress and OnDataAvailable is undefined. 702 int64_t mLoadTransferred; 703 nsCOMPtr<nsITimer> mProgressNotifier; 704 void HandleProgressTimerCallback(); 705 706 bool mIsSystem; 707 bool mIsAnon; 708 709 // Prevent duplicate OnStopRequest calls due to the explicit 710 // OnStopRequest in the sync path of SendInternal 711 bool mAlreadyGotStopRequest; 712 713 /** 714 * Close the XMLHttpRequest's channels. 715 */ 716 void CloseRequest(nsresult detail); 717 718 void TerminateOngoingFetch(nsresult detail); 719 720 /** 721 * Close the XMLHttpRequest's channels and dispatch appropriate progress 722 * events. 723 * 724 * @param aType The progress event type. 725 */ 726 void CloseRequestWithError(const ErrorProgressEventType& aType); 727 728 nsCOMPtr<nsIAsyncVerifyRedirectCallback> mRedirectCallback; 729 nsCOMPtr<nsIChannel> mNewRedirectChannel; 730 731 JS::Heap<JS::Value> mResultJSON; 732 733 RefPtr<ArrayBufferBuilder> mArrayBufferBuilder; 734 JS::Heap<JSObject*> mResultArrayBuffer; 735 bool mIsMappedArrayBuffer; 736 737 void ResetResponse(); 738 739 bool ShouldBlockAuthPrompt(); 740 741 RequestHeaders mAuthorRequestHeaders; 742 743 // Helper object to manage our XPCOM scriptability bits 744 nsXMLHttpRequestXPCOMifier* mXPCOMifier; 745 746 // When this is set to true, the event dispatching is suspended. This is 747 // useful to change the correct state when XHR is working sync. 748 bool mEventDispatchingSuspended; 749 750 // True iff mDecoder has processed the end of the stream. 751 // Used in lazy decoding to distinguish between having 752 // processed all the bytes but not the EOF and having 753 // processed all the bytes and the EOF. 754 bool mEofDecoded; 755 756 // This flag will be set in `Send()` when we successfully reuse a "fetch" 757 // preload to satisfy this XHR. 758 bool mFromPreload = false; 759 760 // Our parse-end listener, if we are parsing. 761 RefPtr<nsXHRParseEndListener> mParseEndListener; 762 763 XMLHttpRequestDoneNotifier* mDelayedDoneNotifier; 764 void DisconnectDoneNotifier(); 765 766 // Any stack information for the point the XHR was opened. This is deleted 767 // after the XHR is opened, to avoid retaining references to the worker. 768 UniquePtr<SerializedStackHolder> mOriginStack; 769 770 static bool sDontWarnAboutSyncXHR; 771 }; 772 773 class MOZ_STACK_CLASS AutoDontWarnAboutSyncXHR { 774 public: 775 AutoDontWarnAboutSyncXHR() 776 : mOldVal(XMLHttpRequestMainThread::DontWarnAboutSyncXHR()) { 777 XMLHttpRequestMainThread::SetDontWarnAboutSyncXHR(true); 778 } 779 780 ~AutoDontWarnAboutSyncXHR() { 781 XMLHttpRequestMainThread::SetDontWarnAboutSyncXHR(mOldVal); 782 } 783 784 private: 785 bool mOldVal; 786 }; 787 788 // A shim class designed to expose the non-DOM interfaces of 789 // XMLHttpRequest via XPCOM stuff. 790 class nsXMLHttpRequestXPCOMifier final : public nsIStreamListener, 791 public nsIChannelEventSink, 792 public nsIAsyncVerifyRedirectCallback, 793 public nsIProgressEventSink, 794 public nsIInterfaceRequestor, 795 public nsITimerCallback, 796 public nsINamed { 797 NS_DECL_CYCLE_COLLECTING_ISUPPORTS 798 NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(nsXMLHttpRequestXPCOMifier, 799 nsIStreamListener) 800 801 explicit nsXMLHttpRequestXPCOMifier(XMLHttpRequestMainThread* aXHR) 802 : mXHR(aXHR) {} 803 804 private: 805 ~nsXMLHttpRequestXPCOMifier() { 806 if (mXHR) { 807 mXHR->mXPCOMifier = nullptr; 808 } 809 } 810 811 public: 812 NS_FORWARD_NSISTREAMLISTENER(mXHR->) 813 NS_FORWARD_NSIREQUESTOBSERVER(mXHR->) 814 NS_FORWARD_NSICHANNELEVENTSINK(mXHR->) 815 NS_FORWARD_NSIASYNCVERIFYREDIRECTCALLBACK(mXHR->) 816 NS_FORWARD_NSIPROGRESSEVENTSINK(mXHR->) 817 NS_FORWARD_NSITIMERCALLBACK(mXHR->) 818 NS_FORWARD_NSINAMED(mXHR->) 819 820 NS_DECL_NSIINTERFACEREQUESTOR 821 822 private: 823 RefPtr<XMLHttpRequestMainThread> mXHR; 824 }; 825 826 class XMLHttpRequestDoneNotifier : public Runnable { 827 public: 828 explicit XMLHttpRequestDoneNotifier(XMLHttpRequestMainThread* aXHR) 829 : Runnable("XMLHttpRequestDoneNotifier"), mXHR(aXHR) {} 830 831 NS_IMETHOD Run() override { 832 if (mXHR) { 833 RefPtr<XMLHttpRequestMainThread> xhr = mXHR; 834 // ChangeStateToDoneInternal ends up calling Disconnect(); 835 xhr->ChangeStateToDoneInternal(); 836 MOZ_ASSERT(!mXHR); 837 } 838 return NS_OK; 839 } 840 841 void Disconnect() { mXHR = nullptr; } 842 843 private: 844 RefPtr<XMLHttpRequestMainThread> mXHR; 845 }; 846 847 class nsXHRParseEndListener : public nsIDOMEventListener { 848 public: 849 NS_DECL_ISUPPORTS 850 NS_IMETHOD HandleEvent(Event* event) override { 851 if (mXHR) { 852 mXHR->OnBodyParseEnd(); 853 } 854 mXHR = nullptr; 855 return NS_OK; 856 } 857 858 explicit nsXHRParseEndListener(XMLHttpRequestMainThread* aXHR) : mXHR(aXHR) {} 859 860 void SetIsStale() { mXHR = nullptr; } 861 862 private: 863 virtual ~nsXHRParseEndListener() = default; 864 865 XMLHttpRequestMainThread* mXHR; 866 }; 867 868 } // namespace dom 869 } // namespace mozilla 870 871 #endif // mozilla_dom_XMLHttpRequestMainThread_h