Thu, 15 Jan 2015 21:03:48 +0100
Integrate friendly tips from Tor colleagues to make (or not) 4.5 alpha 3;
This includes removal of overloaded (but unused) methods, and addition of
a overlooked call to DataStruct::SetData(nsISupports, uint32_t, bool.)
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/. */
7 #ifndef nsXMLHttpRequest_h__
8 #define nsXMLHttpRequest_h__
10 #include "mozilla/Attributes.h"
11 #include "nsIXMLHttpRequest.h"
12 #include "nsISupportsUtils.h"
13 #include "nsString.h"
14 #include "nsIURI.h"
15 #include "nsIHttpChannel.h"
16 #include "nsIDocument.h"
17 #include "nsIContent.h"
18 #include "nsIStreamListener.h"
19 #include "nsWeakReference.h"
20 #include "nsIChannelEventSink.h"
21 #include "nsIAsyncVerifyRedirectCallback.h"
22 #include "nsIInterfaceRequestor.h"
23 #include "nsIHttpHeaderVisitor.h"
24 #include "nsIProgressEventSink.h"
25 #include "nsJSUtils.h"
26 #include "nsTArray.h"
27 #include "nsITimer.h"
28 #include "nsIPrincipal.h"
29 #include "nsIScriptObjectPrincipal.h"
30 #include "nsISizeOfEventTarget.h"
31 #include "nsIXPConnect.h"
32 #include "nsIInputStream.h"
33 #include "mozilla/Assertions.h"
34 #include "mozilla/DOMEventTargetHelper.h"
35 #include "mozilla/MemoryReporting.h"
36 #include "mozilla/dom/TypedArray.h"
37 #include "mozilla/dom/XMLHttpRequestBinding.h"
39 #ifdef Status
40 /* Xlib headers insist on this for some reason... Nuke it because
41 it'll override our member name */
42 #undef Status
43 #endif
45 class AsyncVerifyRedirectCallbackForwarder;
46 class BlobSet;
47 class nsDOMFile;
48 class nsFormData;
49 class nsIJARChannel;
50 class nsILoadGroup;
51 class nsIUnicodeDecoder;
52 class nsIJSID;
54 namespace mozilla {
56 // A helper for building up an ArrayBuffer object's data
57 // before creating the ArrayBuffer itself. Will do doubling
58 // based reallocation, up to an optional maximum growth given.
59 //
60 // When all the data has been appended, call getArrayBuffer,
61 // passing in the JSContext* for which the ArrayBuffer object
62 // is to be created. This also implicitly resets the builder,
63 // or it can be reset explicitly at any point by calling reset().
64 class ArrayBufferBuilder
65 {
66 uint8_t* mDataPtr;
67 uint32_t mCapacity;
68 uint32_t mLength;
69 public:
70 ArrayBufferBuilder();
71 ~ArrayBufferBuilder();
73 void reset();
75 // Will truncate if aNewCap is < length().
76 bool setCapacity(uint32_t aNewCap);
78 // Append aDataLen bytes from data to the current buffer. If we
79 // need to grow the buffer, grow by doubling the size up to a
80 // maximum of aMaxGrowth (if given). If aDataLen is greater than
81 // what the new capacity would end up as, then grow by aDataLen.
82 //
83 // The data parameter must not overlap with anything beyond the
84 // builder's current valid contents [0..length)
85 bool append(const uint8_t* aNewData, uint32_t aDataLen,
86 uint32_t aMaxGrowth = 0);
88 uint32_t length() { return mLength; }
89 uint32_t capacity() { return mCapacity; }
91 JSObject* getArrayBuffer(JSContext* aCx);
93 protected:
94 static bool areOverlappingRegions(const uint8_t* aStart1, uint32_t aLength1,
95 const uint8_t* aStart2, uint32_t aLength2);
96 };
98 } // namespace mozilla
100 class nsXHREventTarget : public mozilla::DOMEventTargetHelper,
101 public nsIXMLHttpRequestEventTarget
102 {
103 protected:
104 nsXHREventTarget(mozilla::DOMEventTargetHelper* aOwner)
105 : mozilla::DOMEventTargetHelper(aOwner)
106 {
107 }
109 nsXHREventTarget()
110 {
111 }
113 public:
114 typedef mozilla::dom::XMLHttpRequestResponseType
115 XMLHttpRequestResponseType;
116 typedef mozilla::ErrorResult
117 ErrorResult;
119 virtual ~nsXHREventTarget() {}
120 NS_DECL_ISUPPORTS_INHERITED
121 NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(nsXHREventTarget,
122 mozilla::DOMEventTargetHelper)
123 NS_DECL_NSIXMLHTTPREQUESTEVENTTARGET
124 NS_REALLY_FORWARD_NSIDOMEVENTTARGET(mozilla::DOMEventTargetHelper)
126 IMPL_EVENT_HANDLER(loadstart)
127 IMPL_EVENT_HANDLER(progress)
128 IMPL_EVENT_HANDLER(abort)
129 IMPL_EVENT_HANDLER(error)
130 IMPL_EVENT_HANDLER(load)
131 IMPL_EVENT_HANDLER(timeout)
132 IMPL_EVENT_HANDLER(loadend)
134 virtual void DisconnectFromOwner();
135 };
137 class nsXMLHttpRequestUpload MOZ_FINAL : public nsXHREventTarget,
138 public nsIXMLHttpRequestUpload
139 {
140 public:
141 nsXMLHttpRequestUpload(mozilla::DOMEventTargetHelper* aOwner)
142 : nsXHREventTarget(aOwner)
143 {
144 }
146 NS_DECL_ISUPPORTS_INHERITED
147 NS_FORWARD_NSIXMLHTTPREQUESTEVENTTARGET(nsXHREventTarget::)
148 NS_REALLY_FORWARD_NSIDOMEVENTTARGET(nsXHREventTarget)
149 NS_DECL_NSIXMLHTTPREQUESTUPLOAD
151 virtual JSObject* WrapObject(JSContext *cx) MOZ_OVERRIDE;
152 nsISupports* GetParentObject()
153 {
154 return GetOwner();
155 }
157 bool HasListeners()
158 {
159 return mListenerManager && mListenerManager->HasListeners();
160 }
161 };
163 class nsXMLHttpRequestXPCOMifier;
165 // Make sure that any non-DOM interfaces added here are also added to
166 // nsXMLHttpRequestXPCOMifier.
167 class nsXMLHttpRequest : public nsXHREventTarget,
168 public nsIXMLHttpRequest,
169 public nsIJSXMLHttpRequest,
170 public nsIStreamListener,
171 public nsIChannelEventSink,
172 public nsIProgressEventSink,
173 public nsIInterfaceRequestor,
174 public nsSupportsWeakReference,
175 public nsITimerCallback,
176 public nsISizeOfEventTarget
177 {
178 friend class nsXHRParseEndListener;
179 friend class nsXMLHttpRequestXPCOMifier;
181 public:
182 nsXMLHttpRequest();
183 virtual ~nsXMLHttpRequest();
185 virtual JSObject* WrapObject(JSContext *cx) MOZ_OVERRIDE
186 {
187 return mozilla::dom::XMLHttpRequestBinding::Wrap(cx, this);
188 }
189 nsISupports* GetParentObject()
190 {
191 return GetOwner();
192 }
194 // The WebIDL constructors.
195 static already_AddRefed<nsXMLHttpRequest>
196 Constructor(const mozilla::dom::GlobalObject& aGlobal,
197 JSContext* aCx,
198 const mozilla::dom::MozXMLHttpRequestParameters& aParams,
199 ErrorResult& aRv)
200 {
201 nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(aGlobal.GetAsSupports());
202 nsCOMPtr<nsIScriptObjectPrincipal> principal =
203 do_QueryInterface(aGlobal.GetAsSupports());
204 if (!global || ! principal) {
205 aRv.Throw(NS_ERROR_FAILURE);
206 return nullptr;
207 }
209 nsRefPtr<nsXMLHttpRequest> req = new nsXMLHttpRequest();
210 req->Construct(principal->GetPrincipal(), global);
211 req->InitParameters(aParams.mMozAnon, aParams.mMozSystem);
212 return req.forget();
213 }
215 static already_AddRefed<nsXMLHttpRequest>
216 Constructor(const mozilla::dom::GlobalObject& aGlobal,
217 JSContext* aCx,
218 const nsAString& ignored,
219 ErrorResult& aRv)
220 {
221 // Pretend like someone passed null, so we can pick up the default values
222 mozilla::dom::MozXMLHttpRequestParameters params;
223 if (!params.Init(aCx, JS::NullHandleValue)) {
224 aRv.Throw(NS_ERROR_UNEXPECTED);
225 return nullptr;
226 }
228 return Constructor(aGlobal, aCx, params, aRv);
229 }
231 void Construct(nsIPrincipal* aPrincipal,
232 nsIGlobalObject* aGlobalObject,
233 nsIURI* aBaseURI = nullptr)
234 {
235 MOZ_ASSERT(aPrincipal);
236 MOZ_ASSERT_IF(nsCOMPtr<nsPIDOMWindow> win = do_QueryInterface(
237 aGlobalObject), win->IsInnerWindow());
238 mPrincipal = aPrincipal;
239 BindToOwner(aGlobalObject);
240 mBaseURI = aBaseURI;
241 }
243 void InitParameters(bool aAnon, bool aSystem);
245 void SetParameters(bool aAnon, bool aSystem)
246 {
247 mIsAnon = aAnon || aSystem;
248 mIsSystem = aSystem;
249 }
251 NS_DECL_ISUPPORTS_INHERITED
253 // nsIXMLHttpRequest
254 NS_DECL_NSIXMLHTTPREQUEST
256 NS_FORWARD_NSIXMLHTTPREQUESTEVENTTARGET(nsXHREventTarget::)
258 // nsIStreamListener
259 NS_DECL_NSISTREAMLISTENER
261 // nsIRequestObserver
262 NS_DECL_NSIREQUESTOBSERVER
264 // nsIChannelEventSink
265 NS_DECL_NSICHANNELEVENTSINK
267 // nsIProgressEventSink
268 NS_DECL_NSIPROGRESSEVENTSINK
270 // nsIInterfaceRequestor
271 NS_DECL_NSIINTERFACEREQUESTOR
273 // nsITimerCallback
274 NS_DECL_NSITIMERCALLBACK
276 // nsISizeOfEventTarget
277 virtual size_t
278 SizeOfEventTargetIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const;
280 NS_REALLY_FORWARD_NSIDOMEVENTTARGET(nsXHREventTarget)
282 #ifdef DEBUG
283 void StaticAssertions();
284 #endif
286 // event handler
287 IMPL_EVENT_HANDLER(readystatechange)
289 // states
290 uint16_t ReadyState();
292 // request
293 void Open(const nsACString& aMethod, const nsAString& aUrl, ErrorResult& aRv)
294 {
295 Open(aMethod, aUrl, true,
296 mozilla::dom::Optional<nsAString>(),
297 mozilla::dom::Optional<nsAString>(),
298 aRv);
299 }
300 void Open(const nsACString& aMethod, const nsAString& aUrl, bool aAsync,
301 const mozilla::dom::Optional<nsAString>& aUser,
302 const mozilla::dom::Optional<nsAString>& aPassword,
303 ErrorResult& aRv)
304 {
305 aRv = Open(aMethod, NS_ConvertUTF16toUTF8(aUrl),
306 aAsync, aUser, aPassword);
307 }
308 void SetRequestHeader(const nsACString& aHeader, const nsACString& aValue,
309 ErrorResult& aRv)
310 {
311 aRv = SetRequestHeader(aHeader, aValue);
312 }
313 uint32_t Timeout()
314 {
315 return mTimeoutMilliseconds;
316 }
317 void SetTimeout(uint32_t aTimeout, ErrorResult& aRv);
318 bool WithCredentials();
319 void SetWithCredentials(bool aWithCredentials, ErrorResult& aRv);
320 nsXMLHttpRequestUpload* Upload();
322 private:
323 class RequestBody
324 {
325 public:
326 RequestBody() : mType(Uninitialized)
327 {
328 }
329 RequestBody(const mozilla::dom::ArrayBuffer* aArrayBuffer) : mType(ArrayBuffer)
330 {
331 mValue.mArrayBuffer = aArrayBuffer;
332 }
333 RequestBody(const mozilla::dom::ArrayBufferView* aArrayBufferView) : mType(ArrayBufferView)
334 {
335 mValue.mArrayBufferView = aArrayBufferView;
336 }
337 RequestBody(nsIDOMBlob* aBlob) : mType(Blob)
338 {
339 mValue.mBlob = aBlob;
340 }
341 RequestBody(nsIDocument* aDocument) : mType(Document)
342 {
343 mValue.mDocument = aDocument;
344 }
345 RequestBody(const nsAString& aString) : mType(DOMString)
346 {
347 mValue.mString = &aString;
348 }
349 RequestBody(nsFormData& aFormData) : mType(FormData)
350 {
351 mValue.mFormData = &aFormData;
352 }
353 RequestBody(nsIInputStream* aStream) : mType(InputStream)
354 {
355 mValue.mStream = aStream;
356 }
358 enum Type {
359 Uninitialized,
360 ArrayBuffer,
361 ArrayBufferView,
362 Blob,
363 Document,
364 DOMString,
365 FormData,
366 InputStream
367 };
368 union Value {
369 const mozilla::dom::ArrayBuffer* mArrayBuffer;
370 const mozilla::dom::ArrayBufferView* mArrayBufferView;
371 nsIDOMBlob* mBlob;
372 nsIDocument* mDocument;
373 const nsAString* mString;
374 nsFormData* mFormData;
375 nsIInputStream* mStream;
376 };
378 Type GetType() const
379 {
380 MOZ_ASSERT(mType != Uninitialized);
381 return mType;
382 }
383 Value GetValue() const
384 {
385 MOZ_ASSERT(mType != Uninitialized);
386 return mValue;
387 }
389 private:
390 Type mType;
391 Value mValue;
392 };
394 static nsresult GetRequestBody(nsIVariant* aVariant,
395 const Nullable<RequestBody>& aBody,
396 nsIInputStream** aResult,
397 uint64_t* aContentLength,
398 nsACString& aContentType,
399 nsACString& aCharset);
401 nsresult Send(nsIVariant* aVariant, const Nullable<RequestBody>& aBody);
402 nsresult Send(const Nullable<RequestBody>& aBody)
403 {
404 return Send(nullptr, aBody);
405 }
406 nsresult Send(const RequestBody& aBody)
407 {
408 return Send(Nullable<RequestBody>(aBody));
409 }
411 public:
412 void Send(JSContext* /*aCx*/, ErrorResult& aRv)
413 {
414 aRv = Send(Nullable<RequestBody>());
415 }
416 void Send(JSContext* /*aCx*/,
417 const mozilla::dom::ArrayBuffer& aArrayBuffer,
418 ErrorResult& aRv)
419 {
420 aRv = Send(RequestBody(&aArrayBuffer));
421 }
422 void Send(JSContext* /*aCx*/,
423 const mozilla::dom::ArrayBufferView& aArrayBufferView,
424 ErrorResult& aRv)
425 {
426 aRv = Send(RequestBody(&aArrayBufferView));
427 }
428 void Send(JSContext* /*aCx*/, nsIDOMBlob* aBlob, ErrorResult& aRv)
429 {
430 NS_ASSERTION(aBlob, "Null should go to string version");
431 aRv = Send(RequestBody(aBlob));
432 }
433 void Send(JSContext* /*aCx*/, nsIDocument& aDoc, ErrorResult& aRv)
434 {
435 aRv = Send(RequestBody(&aDoc));
436 }
437 void Send(JSContext* aCx, const nsAString& aString, ErrorResult& aRv)
438 {
439 if (DOMStringIsNull(aString)) {
440 Send(aCx, aRv);
441 }
442 else {
443 aRv = Send(RequestBody(aString));
444 }
445 }
446 void Send(JSContext* /*aCx*/, nsFormData& aFormData, ErrorResult& aRv)
447 {
448 aRv = Send(RequestBody(aFormData));
449 }
450 void Send(JSContext* aCx, nsIInputStream* aStream, ErrorResult& aRv)
451 {
452 NS_ASSERTION(aStream, "Null should go to string version");
453 nsCOMPtr<nsIXPConnectWrappedJS> wjs = do_QueryInterface(aStream);
454 if (wjs) {
455 JSObject* data = wjs->GetJSObject();
456 if (!data) {
457 aRv.Throw(NS_ERROR_DOM_TYPE_ERR);
458 return;
459 }
460 JS::Rooted<JS::Value> dataAsValue(aCx, JS::ObjectValue(*data));
461 mozilla::dom::binding_detail::FakeDependentString dataAsString;
462 if (ConvertJSValueToString(aCx, dataAsValue, &dataAsValue, mozilla::dom::eNull,
463 mozilla::dom::eNull, dataAsString)) {
464 Send(aCx, dataAsString, aRv);
465 } else {
466 aRv.Throw(NS_ERROR_FAILURE);
467 }
468 return;
469 }
470 aRv = Send(RequestBody(aStream));
471 }
472 void SendAsBinary(const nsAString& aBody, ErrorResult& aRv);
474 void Abort();
476 // response
477 uint32_t Status();
478 void GetStatusText(nsCString& aStatusText);
479 void GetResponseHeader(const nsACString& aHeader, nsACString& aResult,
480 ErrorResult& aRv);
481 void GetResponseHeader(const nsAString& aHeader, nsString& aResult,
482 ErrorResult& aRv)
483 {
484 nsCString result;
485 GetResponseHeader(NS_ConvertUTF16toUTF8(aHeader), result, aRv);
486 if (result.IsVoid()) {
487 aResult.SetIsVoid(true);
488 }
489 else {
490 // The result value should be inflated:
491 CopyASCIItoUTF16(result, aResult);
492 }
493 }
494 void GetAllResponseHeaders(nsCString& aResponseHeaders);
495 bool IsSafeHeader(const nsACString& aHeaderName, nsIHttpChannel* aHttpChannel);
496 void OverrideMimeType(const nsAString& aMimeType)
497 {
498 // XXX Should we do some validation here?
499 mOverrideMimeType = aMimeType;
500 }
501 XMLHttpRequestResponseType ResponseType()
502 {
503 return XMLHttpRequestResponseType(mResponseType);
504 }
505 void SetResponseType(XMLHttpRequestResponseType aType, ErrorResult& aRv);
506 void GetResponse(JSContext* aCx, JS::MutableHandle<JS::Value> aResponse,
507 ErrorResult& aRv);
508 void GetResponseText(nsString& aResponseText, ErrorResult& aRv);
509 nsIDocument* GetResponseXML(ErrorResult& aRv);
511 bool MozBackgroundRequest();
512 void SetMozBackgroundRequest(bool aMozBackgroundRequest, nsresult& aRv);
514 bool MozAnon();
515 bool MozSystem();
517 nsIChannel* GetChannel()
518 {
519 return mChannel;
520 }
522 // We need a GetInterface callable from JS for chrome JS
523 void GetInterface(JSContext* aCx, nsIJSID* aIID,
524 JS::MutableHandle<JS::Value> aRetval, ErrorResult& aRv);
526 // This creates a trusted readystatechange event, which is not cancelable and
527 // doesn't bubble.
528 nsresult CreateReadystatechangeEvent(nsIDOMEvent** aDOMEvent);
529 void DispatchProgressEvent(mozilla::DOMEventTargetHelper* aTarget,
530 const nsAString& aType,
531 bool aLengthComputable,
532 uint64_t aLoaded, uint64_t aTotal);
534 // Dispatch the "progress" event on the XHR or XHR.upload object if we've
535 // received data since the last "progress" event. Also dispatches
536 // "uploadprogress" as needed.
537 void MaybeDispatchProgressEvents(bool aFinalProgress);
539 // This is called by the factory constructor.
540 nsresult Init();
542 nsresult init(nsIPrincipal* principal,
543 nsIScriptContext* scriptContext,
544 nsPIDOMWindow* globalObject,
545 nsIURI* baseURI);
547 void SetRequestObserver(nsIRequestObserver* aObserver);
549 NS_DECL_CYCLE_COLLECTION_SKIPPABLE_SCRIPT_HOLDER_CLASS_INHERITED(nsXMLHttpRequest,
550 nsXHREventTarget)
551 bool AllowUploadProgress();
552 void RootJSResultObjects();
554 virtual void DisconnectFromOwner() MOZ_OVERRIDE;
556 static void SetDontWarnAboutSyncXHR(bool aVal)
557 {
558 sDontWarnAboutSyncXHR = aVal;
559 }
560 static bool DontWarnAboutSyncXHR()
561 {
562 return sDontWarnAboutSyncXHR;
563 }
564 protected:
565 nsresult DetectCharset();
566 nsresult AppendToResponseText(const char * aBuffer, uint32_t aBufferLen);
567 static NS_METHOD StreamReaderFunc(nsIInputStream* in,
568 void* closure,
569 const char* fromRawSegment,
570 uint32_t toOffset,
571 uint32_t count,
572 uint32_t *writeCount);
573 nsresult CreateResponseParsedJSON(JSContext* aCx);
574 void CreatePartialBlob();
575 bool CreateDOMFile(nsIRequest *request);
576 // Change the state of the object with this. The broadcast argument
577 // determines if the onreadystatechange listener should be called.
578 nsresult ChangeState(uint32_t aState, bool aBroadcast = true);
579 already_AddRefed<nsILoadGroup> GetLoadGroup() const;
580 nsIURI *GetBaseURI();
582 already_AddRefed<nsIHttpChannel> GetCurrentHttpChannel();
583 already_AddRefed<nsIJARChannel> GetCurrentJARChannel();
585 bool IsSystemXHR();
587 void ChangeStateToDone();
589 /**
590 * Check if aChannel is ok for a cross-site request by making sure no
591 * inappropriate headers are set, and no username/password is set.
592 *
593 * Also updates the XML_HTTP_REQUEST_USE_XSITE_AC bit.
594 */
595 nsresult CheckChannelForCrossSiteRequest(nsIChannel* aChannel);
597 void StartProgressEventTimer();
599 friend class AsyncVerifyRedirectCallbackForwarder;
600 void OnRedirectVerifyCallback(nsresult result);
602 nsresult Open(const nsACString& method, const nsACString& url, bool async,
603 const mozilla::dom::Optional<nsAString>& user,
604 const mozilla::dom::Optional<nsAString>& password);
606 already_AddRefed<nsXMLHttpRequestXPCOMifier> EnsureXPCOMifier();
608 nsCOMPtr<nsISupports> mContext;
609 nsCOMPtr<nsIPrincipal> mPrincipal;
610 nsCOMPtr<nsIChannel> mChannel;
611 nsCOMPtr<nsIDocument> mResponseXML;
612 nsCOMPtr<nsIChannel> mCORSPreflightChannel;
613 nsTArray<nsCString> mCORSUnsafeHeaders;
615 nsCOMPtr<nsIStreamListener> mXMLParserStreamListener;
617 // used to implement getAllResponseHeaders()
618 class nsHeaderVisitor : public nsIHttpHeaderVisitor {
619 public:
620 NS_DECL_ISUPPORTS
621 NS_DECL_NSIHTTPHEADERVISITOR
622 nsHeaderVisitor(nsXMLHttpRequest* aXMLHttpRequest, nsIHttpChannel* aHttpChannel)
623 : mXHR(aXMLHttpRequest), mHttpChannel(aHttpChannel) {}
624 virtual ~nsHeaderVisitor() {}
625 const nsACString &Headers() { return mHeaders; }
626 private:
627 nsCString mHeaders;
628 nsXMLHttpRequest* mXHR;
629 nsCOMPtr<nsIHttpChannel> mHttpChannel;
630 };
632 // The bytes of our response body. Only used for DEFAULT, ARRAYBUFFER and
633 // BLOB responseTypes
634 nsCString mResponseBody;
636 // The text version of our response body. This is incrementally decoded into
637 // as we receive network data. However for the DEFAULT responseType we
638 // lazily decode into this from mResponseBody only when .responseText is
639 // accessed.
640 // Only used for DEFAULT and TEXT responseTypes.
641 nsString mResponseText;
643 // For DEFAULT responseType we use this to keep track of how far we've
644 // lazily decoded from mResponseBody to mResponseText
645 uint32_t mResponseBodyDecodedPos;
647 // Decoder used for decoding into mResponseText
648 // Only used for DEFAULT, TEXT and JSON responseTypes.
649 // In cases where we've only received half a surrogate, the decoder itself
650 // carries the state to remember this. Next time we receive more data we
651 // simply feed the new data into the decoder which will handle the second
652 // part of the surrogate.
653 nsCOMPtr<nsIUnicodeDecoder> mDecoder;
655 nsCString mResponseCharset;
657 enum ResponseTypeEnum {
658 XML_HTTP_RESPONSE_TYPE_DEFAULT,
659 XML_HTTP_RESPONSE_TYPE_ARRAYBUFFER,
660 XML_HTTP_RESPONSE_TYPE_BLOB,
661 XML_HTTP_RESPONSE_TYPE_DOCUMENT,
662 XML_HTTP_RESPONSE_TYPE_JSON,
663 XML_HTTP_RESPONSE_TYPE_TEXT,
664 XML_HTTP_RESPONSE_TYPE_CHUNKED_TEXT,
665 XML_HTTP_RESPONSE_TYPE_CHUNKED_ARRAYBUFFER,
666 XML_HTTP_RESPONSE_TYPE_MOZ_BLOB
667 };
669 void SetResponseType(nsXMLHttpRequest::ResponseTypeEnum aType, ErrorResult& aRv);
671 ResponseTypeEnum mResponseType;
673 // It is either a cached blob-response from the last call to GetResponse,
674 // but is also explicitly set in OnStopRequest.
675 nsCOMPtr<nsIDOMBlob> mResponseBlob;
676 // Non-null only when we are able to get a os-file representation of the
677 // response, i.e. when loading from a file.
678 nsRefPtr<nsDOMFile> mDOMFile;
679 // We stream data to mBlobSet when response type is "blob" or "moz-blob"
680 // and mDOMFile is null.
681 nsAutoPtr<BlobSet> mBlobSet;
683 nsString mOverrideMimeType;
685 /**
686 * The notification callbacks the channel had when Send() was
687 * called. We want to forward things here as needed.
688 */
689 nsCOMPtr<nsIInterfaceRequestor> mNotificationCallbacks;
690 /**
691 * Sink interfaces that we implement that mNotificationCallbacks may
692 * want to also be notified for. These are inited lazily if we're
693 * asked for the relevant interface.
694 */
695 nsCOMPtr<nsIChannelEventSink> mChannelEventSink;
696 nsCOMPtr<nsIProgressEventSink> mProgressEventSink;
698 nsIRequestObserver* mRequestObserver;
700 nsCOMPtr<nsIURI> mBaseURI;
702 uint32_t mState;
704 nsRefPtr<nsXMLHttpRequestUpload> mUpload;
705 uint64_t mUploadTransferred;
706 uint64_t mUploadTotal;
707 bool mUploadLengthComputable;
708 bool mUploadComplete;
709 bool mProgressSinceLastProgressEvent;
711 // Timeout support
712 PRTime mRequestSentTime;
713 uint32_t mTimeoutMilliseconds;
714 nsCOMPtr<nsITimer> mTimeoutTimer;
715 void StartTimeoutTimer();
716 void HandleTimeoutCallback();
718 bool mErrorLoad;
719 bool mWaitingForOnStopRequest;
720 bool mProgressTimerIsActive;
721 bool mIsHtml;
722 bool mWarnAboutMultipartHtml;
723 bool mWarnAboutSyncHtml;
724 bool mLoadLengthComputable;
725 uint64_t mLoadTotal; // 0 if not known.
726 uint64_t mLoadTransferred;
727 nsCOMPtr<nsITimer> mProgressNotifier;
728 void HandleProgressTimerCallback();
730 bool mIsSystem;
731 bool mIsAnon;
733 /**
734 * Close the XMLHttpRequest's channels and dispatch appropriate progress
735 * events.
736 *
737 * @param aType The progress event type.
738 * @param aFlag A XML_HTTP_REQUEST_* state flag defined in
739 * nsXMLHttpRequest.cpp.
740 */
741 void CloseRequestWithError(const nsAString& aType, const uint32_t aFlag);
743 bool mFirstStartRequestSeen;
744 bool mInLoadProgressEvent;
746 nsCOMPtr<nsIAsyncVerifyRedirectCallback> mRedirectCallback;
747 nsCOMPtr<nsIChannel> mNewRedirectChannel;
749 JS::Heap<JS::Value> mResultJSON;
751 mozilla::ArrayBufferBuilder mArrayBufferBuilder;
752 JS::Heap<JSObject*> mResultArrayBuffer;
754 void ResetResponse();
756 struct RequestHeader
757 {
758 nsCString header;
759 nsCString value;
760 };
761 nsTArray<RequestHeader> mModifiedRequestHeaders;
763 nsTHashtable<nsCStringHashKey> mAlreadySetHeaders;
765 // Helper object to manage our XPCOM scriptability bits
766 nsXMLHttpRequestXPCOMifier* mXPCOMifier;
768 static bool sDontWarnAboutSyncXHR;
769 };
771 class MOZ_STACK_CLASS AutoDontWarnAboutSyncXHR
772 {
773 public:
774 AutoDontWarnAboutSyncXHR() : mOldVal(nsXMLHttpRequest::DontWarnAboutSyncXHR())
775 {
776 nsXMLHttpRequest::SetDontWarnAboutSyncXHR(true);
777 }
779 ~AutoDontWarnAboutSyncXHR()
780 {
781 nsXMLHttpRequest::SetDontWarnAboutSyncXHR(mOldVal);
782 }
784 private:
785 bool mOldVal;
786 };
788 // A shim class designed to expose the non-DOM interfaces of
789 // XMLHttpRequest via XPCOM stuff.
790 class nsXMLHttpRequestXPCOMifier MOZ_FINAL : public nsIStreamListener,
791 public nsIChannelEventSink,
792 public nsIProgressEventSink,
793 public nsIInterfaceRequestor,
794 public nsITimerCallback
795 {
796 NS_DECL_CYCLE_COLLECTING_ISUPPORTS
797 NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(nsXMLHttpRequestXPCOMifier,
798 nsIStreamListener)
800 nsXMLHttpRequestXPCOMifier(nsXMLHttpRequest* aXHR) :
801 mXHR(aXHR)
802 {
803 }
805 ~nsXMLHttpRequestXPCOMifier() {
806 if (mXHR) {
807 mXHR->mXPCOMifier = nullptr;
808 }
809 }
811 NS_FORWARD_NSISTREAMLISTENER(mXHR->)
812 NS_FORWARD_NSIREQUESTOBSERVER(mXHR->)
813 NS_FORWARD_NSICHANNELEVENTSINK(mXHR->)
814 NS_FORWARD_NSIPROGRESSEVENTSINK(mXHR->)
815 NS_FORWARD_NSITIMERCALLBACK(mXHR->)
817 NS_DECL_NSIINTERFACEREQUESTOR
819 private:
820 nsRefPtr<nsXMLHttpRequest> mXHR;
821 };
823 class nsXHRParseEndListener : public nsIDOMEventListener
824 {
825 public:
826 NS_DECL_ISUPPORTS
827 NS_IMETHOD HandleEvent(nsIDOMEvent *event) MOZ_OVERRIDE
828 {
829 nsCOMPtr<nsIXMLHttpRequest> xhr = do_QueryReferent(mXHR);
830 if (xhr) {
831 static_cast<nsXMLHttpRequest*>(xhr.get())->ChangeStateToDone();
832 }
833 mXHR = nullptr;
834 return NS_OK;
835 }
836 nsXHRParseEndListener(nsIXMLHttpRequest* aXHR)
837 : mXHR(do_GetWeakReference(aXHR)) {}
838 virtual ~nsXHRParseEndListener() {}
839 private:
840 nsWeakPtr mXHR;
841 };
843 #endif