gecko/netwerk/protocol/http/HttpBaseChannel.h
Ehsan Akhgari 5236854e21 Bug 741059 - Part 1: Add APIs to nsIChannel to allow callers to override the private bit on the channel; r=jduell
This is probably the worst patch that I have ever written!

We add a setPrivate method to nsIPrivateBrowsingChannel which will be
implemented by channels who care about private browsing.  This allows the
client to explicitly override the private bit on the channel.
NS_UsePrivateBrowsing is also taught about this override bit using the
internal nsIPrivateBrowsingChannel::IsPrivateModeOverriden API.  This patch
implements the new API for HTTP, FTP and wyciwyg channels.  This also
modifies the IPC implementations of these channels to correctly transfer that
bit to the parent process if it has been set in the child process channel.
2012-09-04 20:37:45 -04:00

362 lines
14 KiB
C++

/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set sw=2 ts=8 et tw=80 : */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef mozilla_net_HttpBaseChannel_h
#define mozilla_net_HttpBaseChannel_h
#include "nsHttp.h"
#include "nsAutoPtr.h"
#include "nsHashPropertyBag.h"
#include "nsProxyInfo.h"
#include "nsHttpRequestHead.h"
#include "nsHttpResponseHead.h"
#include "nsHttpConnectionInfo.h"
#include "nsIEncodedChannel.h"
#include "nsIHttpChannel.h"
#include "nsIHttpChannelInternal.h"
#include "nsIUploadChannel.h"
#include "nsIUploadChannel2.h"
#include "nsIProgressEventSink.h"
#include "nsIURI.h"
#include "nsIStringEnumerator.h"
#include "nsISupportsPriority.h"
#include "nsIApplicationCache.h"
#include "nsIResumableChannel.h"
#include "nsITraceableChannel.h"
#include "nsILoadContext.h"
#include "mozilla/net/NeckoCommon.h"
#include "nsThreadUtils.h"
#include "PrivateBrowsingChannel.h"
namespace mozilla {
namespace net {
/*
* This class is a partial implementation of nsIHttpChannel. It contains code
* shared by nsHttpChannel and HttpChannelChild.
* - Note that this class has nothing to do with nsBaseChannel, which is an
* earlier effort at a base class for channels that somehow never made it all
* the way to the HTTP channel.
*/
class HttpBaseChannel : public nsHashPropertyBag
, public nsIEncodedChannel
, public nsIHttpChannel
, public nsIHttpChannelInternal
, public nsIUploadChannel
, public nsIUploadChannel2
, public nsISupportsPriority
, public nsIResumableChannel
, public nsITraceableChannel
, public PrivateBrowsingChannel<HttpBaseChannel>
{
public:
NS_DECL_ISUPPORTS_INHERITED
NS_DECL_NSIUPLOADCHANNEL
NS_DECL_NSIUPLOADCHANNEL2
NS_DECL_NSITRACEABLECHANNEL
HttpBaseChannel();
virtual ~HttpBaseChannel();
virtual nsresult Init(nsIURI *aURI, uint8_t aCaps, nsProxyInfo *aProxyInfo);
// nsIRequest
NS_IMETHOD GetName(nsACString& aName);
NS_IMETHOD IsPending(bool *aIsPending);
NS_IMETHOD GetStatus(nsresult *aStatus);
NS_IMETHOD GetLoadGroup(nsILoadGroup **aLoadGroup);
NS_IMETHOD SetLoadGroup(nsILoadGroup *aLoadGroup);
NS_IMETHOD GetLoadFlags(nsLoadFlags *aLoadFlags);
NS_IMETHOD SetLoadFlags(nsLoadFlags aLoadFlags);
// nsIChannel
NS_IMETHOD GetOriginalURI(nsIURI **aOriginalURI);
NS_IMETHOD SetOriginalURI(nsIURI *aOriginalURI);
NS_IMETHOD GetURI(nsIURI **aURI);
NS_IMETHOD GetOwner(nsISupports **aOwner);
NS_IMETHOD SetOwner(nsISupports *aOwner);
NS_IMETHOD GetNotificationCallbacks(nsIInterfaceRequestor **aCallbacks);
NS_IMETHOD SetNotificationCallbacks(nsIInterfaceRequestor *aCallbacks);
NS_IMETHOD GetContentType(nsACString& aContentType);
NS_IMETHOD SetContentType(const nsACString& aContentType);
NS_IMETHOD GetContentCharset(nsACString& aContentCharset);
NS_IMETHOD SetContentCharset(const nsACString& aContentCharset);
NS_IMETHOD GetContentDisposition(uint32_t *aContentDisposition);
NS_IMETHOD GetContentDispositionFilename(nsAString& aContentDispositionFilename);
NS_IMETHOD GetContentDispositionHeader(nsACString& aContentDispositionHeader);
NS_IMETHOD GetContentLength(int32_t *aContentLength);
NS_IMETHOD SetContentLength(int32_t aContentLength);
NS_IMETHOD Open(nsIInputStream **aResult);
// nsIEncodedChannel
NS_IMETHOD GetApplyConversion(bool *value);
NS_IMETHOD SetApplyConversion(bool value);
NS_IMETHOD GetContentEncodings(nsIUTF8StringEnumerator** aEncodings);
// HttpBaseChannel::nsIHttpChannel
NS_IMETHOD GetRequestMethod(nsACString& aMethod);
NS_IMETHOD SetRequestMethod(const nsACString& aMethod);
NS_IMETHOD GetReferrer(nsIURI **referrer);
NS_IMETHOD SetReferrer(nsIURI *referrer);
NS_IMETHOD GetRequestHeader(const nsACString& aHeader, nsACString& aValue);
NS_IMETHOD SetRequestHeader(const nsACString& aHeader,
const nsACString& aValue, bool aMerge);
NS_IMETHOD VisitRequestHeaders(nsIHttpHeaderVisitor *visitor);
NS_IMETHOD GetResponseHeader(const nsACString &header, nsACString &value);
NS_IMETHOD SetResponseHeader(const nsACString& header,
const nsACString& value, bool merge);
NS_IMETHOD VisitResponseHeaders(nsIHttpHeaderVisitor *visitor);
NS_IMETHOD GetAllowPipelining(bool *value);
NS_IMETHOD SetAllowPipelining(bool value);
NS_IMETHOD GetRedirectionLimit(uint32_t *value);
NS_IMETHOD SetRedirectionLimit(uint32_t value);
NS_IMETHOD IsNoStoreResponse(bool *value);
NS_IMETHOD IsNoCacheResponse(bool *value);
NS_IMETHOD GetResponseStatus(uint32_t *aValue);
NS_IMETHOD GetResponseStatusText(nsACString& aValue);
NS_IMETHOD GetRequestSucceeded(bool *aValue);
// nsIHttpChannelInternal
NS_IMETHOD GetDocumentURI(nsIURI **aDocumentURI);
NS_IMETHOD SetDocumentURI(nsIURI *aDocumentURI);
NS_IMETHOD GetRequestVersion(uint32_t *major, uint32_t *minor);
NS_IMETHOD GetResponseVersion(uint32_t *major, uint32_t *minor);
NS_IMETHOD SetCookie(const char *aCookieHeader);
NS_IMETHOD GetForceAllowThirdPartyCookie(bool *aForce);
NS_IMETHOD SetForceAllowThirdPartyCookie(bool aForce);
NS_IMETHOD GetCanceled(bool *aCanceled);
NS_IMETHOD GetChannelIsForDownload(bool *aChannelIsForDownload);
NS_IMETHOD SetChannelIsForDownload(bool aChannelIsForDownload);
NS_IMETHOD SetCacheKeysRedirectChain(nsTArray<nsCString> *cacheKeys);
NS_IMETHOD GetLocalAddress(nsACString& addr);
NS_IMETHOD GetLocalPort(int32_t* port);
NS_IMETHOD GetRemoteAddress(nsACString& addr);
NS_IMETHOD GetRemotePort(int32_t* port);
NS_IMETHOD GetAllowSpdy(bool *aAllowSpdy);
NS_IMETHOD SetAllowSpdy(bool aAllowSpdy);
inline void CleanRedirectCacheChainIfNecessary()
{
mRedirectedCachekeys = nullptr;
}
NS_IMETHOD HTTPUpgrade(const nsACString & aProtocolName,
nsIHttpUpgradeListener *aListener);
// nsISupportsPriority
NS_IMETHOD GetPriority(int32_t *value);
NS_IMETHOD AdjustPriority(int32_t delta);
// nsIResumableChannel
NS_IMETHOD GetEntityID(nsACString& aEntityID);
class nsContentEncodings : public nsIUTF8StringEnumerator
{
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIUTF8STRINGENUMERATOR
nsContentEncodings(nsIHttpChannel* aChannel, const char* aEncodingHeader);
virtual ~nsContentEncodings();
private:
nsresult PrepareForNext(void);
// We do not own the buffer. The channel owns it.
const char* mEncodingHeader;
const char* mCurStart; // points to start of current header
const char* mCurEnd; // points to end of current header
// Hold a ref to our channel so that it can't go away and take the
// header with it.
nsCOMPtr<nsIHttpChannel> mChannel;
bool mReady;
};
nsHttpResponseHead * GetResponseHead() const { return mResponseHead; }
nsHttpRequestHead * GetRequestHead() { return &mRequestHead; }
const PRNetAddr& GetSelfAddr() { return mSelfAddr; }
const PRNetAddr& GetPeerAddr() { return mPeerAddr; }
public: /* Necko internal use only... */
bool ShouldRewriteRedirectToGET(uint32_t httpStatus, nsHttpAtom method);
bool IsSafeMethod(nsHttpAtom method);
protected:
// Handle notifying listener, removing from loadgroup if request failed.
void DoNotifyListener();
virtual void DoNotifyListenerCleanup() = 0;
nsresult ApplyContentConversions();
void AddCookiesToRequest();
virtual nsresult SetupReplacementChannel(nsIURI *,
nsIChannel *,
bool preserveMethod);
// Helper function to simplify getting notification callbacks.
template <class T>
void GetCallback(nsCOMPtr<T> &aResult)
{
NS_QueryNotificationCallbacks(mCallbacks, mLoadGroup,
NS_GET_TEMPLATE_IID(T),
getter_AddRefs(aResult));
}
friend class PrivateBrowsingChannel<HttpBaseChannel>;
nsCOMPtr<nsIURI> mURI;
nsCOMPtr<nsIURI> mOriginalURI;
nsCOMPtr<nsIURI> mDocumentURI;
nsCOMPtr<nsIStreamListener> mListener;
nsCOMPtr<nsISupports> mListenerContext;
nsCOMPtr<nsILoadGroup> mLoadGroup;
nsCOMPtr<nsISupports> mOwner;
nsCOMPtr<nsIInterfaceRequestor> mCallbacks;
nsCOMPtr<nsIProgressEventSink> mProgressSink;
nsCOMPtr<nsIURI> mReferrer;
nsCOMPtr<nsIApplicationCache> mApplicationCache;
nsHttpRequestHead mRequestHead;
nsCOMPtr<nsIInputStream> mUploadStream;
nsAutoPtr<nsHttpResponseHead> mResponseHead;
nsRefPtr<nsHttpConnectionInfo> mConnectionInfo;
nsCString mSpec; // ASCII encoded URL spec
nsCString mContentTypeHint;
nsCString mContentCharsetHint;
nsCString mUserSetCookieHeader;
PRNetAddr mSelfAddr;
PRNetAddr mPeerAddr;
// HTTP Upgrade Data
nsCString mUpgradeProtocol;
nsCOMPtr<nsIHttpUpgradeListener> mUpgradeProtocolCallback;
// Resumable channel specific data
nsCString mEntityID;
uint64_t mStartPos;
nsresult mStatus;
uint32_t mLoadFlags;
int16_t mPriority;
uint8_t mCaps;
uint8_t mRedirectionLimit;
uint32_t mApplyConversion : 1;
uint32_t mCanceled : 1;
uint32_t mIsPending : 1;
uint32_t mWasOpened : 1;
uint32_t mResponseHeadersModified : 1;
uint32_t mAllowPipelining : 1;
uint32_t mForceAllowThirdPartyCookie : 1;
uint32_t mUploadStreamHasHeaders : 1;
uint32_t mInheritApplicationCache : 1;
uint32_t mChooseApplicationCache : 1;
uint32_t mLoadedFromApplicationCache : 1;
uint32_t mChannelIsForDownload : 1;
uint32_t mTracingEnabled : 1;
// True if timing collection is enabled
uint32_t mTimingEnabled : 1;
uint32_t mAllowSpdy : 1;
// Current suspension depth for this channel object
uint32_t mSuspendCount;
nsAutoPtr<nsTArray<nsCString> > mRedirectedCachekeys;
};
// Share some code while working around C++'s absurd inability to handle casting
// of member functions between base/derived types.
// - We want to store member function pointer to call at resume time, but one
// such function--HandleAsyncAbort--we want to share between the
// nsHttpChannel/HttpChannelChild. Can't define it in base class, because
// then we'd have to cast member function ptr between base/derived class
// types. Sigh...
template <class T>
class HttpAsyncAborter
{
public:
HttpAsyncAborter(T *derived) : mThis(derived), mCallOnResume(0) {}
// Aborts channel: calls OnStart/Stop with provided status, removes channel
// from loadGroup.
nsresult AsyncAbort(nsresult status);
// Does most the actual work.
void HandleAsyncAbort();
// AsyncCall calls a member function asynchronously (via an event).
// retval isn't refcounted and is set only when event was successfully
// posted, the event is returned for the purpose of cancelling when needed
nsresult AsyncCall(void (T::*funcPtr)(),
nsRunnableMethod<T> **retval = nullptr);
private:
T *mThis;
protected:
// Function to be called at resume time
void (T::* mCallOnResume)(void);
};
template <class T>
nsresult HttpAsyncAborter<T>::AsyncAbort(nsresult status)
{
LOG(("HttpAsyncAborter::AsyncAbort [this=%p status=%x]\n", mThis, status));
mThis->mStatus = status;
mThis->mIsPending = false;
// if this fails? Callers ignore our return value anyway....
return AsyncCall(&T::HandleAsyncAbort);
}
// Each subclass needs to define its own version of this (which just calls this
// base version), else we wind up casting base/derived member function ptrs
template <class T>
inline void HttpAsyncAborter<T>::HandleAsyncAbort()
{
NS_PRECONDITION(!mCallOnResume, "How did that happen?");
if (mThis->mSuspendCount) {
LOG(("Waiting until resume to do async notification [this=%p]\n",
mThis));
mCallOnResume = &T::HandleAsyncAbort;
return;
}
mThis->DoNotifyListener();
// finally remove ourselves from the load group.
if (mThis->mLoadGroup)
mThis->mLoadGroup->RemoveRequest(mThis, nullptr, mThis->mStatus);
}
template <class T>
nsresult HttpAsyncAborter<T>::AsyncCall(void (T::*funcPtr)(),
nsRunnableMethod<T> **retval)
{
nsresult rv;
nsRefPtr<nsRunnableMethod<T> > event = NS_NewRunnableMethod(mThis, funcPtr);
rv = NS_DispatchToCurrentThread(event);
if (NS_SUCCEEDED(rv) && retval) {
*retval = event;
}
return rv;
}
} // namespace net
} // namespace mozilla
#endif // mozilla_net_HttpBaseChannel_h