michael@0: /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ michael@0: /* vim:set et cin ts=4 sw=4 sts=4: */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #ifndef nsHttpChannel_h__ michael@0: #define nsHttpChannel_h__ michael@0: michael@0: #include "HttpBaseChannel.h" michael@0: #include "nsTArray.h" michael@0: #include "nsICachingChannel.h" michael@0: #include "nsICacheEntry.h" michael@0: #include "nsICacheEntryOpenCallback.h" michael@0: #include "nsIDNSListener.h" michael@0: #include "nsIApplicationCacheChannel.h" michael@0: #include "nsIProtocolProxyCallback.h" michael@0: #include "nsIHttpAuthenticableChannel.h" michael@0: #include "nsIAsyncVerifyRedirectCallback.h" michael@0: #include "nsIThreadRetargetableRequest.h" michael@0: #include "nsIThreadRetargetableStreamListener.h" michael@0: #include "nsWeakReference.h" michael@0: #include "TimingStruct.h" michael@0: #include "AutoClose.h" michael@0: michael@0: class nsIPrincipal; michael@0: class nsDNSPrefetch; michael@0: class nsICacheEntryDescriptor; michael@0: class nsICancelable; michael@0: class nsIHttpChannelAuthProvider; michael@0: class nsInputStreamPump; michael@0: class nsPerformance; michael@0: michael@0: namespace mozilla { namespace net { michael@0: michael@0: //----------------------------------------------------------------------------- michael@0: // nsHttpChannel michael@0: //----------------------------------------------------------------------------- michael@0: michael@0: class nsHttpChannel : public HttpBaseChannel michael@0: , public HttpAsyncAborter michael@0: , public nsIStreamListener michael@0: , public nsICachingChannel michael@0: , public nsICacheEntryOpenCallback michael@0: , public nsITransportEventSink michael@0: , public nsIProtocolProxyCallback michael@0: , public nsIHttpAuthenticableChannel michael@0: , public nsIApplicationCacheChannel michael@0: , public nsIAsyncVerifyRedirectCallback michael@0: , public nsIThreadRetargetableRequest michael@0: , public nsIThreadRetargetableStreamListener michael@0: , public nsIDNSListener michael@0: , public nsSupportsWeakReference michael@0: { michael@0: public: michael@0: NS_DECL_ISUPPORTS_INHERITED michael@0: NS_DECL_NSIREQUESTOBSERVER michael@0: NS_DECL_NSISTREAMLISTENER michael@0: NS_DECL_NSITHREADRETARGETABLESTREAMLISTENER michael@0: NS_DECL_NSICACHEINFOCHANNEL michael@0: NS_DECL_NSICACHINGCHANNEL michael@0: NS_DECL_NSICACHEENTRYOPENCALLBACK michael@0: NS_DECL_NSITRANSPORTEVENTSINK michael@0: NS_DECL_NSIPROTOCOLPROXYCALLBACK michael@0: NS_DECL_NSIPROXIEDCHANNEL michael@0: NS_DECL_NSIAPPLICATIONCACHECONTAINER michael@0: NS_DECL_NSIAPPLICATIONCACHECHANNEL michael@0: NS_DECL_NSIASYNCVERIFYREDIRECTCALLBACK michael@0: NS_DECL_NSITHREADRETARGETABLEREQUEST michael@0: NS_DECL_NSIDNSLISTENER michael@0: michael@0: // nsIHttpAuthenticableChannel. We can't use michael@0: // NS_DECL_NSIHTTPAUTHENTICABLECHANNEL because it duplicates cancel() and michael@0: // others. michael@0: NS_IMETHOD GetIsSSL(bool *aIsSSL); michael@0: NS_IMETHOD GetProxyMethodIsConnect(bool *aProxyMethodIsConnect); michael@0: NS_IMETHOD GetServerResponseHeader(nsACString & aServerResponseHeader); michael@0: NS_IMETHOD GetProxyChallenges(nsACString & aChallenges); michael@0: NS_IMETHOD GetWWWChallenges(nsACString & aChallenges); michael@0: NS_IMETHOD SetProxyCredentials(const nsACString & aCredentials); michael@0: NS_IMETHOD SetWWWCredentials(const nsACString & aCredentials); michael@0: NS_IMETHOD OnAuthAvailable(); michael@0: NS_IMETHOD OnAuthCancelled(bool userCancel); michael@0: // Functions we implement from nsIHttpAuthenticableChannel but are michael@0: // declared in HttpBaseChannel must be implemented in this class. We michael@0: // just call the HttpBaseChannel:: impls. michael@0: NS_IMETHOD GetLoadFlags(nsLoadFlags *aLoadFlags); michael@0: NS_IMETHOD GetURI(nsIURI **aURI); michael@0: NS_IMETHOD GetNotificationCallbacks(nsIInterfaceRequestor **aCallbacks); michael@0: NS_IMETHOD GetLoadGroup(nsILoadGroup **aLoadGroup); michael@0: NS_IMETHOD GetRequestMethod(nsACString& aMethod); michael@0: michael@0: nsHttpChannel(); michael@0: virtual ~nsHttpChannel(); michael@0: michael@0: virtual nsresult Init(nsIURI *aURI, uint32_t aCaps, nsProxyInfo *aProxyInfo, michael@0: uint32_t aProxyResolveFlags, michael@0: nsIURI *aProxyURI); michael@0: michael@0: // Methods HttpBaseChannel didn't implement for us or that we override. michael@0: // michael@0: // nsIRequest michael@0: NS_IMETHOD Cancel(nsresult status); michael@0: NS_IMETHOD Suspend(); michael@0: NS_IMETHOD Resume(); michael@0: NS_IMETHOD IsPending(bool *aIsPending); michael@0: // nsIChannel michael@0: NS_IMETHOD GetSecurityInfo(nsISupports **aSecurityInfo); michael@0: NS_IMETHOD AsyncOpen(nsIStreamListener *listener, nsISupports *aContext); michael@0: // nsIHttpChannelInternal michael@0: NS_IMETHOD SetupFallbackChannel(const char *aFallbackKey); michael@0: // nsISupportsPriority michael@0: NS_IMETHOD SetPriority(int32_t value); michael@0: // nsIResumableChannel michael@0: NS_IMETHOD ResumeAt(uint64_t startPos, const nsACString& entityID); michael@0: michael@0: NS_IMETHOD SetNotificationCallbacks(nsIInterfaceRequestor *aCallbacks); michael@0: NS_IMETHOD SetLoadGroup(nsILoadGroup *aLoadGroup); michael@0: // nsITimedChannel michael@0: NS_IMETHOD GetDomainLookupStart(mozilla::TimeStamp *aDomainLookupStart); michael@0: NS_IMETHOD GetDomainLookupEnd(mozilla::TimeStamp *aDomainLookupEnd); michael@0: NS_IMETHOD GetConnectStart(mozilla::TimeStamp *aConnectStart); michael@0: NS_IMETHOD GetConnectEnd(mozilla::TimeStamp *aConnectEnd); michael@0: NS_IMETHOD GetRequestStart(mozilla::TimeStamp *aRequestStart); michael@0: NS_IMETHOD GetResponseStart(mozilla::TimeStamp *aResponseStart); michael@0: NS_IMETHOD GetResponseEnd(mozilla::TimeStamp *aResponseEnd); michael@0: michael@0: public: /* internal necko use only */ michael@0: michael@0: void InternalSetUploadStream(nsIInputStream *uploadStream) michael@0: { mUploadStream = uploadStream; } michael@0: void SetUploadStreamHasHeaders(bool hasHeaders) michael@0: { mUploadStreamHasHeaders = hasHeaders; } michael@0: michael@0: nsresult SetReferrerInternal(nsIURI *referrer) { michael@0: nsAutoCString spec; michael@0: nsresult rv = referrer->GetAsciiSpec(spec); michael@0: if (NS_FAILED(rv)) return rv; michael@0: mReferrer = referrer; michael@0: mRequestHead.SetHeader(nsHttp::Referer, spec); michael@0: return NS_OK; michael@0: } michael@0: michael@0: // This allows cache entry to be marked as foreign even after channel itself michael@0: // is gone. Needed for e10s (see HttpChannelParent::RecvDocumentChannelCleanup) michael@0: class OfflineCacheEntryAsForeignMarker { michael@0: nsCOMPtr mApplicationCache; michael@0: nsCOMPtr mCacheURI; michael@0: public: michael@0: OfflineCacheEntryAsForeignMarker(nsIApplicationCache* appCache, michael@0: nsIURI* aURI) michael@0: : mApplicationCache(appCache) michael@0: , mCacheURI(aURI) michael@0: {} michael@0: michael@0: nsresult MarkAsForeign(); michael@0: }; michael@0: michael@0: OfflineCacheEntryAsForeignMarker* GetOfflineCacheEntryAsForeignMarker(); michael@0: michael@0: // Helper to keep cache callbacks wait flags consistent michael@0: class AutoCacheWaitFlags michael@0: { michael@0: public: michael@0: AutoCacheWaitFlags(nsHttpChannel* channel) michael@0: : mChannel(channel) michael@0: , mKeep(0) michael@0: { michael@0: // Flags must be set before entering any AsyncOpenCacheEntry call. michael@0: mChannel->mCacheEntriesToWaitFor = michael@0: nsHttpChannel::WAIT_FOR_CACHE_ENTRY | michael@0: nsHttpChannel::WAIT_FOR_OFFLINE_CACHE_ENTRY; michael@0: } michael@0: michael@0: void Keep(uint32_t flags) michael@0: { michael@0: // Called after successful call to appropriate AsyncOpenCacheEntry call. michael@0: mKeep |= flags; michael@0: } michael@0: michael@0: ~AutoCacheWaitFlags() michael@0: { michael@0: // Keep only flags those are left to be wait for. michael@0: mChannel->mCacheEntriesToWaitFor &= mKeep; michael@0: } michael@0: michael@0: private: michael@0: nsHttpChannel* mChannel; michael@0: uint32_t mKeep : 2; michael@0: }; michael@0: michael@0: void ForcePending(bool aForcePending); michael@0: michael@0: private: michael@0: typedef nsresult (nsHttpChannel::*nsContinueRedirectionFunc)(nsresult result); michael@0: michael@0: bool RequestIsConditional(); michael@0: nsresult BeginConnect(); michael@0: nsresult Connect(); michael@0: nsresult ContinueConnect(); michael@0: void SpeculativeConnect(); michael@0: nsresult SetupTransaction(); michael@0: void SetupTransactionLoadGroupInfo(); michael@0: nsresult CallOnStartRequest(); michael@0: nsresult ProcessResponse(); michael@0: nsresult ContinueProcessResponse(nsresult); michael@0: nsresult ProcessNormal(); michael@0: nsresult ContinueProcessNormal(nsresult); michael@0: nsresult ProcessNotModified(); michael@0: nsresult AsyncProcessRedirection(uint32_t httpStatus); michael@0: nsresult ContinueProcessRedirection(nsresult); michael@0: nsresult ContinueProcessRedirectionAfterFallback(nsresult); michael@0: nsresult ProcessFailedProxyConnect(uint32_t httpStatus); michael@0: nsresult ProcessFallback(bool *waitingForRedirectCallback); michael@0: nsresult ContinueProcessFallback(nsresult); michael@0: void HandleAsyncAbort(); michael@0: nsresult EnsureAssocReq(); michael@0: void ProcessSSLInformation(); michael@0: bool IsHTTPS(); michael@0: void RetrieveSSLOptions(); michael@0: michael@0: nsresult ContinueOnStartRequest1(nsresult); michael@0: nsresult ContinueOnStartRequest2(nsresult); michael@0: nsresult ContinueOnStartRequest3(nsresult); michael@0: michael@0: // redirection specific methods michael@0: void HandleAsyncRedirect(); michael@0: void HandleAsyncAPIRedirect(); michael@0: nsresult ContinueHandleAsyncRedirect(nsresult); michael@0: void HandleAsyncNotModified(); michael@0: void HandleAsyncFallback(); michael@0: nsresult ContinueHandleAsyncFallback(nsresult); michael@0: nsresult PromptTempRedirect(); michael@0: nsresult StartRedirectChannelToURI(nsIURI *, uint32_t); michael@0: virtual nsresult SetupReplacementChannel(nsIURI *, nsIChannel *, bool preserveMethod); michael@0: michael@0: // proxy specific methods michael@0: nsresult ProxyFailover(); michael@0: nsresult AsyncDoReplaceWithProxy(nsIProxyInfo *); michael@0: nsresult ContinueDoReplaceWithProxy(nsresult); michael@0: nsresult ResolveProxy(); michael@0: michael@0: // cache specific methods michael@0: nsresult OpenCacheEntry(bool usingSSL); michael@0: nsresult OnOfflineCacheEntryAvailable(nsICacheEntry *aEntry, michael@0: bool aNew, michael@0: nsIApplicationCache* aAppCache, michael@0: nsresult aResult); michael@0: nsresult OnNormalCacheEntryAvailable(nsICacheEntry *aEntry, michael@0: bool aNew, michael@0: nsresult aResult); michael@0: nsresult OpenOfflineCacheEntryForWriting(); michael@0: nsresult OnOfflineCacheEntryForWritingAvailable(nsICacheEntry *aEntry, michael@0: nsIApplicationCache* aAppCache, michael@0: nsresult aResult); michael@0: nsresult OnCacheEntryAvailableInternal(nsICacheEntry *entry, michael@0: bool aNew, michael@0: nsIApplicationCache* aAppCache, michael@0: nsresult status); michael@0: nsresult GenerateCacheKey(uint32_t postID, nsACString &key); michael@0: nsresult UpdateExpirationTime(); michael@0: nsresult CheckPartial(nsICacheEntry* aEntry, int64_t *aSize, int64_t *aContentLength); michael@0: bool ShouldUpdateOfflineCacheEntry(); michael@0: nsresult ReadFromCache(bool alreadyMarkedValid); michael@0: void CloseCacheEntry(bool doomOnFailure); michael@0: void CloseOfflineCacheEntry(); michael@0: nsresult InitCacheEntry(); michael@0: void UpdateInhibitPersistentCachingFlag(); michael@0: nsresult InitOfflineCacheEntry(); michael@0: nsresult AddCacheEntryHeaders(nsICacheEntry *entry); michael@0: nsresult StoreAuthorizationMetaData(nsICacheEntry *entry); michael@0: nsresult FinalizeCacheEntry(); michael@0: nsresult InstallCacheListener(int64_t offset = 0); michael@0: nsresult InstallOfflineCacheListener(int64_t offset = 0); michael@0: void MaybeInvalidateCacheEntryForSubsequentGet(); michael@0: void AsyncOnExamineCachedResponse(); michael@0: michael@0: // Handle the bogus Content-Encoding Apache sometimes sends michael@0: void ClearBogusContentEncodingIfNeeded(); michael@0: michael@0: // byte range request specific methods michael@0: nsresult ProcessPartialContent(); michael@0: nsresult OnDoneReadingPartialCacheEntry(bool *streamDone); michael@0: michael@0: nsresult DoAuthRetry(nsAHttpConnection *); michael@0: michael@0: void HandleAsyncRedirectChannelToHttps(); michael@0: nsresult StartRedirectChannelToHttps(); michael@0: nsresult ContinueAsyncRedirectChannelToURI(nsresult rv); michael@0: nsresult OpenRedirectChannel(nsresult rv); michael@0: michael@0: /** michael@0: * A function that takes care of reading STS headers and enforcing STS michael@0: * load rules. After a secure channel is erected, STS requires the channel michael@0: * to be trusted or any STS header data on the channel is ignored. michael@0: * This is called from ProcessResponse. michael@0: */ michael@0: nsresult ProcessSTSHeader(); michael@0: michael@0: void InvalidateCacheEntryForLocation(const char *location); michael@0: void AssembleCacheKey(const char *spec, uint32_t postID, nsACString &key); michael@0: nsresult CreateNewURI(const char *loc, nsIURI **newURI); michael@0: void DoInvalidateCacheEntry(nsIURI* aURI); michael@0: michael@0: // Ref RFC2616 13.10: "invalidation... MUST only be performed if michael@0: // the host part is the same as in the Request-URI" michael@0: inline bool HostPartIsTheSame(nsIURI *uri) { michael@0: nsAutoCString tmpHost1, tmpHost2; michael@0: return (NS_SUCCEEDED(mURI->GetAsciiHost(tmpHost1)) && michael@0: NS_SUCCEEDED(uri->GetAsciiHost(tmpHost2)) && michael@0: (tmpHost1 == tmpHost2)); michael@0: } michael@0: michael@0: inline static bool DoNotRender3xxBody(nsresult rv) { michael@0: return rv == NS_ERROR_REDIRECT_LOOP || michael@0: rv == NS_ERROR_CORRUPTED_CONTENT || michael@0: rv == NS_ERROR_UNKNOWN_PROTOCOL || michael@0: rv == NS_ERROR_MALFORMED_URI; michael@0: } michael@0: michael@0: // Create a aggregate set of the current notification callbacks michael@0: // and ensure the transaction is updated to use it. michael@0: void UpdateAggregateCallbacks(); michael@0: michael@0: static bool HasQueryString(nsHttpRequestHead::ParsedMethodType method, nsIURI * uri); michael@0: bool ResponseWouldVary(nsICacheEntry* entry) const; michael@0: bool MustValidateBasedOnQueryUrl() const; michael@0: bool IsResumable(int64_t partialLen, int64_t contentLength, michael@0: bool ignoreMissingPartialLen = false) const; michael@0: nsresult MaybeSetupByteRangeRequest(int64_t partialLen, int64_t contentLength); michael@0: nsresult SetupByteRangeRequest(int64_t partialLen); michael@0: nsresult OpenCacheInputStream(nsICacheEntry* cacheEntry, bool startBuffering); michael@0: michael@0: private: michael@0: nsCOMPtr mSecurityInfo; michael@0: nsCOMPtr mProxyRequest; michael@0: michael@0: nsRefPtr mTransactionPump; michael@0: nsRefPtr mTransaction; michael@0: michael@0: uint64_t mLogicalOffset; michael@0: michael@0: // cache specific data michael@0: nsCOMPtr mCacheEntry; michael@0: // We must close mCacheInputStream explicitly to avoid leaks. michael@0: AutoClose mCacheInputStream; michael@0: nsRefPtr mCachePump; michael@0: nsAutoPtr mCachedResponseHead; michael@0: nsCOMPtr mCachedSecurityInfo; michael@0: uint32_t mPostID; michael@0: uint32_t mRequestTime; michael@0: michael@0: nsCOMPtr mOfflineCacheEntry; michael@0: uint32_t mOfflineCacheLastModifiedTime; michael@0: nsCOMPtr mApplicationCacheForWrite; michael@0: nsCString mCacheDomain; michael@0: michael@0: // auth specific data michael@0: nsCOMPtr mAuthProvider; michael@0: michael@0: // If the channel is associated with a cache, and the URI matched michael@0: // a fallback namespace, this will hold the key for the fallback michael@0: // cache entry. michael@0: nsCString mFallbackKey; michael@0: michael@0: friend class AutoRedirectVetoNotifier; michael@0: friend class HttpAsyncAborter; michael@0: michael@0: nsCOMPtr mRedirectURI; michael@0: nsCOMPtr mRedirectChannel; michael@0: uint32_t mRedirectType; michael@0: michael@0: static const uint32_t WAIT_FOR_CACHE_ENTRY = 1; michael@0: static const uint32_t WAIT_FOR_OFFLINE_CACHE_ENTRY = 2; michael@0: michael@0: // state flags michael@0: uint32_t mCachedContentIsValid : 1; michael@0: uint32_t mCachedContentIsPartial : 1; michael@0: uint32_t mTransactionReplaced : 1; michael@0: uint32_t mAuthRetryPending : 1; michael@0: uint32_t mProxyAuthPending : 1; michael@0: uint32_t mResuming : 1; michael@0: uint32_t mInitedCacheEntry : 1; michael@0: // True if we are loading a fallback cache entry from the michael@0: // application cache. michael@0: uint32_t mFallbackChannel : 1; michael@0: // True if consumer added its own If-None-Match or If-Modified-Since michael@0: // headers. In such a case we must not override them in the cache code michael@0: // and also we want to pass possible 304 code response through. michael@0: uint32_t mCustomConditionalRequest : 1; michael@0: uint32_t mFallingBack : 1; michael@0: uint32_t mWaitingForRedirectCallback : 1; michael@0: // True if mRequestTime has been set. In such a case it is safe to update michael@0: // the cache entry's expiration time. Otherwise, it is not(see bug 567360). michael@0: uint32_t mRequestTimeInitialized : 1; michael@0: uint32_t mCacheEntryIsReadOnly : 1; michael@0: uint32_t mCacheEntryIsWriteOnly : 1; michael@0: // see WAIT_FOR_* constants above michael@0: uint32_t mCacheEntriesToWaitFor : 2; michael@0: uint32_t mHasQueryString : 1; michael@0: // whether cache entry data write was in progress during cache entry check michael@0: // when true, after we finish read from cache we must check all data michael@0: // had been loaded from cache. If not, then an error has to be propagated michael@0: // to the consumer. michael@0: uint32_t mConcurentCacheAccess : 1; michael@0: // whether the request is setup be byte-range michael@0: uint32_t mIsPartialRequest : 1; michael@0: // true iff there is AutoRedirectVetoNotifier on the stack michael@0: uint32_t mHasAutoRedirectVetoNotifier : 1; michael@0: michael@0: nsTArray mRedirectFuncStack; michael@0: michael@0: // Needed for accurate DNS timing michael@0: nsRefPtr mDNSPrefetch; michael@0: michael@0: nsresult WaitForRedirectCallback(); michael@0: void PushRedirectAsyncFunc(nsContinueRedirectionFunc func); michael@0: void PopRedirectAsyncFunc(nsContinueRedirectionFunc func); michael@0: michael@0: protected: michael@0: virtual void DoNotifyListenerCleanup(); michael@0: nsPerformance* GetPerformance(); michael@0: michael@0: private: // cache telemetry michael@0: bool mDidReval; michael@0: michael@0: private: michael@0: nsIPrincipal *GetPrincipal(); michael@0: nsCOMPtr mPrincipal; michael@0: bool mForcePending; michael@0: }; michael@0: michael@0: } } // namespace mozilla::net michael@0: michael@0: #endif // nsHttpChannel_h__