1 : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* vim: set sw=2 ts=8 et tw=80 : */
3 :
4 : /* ***** BEGIN LICENSE BLOCK *****
5 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
6 : *
7 : * The contents of this file are subject to the Mozilla Public License Version
8 : * 1.1 (the "License"); you may not use this file except in compliance with
9 : * the License. You may obtain a copy of the License at
10 : * http://www.mozilla.org/MPL/
11 : *
12 : * Software distributed under the License is distributed on an "AS IS" basis,
13 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
14 : * for the specific language governing rights and limitations under the
15 : * License.
16 : *
17 : * The Original Code is mozilla.org code.
18 : *
19 : * The Initial Developer of the Original Code is
20 : * The Mozilla Foundation.
21 : * Portions created by the Initial Developer are Copyright (C) 2010
22 : * the Initial Developer. All Rights Reserved.
23 : *
24 : * Contributor(s):
25 : * Daniel Witte <dwitte@mozilla.com>
26 : * Jason Duell <jduell.mcbugs@gmail.com>
27 : *
28 : * Alternatively, the contents of this file may be used under the terms of
29 : * either the GNU General Public License Version 2 or later (the "GPL"), or
30 : * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
31 : * in which case the provisions of the GPL or the LGPL are applicable instead
32 : * of those above. If you wish to allow use of your version of this file only
33 : * under the terms of either the GPL or the LGPL, and not to allow others to
34 : * use your version of this file under the terms of the MPL, indicate your
35 : * decision by deleting the provisions above and replace them with the notice
36 : * and other provisions required by the GPL or the LGPL. If you do not delete
37 : * the provisions above, a recipient may use your version of this file under
38 : * the terms of any one of the MPL, the GPL or the LGPL.
39 : *
40 : * ***** END LICENSE BLOCK ***** */
41 :
42 : #ifndef mozilla_net_HttpBaseChannel_h
43 : #define mozilla_net_HttpBaseChannel_h
44 :
45 : #include "nsHttp.h"
46 : #include "nsAutoPtr.h"
47 : #include "nsHashPropertyBag.h"
48 : #include "nsProxyInfo.h"
49 : #include "nsHttpRequestHead.h"
50 : #include "nsHttpResponseHead.h"
51 : #include "nsHttpConnectionInfo.h"
52 : #include "nsIEncodedChannel.h"
53 : #include "nsIHttpChannel.h"
54 : #include "nsIHttpChannelInternal.h"
55 : #include "nsIUploadChannel.h"
56 : #include "nsIUploadChannel2.h"
57 : #include "nsIProgressEventSink.h"
58 : #include "nsIURI.h"
59 : #include "nsIStringEnumerator.h"
60 : #include "nsISupportsPriority.h"
61 : #include "nsIApplicationCache.h"
62 : #include "nsIResumableChannel.h"
63 : #include "nsITraceableChannel.h"
64 : #include "mozilla/net/NeckoCommon.h"
65 : #include "nsThreadUtils.h"
66 :
67 : namespace mozilla {
68 : namespace net {
69 :
70 : /*
71 : * This class is a partial implementation of nsIHttpChannel. It contains code
72 : * shared by nsHttpChannel and HttpChannelChild.
73 : * - Note that this class has nothing to do with nsBaseChannel, which is an
74 : * earlier effort at a base class for channels that somehow never made it all
75 : * the way to the HTTP channel.
76 : */
77 : class HttpBaseChannel : public nsHashPropertyBag
78 : , public nsIEncodedChannel
79 : , public nsIHttpChannel
80 : , public nsIHttpChannelInternal
81 : , public nsIUploadChannel
82 : , public nsIUploadChannel2
83 : , public nsISupportsPriority
84 : , public nsIResumableChannel
85 : , public nsITraceableChannel
86 : {
87 : public:
88 : NS_DECL_ISUPPORTS_INHERITED
89 : NS_DECL_NSIUPLOADCHANNEL
90 : NS_DECL_NSIUPLOADCHANNEL2
91 : NS_DECL_NSITRACEABLECHANNEL
92 :
93 : HttpBaseChannel();
94 : virtual ~HttpBaseChannel();
95 :
96 : virtual nsresult Init(nsIURI *aURI, PRUint8 aCaps, nsProxyInfo *aProxyInfo);
97 :
98 : // nsIRequest
99 : NS_IMETHOD GetName(nsACString& aName);
100 : NS_IMETHOD IsPending(bool *aIsPending);
101 : NS_IMETHOD GetStatus(nsresult *aStatus);
102 : NS_IMETHOD GetLoadGroup(nsILoadGroup **aLoadGroup);
103 : NS_IMETHOD SetLoadGroup(nsILoadGroup *aLoadGroup);
104 : NS_IMETHOD GetLoadFlags(nsLoadFlags *aLoadFlags);
105 : NS_IMETHOD SetLoadFlags(nsLoadFlags aLoadFlags);
106 :
107 : // nsIChannel
108 : NS_IMETHOD GetOriginalURI(nsIURI **aOriginalURI);
109 : NS_IMETHOD SetOriginalURI(nsIURI *aOriginalURI);
110 : NS_IMETHOD GetURI(nsIURI **aURI);
111 : NS_IMETHOD GetOwner(nsISupports **aOwner);
112 : NS_IMETHOD SetOwner(nsISupports *aOwner);
113 : NS_IMETHOD GetNotificationCallbacks(nsIInterfaceRequestor **aCallbacks);
114 : NS_IMETHOD SetNotificationCallbacks(nsIInterfaceRequestor *aCallbacks);
115 : NS_IMETHOD GetContentType(nsACString& aContentType);
116 : NS_IMETHOD SetContentType(const nsACString& aContentType);
117 : NS_IMETHOD GetContentCharset(nsACString& aContentCharset);
118 : NS_IMETHOD SetContentCharset(const nsACString& aContentCharset);
119 : NS_IMETHOD GetContentDisposition(PRUint32 *aContentDisposition);
120 : NS_IMETHOD GetContentDispositionFilename(nsAString& aContentDispositionFilename);
121 : NS_IMETHOD GetContentDispositionHeader(nsACString& aContentDispositionHeader);
122 : NS_IMETHOD GetContentLength(PRInt32 *aContentLength);
123 : NS_IMETHOD SetContentLength(PRInt32 aContentLength);
124 : NS_IMETHOD Open(nsIInputStream **aResult);
125 :
126 : // nsIEncodedChannel
127 : NS_IMETHOD GetApplyConversion(bool *value);
128 : NS_IMETHOD SetApplyConversion(bool value);
129 : NS_IMETHOD GetContentEncodings(nsIUTF8StringEnumerator** aEncodings);
130 :
131 : // HttpBaseChannel::nsIHttpChannel
132 : NS_IMETHOD GetRequestMethod(nsACString& aMethod);
133 : NS_IMETHOD SetRequestMethod(const nsACString& aMethod);
134 : NS_IMETHOD GetReferrer(nsIURI **referrer);
135 : NS_IMETHOD SetReferrer(nsIURI *referrer);
136 : NS_IMETHOD GetRequestHeader(const nsACString& aHeader, nsACString& aValue);
137 : NS_IMETHOD SetRequestHeader(const nsACString& aHeader,
138 : const nsACString& aValue, bool aMerge);
139 : NS_IMETHOD VisitRequestHeaders(nsIHttpHeaderVisitor *visitor);
140 : NS_IMETHOD GetResponseHeader(const nsACString &header, nsACString &value);
141 : NS_IMETHOD SetResponseHeader(const nsACString& header,
142 : const nsACString& value, bool merge);
143 : NS_IMETHOD VisitResponseHeaders(nsIHttpHeaderVisitor *visitor);
144 : NS_IMETHOD GetAllowPipelining(bool *value);
145 : NS_IMETHOD SetAllowPipelining(bool value);
146 : NS_IMETHOD GetRedirectionLimit(PRUint32 *value);
147 : NS_IMETHOD SetRedirectionLimit(PRUint32 value);
148 : NS_IMETHOD IsNoStoreResponse(bool *value);
149 : NS_IMETHOD IsNoCacheResponse(bool *value);
150 : NS_IMETHOD GetResponseStatus(PRUint32 *aValue);
151 : NS_IMETHOD GetResponseStatusText(nsACString& aValue);
152 : NS_IMETHOD GetRequestSucceeded(bool *aValue);
153 :
154 : // nsIHttpChannelInternal
155 : NS_IMETHOD GetDocumentURI(nsIURI **aDocumentURI);
156 : NS_IMETHOD SetDocumentURI(nsIURI *aDocumentURI);
157 : NS_IMETHOD GetRequestVersion(PRUint32 *major, PRUint32 *minor);
158 : NS_IMETHOD GetResponseVersion(PRUint32 *major, PRUint32 *minor);
159 : NS_IMETHOD SetCookie(const char *aCookieHeader);
160 : NS_IMETHOD GetForceAllowThirdPartyCookie(bool *aForce);
161 : NS_IMETHOD SetForceAllowThirdPartyCookie(bool aForce);
162 : NS_IMETHOD GetCanceled(bool *aCanceled);
163 : NS_IMETHOD GetChannelIsForDownload(bool *aChannelIsForDownload);
164 : NS_IMETHOD SetChannelIsForDownload(bool aChannelIsForDownload);
165 : NS_IMETHOD SetCacheKeysRedirectChain(nsTArray<nsCString> *cacheKeys);
166 : NS_IMETHOD GetLocalAddress(nsACString& addr);
167 : NS_IMETHOD GetLocalPort(PRInt32* port);
168 : NS_IMETHOD GetRemoteAddress(nsACString& addr);
169 : NS_IMETHOD GetRemotePort(PRInt32* port);
170 : NS_IMETHOD GetAllowSpdy(bool *aAllowSpdy);
171 : NS_IMETHOD SetAllowSpdy(bool aAllowSpdy);
172 :
173 0 : inline void CleanRedirectCacheChainIfNecessary()
174 : {
175 0 : if (mRedirectedCachekeys) {
176 0 : delete mRedirectedCachekeys;
177 0 : mRedirectedCachekeys = nsnull;
178 : }
179 0 : }
180 : NS_IMETHOD HTTPUpgrade(const nsACString & aProtocolName,
181 : nsIHttpUpgradeListener *aListener);
182 :
183 : // nsISupportsPriority
184 : NS_IMETHOD GetPriority(PRInt32 *value);
185 : NS_IMETHOD AdjustPriority(PRInt32 delta);
186 :
187 : // nsIResumableChannel
188 : NS_IMETHOD GetEntityID(nsACString& aEntityID);
189 :
190 : class nsContentEncodings : public nsIUTF8StringEnumerator
191 : {
192 : public:
193 : NS_DECL_ISUPPORTS
194 : NS_DECL_NSIUTF8STRINGENUMERATOR
195 :
196 : nsContentEncodings(nsIHttpChannel* aChannel, const char* aEncodingHeader);
197 : virtual ~nsContentEncodings();
198 :
199 : private:
200 : nsresult PrepareForNext(void);
201 :
202 : // We do not own the buffer. The channel owns it.
203 : const char* mEncodingHeader;
204 : const char* mCurStart; // points to start of current header
205 : const char* mCurEnd; // points to end of current header
206 :
207 : // Hold a ref to our channel so that it can't go away and take the
208 : // header with it.
209 : nsCOMPtr<nsIHttpChannel> mChannel;
210 :
211 : bool mReady;
212 : };
213 :
214 0 : nsHttpResponseHead * GetResponseHead() const { return mResponseHead; }
215 0 : nsHttpRequestHead * GetRequestHead() { return &mRequestHead; }
216 :
217 0 : const PRNetAddr& GetSelfAddr() { return mSelfAddr; }
218 0 : const PRNetAddr& GetPeerAddr() { return mPeerAddr; }
219 :
220 : public: /* Necko internal use only... */
221 :
222 : bool ShouldRewriteRedirectToGET(PRUint32 httpStatus, nsHttpAtom method);
223 : bool IsSafeMethod(nsHttpAtom method);
224 :
225 : protected:
226 :
227 : // Handle notifying listener, removing from loadgroup if request failed.
228 : void DoNotifyListener();
229 : virtual void DoNotifyListenerCleanup() = 0;
230 :
231 : nsresult ApplyContentConversions();
232 :
233 : void AddCookiesToRequest();
234 : virtual nsresult SetupReplacementChannel(nsIURI *,
235 : nsIChannel *,
236 : bool preserveMethod,
237 : bool forProxy);
238 :
239 : // Helper function to simplify getting notification callbacks.
240 : template <class T>
241 7955 : void GetCallback(nsCOMPtr<T> &aResult)
242 : {
243 7955 : NS_QueryNotificationCallbacks(mCallbacks, mLoadGroup,
244 : NS_GET_TEMPLATE_IID(T),
245 : getter_AddRefs(aResult));
246 7955 : }
247 :
248 : nsCOMPtr<nsIURI> mURI;
249 : nsCOMPtr<nsIURI> mOriginalURI;
250 : nsCOMPtr<nsIURI> mDocumentURI;
251 : nsCOMPtr<nsIStreamListener> mListener;
252 : nsCOMPtr<nsISupports> mListenerContext;
253 : nsCOMPtr<nsILoadGroup> mLoadGroup;
254 : nsCOMPtr<nsISupports> mOwner;
255 : nsCOMPtr<nsIInterfaceRequestor> mCallbacks;
256 : nsCOMPtr<nsIProgressEventSink> mProgressSink;
257 : nsCOMPtr<nsIURI> mReferrer;
258 : nsCOMPtr<nsIApplicationCache> mApplicationCache;
259 :
260 : nsHttpRequestHead mRequestHead;
261 : nsCOMPtr<nsIInputStream> mUploadStream;
262 : nsAutoPtr<nsHttpResponseHead> mResponseHead;
263 : nsRefPtr<nsHttpConnectionInfo> mConnectionInfo;
264 :
265 : nsCString mSpec; // ASCII encoded URL spec
266 : nsCString mContentTypeHint;
267 : nsCString mContentCharsetHint;
268 : nsCString mUserSetCookieHeader;
269 :
270 : PRNetAddr mSelfAddr;
271 : PRNetAddr mPeerAddr;
272 :
273 : // HTTP Upgrade Data
274 : nsCString mUpgradeProtocol;
275 : nsCOMPtr<nsIHttpUpgradeListener> mUpgradeProtocolCallback;
276 :
277 : // Resumable channel specific data
278 : nsCString mEntityID;
279 : PRUint64 mStartPos;
280 :
281 : nsresult mStatus;
282 : PRUint32 mLoadFlags;
283 : PRInt16 mPriority;
284 : PRUint8 mCaps;
285 : PRUint8 mRedirectionLimit;
286 :
287 : PRUint32 mApplyConversion : 1;
288 : PRUint32 mCanceled : 1;
289 : PRUint32 mIsPending : 1;
290 : PRUint32 mWasOpened : 1;
291 : PRUint32 mResponseHeadersModified : 1;
292 : PRUint32 mAllowPipelining : 1;
293 : PRUint32 mForceAllowThirdPartyCookie : 1;
294 : PRUint32 mUploadStreamHasHeaders : 1;
295 : PRUint32 mInheritApplicationCache : 1;
296 : PRUint32 mChooseApplicationCache : 1;
297 : PRUint32 mLoadedFromApplicationCache : 1;
298 : PRUint32 mChannelIsForDownload : 1;
299 : PRUint32 mTracingEnabled : 1;
300 : // True if timing collection is enabled
301 : PRUint32 mTimingEnabled : 1;
302 : PRUint32 mAllowSpdy : 1;
303 :
304 : // Current suspension depth for this channel object
305 : PRUint32 mSuspendCount;
306 :
307 : nsTArray<nsCString> *mRedirectedCachekeys;
308 : };
309 :
310 : // Share some code while working around C++'s absurd inability to handle casting
311 : // of member functions between base/derived types.
312 : // - We want to store member function pointer to call at resume time, but one
313 : // such function--HandleAsyncAbort--we want to share between the
314 : // nsHttpChannel/HttpChannelChild. Can't define it in base class, because
315 : // then we'd have to cast member function ptr between base/derived class
316 : // types. Sigh...
317 : template <class T>
318 : class HttpAsyncAborter
319 : {
320 : public:
321 3514 : HttpAsyncAborter(T *derived) : mThis(derived), mCallOnResume(0) {}
322 :
323 : // Aborts channel: calls OnStart/Stop with provided status, removes channel
324 : // from loadGroup.
325 : nsresult AsyncAbort(nsresult status);
326 :
327 : // Does most the actual work.
328 : void HandleAsyncAbort();
329 :
330 : // AsyncCall calls a member function asynchronously (via an event).
331 : // retval isn't refcounted and is set only when event was successfully
332 : // posted, the event is returned for the purpose of cancelling when needed
333 : nsresult AsyncCall(void (T::*funcPtr)(),
334 : nsRunnableMethod<T> **retval = nsnull);
335 : private:
336 : T *mThis;
337 :
338 : protected:
339 : // Function to be called at resume time
340 : void (T::* mCallOnResume)(void);
341 : };
342 :
343 : template <class T>
344 36 : nsresult HttpAsyncAborter<T>::AsyncAbort(nsresult status)
345 : {
346 36 : LOG(("HttpAsyncAborter::AsyncAbort [this=%p status=%x]\n", mThis, status));
347 :
348 36 : mThis->mStatus = status;
349 36 : mThis->mIsPending = false;
350 :
351 : // if this fails? Callers ignore our return value anyway....
352 36 : return AsyncCall(&T::HandleAsyncAbort);
353 : }
354 :
355 : // Each subclass needs to define its own version of this (which just calls this
356 : // base version), else we wind up casting base/derived member function ptrs
357 : template <class T>
358 36 : inline void HttpAsyncAborter<T>::HandleAsyncAbort()
359 : {
360 36 : NS_PRECONDITION(!mCallOnResume, "How did that happen?");
361 :
362 36 : if (mThis->mSuspendCount) {
363 0 : LOG(("Waiting until resume to do async notification [this=%p]\n",
364 : mThis));
365 0 : mCallOnResume = &T::HandleAsyncAbort;
366 0 : return;
367 : }
368 :
369 36 : mThis->DoNotifyListener();
370 :
371 : // finally remove ourselves from the load group.
372 36 : if (mThis->mLoadGroup)
373 0 : mThis->mLoadGroup->RemoveRequest(mThis, nsnull, mThis->mStatus);
374 : }
375 :
376 : template <class T>
377 269 : nsresult HttpAsyncAborter<T>::AsyncCall(void (T::*funcPtr)(),
378 : nsRunnableMethod<T> **retval)
379 : {
380 : nsresult rv;
381 :
382 538 : nsRefPtr<nsRunnableMethod<T> > event = NS_NewRunnableMethod(mThis, funcPtr);
383 269 : rv = NS_DispatchToCurrentThread(event);
384 269 : if (NS_SUCCEEDED(rv) && retval) {
385 220 : *retval = event;
386 : }
387 :
388 269 : return rv;
389 : }
390 :
391 : } // namespace net
392 : } // namespace mozilla
393 :
394 : #endif // mozilla_net_HttpBaseChannel_h
|