Line data Source code
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 : #include "nsAutoPtr.h"
12 : #include "nsIXMLHttpRequest.h"
13 : #include "nsISupportsUtils.h"
14 : #include "nsIURI.h"
15 : #include "nsIHttpChannel.h"
16 : #include "nsIDocument.h"
17 : #include "nsIStreamListener.h"
18 : #include "nsWeakReference.h"
19 : #include "nsIChannelEventSink.h"
20 : #include "nsIAsyncVerifyRedirectCallback.h"
21 : #include "nsIInterfaceRequestor.h"
22 : #include "nsIHttpHeaderVisitor.h"
23 : #include "nsIProgressEventSink.h"
24 : #include "nsJSUtils.h"
25 : #include "nsTArray.h"
26 : #include "nsITimer.h"
27 : #include "nsIPrincipal.h"
28 : #include "nsIScriptObjectPrincipal.h"
29 : #include "nsISizeOfEventTarget.h"
30 : #include "nsIXPConnect.h"
31 : #include "nsIInputStream.h"
32 : #include "mozilla/Assertions.h"
33 : #include "mozilla/Attributes.h"
34 : #include "mozilla/DOMEventTargetHelper.h"
35 : #include "mozilla/MemoryReporting.h"
36 : #include "mozilla/NotNull.h"
37 : #include "mozilla/dom/MutableBlobStorage.h"
38 : #include "mozilla/dom/BodyExtractor.h"
39 : #include "mozilla/dom/TypedArray.h"
40 : #include "mozilla/dom/File.h"
41 : #include "mozilla/dom/FormData.h"
42 : #include "mozilla/dom/URLSearchParams.h"
43 : #include "mozilla/dom/XMLHttpRequest.h"
44 : #include "mozilla/dom/XMLHttpRequestBinding.h"
45 : #include "mozilla/dom/XMLHttpRequestEventTarget.h"
46 : #include "mozilla/dom/XMLHttpRequestString.h"
47 : #include "mozilla/Encoding.h"
48 :
49 : #ifdef Status
50 : /* Xlib headers insist on this for some reason... Nuke it because
51 : it'll override our member name */
52 : #undef Status
53 : #endif
54 :
55 : class nsIJARChannel;
56 : class nsILoadGroup;
57 : class nsIJSID;
58 :
59 : namespace mozilla {
60 : namespace dom {
61 :
62 : class BlobSet;
63 : class DOMString;
64 : class XMLHttpRequestUpload;
65 : struct OriginAttributesDictionary;
66 :
67 : // A helper for building up an ArrayBuffer object's data
68 : // before creating the ArrayBuffer itself. Will do doubling
69 : // based reallocation, up to an optional maximum growth given.
70 : //
71 : // When all the data has been appended, call getArrayBuffer,
72 : // passing in the JSContext* for which the ArrayBuffer object
73 : // is to be created. This also implicitly resets the builder,
74 : // or it can be reset explicitly at any point by calling reset().
75 : class ArrayBufferBuilder
76 : {
77 : uint8_t* mDataPtr;
78 : uint32_t mCapacity;
79 : uint32_t mLength;
80 : void* mMapPtr;
81 : public:
82 : ArrayBufferBuilder();
83 : ~ArrayBufferBuilder();
84 :
85 : void reset();
86 :
87 : // Will truncate if aNewCap is < length().
88 : bool setCapacity(uint32_t aNewCap);
89 :
90 : // Append aDataLen bytes from data to the current buffer. If we
91 : // need to grow the buffer, grow by doubling the size up to a
92 : // maximum of aMaxGrowth (if given). If aDataLen is greater than
93 : // what the new capacity would end up as, then grow by aDataLen.
94 : //
95 : // The data parameter must not overlap with anything beyond the
96 : // builder's current valid contents [0..length)
97 : bool append(const uint8_t* aNewData, uint32_t aDataLen,
98 : uint32_t aMaxGrowth = 0);
99 :
100 0 : uint32_t length() { return mLength; }
101 0 : uint32_t capacity() { return mCapacity; }
102 :
103 : JSObject* getArrayBuffer(JSContext* aCx);
104 :
105 : // Memory mapping to starting position of file(aFile) in the zip
106 : // package(aJarFile).
107 : //
108 : // The file in the zip package has to be uncompressed and the starting
109 : // position of the file must be aligned according to array buffer settings
110 : // in JS engine.
111 : nsresult mapToFileInPackage(const nsCString& aFile, nsIFile* aJarFile);
112 :
113 : protected:
114 : static bool areOverlappingRegions(const uint8_t* aStart1, uint32_t aLength1,
115 : const uint8_t* aStart2, uint32_t aLength2);
116 : };
117 :
118 : class nsXMLHttpRequestXPCOMifier;
119 :
120 3 : class RequestHeaders
121 : {
122 0 : struct RequestHeader
123 : {
124 : nsCString mName;
125 : nsCString mValue;
126 : };
127 : nsTArray<RequestHeader> mHeaders;
128 : RequestHeader* Find(const nsACString& aName);
129 :
130 : public:
131 : class CharsetIterator
132 : {
133 : bool mValid;
134 : int32_t mCurPos, mCurLen, mCutoff;
135 : nsACString& mSource;
136 :
137 : public:
138 : explicit CharsetIterator(nsACString& aSource);
139 : bool Equals(const nsACString& aOther, const nsCStringComparator& aCmp) const;
140 : void Replace(const nsACString& aReplacement);
141 : bool Next();
142 : };
143 :
144 : bool Has(const char* aName);
145 : bool Has(const nsACString& aName);
146 : void Get(const char* aName, nsACString& aValue);
147 : void Get(const nsACString& aName, nsACString& aValue);
148 : void Set(const char* aName, const nsACString& aValue);
149 : void Set(const nsACString& aName, const nsACString& aValue);
150 : void MergeOrSet(const char* aName, const nsACString& aValue);
151 : void MergeOrSet(const nsACString& aName, const nsACString& aValue);
152 : void Clear();
153 : void ApplyToChannel(nsIHttpChannel* aChannel) const;
154 : void GetCORSUnsafeHeaders(nsTArray<nsCString>& aArray) const;
155 : };
156 :
157 : // Make sure that any non-DOM interfaces added here are also added to
158 : // nsXMLHttpRequestXPCOMifier.
159 : class XMLHttpRequestMainThread final : public XMLHttpRequest,
160 : public nsIXMLHttpRequest,
161 : public nsIJSXMLHttpRequest,
162 : public nsIStreamListener,
163 : public nsIChannelEventSink,
164 : public nsIProgressEventSink,
165 : public nsIInterfaceRequestor,
166 : public nsSupportsWeakReference,
167 : public nsITimerCallback,
168 : public nsISizeOfEventTarget,
169 : public nsINamed,
170 : public MutableBlobStorageCallback
171 : {
172 : friend class nsXHRParseEndListener;
173 : friend class nsXMLHttpRequestXPCOMifier;
174 :
175 : public:
176 : enum class ProgressEventType : uint8_t {
177 : loadstart,
178 : progress,
179 : error,
180 : abort,
181 : timeout,
182 : load,
183 : loadend,
184 : ENUM_MAX
185 : };
186 :
187 : enum class ErrorType : uint16_t {
188 : eOK,
189 : eRequest,
190 : eUnreachable,
191 : eChannelOpen,
192 : eRedirect,
193 : ENUM_MAX
194 : };
195 :
196 : XMLHttpRequestMainThread();
197 :
198 3 : void Construct(nsIPrincipal* aPrincipal,
199 : nsIGlobalObject* aGlobalObject,
200 : nsIURI* aBaseURI = nullptr,
201 : nsILoadGroup* aLoadGroup = nullptr)
202 : {
203 3 : MOZ_ASSERT(aPrincipal);
204 3 : MOZ_ASSERT_IF(nsCOMPtr<nsPIDOMWindowInner> win = do_QueryInterface(
205 : aGlobalObject), win->IsInnerWindow());
206 3 : mPrincipal = aPrincipal;
207 3 : BindToOwner(aGlobalObject);
208 3 : mBaseURI = aBaseURI;
209 3 : mLoadGroup = aLoadGroup;
210 3 : }
211 :
212 : void InitParameters(bool aAnon, bool aSystem);
213 :
214 3 : void SetParameters(bool aAnon, bool aSystem)
215 : {
216 3 : mIsAnon = aAnon || aSystem;
217 3 : mIsSystem = aSystem;
218 3 : }
219 :
220 : NS_DECL_ISUPPORTS_INHERITED
221 :
222 : // nsIXMLHttpRequest
223 : NS_DECL_NSIXMLHTTPREQUEST
224 :
225 : NS_FORWARD_NSIXMLHTTPREQUESTEVENTTARGET(XMLHttpRequestEventTarget::)
226 :
227 : // nsIStreamListener
228 : NS_DECL_NSISTREAMLISTENER
229 :
230 : // nsIRequestObserver
231 : NS_DECL_NSIREQUESTOBSERVER
232 :
233 : // nsIChannelEventSink
234 : NS_DECL_NSICHANNELEVENTSINK
235 :
236 : // nsIProgressEventSink
237 : NS_DECL_NSIPROGRESSEVENTSINK
238 :
239 : // nsIInterfaceRequestor
240 : NS_DECL_NSIINTERFACEREQUESTOR
241 :
242 : // nsITimerCallback
243 : NS_DECL_NSITIMERCALLBACK
244 :
245 : // nsINamed
246 : NS_DECL_NSINAMED
247 :
248 : // nsISizeOfEventTarget
249 : virtual size_t
250 : SizeOfEventTargetIncludingThis(MallocSizeOf aMallocSizeOf) const override;
251 :
252 192 : NS_REALLY_FORWARD_NSIDOMEVENTTARGET(XMLHttpRequestEventTarget)
253 :
254 : // states
255 : virtual uint16_t ReadyState() const override;
256 :
257 : // request
258 : nsresult CreateChannel();
259 : nsresult InitiateFetch(nsIInputStream* aUploadStream,
260 : int64_t aUploadLength,
261 : nsACString& aUploadContentType);
262 :
263 : virtual void
264 : Open(const nsACString& aMethod, const nsAString& aUrl,
265 : ErrorResult& aRv) override;
266 :
267 : virtual void
268 : Open(const nsACString& aMethod, const nsAString& aUrl, bool aAsync,
269 : const nsAString& aUsername, const nsAString& aPassword,
270 : ErrorResult& aRv) override;
271 :
272 : nsresult
273 : Open(const nsACString& aMethod,
274 : const nsACString& aUrl,
275 : bool aAsync,
276 : const nsAString& aUsername,
277 : const nsAString& aPassword);
278 :
279 : virtual void
280 0 : SetRequestHeader(const nsACString& aName, const nsACString& aValue,
281 : ErrorResult& aRv) override
282 : {
283 0 : aRv = SetRequestHeader(aName, aValue);
284 0 : }
285 :
286 : virtual uint32_t
287 0 : Timeout() const override
288 : {
289 0 : return mTimeoutMilliseconds;
290 : }
291 :
292 : virtual void
293 : SetTimeout(uint32_t aTimeout, ErrorResult& aRv) override;
294 :
295 : virtual bool WithCredentials() const override;
296 :
297 : virtual void
298 : SetWithCredentials(bool aWithCredentials, ErrorResult& aRv) override;
299 :
300 : virtual XMLHttpRequestUpload*
301 : GetUpload(ErrorResult& aRv) override;
302 :
303 : private:
304 : virtual ~XMLHttpRequestMainThread();
305 :
306 : nsresult SendInternal(const BodyExtractorBase* aBody);
307 :
308 : bool IsCrossSiteCORSRequest() const;
309 : bool IsDeniedCrossSiteCORSRequest();
310 :
311 : // Tell our channel what network interface ID we were told to use.
312 : // If it's an HTTP channel and we were told to use a non-default
313 : // interface ID.
314 : void PopulateNetworkInterfaceId();
315 :
316 : void UnsuppressEventHandlingAndResume();
317 :
318 : // Check pref "dom.mapped_arraybuffer.enabled" to make sure ArrayBuffer is
319 : // supported.
320 : static bool IsMappedArrayBufferEnabled();
321 :
322 : // Check pref "dom.xhr.lowercase_header.enabled" to make sure lowercased
323 : // response header is supported.
324 : static bool IsLowercaseResponseHeader();
325 :
326 : void MaybeLowerChannelPriority();
327 :
328 : public:
329 : virtual void
330 0 : Send(JSContext* /*aCx*/, ErrorResult& aRv) override
331 : {
332 0 : aRv = SendInternal(nullptr);
333 0 : }
334 :
335 : virtual void
336 0 : Send(JSContext* /*aCx*/, const ArrayBuffer& aArrayBuffer,
337 : ErrorResult& aRv) override
338 : {
339 0 : BodyExtractor<const ArrayBuffer> body(&aArrayBuffer);
340 0 : aRv = SendInternal(&body);
341 0 : }
342 :
343 : virtual void
344 0 : Send(JSContext* /*aCx*/, const ArrayBufferView& aArrayBufferView,
345 : ErrorResult& aRv) override
346 : {
347 0 : BodyExtractor<const ArrayBufferView> body(&aArrayBufferView);
348 0 : aRv = SendInternal(&body);
349 0 : }
350 :
351 : virtual void
352 0 : Send(JSContext* /*aCx*/, Blob& aBlob, ErrorResult& aRv) override
353 : {
354 0 : BodyExtractor<nsIXHRSendable> body(&aBlob);
355 0 : aRv = SendInternal(&body);
356 0 : }
357 :
358 0 : virtual void Send(JSContext* /*aCx*/, URLSearchParams& aURLSearchParams,
359 : ErrorResult& aRv) override
360 : {
361 0 : BodyExtractor<nsIXHRSendable> body(&aURLSearchParams);
362 0 : aRv = SendInternal(&body);
363 0 : }
364 :
365 : virtual void
366 0 : Send(JSContext* /*aCx*/, nsIDocument& aDoc, ErrorResult& aRv) override
367 : {
368 0 : BodyExtractor<nsIDocument> body(&aDoc);
369 0 : aRv = SendInternal(&body);
370 0 : }
371 :
372 : virtual void
373 0 : Send(JSContext* aCx, const nsAString& aString, ErrorResult& aRv) override
374 : {
375 0 : if (DOMStringIsNull(aString)) {
376 0 : Send(aCx, aRv);
377 : } else {
378 0 : BodyExtractor<const nsAString> body(&aString);
379 0 : aRv = SendInternal(&body);
380 : }
381 0 : }
382 :
383 : virtual void
384 0 : Send(JSContext* /*aCx*/, FormData& aFormData, ErrorResult& aRv) override
385 : {
386 0 : BodyExtractor<nsIXHRSendable> body(&aFormData);
387 0 : aRv = SendInternal(&body);
388 0 : }
389 :
390 : virtual void
391 0 : Send(JSContext* aCx, nsIInputStream* aStream, ErrorResult& aRv) override
392 : {
393 0 : NS_ASSERTION(aStream, "Null should go to string version");
394 0 : BodyExtractor<nsIInputStream> body(aStream);
395 0 : aRv = SendInternal(&body);
396 0 : }
397 :
398 : void
399 : RequestErrorSteps(const ProgressEventType aEventType,
400 : const nsresult aOptionalException,
401 : ErrorResult& aRv);
402 :
403 : void
404 0 : Abort()
405 : {
406 0 : ErrorResult rv;
407 0 : Abort(rv);
408 0 : MOZ_ASSERT(!rv.Failed());
409 0 : }
410 :
411 : virtual void
412 : Abort(ErrorResult& aRv) override;
413 :
414 : // response
415 : virtual void
416 : GetResponseURL(nsAString& aUrl) override;
417 :
418 : virtual uint32_t
419 : GetStatus(ErrorResult& aRv) override;
420 :
421 : virtual void
422 : GetStatusText(nsACString& aStatusText, ErrorResult& aRv) override;
423 :
424 : virtual void
425 : GetResponseHeader(const nsACString& aHeader, nsACString& aResult,
426 : ErrorResult& aRv) override;
427 :
428 : void
429 : GetResponseHeader(const nsAString& aHeader, nsAString& aResult,
430 : ErrorResult& aRv)
431 : {
432 : nsAutoCString result;
433 : GetResponseHeader(NS_ConvertUTF16toUTF8(aHeader), result, aRv);
434 : if (result.IsVoid()) {
435 : aResult.SetIsVoid(true);
436 : }
437 : else {
438 : // The result value should be inflated:
439 : CopyASCIItoUTF16(result, aResult);
440 : }
441 : }
442 :
443 : virtual void
444 : GetAllResponseHeaders(nsACString& aResponseHeaders,
445 : ErrorResult& aRv) override;
446 :
447 : bool IsSafeHeader(const nsACString& aHeaderName,
448 : NotNull<nsIHttpChannel*> aHttpChannel) const;
449 :
450 : virtual void
451 : OverrideMimeType(const nsAString& aMimeType, ErrorResult& aRv) override;
452 :
453 : virtual XMLHttpRequestResponseType
454 2 : ResponseType() const override
455 : {
456 2 : return XMLHttpRequestResponseType(mResponseType);
457 : }
458 :
459 : virtual void
460 : SetResponseType(XMLHttpRequestResponseType aType,
461 : ErrorResult& aRv) override;
462 :
463 : virtual void
464 : GetResponse(JSContext* aCx, JS::MutableHandle<JS::Value> aResponse,
465 : ErrorResult& aRv) override;
466 :
467 : virtual void
468 : GetResponseText(DOMString& aResponseText, ErrorResult& aRv) override;
469 :
470 : void
471 : GetResponseText(XMLHttpRequestStringSnapshot& aSnapshot,
472 : ErrorResult& aRv);
473 :
474 : virtual nsIDocument*
475 : GetResponseXML(ErrorResult& aRv) override;
476 :
477 : virtual bool
478 : MozBackgroundRequest() const override;
479 :
480 : virtual void
481 : SetMozBackgroundRequest(bool aMozBackgroundRequest, ErrorResult& aRv) override;
482 :
483 : virtual uint16_t
484 0 : ErrorCode() const override
485 : {
486 0 : return static_cast<uint16_t>(mErrorLoad);
487 : }
488 :
489 : virtual bool
490 : MozAnon() const override;
491 :
492 : virtual bool
493 : MozSystem() const override;
494 :
495 : virtual nsIChannel*
496 0 : GetChannel() const override
497 : {
498 0 : return mChannel;
499 : }
500 :
501 : virtual void
502 0 : GetNetworkInterfaceId(nsACString& aId) const override
503 : {
504 0 : aId = mNetworkInterfaceId;
505 0 : }
506 :
507 : virtual void
508 0 : SetNetworkInterfaceId(const nsACString& aId) override
509 : {
510 0 : mNetworkInterfaceId = aId;
511 0 : }
512 :
513 : // We need a GetInterface callable from JS for chrome JS
514 : virtual void
515 : GetInterface(JSContext* aCx, nsIJSID* aIID,
516 : JS::MutableHandle<JS::Value> aRetval,
517 : ErrorResult& aRv) override;
518 :
519 : // This fires a trusted readystatechange event, which is not cancelable and
520 : // doesn't bubble.
521 : nsresult FireReadystatechangeEvent();
522 : void DispatchProgressEvent(DOMEventTargetHelper* aTarget,
523 : const ProgressEventType aType,
524 : int64_t aLoaded, int64_t aTotal);
525 :
526 : // This is called by the factory constructor.
527 : nsresult Init();
528 :
529 : nsresult init(nsIPrincipal* principal,
530 : nsPIDOMWindowInner* globalObject,
531 : nsIURI* baseURI);
532 :
533 : void SetRequestObserver(nsIRequestObserver* aObserver);
534 :
535 65 : NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED(XMLHttpRequestMainThread,
536 : XMLHttpRequest)
537 : virtual bool IsCertainlyAliveForCC() const override;
538 :
539 : bool AllowUploadProgress();
540 :
541 : virtual void DisconnectFromOwner() override;
542 :
543 18 : static void SetDontWarnAboutSyncXHR(bool aVal)
544 : {
545 18 : sDontWarnAboutSyncXHR = aVal;
546 18 : }
547 9 : static bool DontWarnAboutSyncXHR()
548 : {
549 9 : return sDontWarnAboutSyncXHR;
550 : }
551 :
552 : virtual void
553 : SetOriginAttributes(const mozilla::dom::OriginAttributesDictionary& aAttrs) override;
554 :
555 : void BlobStoreCompleted(MutableBlobStorage* aBlobStorage,
556 : Blob* aBlob,
557 : nsresult aResult) override;
558 :
559 : void
560 : LocalFileToBlobCompleted(Blob* aBlob);
561 :
562 : protected:
563 : // XHR states are meant to mirror the XHR2 spec:
564 : // https://xhr.spec.whatwg.org/#states
565 : enum class State : uint8_t {
566 : unsent, // object has been constructed.
567 : opened, // open() has been successfully invoked.
568 : headers_received, // redirects followed and response headers received.
569 : loading, // response body is being received.
570 : done, // data transfer concluded, whether success or error.
571 : };
572 :
573 : nsresult DetectCharset();
574 : nsresult AppendToResponseText(const char * aBuffer, uint32_t aBufferLen);
575 : static nsresult StreamReaderFunc(nsIInputStream* in,
576 : void* closure,
577 : const char* fromRawSegment,
578 : uint32_t toOffset,
579 : uint32_t count,
580 : uint32_t *writeCount);
581 : nsresult CreateResponseParsedJSON(JSContext* aCx);
582 : void CreatePartialBlob(ErrorResult& aRv);
583 : // Change the state of the object with this. The broadcast argument
584 : // determines if the onreadystatechange listener should be called.
585 : nsresult ChangeState(State aState, bool aBroadcast = true);
586 : already_AddRefed<nsILoadGroup> GetLoadGroup() const;
587 : nsIURI *GetBaseURI();
588 :
589 : already_AddRefed<nsIHttpChannel> GetCurrentHttpChannel();
590 : already_AddRefed<nsIJARChannel> GetCurrentJARChannel();
591 :
592 : void TruncateResponseText();
593 :
594 : bool IsSystemXHR() const;
595 : bool InUploadPhase() const;
596 :
597 : void OnBodyParseEnd();
598 : void ChangeStateToDone();
599 :
600 : void StartProgressEventTimer();
601 : void StopProgressEventTimer();
602 :
603 : void MaybeCreateBlobStorage();
604 :
605 : nsresult OnRedirectVerifyCallback(nsresult result);
606 :
607 : void SetTimerEventTarget(nsITimer* aTimer);
608 :
609 : nsresult DispatchToMainThread(already_AddRefed<nsIRunnable> aRunnable);
610 :
611 : void DispatchOrStoreEvent(DOMEventTargetHelper* aTarget, Event* aEvent);
612 :
613 : already_AddRefed<nsXMLHttpRequestXPCOMifier> EnsureXPCOMifier();
614 :
615 : void SuspendEventDispatching();
616 : void ResumeEventDispatching();
617 :
618 0 : struct PendingEvent
619 : {
620 : RefPtr<DOMEventTargetHelper> mTarget;
621 : RefPtr<Event> mEvent;
622 : };
623 :
624 : nsTArray<PendingEvent> mPendingEvents;
625 :
626 : nsCOMPtr<nsISupports> mContext;
627 : nsCOMPtr<nsIPrincipal> mPrincipal;
628 : nsCOMPtr<nsIChannel> mChannel;
629 : nsCString mRequestMethod;
630 : nsCOMPtr<nsIURI> mRequestURL;
631 : nsCOMPtr<nsIDocument> mResponseXML;
632 :
633 : nsCOMPtr<nsIStreamListener> mXMLParserStreamListener;
634 :
635 : // used to implement getAllResponseHeaders()
636 : class nsHeaderVisitor : public nsIHttpHeaderVisitor
637 : {
638 0 : struct HeaderEntry final
639 : {
640 : nsCString mName;
641 : nsCString mValue;
642 :
643 0 : HeaderEntry(const nsACString& aName, const nsACString& aValue)
644 0 : : mName(aName), mValue(aValue)
645 0 : {}
646 :
647 : bool
648 0 : operator==(const HeaderEntry& aOther) const
649 : {
650 0 : return mName == aOther.mName;
651 : }
652 :
653 : bool
654 0 : operator<(const HeaderEntry& aOther) const
655 : {
656 0 : return mName < aOther.mName;
657 : }
658 : };
659 :
660 : public:
661 : NS_DECL_ISUPPORTS
662 : NS_DECL_NSIHTTPHEADERVISITOR
663 0 : nsHeaderVisitor(const XMLHttpRequestMainThread& aXMLHttpRequest,
664 : NotNull<nsIHttpChannel*> aHttpChannel)
665 0 : : mXHR(aXMLHttpRequest), mHttpChannel(aHttpChannel) {}
666 0 : const nsACString &Headers()
667 : {
668 0 : for (uint32_t i = 0; i < mHeaderList.Length(); i++) {
669 0 : HeaderEntry& header = mHeaderList.ElementAt(i);
670 :
671 0 : mHeaders.Append(header.mName);
672 0 : mHeaders.AppendLiteral(": ");
673 0 : mHeaders.Append(header.mValue);
674 0 : mHeaders.AppendLiteral("\r\n");
675 : }
676 0 : return mHeaders;
677 : }
678 :
679 : private:
680 0 : virtual ~nsHeaderVisitor() {}
681 :
682 : nsTArray<HeaderEntry> mHeaderList;
683 : nsCString mHeaders;
684 : const XMLHttpRequestMainThread& mXHR;
685 : NotNull<nsCOMPtr<nsIHttpChannel>> mHttpChannel;
686 : };
687 :
688 : // The bytes of our response body. Only used for DEFAULT, ARRAYBUFFER and
689 : // BLOB responseTypes
690 : nsCString mResponseBody;
691 :
692 : // The text version of our response body. This is incrementally decoded into
693 : // as we receive network data. However for the DEFAULT responseType we
694 : // lazily decode into this from mResponseBody only when .responseText is
695 : // accessed.
696 : // Only used for DEFAULT and TEXT responseTypes.
697 : XMLHttpRequestString mResponseText;
698 :
699 : // For DEFAULT responseType we use this to keep track of how far we've
700 : // lazily decoded from mResponseBody to mResponseText
701 : uint32_t mResponseBodyDecodedPos;
702 :
703 : // Decoder used for decoding into mResponseText
704 : // Only used for DEFAULT, TEXT and JSON responseTypes.
705 : // In cases where we've only received half a surrogate, the decoder itself
706 : // carries the state to remember this. Next time we receive more data we
707 : // simply feed the new data into the decoder which will handle the second
708 : // part of the surrogate.
709 : mozilla::UniquePtr<mozilla::Decoder> mDecoder;
710 :
711 : const Encoding* mResponseCharset;
712 :
713 : void MatchCharsetAndDecoderToResponseDocument();
714 :
715 : XMLHttpRequestResponseType mResponseType;
716 :
717 : // It is either a cached blob-response from the last call to GetResponse,
718 : // but is also explicitly set in OnStopRequest.
719 : RefPtr<Blob> mResponseBlob;
720 : // We stream data to mBlobStorage when response type is "blob".
721 : RefPtr<MutableBlobStorage> mBlobStorage;
722 : // We stream data to mBlobSet when response type is "moz-blob".
723 : nsAutoPtr<BlobSet> mBlobSet;
724 :
725 : nsString mOverrideMimeType;
726 :
727 : /**
728 : * The notification callbacks the channel had when Send() was
729 : * called. We want to forward things here as needed.
730 : */
731 : nsCOMPtr<nsIInterfaceRequestor> mNotificationCallbacks;
732 : /**
733 : * Sink interfaces that we implement that mNotificationCallbacks may
734 : * want to also be notified for. These are inited lazily if we're
735 : * asked for the relevant interface.
736 : */
737 : nsCOMPtr<nsIChannelEventSink> mChannelEventSink;
738 : nsCOMPtr<nsIProgressEventSink> mProgressEventSink;
739 :
740 : nsIRequestObserver* mRequestObserver;
741 :
742 : nsCOMPtr<nsIURI> mBaseURI;
743 : nsCOMPtr<nsILoadGroup> mLoadGroup;
744 :
745 : State mState;
746 :
747 : bool mFlagSynchronous;
748 : bool mFlagAborted;
749 : bool mFlagParseBody;
750 : bool mFlagSyncLooping;
751 : bool mFlagBackgroundRequest;
752 : bool mFlagHadUploadListenersOnSend;
753 : bool mFlagACwithCredentials;
754 : bool mFlagTimedOut;
755 : bool mFlagDeleted;
756 :
757 : // The XHR2 spec's send() flag. Set when the XHR begins uploading, until it
758 : // finishes downloading (or an error/abort has occurred during either phase).
759 : // Used to guard against the user trying to alter headers/etc when it's too
760 : // late, and ensure the XHR only handles one in-flight request at once.
761 : bool mFlagSend;
762 :
763 : RefPtr<XMLHttpRequestUpload> mUpload;
764 : int64_t mUploadTransferred;
765 : int64_t mUploadTotal;
766 : bool mUploadComplete;
767 : bool mProgressSinceLastProgressEvent;
768 :
769 : // Timeout support
770 : PRTime mRequestSentTime;
771 : uint32_t mTimeoutMilliseconds;
772 : nsCOMPtr<nsITimer> mTimeoutTimer;
773 : void StartTimeoutTimer();
774 : void HandleTimeoutCallback();
775 :
776 : nsCOMPtr<nsIDocument> mSuspendedDoc;
777 : nsCOMPtr<nsIRunnable> mResumeTimeoutRunnable;
778 :
779 : nsCOMPtr<nsITimer> mSyncTimeoutTimer;
780 :
781 : enum SyncTimeoutType {
782 : eErrorOrExpired,
783 : eTimerStarted,
784 : eNoTimerNeeded
785 : };
786 :
787 : SyncTimeoutType MaybeStartSyncTimeoutTimer();
788 : void HandleSyncTimeoutTimer();
789 : void CancelSyncTimeoutTimer();
790 :
791 : ErrorType mErrorLoad;
792 : bool mErrorParsingXML;
793 : bool mWaitingForOnStopRequest;
794 : bool mProgressTimerIsActive;
795 : bool mIsHtml;
796 : bool mWarnAboutSyncHtml;
797 : int64_t mLoadTotal; // -1 if not known.
798 : // Number of HTTP message body bytes received so far. This quantity is
799 : // in the same units as Content-Length and mLoadTotal, and hence counts
800 : // compressed bytes when the channel has gzip Content-Encoding. If the
801 : // channel does not have Content-Encoding, this will be the same as
802 : // mDataReceived except between the OnProgress that changes mLoadTransferred
803 : // and the corresponding OnDataAvailable (which changes mDataReceived).
804 : // Ordering of OnProgress and OnDataAvailable is undefined.
805 : int64_t mLoadTransferred;
806 : nsCOMPtr<nsITimer> mProgressNotifier;
807 : void HandleProgressTimerCallback();
808 :
809 : bool mIsSystem;
810 : bool mIsAnon;
811 :
812 : // A platform-specific identifer to represent the network interface
813 : // that this request is associated with.
814 : nsCString mNetworkInterfaceId;
815 :
816 : /**
817 : * Close the XMLHttpRequest's channels.
818 : */
819 : void CloseRequest();
820 :
821 : /**
822 : * Close the XMLHttpRequest's channels and dispatch appropriate progress
823 : * events.
824 : *
825 : * @param aType The progress event type.
826 : */
827 : void CloseRequestWithError(const ProgressEventType aType);
828 :
829 : bool mFirstStartRequestSeen;
830 : bool mInLoadProgressEvent;
831 :
832 : nsCOMPtr<nsIAsyncVerifyRedirectCallback> mRedirectCallback;
833 : nsCOMPtr<nsIChannel> mNewRedirectChannel;
834 :
835 : JS::Heap<JS::Value> mResultJSON;
836 :
837 : ArrayBufferBuilder mArrayBufferBuilder;
838 : JS::Heap<JSObject*> mResultArrayBuffer;
839 : bool mIsMappedArrayBuffer;
840 :
841 : void ResetResponse();
842 :
843 : bool ShouldBlockAuthPrompt();
844 :
845 : RequestHeaders mAuthorRequestHeaders;
846 :
847 : // Helper object to manage our XPCOM scriptability bits
848 : nsXMLHttpRequestXPCOMifier* mXPCOMifier;
849 :
850 : // When this is set to true, the event dispatching is suspended. This is
851 : // useful to change the correct state when XHR is working sync.
852 : bool mEventDispatchingSuspended;
853 :
854 : static bool sDontWarnAboutSyncXHR;
855 : };
856 :
857 : class MOZ_STACK_CLASS AutoDontWarnAboutSyncXHR
858 : {
859 : public:
860 9 : AutoDontWarnAboutSyncXHR() : mOldVal(XMLHttpRequestMainThread::DontWarnAboutSyncXHR())
861 : {
862 9 : XMLHttpRequestMainThread::SetDontWarnAboutSyncXHR(true);
863 9 : }
864 :
865 9 : ~AutoDontWarnAboutSyncXHR()
866 9 : {
867 9 : XMLHttpRequestMainThread::SetDontWarnAboutSyncXHR(mOldVal);
868 9 : }
869 :
870 : private:
871 : bool mOldVal;
872 : };
873 :
874 : // A shim class designed to expose the non-DOM interfaces of
875 : // XMLHttpRequest via XPCOM stuff.
876 : class nsXMLHttpRequestXPCOMifier final : public nsIStreamListener,
877 : public nsIChannelEventSink,
878 : public nsIAsyncVerifyRedirectCallback,
879 : public nsIProgressEventSink,
880 : public nsIInterfaceRequestor,
881 : public nsITimerCallback
882 : {
883 : NS_DECL_CYCLE_COLLECTING_ISUPPORTS
884 24 : NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(nsXMLHttpRequestXPCOMifier,
885 : nsIStreamListener)
886 :
887 2 : explicit nsXMLHttpRequestXPCOMifier(XMLHttpRequestMainThread* aXHR) :
888 2 : mXHR(aXHR)
889 : {
890 2 : }
891 :
892 : private:
893 4 : ~nsXMLHttpRequestXPCOMifier() {
894 2 : if (mXHR) {
895 2 : mXHR->mXPCOMifier = nullptr;
896 : }
897 2 : }
898 :
899 : public:
900 0 : NS_FORWARD_NSISTREAMLISTENER(mXHR->)
901 0 : NS_FORWARD_NSIREQUESTOBSERVER(mXHR->)
902 0 : NS_FORWARD_NSICHANNELEVENTSINK(mXHR->)
903 0 : NS_FORWARD_NSIASYNCVERIFYREDIRECTCALLBACK(mXHR->)
904 2 : NS_FORWARD_NSIPROGRESSEVENTSINK(mXHR->)
905 0 : NS_FORWARD_NSITIMERCALLBACK(mXHR->)
906 :
907 : NS_DECL_NSIINTERFACEREQUESTOR
908 :
909 : private:
910 : RefPtr<XMLHttpRequestMainThread> mXHR;
911 : };
912 :
913 : class nsXHRParseEndListener : public nsIDOMEventListener
914 : {
915 : public:
916 : NS_DECL_ISUPPORTS
917 0 : NS_IMETHOD HandleEvent(nsIDOMEvent *event) override
918 : {
919 0 : nsCOMPtr<nsIXMLHttpRequest> xhr = do_QueryReferent(mXHR);
920 0 : if (xhr) {
921 0 : static_cast<XMLHttpRequestMainThread*>(xhr.get())->OnBodyParseEnd();
922 : }
923 0 : mXHR = nullptr;
924 0 : return NS_OK;
925 : }
926 0 : explicit nsXHRParseEndListener(nsIXMLHttpRequest* aXHR)
927 0 : : mXHR(do_GetWeakReference(aXHR)) {}
928 : private:
929 0 : virtual ~nsXHRParseEndListener() {}
930 :
931 : nsWeakPtr mXHR;
932 : };
933 :
934 : } // dom namespace
935 : } // mozilla namespace
936 :
937 : #endif // mozilla_dom_XMLHttpRequestMainThread_h
|