1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/netwerk/protocol/http/HttpBaseChannel.h Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,442 @@ 1.4 +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* vim: set sw=2 ts=8 et tw=80 : */ 1.6 + 1.7 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.8 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.9 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.10 + 1.11 +#ifndef mozilla_net_HttpBaseChannel_h 1.12 +#define mozilla_net_HttpBaseChannel_h 1.13 + 1.14 +#include "nsHttp.h" 1.15 +#include "nsAutoPtr.h" 1.16 +#include "nsHashPropertyBag.h" 1.17 +#include "nsProxyInfo.h" 1.18 +#include "nsHttpRequestHead.h" 1.19 +#include "nsHttpResponseHead.h" 1.20 +#include "nsHttpConnectionInfo.h" 1.21 +#include "nsIEncodedChannel.h" 1.22 +#include "nsIHttpChannel.h" 1.23 +#include "nsHttpHandler.h" 1.24 +#include "nsIHttpChannelInternal.h" 1.25 +#include "nsIUploadChannel.h" 1.26 +#include "nsIUploadChannel2.h" 1.27 +#include "nsIProgressEventSink.h" 1.28 +#include "nsIURI.h" 1.29 +#include "nsIEffectiveTLDService.h" 1.30 +#include "nsIStringEnumerator.h" 1.31 +#include "nsISupportsPriority.h" 1.32 +#include "nsIApplicationCache.h" 1.33 +#include "nsIResumableChannel.h" 1.34 +#include "nsITraceableChannel.h" 1.35 +#include "nsILoadContext.h" 1.36 +#include "mozilla/net/NeckoCommon.h" 1.37 +#include "nsThreadUtils.h" 1.38 +#include "PrivateBrowsingChannel.h" 1.39 +#include "mozilla/net/DNS.h" 1.40 +#include "nsITimedChannel.h" 1.41 +#include "nsISecurityConsoleMessage.h" 1.42 + 1.43 +extern PRLogModuleInfo *gHttpLog; 1.44 + 1.45 +namespace mozilla { 1.46 +namespace net { 1.47 + 1.48 +/* 1.49 + * This class is a partial implementation of nsIHttpChannel. It contains code 1.50 + * shared by nsHttpChannel and HttpChannelChild. 1.51 + * - Note that this class has nothing to do with nsBaseChannel, which is an 1.52 + * earlier effort at a base class for channels that somehow never made it all 1.53 + * the way to the HTTP channel. 1.54 + */ 1.55 +class HttpBaseChannel : public nsHashPropertyBag 1.56 + , public nsIEncodedChannel 1.57 + , public nsIHttpChannel 1.58 + , public nsIHttpChannelInternal 1.59 + , public nsIUploadChannel 1.60 + , public nsIUploadChannel2 1.61 + , public nsISupportsPriority 1.62 + , public nsIResumableChannel 1.63 + , public nsITraceableChannel 1.64 + , public PrivateBrowsingChannel<HttpBaseChannel> 1.65 + , public nsITimedChannel 1.66 +{ 1.67 +public: 1.68 + NS_DECL_ISUPPORTS_INHERITED 1.69 + NS_DECL_NSIUPLOADCHANNEL 1.70 + NS_DECL_NSIUPLOADCHANNEL2 1.71 + NS_DECL_NSITRACEABLECHANNEL 1.72 + NS_DECL_NSITIMEDCHANNEL 1.73 + 1.74 + HttpBaseChannel(); 1.75 + virtual ~HttpBaseChannel(); 1.76 + 1.77 + virtual nsresult Init(nsIURI *aURI, uint32_t aCaps, nsProxyInfo *aProxyInfo, 1.78 + uint32_t aProxyResolveFlags, 1.79 + nsIURI *aProxyURI); 1.80 + 1.81 + // nsIRequest 1.82 + NS_IMETHOD GetName(nsACString& aName); 1.83 + NS_IMETHOD IsPending(bool *aIsPending); 1.84 + NS_IMETHOD GetStatus(nsresult *aStatus); 1.85 + NS_IMETHOD GetLoadGroup(nsILoadGroup **aLoadGroup); 1.86 + NS_IMETHOD SetLoadGroup(nsILoadGroup *aLoadGroup); 1.87 + NS_IMETHOD GetLoadFlags(nsLoadFlags *aLoadFlags); 1.88 + NS_IMETHOD SetLoadFlags(nsLoadFlags aLoadFlags); 1.89 + 1.90 + // nsIChannel 1.91 + NS_IMETHOD GetOriginalURI(nsIURI **aOriginalURI); 1.92 + NS_IMETHOD SetOriginalURI(nsIURI *aOriginalURI); 1.93 + NS_IMETHOD GetURI(nsIURI **aURI); 1.94 + NS_IMETHOD GetOwner(nsISupports **aOwner); 1.95 + NS_IMETHOD SetOwner(nsISupports *aOwner); 1.96 + NS_IMETHOD GetNotificationCallbacks(nsIInterfaceRequestor **aCallbacks); 1.97 + NS_IMETHOD SetNotificationCallbacks(nsIInterfaceRequestor *aCallbacks); 1.98 + NS_IMETHOD GetContentType(nsACString& aContentType); 1.99 + NS_IMETHOD SetContentType(const nsACString& aContentType); 1.100 + NS_IMETHOD GetContentCharset(nsACString& aContentCharset); 1.101 + NS_IMETHOD SetContentCharset(const nsACString& aContentCharset); 1.102 + NS_IMETHOD GetContentDisposition(uint32_t *aContentDisposition); 1.103 + NS_IMETHOD SetContentDisposition(uint32_t aContentDisposition); 1.104 + NS_IMETHOD GetContentDispositionFilename(nsAString& aContentDispositionFilename); 1.105 + NS_IMETHOD SetContentDispositionFilename(const nsAString& aContentDispositionFilename); 1.106 + NS_IMETHOD GetContentDispositionHeader(nsACString& aContentDispositionHeader); 1.107 + NS_IMETHOD GetContentLength(int64_t *aContentLength); 1.108 + NS_IMETHOD SetContentLength(int64_t aContentLength); 1.109 + NS_IMETHOD Open(nsIInputStream **aResult); 1.110 + 1.111 + // nsIEncodedChannel 1.112 + NS_IMETHOD GetApplyConversion(bool *value); 1.113 + NS_IMETHOD SetApplyConversion(bool value); 1.114 + NS_IMETHOD GetContentEncodings(nsIUTF8StringEnumerator** aEncodings); 1.115 + 1.116 + // HttpBaseChannel::nsIHttpChannel 1.117 + NS_IMETHOD GetRequestMethod(nsACString& aMethod); 1.118 + NS_IMETHOD SetRequestMethod(const nsACString& aMethod); 1.119 + NS_IMETHOD GetReferrer(nsIURI **referrer); 1.120 + NS_IMETHOD SetReferrer(nsIURI *referrer); 1.121 + NS_IMETHOD GetProxyURI(nsIURI **proxyURI); 1.122 + NS_IMETHOD GetRequestHeader(const nsACString& aHeader, nsACString& aValue); 1.123 + NS_IMETHOD SetRequestHeader(const nsACString& aHeader, 1.124 + const nsACString& aValue, bool aMerge); 1.125 + NS_IMETHOD VisitRequestHeaders(nsIHttpHeaderVisitor *visitor); 1.126 + NS_IMETHOD GetResponseHeader(const nsACString &header, nsACString &value); 1.127 + NS_IMETHOD SetResponseHeader(const nsACString& header, 1.128 + const nsACString& value, bool merge); 1.129 + NS_IMETHOD VisitResponseHeaders(nsIHttpHeaderVisitor *visitor); 1.130 + NS_IMETHOD GetAllowPipelining(bool *value); 1.131 + NS_IMETHOD SetAllowPipelining(bool value); 1.132 + NS_IMETHOD GetRedirectionLimit(uint32_t *value); 1.133 + NS_IMETHOD SetRedirectionLimit(uint32_t value); 1.134 + NS_IMETHOD IsNoStoreResponse(bool *value); 1.135 + NS_IMETHOD IsNoCacheResponse(bool *value); 1.136 + NS_IMETHOD GetResponseStatus(uint32_t *aValue); 1.137 + NS_IMETHOD GetResponseStatusText(nsACString& aValue); 1.138 + NS_IMETHOD GetRequestSucceeded(bool *aValue); 1.139 + NS_IMETHOD RedirectTo(nsIURI *newURI); 1.140 + 1.141 + // nsIHttpChannelInternal 1.142 + NS_IMETHOD GetDocumentURI(nsIURI **aDocumentURI); 1.143 + NS_IMETHOD SetDocumentURI(nsIURI *aDocumentURI); 1.144 + NS_IMETHOD GetRequestVersion(uint32_t *major, uint32_t *minor); 1.145 + NS_IMETHOD GetResponseVersion(uint32_t *major, uint32_t *minor); 1.146 + NS_IMETHOD SetCookie(const char *aCookieHeader); 1.147 + NS_IMETHOD GetForceAllowThirdPartyCookie(bool *aForce); 1.148 + NS_IMETHOD SetForceAllowThirdPartyCookie(bool aForce); 1.149 + NS_IMETHOD GetCanceled(bool *aCanceled); 1.150 + NS_IMETHOD GetChannelIsForDownload(bool *aChannelIsForDownload); 1.151 + NS_IMETHOD SetChannelIsForDownload(bool aChannelIsForDownload); 1.152 + NS_IMETHOD SetCacheKeysRedirectChain(nsTArray<nsCString> *cacheKeys); 1.153 + NS_IMETHOD GetLocalAddress(nsACString& addr); 1.154 + NS_IMETHOD GetLocalPort(int32_t* port); 1.155 + NS_IMETHOD GetRemoteAddress(nsACString& addr); 1.156 + NS_IMETHOD GetRemotePort(int32_t* port); 1.157 + NS_IMETHOD GetAllowSpdy(bool *aAllowSpdy); 1.158 + NS_IMETHOD SetAllowSpdy(bool aAllowSpdy); 1.159 + NS_IMETHOD GetLoadAsBlocking(bool *aLoadAsBlocking); 1.160 + NS_IMETHOD SetLoadAsBlocking(bool aLoadAsBlocking); 1.161 + NS_IMETHOD GetLoadUnblocked(bool *aLoadUnblocked); 1.162 + NS_IMETHOD SetLoadUnblocked(bool aLoadUnblocked); 1.163 + NS_IMETHOD GetApiRedirectToURI(nsIURI * *aApiRedirectToURI); 1.164 + NS_IMETHOD AddSecurityMessage(const nsAString &aMessageTag, const nsAString &aMessageCategory); 1.165 + NS_IMETHOD TakeAllSecurityMessages(nsCOMArray<nsISecurityConsoleMessage> &aMessages); 1.166 + NS_IMETHOD GetResponseTimeoutEnabled(bool *aEnable); 1.167 + NS_IMETHOD SetResponseTimeoutEnabled(bool aEnable); 1.168 + 1.169 + inline void CleanRedirectCacheChainIfNecessary() 1.170 + { 1.171 + mRedirectedCachekeys = nullptr; 1.172 + } 1.173 + NS_IMETHOD HTTPUpgrade(const nsACString & aProtocolName, 1.174 + nsIHttpUpgradeListener *aListener); 1.175 + 1.176 + // nsISupportsPriority 1.177 + NS_IMETHOD GetPriority(int32_t *value); 1.178 + NS_IMETHOD AdjustPriority(int32_t delta); 1.179 + 1.180 + // nsIResumableChannel 1.181 + NS_IMETHOD GetEntityID(nsACString& aEntityID); 1.182 + 1.183 + class nsContentEncodings : public nsIUTF8StringEnumerator 1.184 + { 1.185 + public: 1.186 + NS_DECL_ISUPPORTS 1.187 + NS_DECL_NSIUTF8STRINGENUMERATOR 1.188 + 1.189 + nsContentEncodings(nsIHttpChannel* aChannel, const char* aEncodingHeader); 1.190 + virtual ~nsContentEncodings(); 1.191 + 1.192 + private: 1.193 + nsresult PrepareForNext(void); 1.194 + 1.195 + // We do not own the buffer. The channel owns it. 1.196 + const char* mEncodingHeader; 1.197 + const char* mCurStart; // points to start of current header 1.198 + const char* mCurEnd; // points to end of current header 1.199 + 1.200 + // Hold a ref to our channel so that it can't go away and take the 1.201 + // header with it. 1.202 + nsCOMPtr<nsIHttpChannel> mChannel; 1.203 + 1.204 + bool mReady; 1.205 + }; 1.206 + 1.207 + nsHttpResponseHead * GetResponseHead() const { return mResponseHead; } 1.208 + nsHttpRequestHead * GetRequestHead() { return &mRequestHead; } 1.209 + 1.210 + const NetAddr& GetSelfAddr() { return mSelfAddr; } 1.211 + const NetAddr& GetPeerAddr() { return mPeerAddr; } 1.212 + 1.213 +public: /* Necko internal use only... */ 1.214 + 1.215 + 1.216 + // Return whether upon a redirect code of httpStatus for method, the 1.217 + // request method should be rewritten to GET. 1.218 + static bool ShouldRewriteRedirectToGET(uint32_t httpStatus, 1.219 + nsHttpRequestHead::ParsedMethodType method); 1.220 + 1.221 +protected: 1.222 + nsCOMArray<nsISecurityConsoleMessage> mSecurityConsoleMessages; 1.223 + 1.224 + // Handle notifying listener, removing from loadgroup if request failed. 1.225 + void DoNotifyListener(); 1.226 + virtual void DoNotifyListenerCleanup() = 0; 1.227 + 1.228 + // drop reference to listener, its callbacks, and the progress sink 1.229 + void ReleaseListeners(); 1.230 + 1.231 + nsresult ApplyContentConversions(); 1.232 + 1.233 + void AddCookiesToRequest(); 1.234 + virtual nsresult SetupReplacementChannel(nsIURI *, 1.235 + nsIChannel *, 1.236 + bool preserveMethod); 1.237 + 1.238 + // bundle calling OMR observers and marking flag into one function 1.239 + inline void CallOnModifyRequestObservers() { 1.240 + gHttpHandler->OnModifyRequest(this); 1.241 + mRequestObserversCalled = true; 1.242 + } 1.243 + 1.244 + // Helper function to simplify getting notification callbacks. 1.245 + template <class T> 1.246 + void GetCallback(nsCOMPtr<T> &aResult) 1.247 + { 1.248 + NS_QueryNotificationCallbacks(mCallbacks, mLoadGroup, 1.249 + NS_GET_TEMPLATE_IID(T), 1.250 + getter_AddRefs(aResult)); 1.251 + } 1.252 + 1.253 + // Redirect tracking 1.254 + // Checks whether or not aURI and mOriginalURI share the same domain. 1.255 + bool SameOriginWithOriginalUri(nsIURI *aURI); 1.256 + 1.257 + friend class PrivateBrowsingChannel<HttpBaseChannel>; 1.258 + 1.259 + nsCOMPtr<nsIURI> mURI; 1.260 + nsCOMPtr<nsIURI> mOriginalURI; 1.261 + nsCOMPtr<nsIURI> mDocumentURI; 1.262 + nsCOMPtr<nsIStreamListener> mListener; 1.263 + nsCOMPtr<nsISupports> mListenerContext; 1.264 + nsCOMPtr<nsILoadGroup> mLoadGroup; 1.265 + nsCOMPtr<nsISupports> mOwner; 1.266 + nsCOMPtr<nsIInterfaceRequestor> mCallbacks; 1.267 + nsCOMPtr<nsIProgressEventSink> mProgressSink; 1.268 + nsCOMPtr<nsIURI> mReferrer; 1.269 + nsCOMPtr<nsIApplicationCache> mApplicationCache; 1.270 + 1.271 + nsHttpRequestHead mRequestHead; 1.272 + nsCOMPtr<nsIInputStream> mUploadStream; 1.273 + nsAutoPtr<nsHttpResponseHead> mResponseHead; 1.274 + nsRefPtr<nsHttpConnectionInfo> mConnectionInfo; 1.275 + nsCOMPtr<nsIProxyInfo> mProxyInfo; 1.276 + 1.277 + nsCString mSpec; // ASCII encoded URL spec 1.278 + nsCString mContentTypeHint; 1.279 + nsCString mContentCharsetHint; 1.280 + nsCString mUserSetCookieHeader; 1.281 + 1.282 + NetAddr mSelfAddr; 1.283 + NetAddr mPeerAddr; 1.284 + 1.285 + // HTTP Upgrade Data 1.286 + nsCString mUpgradeProtocol; 1.287 + nsCOMPtr<nsIHttpUpgradeListener> mUpgradeProtocolCallback; 1.288 + 1.289 + // Resumable channel specific data 1.290 + nsCString mEntityID; 1.291 + uint64_t mStartPos; 1.292 + 1.293 + nsresult mStatus; 1.294 + uint32_t mLoadFlags; 1.295 + uint32_t mCaps; 1.296 + int16_t mPriority; 1.297 + uint8_t mRedirectionLimit; 1.298 + 1.299 + uint32_t mApplyConversion : 1; 1.300 + uint32_t mCanceled : 1; 1.301 + uint32_t mIsPending : 1; 1.302 + uint32_t mWasOpened : 1; 1.303 + // if 1 all "http-on-{opening|modify|etc}-request" observers have been called 1.304 + uint32_t mRequestObserversCalled : 1; 1.305 + uint32_t mResponseHeadersModified : 1; 1.306 + uint32_t mAllowPipelining : 1; 1.307 + uint32_t mForceAllowThirdPartyCookie : 1; 1.308 + uint32_t mUploadStreamHasHeaders : 1; 1.309 + uint32_t mInheritApplicationCache : 1; 1.310 + uint32_t mChooseApplicationCache : 1; 1.311 + uint32_t mLoadedFromApplicationCache : 1; 1.312 + uint32_t mChannelIsForDownload : 1; 1.313 + uint32_t mTracingEnabled : 1; 1.314 + // True if timing collection is enabled 1.315 + uint32_t mTimingEnabled : 1; 1.316 + uint32_t mAllowSpdy : 1; 1.317 + uint32_t mLoadAsBlocking : 1; 1.318 + uint32_t mLoadUnblocked : 1; 1.319 + uint32_t mResponseTimeoutEnabled : 1; 1.320 + // A flag that should be false only if a cross-domain redirect occurred 1.321 + uint32_t mAllRedirectsSameOrigin : 1; 1.322 + 1.323 + // Current suspension depth for this channel object 1.324 + uint32_t mSuspendCount; 1.325 + 1.326 + nsCOMPtr<nsIURI> mAPIRedirectToURI; 1.327 + nsAutoPtr<nsTArray<nsCString> > mRedirectedCachekeys; 1.328 + 1.329 + uint32_t mProxyResolveFlags; 1.330 + nsCOMPtr<nsIURI> mProxyURI; 1.331 + 1.332 + uint32_t mContentDispositionHint; 1.333 + nsAutoPtr<nsString> mContentDispositionFilename; 1.334 + 1.335 + nsRefPtr<nsHttpHandler> mHttpHandler; // keep gHttpHandler alive 1.336 + 1.337 + // Performance tracking 1.338 + // The initiator type (for this resource) - how was the resource referenced in 1.339 + // the HTML file. 1.340 + nsString mInitiatorType; 1.341 + // Number of redirects that has occurred. 1.342 + int16_t mRedirectCount; 1.343 + // A time value equal to the starting time of the fetch that initiates the 1.344 + // redirect. 1.345 + mozilla::TimeStamp mRedirectStartTimeStamp; 1.346 + // A time value equal to the time immediately after receiving the last byte of 1.347 + // the response of the last redirect. 1.348 + mozilla::TimeStamp mRedirectEndTimeStamp; 1.349 + 1.350 + PRTime mChannelCreationTime; 1.351 + TimeStamp mChannelCreationTimestamp; 1.352 + TimeStamp mAsyncOpenTime; 1.353 + TimeStamp mCacheReadStart; 1.354 + TimeStamp mCacheReadEnd; 1.355 + // copied from the transaction before we null out mTransaction 1.356 + // so that the timing can still be queried from OnStopRequest 1.357 + TimingStruct mTransactionTimings; 1.358 +}; 1.359 + 1.360 +// Share some code while working around C++'s absurd inability to handle casting 1.361 +// of member functions between base/derived types. 1.362 +// - We want to store member function pointer to call at resume time, but one 1.363 +// such function--HandleAsyncAbort--we want to share between the 1.364 +// nsHttpChannel/HttpChannelChild. Can't define it in base class, because 1.365 +// then we'd have to cast member function ptr between base/derived class 1.366 +// types. Sigh... 1.367 +template <class T> 1.368 +class HttpAsyncAborter 1.369 +{ 1.370 +public: 1.371 + HttpAsyncAborter(T *derived) : mThis(derived), mCallOnResume(0) {} 1.372 + 1.373 + // Aborts channel: calls OnStart/Stop with provided status, removes channel 1.374 + // from loadGroup. 1.375 + nsresult AsyncAbort(nsresult status); 1.376 + 1.377 + // Does most the actual work. 1.378 + void HandleAsyncAbort(); 1.379 + 1.380 + // AsyncCall calls a member function asynchronously (via an event). 1.381 + // retval isn't refcounted and is set only when event was successfully 1.382 + // posted, the event is returned for the purpose of cancelling when needed 1.383 + nsresult AsyncCall(void (T::*funcPtr)(), 1.384 + nsRunnableMethod<T> **retval = nullptr); 1.385 +private: 1.386 + T *mThis; 1.387 + 1.388 +protected: 1.389 + // Function to be called at resume time 1.390 + void (T::* mCallOnResume)(void); 1.391 +}; 1.392 + 1.393 +template <class T> 1.394 +nsresult HttpAsyncAborter<T>::AsyncAbort(nsresult status) 1.395 +{ 1.396 + PR_LOG(gHttpLog, 4, 1.397 + ("HttpAsyncAborter::AsyncAbort [this=%p status=%x]\n", mThis, status)); 1.398 + 1.399 + mThis->mStatus = status; 1.400 + mThis->mIsPending = false; 1.401 + 1.402 + // if this fails? Callers ignore our return value anyway.... 1.403 + return AsyncCall(&T::HandleAsyncAbort); 1.404 +} 1.405 + 1.406 +// Each subclass needs to define its own version of this (which just calls this 1.407 +// base version), else we wind up casting base/derived member function ptrs 1.408 +template <class T> 1.409 +inline void HttpAsyncAborter<T>::HandleAsyncAbort() 1.410 +{ 1.411 + NS_PRECONDITION(!mCallOnResume, "How did that happen?"); 1.412 + 1.413 + if (mThis->mSuspendCount) { 1.414 + PR_LOG(gHttpLog, 4, 1.415 + ("Waiting until resume to do async notification [this=%p]\n", mThis)); 1.416 + mCallOnResume = &T::HandleAsyncAbort; 1.417 + return; 1.418 + } 1.419 + 1.420 + mThis->DoNotifyListener(); 1.421 + 1.422 + // finally remove ourselves from the load group. 1.423 + if (mThis->mLoadGroup) 1.424 + mThis->mLoadGroup->RemoveRequest(mThis, nullptr, mThis->mStatus); 1.425 +} 1.426 + 1.427 +template <class T> 1.428 +nsresult HttpAsyncAborter<T>::AsyncCall(void (T::*funcPtr)(), 1.429 + nsRunnableMethod<T> **retval) 1.430 +{ 1.431 + nsresult rv; 1.432 + 1.433 + nsRefPtr<nsRunnableMethod<T> > event = NS_NewRunnableMethod(mThis, funcPtr); 1.434 + rv = NS_DispatchToCurrentThread(event); 1.435 + if (NS_SUCCEEDED(rv) && retval) { 1.436 + *retval = event; 1.437 + } 1.438 + 1.439 + return rv; 1.440 +} 1.441 + 1.442 +} // namespace net 1.443 +} // namespace mozilla 1.444 + 1.445 +#endif // mozilla_net_HttpBaseChannel_h