|
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 /* This Source Code Form is subject to the terms of the Mozilla Public |
|
5 * License, v. 2.0. If a copy of the MPL was not distributed with this |
|
6 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
|
7 |
|
8 #ifndef mozilla_net_HttpBaseChannel_h |
|
9 #define mozilla_net_HttpBaseChannel_h |
|
10 |
|
11 #include "nsHttp.h" |
|
12 #include "nsAutoPtr.h" |
|
13 #include "nsHashPropertyBag.h" |
|
14 #include "nsProxyInfo.h" |
|
15 #include "nsHttpRequestHead.h" |
|
16 #include "nsHttpResponseHead.h" |
|
17 #include "nsHttpConnectionInfo.h" |
|
18 #include "nsIEncodedChannel.h" |
|
19 #include "nsIHttpChannel.h" |
|
20 #include "nsHttpHandler.h" |
|
21 #include "nsIHttpChannelInternal.h" |
|
22 #include "nsIUploadChannel.h" |
|
23 #include "nsIUploadChannel2.h" |
|
24 #include "nsIProgressEventSink.h" |
|
25 #include "nsIURI.h" |
|
26 #include "nsIEffectiveTLDService.h" |
|
27 #include "nsIStringEnumerator.h" |
|
28 #include "nsISupportsPriority.h" |
|
29 #include "nsIApplicationCache.h" |
|
30 #include "nsIResumableChannel.h" |
|
31 #include "nsITraceableChannel.h" |
|
32 #include "nsILoadContext.h" |
|
33 #include "mozilla/net/NeckoCommon.h" |
|
34 #include "nsThreadUtils.h" |
|
35 #include "PrivateBrowsingChannel.h" |
|
36 #include "mozilla/net/DNS.h" |
|
37 #include "nsITimedChannel.h" |
|
38 #include "nsISecurityConsoleMessage.h" |
|
39 |
|
40 extern PRLogModuleInfo *gHttpLog; |
|
41 |
|
42 namespace mozilla { |
|
43 namespace net { |
|
44 |
|
45 /* |
|
46 * This class is a partial implementation of nsIHttpChannel. It contains code |
|
47 * shared by nsHttpChannel and HttpChannelChild. |
|
48 * - Note that this class has nothing to do with nsBaseChannel, which is an |
|
49 * earlier effort at a base class for channels that somehow never made it all |
|
50 * the way to the HTTP channel. |
|
51 */ |
|
52 class HttpBaseChannel : public nsHashPropertyBag |
|
53 , public nsIEncodedChannel |
|
54 , public nsIHttpChannel |
|
55 , public nsIHttpChannelInternal |
|
56 , public nsIUploadChannel |
|
57 , public nsIUploadChannel2 |
|
58 , public nsISupportsPriority |
|
59 , public nsIResumableChannel |
|
60 , public nsITraceableChannel |
|
61 , public PrivateBrowsingChannel<HttpBaseChannel> |
|
62 , public nsITimedChannel |
|
63 { |
|
64 public: |
|
65 NS_DECL_ISUPPORTS_INHERITED |
|
66 NS_DECL_NSIUPLOADCHANNEL |
|
67 NS_DECL_NSIUPLOADCHANNEL2 |
|
68 NS_DECL_NSITRACEABLECHANNEL |
|
69 NS_DECL_NSITIMEDCHANNEL |
|
70 |
|
71 HttpBaseChannel(); |
|
72 virtual ~HttpBaseChannel(); |
|
73 |
|
74 virtual nsresult Init(nsIURI *aURI, uint32_t aCaps, nsProxyInfo *aProxyInfo, |
|
75 uint32_t aProxyResolveFlags, |
|
76 nsIURI *aProxyURI); |
|
77 |
|
78 // nsIRequest |
|
79 NS_IMETHOD GetName(nsACString& aName); |
|
80 NS_IMETHOD IsPending(bool *aIsPending); |
|
81 NS_IMETHOD GetStatus(nsresult *aStatus); |
|
82 NS_IMETHOD GetLoadGroup(nsILoadGroup **aLoadGroup); |
|
83 NS_IMETHOD SetLoadGroup(nsILoadGroup *aLoadGroup); |
|
84 NS_IMETHOD GetLoadFlags(nsLoadFlags *aLoadFlags); |
|
85 NS_IMETHOD SetLoadFlags(nsLoadFlags aLoadFlags); |
|
86 |
|
87 // nsIChannel |
|
88 NS_IMETHOD GetOriginalURI(nsIURI **aOriginalURI); |
|
89 NS_IMETHOD SetOriginalURI(nsIURI *aOriginalURI); |
|
90 NS_IMETHOD GetURI(nsIURI **aURI); |
|
91 NS_IMETHOD GetOwner(nsISupports **aOwner); |
|
92 NS_IMETHOD SetOwner(nsISupports *aOwner); |
|
93 NS_IMETHOD GetNotificationCallbacks(nsIInterfaceRequestor **aCallbacks); |
|
94 NS_IMETHOD SetNotificationCallbacks(nsIInterfaceRequestor *aCallbacks); |
|
95 NS_IMETHOD GetContentType(nsACString& aContentType); |
|
96 NS_IMETHOD SetContentType(const nsACString& aContentType); |
|
97 NS_IMETHOD GetContentCharset(nsACString& aContentCharset); |
|
98 NS_IMETHOD SetContentCharset(const nsACString& aContentCharset); |
|
99 NS_IMETHOD GetContentDisposition(uint32_t *aContentDisposition); |
|
100 NS_IMETHOD SetContentDisposition(uint32_t aContentDisposition); |
|
101 NS_IMETHOD GetContentDispositionFilename(nsAString& aContentDispositionFilename); |
|
102 NS_IMETHOD SetContentDispositionFilename(const nsAString& aContentDispositionFilename); |
|
103 NS_IMETHOD GetContentDispositionHeader(nsACString& aContentDispositionHeader); |
|
104 NS_IMETHOD GetContentLength(int64_t *aContentLength); |
|
105 NS_IMETHOD SetContentLength(int64_t aContentLength); |
|
106 NS_IMETHOD Open(nsIInputStream **aResult); |
|
107 |
|
108 // nsIEncodedChannel |
|
109 NS_IMETHOD GetApplyConversion(bool *value); |
|
110 NS_IMETHOD SetApplyConversion(bool value); |
|
111 NS_IMETHOD GetContentEncodings(nsIUTF8StringEnumerator** aEncodings); |
|
112 |
|
113 // HttpBaseChannel::nsIHttpChannel |
|
114 NS_IMETHOD GetRequestMethod(nsACString& aMethod); |
|
115 NS_IMETHOD SetRequestMethod(const nsACString& aMethod); |
|
116 NS_IMETHOD GetReferrer(nsIURI **referrer); |
|
117 NS_IMETHOD SetReferrer(nsIURI *referrer); |
|
118 NS_IMETHOD GetProxyURI(nsIURI **proxyURI); |
|
119 NS_IMETHOD GetRequestHeader(const nsACString& aHeader, nsACString& aValue); |
|
120 NS_IMETHOD SetRequestHeader(const nsACString& aHeader, |
|
121 const nsACString& aValue, bool aMerge); |
|
122 NS_IMETHOD VisitRequestHeaders(nsIHttpHeaderVisitor *visitor); |
|
123 NS_IMETHOD GetResponseHeader(const nsACString &header, nsACString &value); |
|
124 NS_IMETHOD SetResponseHeader(const nsACString& header, |
|
125 const nsACString& value, bool merge); |
|
126 NS_IMETHOD VisitResponseHeaders(nsIHttpHeaderVisitor *visitor); |
|
127 NS_IMETHOD GetAllowPipelining(bool *value); |
|
128 NS_IMETHOD SetAllowPipelining(bool value); |
|
129 NS_IMETHOD GetRedirectionLimit(uint32_t *value); |
|
130 NS_IMETHOD SetRedirectionLimit(uint32_t value); |
|
131 NS_IMETHOD IsNoStoreResponse(bool *value); |
|
132 NS_IMETHOD IsNoCacheResponse(bool *value); |
|
133 NS_IMETHOD GetResponseStatus(uint32_t *aValue); |
|
134 NS_IMETHOD GetResponseStatusText(nsACString& aValue); |
|
135 NS_IMETHOD GetRequestSucceeded(bool *aValue); |
|
136 NS_IMETHOD RedirectTo(nsIURI *newURI); |
|
137 |
|
138 // nsIHttpChannelInternal |
|
139 NS_IMETHOD GetDocumentURI(nsIURI **aDocumentURI); |
|
140 NS_IMETHOD SetDocumentURI(nsIURI *aDocumentURI); |
|
141 NS_IMETHOD GetRequestVersion(uint32_t *major, uint32_t *minor); |
|
142 NS_IMETHOD GetResponseVersion(uint32_t *major, uint32_t *minor); |
|
143 NS_IMETHOD SetCookie(const char *aCookieHeader); |
|
144 NS_IMETHOD GetForceAllowThirdPartyCookie(bool *aForce); |
|
145 NS_IMETHOD SetForceAllowThirdPartyCookie(bool aForce); |
|
146 NS_IMETHOD GetCanceled(bool *aCanceled); |
|
147 NS_IMETHOD GetChannelIsForDownload(bool *aChannelIsForDownload); |
|
148 NS_IMETHOD SetChannelIsForDownload(bool aChannelIsForDownload); |
|
149 NS_IMETHOD SetCacheKeysRedirectChain(nsTArray<nsCString> *cacheKeys); |
|
150 NS_IMETHOD GetLocalAddress(nsACString& addr); |
|
151 NS_IMETHOD GetLocalPort(int32_t* port); |
|
152 NS_IMETHOD GetRemoteAddress(nsACString& addr); |
|
153 NS_IMETHOD GetRemotePort(int32_t* port); |
|
154 NS_IMETHOD GetAllowSpdy(bool *aAllowSpdy); |
|
155 NS_IMETHOD SetAllowSpdy(bool aAllowSpdy); |
|
156 NS_IMETHOD GetLoadAsBlocking(bool *aLoadAsBlocking); |
|
157 NS_IMETHOD SetLoadAsBlocking(bool aLoadAsBlocking); |
|
158 NS_IMETHOD GetLoadUnblocked(bool *aLoadUnblocked); |
|
159 NS_IMETHOD SetLoadUnblocked(bool aLoadUnblocked); |
|
160 NS_IMETHOD GetApiRedirectToURI(nsIURI * *aApiRedirectToURI); |
|
161 NS_IMETHOD AddSecurityMessage(const nsAString &aMessageTag, const nsAString &aMessageCategory); |
|
162 NS_IMETHOD TakeAllSecurityMessages(nsCOMArray<nsISecurityConsoleMessage> &aMessages); |
|
163 NS_IMETHOD GetResponseTimeoutEnabled(bool *aEnable); |
|
164 NS_IMETHOD SetResponseTimeoutEnabled(bool aEnable); |
|
165 |
|
166 inline void CleanRedirectCacheChainIfNecessary() |
|
167 { |
|
168 mRedirectedCachekeys = nullptr; |
|
169 } |
|
170 NS_IMETHOD HTTPUpgrade(const nsACString & aProtocolName, |
|
171 nsIHttpUpgradeListener *aListener); |
|
172 |
|
173 // nsISupportsPriority |
|
174 NS_IMETHOD GetPriority(int32_t *value); |
|
175 NS_IMETHOD AdjustPriority(int32_t delta); |
|
176 |
|
177 // nsIResumableChannel |
|
178 NS_IMETHOD GetEntityID(nsACString& aEntityID); |
|
179 |
|
180 class nsContentEncodings : public nsIUTF8StringEnumerator |
|
181 { |
|
182 public: |
|
183 NS_DECL_ISUPPORTS |
|
184 NS_DECL_NSIUTF8STRINGENUMERATOR |
|
185 |
|
186 nsContentEncodings(nsIHttpChannel* aChannel, const char* aEncodingHeader); |
|
187 virtual ~nsContentEncodings(); |
|
188 |
|
189 private: |
|
190 nsresult PrepareForNext(void); |
|
191 |
|
192 // We do not own the buffer. The channel owns it. |
|
193 const char* mEncodingHeader; |
|
194 const char* mCurStart; // points to start of current header |
|
195 const char* mCurEnd; // points to end of current header |
|
196 |
|
197 // Hold a ref to our channel so that it can't go away and take the |
|
198 // header with it. |
|
199 nsCOMPtr<nsIHttpChannel> mChannel; |
|
200 |
|
201 bool mReady; |
|
202 }; |
|
203 |
|
204 nsHttpResponseHead * GetResponseHead() const { return mResponseHead; } |
|
205 nsHttpRequestHead * GetRequestHead() { return &mRequestHead; } |
|
206 |
|
207 const NetAddr& GetSelfAddr() { return mSelfAddr; } |
|
208 const NetAddr& GetPeerAddr() { return mPeerAddr; } |
|
209 |
|
210 public: /* Necko internal use only... */ |
|
211 |
|
212 |
|
213 // Return whether upon a redirect code of httpStatus for method, the |
|
214 // request method should be rewritten to GET. |
|
215 static bool ShouldRewriteRedirectToGET(uint32_t httpStatus, |
|
216 nsHttpRequestHead::ParsedMethodType method); |
|
217 |
|
218 protected: |
|
219 nsCOMArray<nsISecurityConsoleMessage> mSecurityConsoleMessages; |
|
220 |
|
221 // Handle notifying listener, removing from loadgroup if request failed. |
|
222 void DoNotifyListener(); |
|
223 virtual void DoNotifyListenerCleanup() = 0; |
|
224 |
|
225 // drop reference to listener, its callbacks, and the progress sink |
|
226 void ReleaseListeners(); |
|
227 |
|
228 nsresult ApplyContentConversions(); |
|
229 |
|
230 void AddCookiesToRequest(); |
|
231 virtual nsresult SetupReplacementChannel(nsIURI *, |
|
232 nsIChannel *, |
|
233 bool preserveMethod); |
|
234 |
|
235 // bundle calling OMR observers and marking flag into one function |
|
236 inline void CallOnModifyRequestObservers() { |
|
237 gHttpHandler->OnModifyRequest(this); |
|
238 mRequestObserversCalled = true; |
|
239 } |
|
240 |
|
241 // Helper function to simplify getting notification callbacks. |
|
242 template <class T> |
|
243 void GetCallback(nsCOMPtr<T> &aResult) |
|
244 { |
|
245 NS_QueryNotificationCallbacks(mCallbacks, mLoadGroup, |
|
246 NS_GET_TEMPLATE_IID(T), |
|
247 getter_AddRefs(aResult)); |
|
248 } |
|
249 |
|
250 // Redirect tracking |
|
251 // Checks whether or not aURI and mOriginalURI share the same domain. |
|
252 bool SameOriginWithOriginalUri(nsIURI *aURI); |
|
253 |
|
254 friend class PrivateBrowsingChannel<HttpBaseChannel>; |
|
255 |
|
256 nsCOMPtr<nsIURI> mURI; |
|
257 nsCOMPtr<nsIURI> mOriginalURI; |
|
258 nsCOMPtr<nsIURI> mDocumentURI; |
|
259 nsCOMPtr<nsIStreamListener> mListener; |
|
260 nsCOMPtr<nsISupports> mListenerContext; |
|
261 nsCOMPtr<nsILoadGroup> mLoadGroup; |
|
262 nsCOMPtr<nsISupports> mOwner; |
|
263 nsCOMPtr<nsIInterfaceRequestor> mCallbacks; |
|
264 nsCOMPtr<nsIProgressEventSink> mProgressSink; |
|
265 nsCOMPtr<nsIURI> mReferrer; |
|
266 nsCOMPtr<nsIApplicationCache> mApplicationCache; |
|
267 |
|
268 nsHttpRequestHead mRequestHead; |
|
269 nsCOMPtr<nsIInputStream> mUploadStream; |
|
270 nsAutoPtr<nsHttpResponseHead> mResponseHead; |
|
271 nsRefPtr<nsHttpConnectionInfo> mConnectionInfo; |
|
272 nsCOMPtr<nsIProxyInfo> mProxyInfo; |
|
273 |
|
274 nsCString mSpec; // ASCII encoded URL spec |
|
275 nsCString mContentTypeHint; |
|
276 nsCString mContentCharsetHint; |
|
277 nsCString mUserSetCookieHeader; |
|
278 |
|
279 NetAddr mSelfAddr; |
|
280 NetAddr mPeerAddr; |
|
281 |
|
282 // HTTP Upgrade Data |
|
283 nsCString mUpgradeProtocol; |
|
284 nsCOMPtr<nsIHttpUpgradeListener> mUpgradeProtocolCallback; |
|
285 |
|
286 // Resumable channel specific data |
|
287 nsCString mEntityID; |
|
288 uint64_t mStartPos; |
|
289 |
|
290 nsresult mStatus; |
|
291 uint32_t mLoadFlags; |
|
292 uint32_t mCaps; |
|
293 int16_t mPriority; |
|
294 uint8_t mRedirectionLimit; |
|
295 |
|
296 uint32_t mApplyConversion : 1; |
|
297 uint32_t mCanceled : 1; |
|
298 uint32_t mIsPending : 1; |
|
299 uint32_t mWasOpened : 1; |
|
300 // if 1 all "http-on-{opening|modify|etc}-request" observers have been called |
|
301 uint32_t mRequestObserversCalled : 1; |
|
302 uint32_t mResponseHeadersModified : 1; |
|
303 uint32_t mAllowPipelining : 1; |
|
304 uint32_t mForceAllowThirdPartyCookie : 1; |
|
305 uint32_t mUploadStreamHasHeaders : 1; |
|
306 uint32_t mInheritApplicationCache : 1; |
|
307 uint32_t mChooseApplicationCache : 1; |
|
308 uint32_t mLoadedFromApplicationCache : 1; |
|
309 uint32_t mChannelIsForDownload : 1; |
|
310 uint32_t mTracingEnabled : 1; |
|
311 // True if timing collection is enabled |
|
312 uint32_t mTimingEnabled : 1; |
|
313 uint32_t mAllowSpdy : 1; |
|
314 uint32_t mLoadAsBlocking : 1; |
|
315 uint32_t mLoadUnblocked : 1; |
|
316 uint32_t mResponseTimeoutEnabled : 1; |
|
317 // A flag that should be false only if a cross-domain redirect occurred |
|
318 uint32_t mAllRedirectsSameOrigin : 1; |
|
319 |
|
320 // Current suspension depth for this channel object |
|
321 uint32_t mSuspendCount; |
|
322 |
|
323 nsCOMPtr<nsIURI> mAPIRedirectToURI; |
|
324 nsAutoPtr<nsTArray<nsCString> > mRedirectedCachekeys; |
|
325 |
|
326 uint32_t mProxyResolveFlags; |
|
327 nsCOMPtr<nsIURI> mProxyURI; |
|
328 |
|
329 uint32_t mContentDispositionHint; |
|
330 nsAutoPtr<nsString> mContentDispositionFilename; |
|
331 |
|
332 nsRefPtr<nsHttpHandler> mHttpHandler; // keep gHttpHandler alive |
|
333 |
|
334 // Performance tracking |
|
335 // The initiator type (for this resource) - how was the resource referenced in |
|
336 // the HTML file. |
|
337 nsString mInitiatorType; |
|
338 // Number of redirects that has occurred. |
|
339 int16_t mRedirectCount; |
|
340 // A time value equal to the starting time of the fetch that initiates the |
|
341 // redirect. |
|
342 mozilla::TimeStamp mRedirectStartTimeStamp; |
|
343 // A time value equal to the time immediately after receiving the last byte of |
|
344 // the response of the last redirect. |
|
345 mozilla::TimeStamp mRedirectEndTimeStamp; |
|
346 |
|
347 PRTime mChannelCreationTime; |
|
348 TimeStamp mChannelCreationTimestamp; |
|
349 TimeStamp mAsyncOpenTime; |
|
350 TimeStamp mCacheReadStart; |
|
351 TimeStamp mCacheReadEnd; |
|
352 // copied from the transaction before we null out mTransaction |
|
353 // so that the timing can still be queried from OnStopRequest |
|
354 TimingStruct mTransactionTimings; |
|
355 }; |
|
356 |
|
357 // Share some code while working around C++'s absurd inability to handle casting |
|
358 // of member functions between base/derived types. |
|
359 // - We want to store member function pointer to call at resume time, but one |
|
360 // such function--HandleAsyncAbort--we want to share between the |
|
361 // nsHttpChannel/HttpChannelChild. Can't define it in base class, because |
|
362 // then we'd have to cast member function ptr between base/derived class |
|
363 // types. Sigh... |
|
364 template <class T> |
|
365 class HttpAsyncAborter |
|
366 { |
|
367 public: |
|
368 HttpAsyncAborter(T *derived) : mThis(derived), mCallOnResume(0) {} |
|
369 |
|
370 // Aborts channel: calls OnStart/Stop with provided status, removes channel |
|
371 // from loadGroup. |
|
372 nsresult AsyncAbort(nsresult status); |
|
373 |
|
374 // Does most the actual work. |
|
375 void HandleAsyncAbort(); |
|
376 |
|
377 // AsyncCall calls a member function asynchronously (via an event). |
|
378 // retval isn't refcounted and is set only when event was successfully |
|
379 // posted, the event is returned for the purpose of cancelling when needed |
|
380 nsresult AsyncCall(void (T::*funcPtr)(), |
|
381 nsRunnableMethod<T> **retval = nullptr); |
|
382 private: |
|
383 T *mThis; |
|
384 |
|
385 protected: |
|
386 // Function to be called at resume time |
|
387 void (T::* mCallOnResume)(void); |
|
388 }; |
|
389 |
|
390 template <class T> |
|
391 nsresult HttpAsyncAborter<T>::AsyncAbort(nsresult status) |
|
392 { |
|
393 PR_LOG(gHttpLog, 4, |
|
394 ("HttpAsyncAborter::AsyncAbort [this=%p status=%x]\n", mThis, status)); |
|
395 |
|
396 mThis->mStatus = status; |
|
397 mThis->mIsPending = false; |
|
398 |
|
399 // if this fails? Callers ignore our return value anyway.... |
|
400 return AsyncCall(&T::HandleAsyncAbort); |
|
401 } |
|
402 |
|
403 // Each subclass needs to define its own version of this (which just calls this |
|
404 // base version), else we wind up casting base/derived member function ptrs |
|
405 template <class T> |
|
406 inline void HttpAsyncAborter<T>::HandleAsyncAbort() |
|
407 { |
|
408 NS_PRECONDITION(!mCallOnResume, "How did that happen?"); |
|
409 |
|
410 if (mThis->mSuspendCount) { |
|
411 PR_LOG(gHttpLog, 4, |
|
412 ("Waiting until resume to do async notification [this=%p]\n", mThis)); |
|
413 mCallOnResume = &T::HandleAsyncAbort; |
|
414 return; |
|
415 } |
|
416 |
|
417 mThis->DoNotifyListener(); |
|
418 |
|
419 // finally remove ourselves from the load group. |
|
420 if (mThis->mLoadGroup) |
|
421 mThis->mLoadGroup->RemoveRequest(mThis, nullptr, mThis->mStatus); |
|
422 } |
|
423 |
|
424 template <class T> |
|
425 nsresult HttpAsyncAborter<T>::AsyncCall(void (T::*funcPtr)(), |
|
426 nsRunnableMethod<T> **retval) |
|
427 { |
|
428 nsresult rv; |
|
429 |
|
430 nsRefPtr<nsRunnableMethod<T> > event = NS_NewRunnableMethod(mThis, funcPtr); |
|
431 rv = NS_DispatchToCurrentThread(event); |
|
432 if (NS_SUCCEEDED(rv) && retval) { |
|
433 *retval = event; |
|
434 } |
|
435 |
|
436 return rv; |
|
437 } |
|
438 |
|
439 } // namespace net |
|
440 } // namespace mozilla |
|
441 |
|
442 #endif // mozilla_net_HttpBaseChannel_h |