1 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* ***** BEGIN LICENSE BLOCK *****
3 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4 : *
5 : * The contents of this file are subject to the Mozilla Public License Version
6 : * 1.1 (the "License"); you may not use this file except in compliance with
7 : * the License. You may obtain a copy of the License at
8 : * http://www.mozilla.org/MPL/
9 : *
10 : * Software distributed under the License is distributed on an "AS IS" basis,
11 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 : * for the specific language governing rights and limitations under the
13 : * License.
14 : *
15 : * The Original Code is mozilla.org code.
16 : *
17 : * The Initial Developer of the Original Code is
18 : * Netscape Communications Corporation.
19 : * Portions created by the Initial Developer are Copyright (C) 1998
20 : * the Initial Developer. All Rights Reserved.
21 : *
22 : * Contributor(s):
23 : *
24 : * Alternatively, the contents of this file may be used under the terms of
25 : * either the GNU General Public License Version 2 or later (the "GPL"), or
26 : * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
27 : * in which case the provisions of the GPL or the LGPL are applicable instead
28 : * of those above. If you wish to allow use of your version of this file only
29 : * under the terms of either the GPL or the LGPL, and not to allow others to
30 : * use your version of this file under the terms of the MPL, indicate your
31 : * decision by deleting the provisions above and replace them with the notice
32 : * and other provisions required by the GPL or the LGPL. If you do not delete
33 : * the provisions above, a recipient may use your version of this file under
34 : * the terms of any one of the MPL, the GPL or the LGPL.
35 : *
36 : * ***** END LICENSE BLOCK ***** */
37 :
38 : #ifndef nsXMLHttpRequest_h__
39 : #define nsXMLHttpRequest_h__
40 :
41 : #include "nsIXMLHttpRequest.h"
42 : #include "nsISupportsUtils.h"
43 : #include "nsString.h"
44 : #include "nsIDOMDocument.h"
45 : #include "nsIURI.h"
46 : #include "nsIHttpChannel.h"
47 : #include "nsIDocument.h"
48 : #include "nsIStreamListener.h"
49 : #include "nsWeakReference.h"
50 : #include "jsapi.h"
51 : #include "nsIScriptContext.h"
52 : #include "nsIChannelEventSink.h"
53 : #include "nsIAsyncVerifyRedirectCallback.h"
54 : #include "nsIInterfaceRequestor.h"
55 : #include "nsIHttpHeaderVisitor.h"
56 : #include "nsIProgressEventSink.h"
57 : #include "nsCOMArray.h"
58 : #include "nsJSUtils.h"
59 : #include "nsTArray.h"
60 : #include "nsIJSNativeInitializer.h"
61 : #include "nsIDOMLSProgressEvent.h"
62 : #include "nsIDOMNSEvent.h"
63 : #include "nsITimer.h"
64 : #include "nsIPrivateDOMEvent.h"
65 : #include "nsDOMProgressEvent.h"
66 : #include "nsDOMEventTargetHelper.h"
67 : #include "nsContentUtils.h"
68 : #include "nsDOMFile.h"
69 : #include "nsDOMBlobBuilder.h"
70 :
71 : class nsILoadGroup;
72 : class AsyncVerifyRedirectCallbackForwarder;
73 : class nsIUnicodeDecoder;
74 :
75 : class nsXHREventTarget : public nsDOMEventTargetHelper,
76 : public nsIXMLHttpRequestEventTarget
77 596 : {
78 : public:
79 1192 : virtual ~nsXHREventTarget() {}
80 : NS_DECL_ISUPPORTS_INHERITED
81 3408 : NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(nsXHREventTarget,
82 : nsDOMEventTargetHelper)
83 : NS_DECL_NSIXMLHTTPREQUESTEVENTTARGET
84 33178 : NS_FORWARD_NSIDOMEVENTTARGET(nsDOMEventTargetHelper::)
85 :
86 : virtual void DisconnectFromOwner();
87 : protected:
88 : nsRefPtr<nsDOMEventListenerWrapper> mOnLoadListener;
89 : nsRefPtr<nsDOMEventListenerWrapper> mOnErrorListener;
90 : nsRefPtr<nsDOMEventListenerWrapper> mOnAbortListener;
91 : nsRefPtr<nsDOMEventListenerWrapper> mOnLoadStartListener;
92 : nsRefPtr<nsDOMEventListenerWrapper> mOnProgressListener;
93 : nsRefPtr<nsDOMEventListenerWrapper> mOnLoadendListener;
94 : nsRefPtr<nsDOMEventListenerWrapper> mOnTimeoutListener;
95 : };
96 :
97 : class nsXMLHttpRequestUpload : public nsXHREventTarget,
98 : public nsIXMLHttpRequestUpload
99 0 : {
100 : public:
101 0 : nsXMLHttpRequestUpload(nsDOMEventTargetHelper* aOwner)
102 0 : {
103 0 : BindToOwner(aOwner);
104 0 : }
105 : NS_DECL_ISUPPORTS_INHERITED
106 0 : NS_FORWARD_NSIXMLHTTPREQUESTEVENTTARGET(nsXHREventTarget::)
107 0 : NS_FORWARD_NSIDOMEVENTTARGET(nsXHREventTarget::)
108 : NS_DECL_NSIXMLHTTPREQUESTUPLOAD
109 :
110 0 : bool HasListeners()
111 : {
112 0 : return mListenerManager && mListenerManager->HasListeners();
113 : }
114 : };
115 :
116 : class nsXMLHttpRequest : public nsXHREventTarget,
117 : public nsIXMLHttpRequest,
118 : public nsIJSXMLHttpRequest,
119 : public nsIStreamListener,
120 : public nsIChannelEventSink,
121 : public nsIProgressEventSink,
122 : public nsIInterfaceRequestor,
123 : public nsSupportsWeakReference,
124 : public nsIJSNativeInitializer,
125 : public nsITimerCallback
126 : {
127 : friend class nsXHRParseEndListener;
128 : public:
129 : nsXMLHttpRequest();
130 : virtual ~nsXMLHttpRequest();
131 :
132 : NS_DECL_ISUPPORTS_INHERITED
133 :
134 : // nsIXMLHttpRequest
135 : NS_DECL_NSIXMLHTTPREQUEST
136 :
137 : // nsIJSXMLHttpRequest
138 : NS_IMETHOD GetOnuploadprogress(nsIDOMEventListener** aOnuploadprogress);
139 : NS_IMETHOD SetOnuploadprogress(nsIDOMEventListener* aOnuploadprogress);
140 :
141 0 : NS_FORWARD_NSIXMLHTTPREQUESTEVENTTARGET(nsXHREventTarget::)
142 :
143 : // nsIStreamListener
144 : NS_DECL_NSISTREAMLISTENER
145 :
146 : // nsIRequestObserver
147 : NS_DECL_NSIREQUESTOBSERVER
148 :
149 : // nsIChannelEventSink
150 : NS_DECL_NSICHANNELEVENTSINK
151 :
152 : // nsIProgressEventSink
153 : NS_DECL_NSIPROGRESSEVENTSINK
154 :
155 : // nsIInterfaceRequestor
156 : NS_DECL_NSIINTERFACEREQUESTOR
157 :
158 : // nsITimerCallback
159 : NS_DECL_NSITIMERCALLBACK
160 :
161 : // nsIJSNativeInitializer
162 : NS_IMETHOD Initialize(nsISupports* aOwner, JSContext* cx, JSObject* obj,
163 : PRUint32 argc, jsval* argv);
164 :
165 33178 : NS_FORWARD_NSIDOMEVENTTARGET(nsXHREventTarget::)
166 :
167 : // This creates a trusted readystatechange event, which is not cancelable and
168 : // doesn't bubble.
169 : static nsresult CreateReadystatechangeEvent(nsIDOMEvent** aDOMEvent);
170 : // For backwards compatibility aPosition should contain the headers for upload
171 : // and aTotalSize is LL_MAXUINT when unknown. Both those values are
172 : // used by nsXMLHttpProgressEvent. Normal progress event should not use
173 : // headers in aLoaded and aTotal is 0 when unknown.
174 : void DispatchProgressEvent(nsDOMEventTargetHelper* aTarget,
175 : const nsAString& aType,
176 : // Whether to use nsXMLHttpProgressEvent,
177 : // which implements LS Progress Event.
178 : bool aUseLSEventWrapper,
179 : bool aLengthComputable,
180 : // For Progress Events
181 : PRUint64 aLoaded, PRUint64 aTotal,
182 : // For LS Progress Events
183 : PRUint64 aPosition, PRUint64 aTotalSize);
184 1136 : void DispatchProgressEvent(nsDOMEventTargetHelper* aTarget,
185 : const nsAString& aType,
186 : bool aLengthComputable,
187 : PRUint64 aLoaded, PRUint64 aTotal)
188 : {
189 : DispatchProgressEvent(aTarget, aType, false,
190 : aLengthComputable, aLoaded, aTotal,
191 1136 : aLoaded, aLengthComputable ? aTotal : LL_MAXUINT);
192 1136 : }
193 :
194 : // Dispatch the "progress" event on the XHR or XHR.upload object if we've
195 : // received data since the last "progress" event. Also dispatches
196 : // "uploadprogress" as needed.
197 : void MaybeDispatchProgressEvents(bool aFinalProgress);
198 :
199 : // This is called by the factory constructor.
200 : nsresult Init();
201 :
202 : void SetRequestObserver(nsIRequestObserver* aObserver);
203 :
204 1909 : NS_DECL_CYCLE_COLLECTION_SKIPPABLE_SCRIPT_HOLDER_CLASS_INHERITED(nsXMLHttpRequest,
205 : nsXHREventTarget)
206 : bool AllowUploadProgress();
207 : void RootResultArrayBuffer();
208 :
209 : virtual void DisconnectFromOwner();
210 : protected:
211 : friend class nsMultipartProxyListener;
212 :
213 : nsresult DetectCharset();
214 : nsresult AppendToResponseText(const char * aBuffer, PRUint32 aBufferLen);
215 : static NS_METHOD StreamReaderFunc(nsIInputStream* in,
216 : void* closure,
217 : const char* fromRawSegment,
218 : PRUint32 toOffset,
219 : PRUint32 count,
220 : PRUint32 *writeCount);
221 : nsresult CreateResponseParsedJSON(JSContext* aCx);
222 : nsresult CreatePartialBlob(void);
223 : bool CreateDOMFile(nsIRequest *request);
224 : // Change the state of the object with this. The broadcast argument
225 : // determines if the onreadystatechange listener should be called.
226 : nsresult ChangeState(PRUint32 aState, bool aBroadcast = true);
227 : already_AddRefed<nsILoadGroup> GetLoadGroup() const;
228 : nsIURI *GetBaseURI();
229 :
230 : nsresult RemoveAddEventListener(const nsAString& aType,
231 : nsRefPtr<nsDOMEventListenerWrapper>& aCurrent,
232 : nsIDOMEventListener* aNew);
233 :
234 : nsresult GetInnerEventListener(nsRefPtr<nsDOMEventListenerWrapper>& aWrapper,
235 : nsIDOMEventListener** aListener);
236 :
237 : already_AddRefed<nsIHttpChannel> GetCurrentHttpChannel();
238 :
239 : bool IsSystemXHR();
240 :
241 : void ChangeStateToDone();
242 :
243 : /**
244 : * Check if aChannel is ok for a cross-site request by making sure no
245 : * inappropriate headers are set, and no username/password is set.
246 : *
247 : * Also updates the XML_HTTP_REQUEST_USE_XSITE_AC bit.
248 : */
249 : nsresult CheckChannelForCrossSiteRequest(nsIChannel* aChannel);
250 :
251 : void StartProgressEventTimer();
252 :
253 : friend class AsyncVerifyRedirectCallbackForwarder;
254 : void OnRedirectVerifyCallback(nsresult result);
255 :
256 : nsCOMPtr<nsISupports> mContext;
257 : nsCOMPtr<nsIPrincipal> mPrincipal;
258 : nsCOMPtr<nsIChannel> mChannel;
259 : // mReadRequest is different from mChannel for multipart requests
260 : nsCOMPtr<nsIRequest> mReadRequest;
261 : nsCOMPtr<nsIDOMDocument> mResponseXML;
262 : nsCOMPtr<nsIChannel> mCORSPreflightChannel;
263 : nsTArray<nsCString> mCORSUnsafeHeaders;
264 :
265 : nsRefPtr<nsDOMEventListenerWrapper> mOnUploadProgressListener;
266 : nsRefPtr<nsDOMEventListenerWrapper> mOnReadystatechangeListener;
267 :
268 : nsCOMPtr<nsIStreamListener> mXMLParserStreamListener;
269 :
270 : // used to implement getAllResponseHeaders()
271 : class nsHeaderVisitor : public nsIHttpHeaderVisitor {
272 : public:
273 : NS_DECL_ISUPPORTS
274 : NS_DECL_NSIHTTPHEADERVISITOR
275 0 : nsHeaderVisitor() { }
276 0 : virtual ~nsHeaderVisitor() {}
277 0 : const nsACString &Headers() { return mHeaders; }
278 : private:
279 : nsCString mHeaders;
280 : };
281 :
282 : // The bytes of our response body. Only used for DEFAULT, ARRAYBUFFER and
283 : // BLOB responseTypes
284 : nsCString mResponseBody;
285 :
286 : // The text version of our response body. This is incrementally decoded into
287 : // as we receive network data. However for the DEFAULT responseType we
288 : // lazily decode into this from mResponseBody only when .responseText is
289 : // accessed.
290 : // Only used for DEFAULT and TEXT responseTypes.
291 : nsString mResponseText;
292 :
293 : // For DEFAULT responseType we use this to keep track of how far we've
294 : // lazily decoded from mResponseBody to mResponseText
295 : PRUint32 mResponseBodyDecodedPos;
296 :
297 : // Decoder used for decoding into mResponseText
298 : // Only used for DEFAULT, TEXT and JSON responseTypes.
299 : // In cases where we've only received half a surrogate, the decoder itself
300 : // carries the state to remember this. Next time we receive more data we
301 : // simply feed the new data into the decoder which will handle the second
302 : // part of the surrogate.
303 : nsCOMPtr<nsIUnicodeDecoder> mDecoder;
304 :
305 : nsCString mResponseCharset;
306 :
307 : enum {
308 : XML_HTTP_RESPONSE_TYPE_DEFAULT,
309 : XML_HTTP_RESPONSE_TYPE_ARRAYBUFFER,
310 : XML_HTTP_RESPONSE_TYPE_BLOB,
311 : XML_HTTP_RESPONSE_TYPE_DOCUMENT,
312 : XML_HTTP_RESPONSE_TYPE_TEXT,
313 : XML_HTTP_RESPONSE_TYPE_JSON,
314 : XML_HTTP_RESPONSE_TYPE_CHUNKED_TEXT,
315 : XML_HTTP_RESPONSE_TYPE_CHUNKED_ARRAYBUFFER,
316 : XML_HTTP_RESPONSE_TYPE_MOZ_BLOB
317 : } mResponseType;
318 :
319 : // It is either a cached blob-response from the last call to GetResponse,
320 : // but is also explicitly set in OnStopRequest.
321 : nsCOMPtr<nsIDOMBlob> mResponseBlob;
322 : // Non-null only when we are able to get a os-file representation of the
323 : // response, i.e. when loading from a file, or when the http-stream
324 : // caches into a file or is reading from a cached file.
325 : nsRefPtr<nsDOMFileBase> mDOMFile;
326 : // We stream data to mBuilder when response type is "blob" or "moz-blob"
327 : // and mDOMFile is null.
328 : nsRefPtr<nsDOMBlobBuilder> mBuilder;
329 :
330 : nsCString mOverrideMimeType;
331 :
332 : /**
333 : * The notification callbacks the channel had when Send() was
334 : * called. We want to forward things here as needed.
335 : */
336 : nsCOMPtr<nsIInterfaceRequestor> mNotificationCallbacks;
337 : /**
338 : * Sink interfaces that we implement that mNotificationCallbacks may
339 : * want to also be notified for. These are inited lazily if we're
340 : * asked for the relevant interface.
341 : */
342 : nsCOMPtr<nsIChannelEventSink> mChannelEventSink;
343 : nsCOMPtr<nsIProgressEventSink> mProgressEventSink;
344 :
345 : nsIRequestObserver* mRequestObserver;
346 :
347 : nsCOMPtr<nsIURI> mBaseURI;
348 :
349 : PRUint32 mState;
350 :
351 : nsRefPtr<nsXMLHttpRequestUpload> mUpload;
352 : PRUint64 mUploadTransferred;
353 : PRUint64 mUploadTotal;
354 : bool mUploadLengthComputable;
355 : bool mUploadComplete;
356 : bool mProgressSinceLastProgressEvent;
357 : PRUint64 mUploadProgress; // For legacy
358 : PRUint64 mUploadProgressMax; // For legacy
359 :
360 : // Timeout support
361 : PRTime mRequestSentTime;
362 : PRUint32 mTimeoutMilliseconds;
363 : nsCOMPtr<nsITimer> mTimeoutTimer;
364 : void StartTimeoutTimer();
365 : void HandleTimeoutCallback();
366 :
367 : bool mErrorLoad;
368 : bool mWaitingForOnStopRequest;
369 : bool mProgressTimerIsActive;
370 : bool mProgressEventWasDelayed;
371 : bool mIsHtml;
372 : bool mWarnAboutMultipartHtml;
373 : bool mWarnAboutSyncHtml;
374 : bool mLoadLengthComputable;
375 : PRUint64 mLoadTotal; // 0 if not known.
376 : PRUint64 mLoadTransferred;
377 : nsCOMPtr<nsITimer> mProgressNotifier;
378 : void HandleProgressTimerCallback();
379 :
380 : /**
381 : * Close the XMLHttpRequest's channels and dispatch appropriate progress
382 : * events.
383 : *
384 : * @param aType The progress event type.
385 : * @param aFlag A XML_HTTP_REQUEST_* state flag defined in
386 : * nsXMLHttpRequest.cpp.
387 : */
388 : void CloseRequestWithError(const nsAString& aType, const PRUint32 aFlag);
389 :
390 : bool mFirstStartRequestSeen;
391 : bool mInLoadProgressEvent;
392 :
393 : nsCOMPtr<nsIAsyncVerifyRedirectCallback> mRedirectCallback;
394 : nsCOMPtr<nsIChannel> mNewRedirectChannel;
395 :
396 : jsval mResultJSON;
397 : JSObject* mResultArrayBuffer;
398 :
399 : void ResetResponse();
400 :
401 : struct RequestHeader
402 237 : {
403 : nsCString header;
404 : nsCString value;
405 : };
406 : nsTArray<RequestHeader> mModifiedRequestHeaders;
407 : };
408 :
409 : // helper class to expose a progress DOM Event
410 :
411 : class nsXMLHttpProgressEvent : public nsIDOMProgressEvent,
412 : public nsIDOMLSProgressEvent,
413 : public nsIDOMNSEvent,
414 : public nsIPrivateDOMEvent
415 : {
416 : public:
417 : nsXMLHttpProgressEvent(nsIDOMProgressEvent* aInner,
418 : PRUint64 aCurrentProgress,
419 : PRUint64 aMaxProgress,
420 : nsPIDOMWindow* aWindow);
421 : virtual ~nsXMLHttpProgressEvent();
422 :
423 0 : NS_DECL_CYCLE_COLLECTING_ISUPPORTS
424 8772 : NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(nsXMLHttpProgressEvent, nsIDOMNSEvent)
425 0 : NS_FORWARD_NSIDOMEVENT(mInner->)
426 522 : NS_FORWARD_NSIDOMNSEVENT(mInner->)
427 0 : NS_FORWARD_NSIDOMPROGRESSEVENT(mInner->)
428 : NS_DECL_NSIDOMLSPROGRESSEVENT
429 : // nsPrivateDOMEvent
430 0 : NS_IMETHOD DuplicatePrivateData()
431 : {
432 0 : return mInner->DuplicatePrivateData();
433 : }
434 0 : NS_IMETHOD SetTarget(nsIDOMEventTarget* aTarget)
435 : {
436 0 : return mInner->SetTarget(aTarget);
437 : }
438 0 : NS_IMETHOD_(bool) IsDispatchStopped()
439 : {
440 0 : return mInner->IsDispatchStopped();
441 : }
442 1044 : NS_IMETHOD_(nsEvent*) GetInternalNSEvent()
443 : {
444 1044 : return mInner->GetInternalNSEvent();
445 : }
446 0 : NS_IMETHOD SetTrusted(bool aTrusted)
447 : {
448 0 : return mInner->SetTrusted(aTrusted);
449 : }
450 0 : virtual void Serialize(IPC::Message* aMsg,
451 : bool aSerializeInterfaceType)
452 : {
453 0 : mInner->Serialize(aMsg, aSerializeInterfaceType);
454 0 : }
455 0 : virtual bool Deserialize(const IPC::Message* aMsg, void** aIter)
456 : {
457 0 : return mInner->Deserialize(aMsg, aIter);
458 : }
459 :
460 : protected:
461 : void WarnAboutLSProgressEvent(nsIDocument::DeprecatedOperations);
462 :
463 : // Use nsDOMProgressEvent so that we can forward
464 : // most of the method calls easily.
465 : nsRefPtr<nsDOMProgressEvent> mInner;
466 : nsCOMPtr<nsPIDOMWindow> mWindow;
467 : PRUint64 mCurProgress;
468 : PRUint64 mMaxProgress;
469 : };
470 :
471 : class nsXHRParseEndListener : public nsIDOMEventListener
472 : {
473 : public:
474 : NS_DECL_ISUPPORTS
475 0 : NS_IMETHOD HandleEvent(nsIDOMEvent *event)
476 : {
477 0 : nsCOMPtr<nsIXMLHttpRequest> xhr = do_QueryReferent(mXHR);
478 0 : if (xhr) {
479 0 : static_cast<nsXMLHttpRequest*>(xhr.get())->ChangeStateToDone();
480 : }
481 0 : mXHR = nsnull;
482 0 : return NS_OK;
483 : }
484 0 : nsXHRParseEndListener(nsIXMLHttpRequest* aXHR)
485 0 : : mXHR(do_GetWeakReference(aXHR)) {}
486 0 : virtual ~nsXHRParseEndListener() {}
487 : private:
488 : nsWeakPtr mXHR;
489 : };
490 :
491 : #endif
|