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