Bug 536294 - e10s HTTP: redirects. r=jduell

--HG--
rename : netwerk/protocol/http/HttpChannelParent.cpp => netwerk/protocol/http/HttpChannelParentListener.cpp
rename : netwerk/protocol/http/HttpChannelParent.h => netwerk/protocol/http/HttpChannelParentListener.h
This commit is contained in:
Honza Bambas 2010-08-10 20:11:57 -07:00
parent 82e0af39d5
commit 9eb088087e
25 changed files with 968 additions and 230 deletions

View File

@ -139,6 +139,7 @@ XPIDLSRCS = \
nsIRandomGenerator.idl \
nsIURIWithPrincipal.idl \
nsIURIClassifier.idl \
nsIRedirectResultListener.idl \
$(NULL)
EXPORTS = \

View File

@ -0,0 +1,55 @@
/* -*- Mode: IDL; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is nsIApplicationCache.idl.
*
* The Initial Developer of the Original Code is
* Mozilla Corporation.
* Portions created by the Initial Developer are Copyright (C) 2010
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Honza Bambas <honzab@firemni.cz>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#include "nsISupports.idl"
[scriptable, uuid(85cd2640-e91e-41ac-bdca-1dbf10dc131e)]
interface nsIRedirectResultListener : nsISupports
{
/**
* When an HTTP redirect has been processed (either successfully or not)
* nsIHttpChannel will call this function if its callbacks implement this
* interface.
*
* @param proceeding
* Indicated whether the redirect will be proceeding, or not (i.e.
* has been canceled, or failed).
*/
void onRedirectResult(in PRBool proceeding);
};

View File

@ -23,6 +23,7 @@
*
* Contributor(s):
* Jason Duell <jduell.mcbugs@gmail.com>
* Honza Bambas <honzab@firemni.cz>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
@ -87,11 +88,17 @@ void NeckoChild::DestroyNeckoChild()
}
PHttpChannelChild*
NeckoChild::AllocPHttpChannel(PBrowserChild* iframeEmbedding)
NeckoChild::AllocPHttpChannel(PBrowserChild* browser)
{
// We don't allocate here: see HttpChannelChild::AsyncOpen()
NS_RUNTIMEABORT("AllocPHttpChannel should not be called");
return nsnull;
// This constructor is only used when PHttpChannel is constructed by
// the parent process, e.g. during a redirect. (Normally HttpChannelChild is
// created by nsHttpHandler::NewProxiedChannel(), and then creates the
// PHttpChannel in HttpChannelChild::AsyncOpen().)
// No need to store PBrowser. It is only needed by the parent.
HttpChannelChild* httpChannel = new HttpChannelChild();
httpChannel->AddIPDLReference();
return httpChannel;
}
bool

View File

@ -58,9 +58,9 @@ NeckoParent::~NeckoParent()
}
PHttpChannelParent*
NeckoParent::AllocPHttpChannel(PBrowserParent* iframeEmbedding)
NeckoParent::AllocPHttpChannel(PBrowserParent* browser)
{
HttpChannelParent *p = new HttpChannelParent(iframeEmbedding);
HttpChannelParent *p = new HttpChannelParent(browser);
p->AddRef();
return p;
}

View File

@ -56,7 +56,7 @@ public:
virtual ~NeckoParent();
protected:
virtual PHttpChannelParent* AllocPHttpChannel(PBrowserParent* iframeEmbedding);
virtual PHttpChannelParent* AllocPHttpChannel(PBrowserParent* browser);
virtual bool DeallocPHttpChannel(PHttpChannelParent*);
virtual PCookieServiceParent* AllocPCookieService();
virtual bool DeallocPCookieService(PCookieServiceParent*);

View File

@ -57,10 +57,12 @@ sync protocol PNecko
parent:
__delete__();
PHttpChannel(nullable PBrowser iframeEmbedding);
PCookieService();
HTMLDNSPrefetch(nsString hostname, PRUint16 flags);
both:
PHttpChannel(nullable PBrowser browser);
};

View File

@ -46,6 +46,12 @@
#include "nsMimeTypes.h"
#include "nsNetUtil.h"
#include "nsICachingChannel.h"
#include "nsISeekableStream.h"
#include "nsIEncodedChannel.h"
#include "nsIResumableChannel.h"
#include "nsIApplicationCacheChannel.h"
namespace mozilla {
namespace net {
@ -62,6 +68,9 @@ HttpBaseChannel::HttpBaseChannel()
, mAllowPipelining(PR_TRUE)
, mForceAllowThirdPartyCookie(PR_FALSE)
, mUploadStreamHasHeaders(PR_FALSE)
, mInheritApplicationCache(PR_TRUE)
, mChooseApplicationCache(PR_FALSE)
, mLoadedFromApplicationCache(PR_FALSE)
{
LOG(("Creating HttpBaseChannel @%x\n", this));
@ -980,6 +989,135 @@ HttpBaseChannel::AddCookiesToRequest()
SetRequestHeader(nsDependentCString(nsHttp::Cookie), cookie, PR_FALSE);
}
static PLDHashOperator
CopyProperties(const nsAString& aKey, nsIVariant *aData, void *aClosure)
{
nsIWritablePropertyBag* bag = static_cast<nsIWritablePropertyBag*>
(aClosure);
bag->SetProperty(aKey, aData);
return PL_DHASH_NEXT;
}
nsresult
HttpBaseChannel::SetupReplacementChannel(nsIURI *newURI,
nsIChannel *newChannel,
PRBool preserveMethod)
{
LOG(("HttpBaseChannel::SetupReplacementChannel "
"[this=%p newChannel=%p preserveMethod=%d]",
this, newChannel, preserveMethod));
PRUint32 newLoadFlags = mLoadFlags | LOAD_REPLACE;
// if the original channel was using SSL and this channel is not using
// SSL, then no need to inhibit persistent caching. however, if the
// original channel was not using SSL and has INHIBIT_PERSISTENT_CACHING
// set, then allow the flag to apply to the redirected channel as well.
// since we force set INHIBIT_PERSISTENT_CACHING on all HTTPS channels,
// we only need to check if the original channel was using SSL.
if (mConnectionInfo->UsingSSL())
newLoadFlags &= ~INHIBIT_PERSISTENT_CACHING;
// Do not pass along LOAD_CHECK_OFFLINE_CACHE
newLoadFlags &= ~nsICachingChannel::LOAD_CHECK_OFFLINE_CACHE;
newChannel->SetLoadGroup(mLoadGroup);
newChannel->SetNotificationCallbacks(mCallbacks);
newChannel->SetLoadFlags(newLoadFlags);
nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(newChannel);
if (!httpChannel)
return NS_OK; // no other options to set
if (preserveMethod) {
nsCOMPtr<nsIUploadChannel> uploadChannel =
do_QueryInterface(httpChannel);
nsCOMPtr<nsIUploadChannel2> uploadChannel2 =
do_QueryInterface(httpChannel);
if (mUploadStream && (uploadChannel2 || uploadChannel)) {
// rewind upload stream
nsCOMPtr<nsISeekableStream> seekable = do_QueryInterface(mUploadStream);
if (seekable)
seekable->Seek(nsISeekableStream::NS_SEEK_SET, 0);
// replicate original call to SetUploadStream...
if (uploadChannel2) {
const char *ctype = mRequestHead.PeekHeader(nsHttp::Content_Type);
if (!ctype)
ctype = "";
const char *clen = mRequestHead.PeekHeader(nsHttp::Content_Length);
PRInt64 len = clen ? nsCRT::atoll(clen) : -1;
uploadChannel2->ExplicitSetUploadStream(
mUploadStream,
nsDependentCString(ctype),
len,
nsDependentCString(mRequestHead.Method()),
mUploadStreamHasHeaders);
} else {
if (mUploadStreamHasHeaders) {
uploadChannel->SetUploadStream(mUploadStream, EmptyCString(),
-1);
} else {
const char *ctype =
mRequestHead.PeekHeader(nsHttp::Content_Type);
const char *clen =
mRequestHead.PeekHeader(nsHttp::Content_Length);
if (!ctype) {
ctype = "application/octet-stream";
}
if (clen) {
uploadChannel->SetUploadStream(mUploadStream,
nsDependentCString(ctype),
atoi(clen));
}
}
}
}
// since preserveMethod is true, we need to ensure that the appropriate
// request method gets set on the channel, regardless of whether or not
// we set the upload stream above. This means SetRequestMethod() will
// be called twice if ExplicitSetUploadStream() gets called above.
httpChannel->SetRequestMethod(nsDependentCString(mRequestHead.Method()));
}
// convey the referrer if one was used for this channel to the next one
if (mReferrer)
httpChannel->SetReferrer(mReferrer);
// convey the mAllowPipelining flag
httpChannel->SetAllowPipelining(mAllowPipelining);
// convey the new redirection limit
httpChannel->SetRedirectionLimit(mRedirectionLimit - 1);
nsCOMPtr<nsIHttpChannelInternal> httpInternal = do_QueryInterface(newChannel);
if (httpInternal) {
// convey the mForceAllowThirdPartyCookie flag
httpInternal->SetForceAllowThirdPartyCookie(mForceAllowThirdPartyCookie);
// update the DocumentURI indicator since we are being redirected.
// if this was a top-level document channel, then the new channel
// should have its mDocumentURI point to newURI; otherwise, we
// just need to pass along our mDocumentURI to the new channel.
if (newURI && (mURI == mDocumentURI))
httpInternal->SetDocumentURI(newURI);
else
httpInternal->SetDocumentURI(mDocumentURI);
}
// transfer application cache information
nsCOMPtr<nsIApplicationCacheChannel> appCacheChannel =
do_QueryInterface(newChannel);
if (appCacheChannel) {
appCacheChannel->SetApplicationCache(mApplicationCache);
appCacheChannel->SetInheritApplicationCache(mInheritApplicationCache);
// We purposely avoid transfering mChooseApplicationCache.
}
// transfer any properties
nsCOMPtr<nsIWritablePropertyBag> bag(do_QueryInterface(newChannel));
if (bag)
mPropertyHash.EnumerateRead(CopyProperties, bag.get());
return NS_OK;
}
//------------------------------------------------------------------------------
} // namespace net

View File

@ -55,6 +55,7 @@
#include "nsIProgressEventSink.h"
#include "nsIURI.h"
#include "nsISupportsPriority.h"
#include "nsIApplicationCache.h"
#define DIE_WITH_ASYNC_OPEN_MSG() \
do { \
@ -169,6 +170,9 @@ public:
protected:
void AddCookiesToRequest();
virtual nsresult SetupReplacementChannel(nsIURI *,
nsIChannel *,
PRBool preserveMethod);
// Helper function to simplify getting notification callbacks.
template <class T>
@ -189,6 +193,7 @@ protected:
nsCOMPtr<nsIInterfaceRequestor> mCallbacks;
nsCOMPtr<nsIProgressEventSink> mProgressSink;
nsCOMPtr<nsIURI> mReferrer;
nsCOMPtr<nsIApplicationCache> mApplicationCache;
nsHttpRequestHead mRequestHead;
nsCOMPtr<nsIInputStream> mUploadStream;
@ -206,13 +211,16 @@ protected:
PRUint8 mCaps;
PRUint8 mRedirectionLimit;
PRUint8 mCanceled : 1;
PRUint8 mIsPending : 1;
PRUint8 mWasOpened : 1;
PRUint8 mResponseHeadersModified : 1;
PRUint8 mAllowPipelining : 1;
PRUint8 mForceAllowThirdPartyCookie : 1;
PRUint8 mUploadStreamHasHeaders : 1;
PRUint32 mCanceled : 1;
PRUint32 mIsPending : 1;
PRUint32 mWasOpened : 1;
PRUint32 mResponseHeadersModified : 1;
PRUint32 mAllowPipelining : 1;
PRUint32 mForceAllowThirdPartyCookie : 1;
PRUint32 mUploadStreamHasHeaders : 1;
PRUint32 mInheritApplicationCache : 1;
PRUint32 mChooseApplicationCache : 1;
PRUint32 mLoadedFromApplicationCache : 1;
};

View File

@ -24,6 +24,7 @@
* Contributor(s):
* Jason Duell <jduell.mcbugs@gmail.com>
* Daniel Witte <dwitte@mozilla.com>
* Honza Bambas <honzab@firemni.cz>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
@ -75,7 +76,11 @@ private:
HttpChannelChild *mChannel;
};
// C++ file contents
//-----------------------------------------------------------------------------
// HttpChannelChild
//-----------------------------------------------------------------------------
HttpChannelChild::HttpChannelChild()
: mIsFromCache(PR_FALSE)
, mCacheEntryAvailable(PR_FALSE)
@ -113,6 +118,7 @@ NS_INTERFACE_MAP_BEGIN(HttpChannelChild)
NS_INTERFACE_MAP_ENTRY(nsITraceableChannel)
NS_INTERFACE_MAP_ENTRY(nsIApplicationCacheContainer)
NS_INTERFACE_MAP_ENTRY(nsIApplicationCacheChannel)
NS_INTERFACE_MAP_ENTRY(nsIAsyncVerifyRedirectCallback)
NS_INTERFACE_MAP_END_INHERITING(HttpBaseChannel)
//-----------------------------------------------------------------------------
@ -473,6 +479,160 @@ HttpChannelChild::OnStatus(const nsresult& status,
}
}
class Redirect1Event : public ChildChannelEvent
{
public:
Redirect1Event(HttpChannelChild* child,
PHttpChannelChild* newChannel,
const IPC::URI& newURI,
const PRUint32& redirectFlags,
const nsHttpResponseHead& responseHead)
: mChild(child)
, mNewChannel(newChannel)
, mNewURI(newURI)
, mRedirectFlags(redirectFlags)
, mResponseHead(responseHead) {}
void Run()
{
mChild->Redirect1Begin(mNewChannel, mNewURI, mRedirectFlags,
mResponseHead);
}
private:
HttpChannelChild* mChild;
PHttpChannelChild* mNewChannel;
IPC::URI mNewURI;
PRUint32 mRedirectFlags;
nsHttpResponseHead mResponseHead;
};
bool
HttpChannelChild::RecvRedirect1Begin(PHttpChannelChild* newChannel,
const IPC::URI& newURI,
const PRUint32& redirectFlags,
const nsHttpResponseHead& responseHead)
{
if (ShouldEnqueue()) {
EnqueueEvent(new Redirect1Event(this, newChannel, newURI, redirectFlags,
responseHead));
} else {
Redirect1Begin(newChannel, newURI, redirectFlags, responseHead);
}
return true;
}
void
HttpChannelChild::Redirect1Begin(PHttpChannelChild* newChannel,
const IPC::URI& newURI,
const PRUint32& redirectFlags,
const nsHttpResponseHead& responseHead)
{
HttpChannelChild*
newHttpChannelChild = static_cast<HttpChannelChild*>(newChannel);
nsCOMPtr<nsIURI> uri(newURI);
nsresult rv =
newHttpChannelChild->HttpBaseChannel::Init(uri, mCaps,
mConnectionInfo->ProxyInfo());
if (NS_FAILED(rv))
return; // TODO Bug 536317
// We won't get OnStartRequest, set cookies here.
mResponseHead = new nsHttpResponseHead(responseHead);
SetCookie(mResponseHead->PeekHeader(nsHttp::Set_Cookie));
PRBool preserveMethod = (mResponseHead->Status() == 307);
rv = SetupReplacementChannel(uri, newHttpChannelChild, preserveMethod);
if (NS_FAILED(rv))
return; // TODO Bug 536317
mRedirectChannelChild = newHttpChannelChild;
nsresult result = gHttpHandler->AsyncOnChannelRedirect(this,
newHttpChannelChild,
redirectFlags);
if (NS_FAILED(result))
OnRedirectVerifyCallback(result);
}
class Redirect3Event : public ChildChannelEvent
{
public:
Redirect3Event(HttpChannelChild* child) : mChild(child) {}
void Run() { mChild->Redirect3Complete(); }
private:
HttpChannelChild* mChild;
};
bool
HttpChannelChild::RecvRedirect3Complete()
{
if (ShouldEnqueue()) {
EnqueueEvent(new Redirect3Event(this));
} else {
Redirect3Complete();
}
return true;
}
void
HttpChannelChild::Redirect3Complete()
{
nsresult rv;
// Redirecting to new channel: shut this down and init new channel
if (mLoadGroup)
mLoadGroup->RemoveRequest(this, nsnull, NS_BINDING_ABORTED);
// Chrome channel has been AsyncOpen'd. Reflect this in child.
rv = mRedirectChannelChild->CompleteRedirectSetup(mListener,
mListenerContext);
if (NS_FAILED(rv))
; // TODO Cancel: Bug 536317
}
nsresult
HttpChannelChild::CompleteRedirectSetup(nsIStreamListener *listener,
nsISupports *aContext)
{
LOG(("HttpChannelChild::FinishRedirectSetup [this=%x]\n", this));
NS_ENSURE_TRUE(!mIsPending, NS_ERROR_IN_PROGRESS);
NS_ENSURE_TRUE(!mWasOpened, NS_ERROR_ALREADY_OPENED);
// notify "http-on-modify-request" observers
gHttpHandler->OnModifyRequest(this);
mIsPending = PR_TRUE;
mWasOpened = PR_TRUE;
mListener = listener;
mListenerContext = aContext;
// add ourselves to the load group.
if (mLoadGroup)
mLoadGroup->AddRequest(this, nsnull);
// TODO: may have been canceled by on-modify-request observers: bug 536317
mState = HCC_OPENED;
return NS_OK;
}
//-----------------------------------------------------------------------------
// HttpChannelChild::nsIAsyncVerifyRedirectCallback
//-----------------------------------------------------------------------------
NS_IMETHODIMP
HttpChannelChild::OnRedirectVerifyCallback(nsresult result)
{
// Cookies may have been changed by redirect observers
mRedirectChannelChild->AddCookiesToRequest();
// Must not be called until after redirect observers called.
mRedirectChannelChild->SetOriginalURI(mRedirectOriginalURI);
return SendRedirect2Result(result, mRedirectChannelChild->mRequestHeaders);
}
//-----------------------------------------------------------------------------
// HttpChannelChild::nsIRequest
//-----------------------------------------------------------------------------
@ -600,16 +760,16 @@ HttpChannelChild::AsyncOpen(nsIStreamListener *listener, nsISupports *aContext)
tabChild = static_cast<mozilla::dom::TabChild*>(iTabChild.get());
}
// The socket transport layer in the chrome process now has a logical ref to
// us, until either OnStopRequest or OnRedirect is called.
// The socket transport in the chrome process now holds a logical ref to us
// until OnStopRequest, or we do a redirect, or we hit an IPDL error.
AddIPDLReference();
gNeckoChild->SendPHttpChannelConstructor(this, tabChild);
SendAsyncOpen(IPC::URI(mURI), IPC::URI(mOriginalURI), IPC::URI(mDocumentURI),
IPC::URI(mReferrer), mLoadFlags, mRequestHeaders,
mRequestHead.Method(), uploadStreamData,
uploadStreamInfo, mPriority, mRedirectionLimit,
SendAsyncOpen(IPC::URI(mURI), IPC::URI(mOriginalURI),
IPC::URI(mDocumentURI), IPC::URI(mReferrer), mLoadFlags,
mRequestHeaders, mRequestHead.Method(), uploadStreamData,
uploadStreamInfo, mPriority, mRedirectionLimit,
mAllowPipelining, mForceAllowThirdPartyCookie);
mState = HCC_OPENED;
@ -784,7 +944,8 @@ HttpChannelChild::GetApplicationCache(nsIApplicationCache **aApplicationCache)
NS_IMETHODIMP
HttpChannelChild::SetApplicationCache(nsIApplicationCache *aApplicationCache)
{
DROP_DEAD();
// FIXME: redirects call. so stub OK for now. Fix in bug 536295.
return NS_ERROR_NOT_IMPLEMENTED;
}
//-----------------------------------------------------------------------------
@ -825,5 +986,6 @@ HttpChannelChild::SetChooseApplicationCache(PRBool aChooseApplicationCache)
//------------------------------------------------------------------------------
}} // mozilla::net

View File

@ -24,6 +24,7 @@
* Contributor(s):
* Jason Duell <jduell.mcbugs@gmail.com>
* Daniel Witte <dwitte@mozilla.com>
* Honza Bambas <honzab@firemni.cz>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
@ -58,6 +59,7 @@
#include "nsIResumableChannel.h"
#include "nsIProxiedChannel.h"
#include "nsITraceableChannel.h"
#include "nsIAsyncVerifyRedirectCallback.h"
namespace mozilla {
namespace net {
@ -73,7 +75,6 @@ enum HttpChannelChildState {
HCC_ONSTOP
};
// Header file contents
class HttpChannelChild : public PHttpChannelChild
, public HttpBaseChannel
, public nsICacheInfoChannel
@ -82,6 +83,7 @@ class HttpChannelChild : public PHttpChannelChild
, public nsIProxiedChannel
, public nsITraceableChannel
, public nsIApplicationCacheChannel
, public nsIAsyncVerifyRedirectCallback
{
public:
NS_DECL_ISUPPORTS_INHERITED
@ -92,6 +94,7 @@ public:
NS_DECL_NSITRACEABLECHANNEL
NS_DECL_NSIAPPLICATIONCACHECONTAINER
NS_DECL_NSIAPPLICATIONCACHECHANNEL
NS_DECL_NSIASYNCVERIFYREDIRECTCALLBACK
HttpChannelChild();
virtual ~HttpChannelChild();
@ -114,6 +117,10 @@ public:
// nsISupportsPriority
NS_IMETHOD SetPriority(PRInt32 value);
// Final setup when redirect has proceeded successfully in chrome
nsresult CompleteRedirectSetup(nsIStreamListener *listener,
nsISupports *aContext);
// IPDL holds a reference while the PHttpChannel protocol is live (starting at
// AsyncOpen, and ending at either OnStopRequest or any IPDL error, either of
// which call NeckoChild::DeallocPHttpChannel()).
@ -133,9 +140,16 @@ protected:
bool RecvOnStopRequest(const nsresult& statusCode);
bool RecvOnProgress(const PRUint64& progress, const PRUint64& progressMax);
bool RecvOnStatus(const nsresult& status, const nsString& statusArg);
bool RecvRedirect1Begin(PHttpChannelChild* newChannel,
const URI& newURI,
const PRUint32& redirectFlags,
const nsHttpResponseHead& responseHead);
bool RecvRedirect3Complete();
private:
RequestHeaderTuples mRequestHeaders;
nsRefPtr<HttpChannelChild> mRedirectChannelChild;
nsCOMPtr<nsIURI> mRedirectOriginalURI;
PRPackedBool mIsFromCache;
PRPackedBool mCacheEntryAvailable;
@ -175,6 +189,10 @@ private:
void OnStopRequest(const nsresult& statusCode);
void OnProgress(const PRUint64& progress, const PRUint64& progressMax);
void OnStatus(const nsresult& status, const nsString& statusArg);
void Redirect1Begin(PHttpChannelChild* newChannel, const URI& newURI,
const PRUint32& redirectFlags,
const nsHttpResponseHead& responseHead);
void Redirect3Complete();
friend class AutoEventEnqueuer;
friend class StartRequestEvent;
@ -182,6 +200,8 @@ private:
friend class DataAvailableEvent;
friend class ProgressEvent;
friend class StatusEvent;
friend class Redirect1Event;
friend class Redirect3Event;
};
//-----------------------------------------------------------------------------

View File

@ -23,6 +23,7 @@
*
* Contributor(s):
* Jason Duell <jduell.mcbugs@gmail.com>
* Honza Bambas <honzab@firemni.cz>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
@ -40,6 +41,8 @@
#include "mozilla/net/HttpChannelParent.h"
#include "mozilla/dom/TabParent.h"
#include "mozilla/net/NeckoParent.h"
#include "HttpChannelParentListener.h"
#include "nsHttpChannel.h"
#include "nsHttpHandler.h"
#include "nsNetUtil.h"
@ -52,7 +55,6 @@
namespace mozilla {
namespace net {
// C++ file contents
HttpChannelParent::HttpChannelParent(PBrowserParent* iframeEmbedding)
: mIPCClosed(false)
{
@ -82,11 +84,8 @@ HttpChannelParent::ActorDestroy(ActorDestroyReason why)
// HttpChannelParent::nsISupports
//-----------------------------------------------------------------------------
NS_IMPL_ISUPPORTS4(HttpChannelParent,
nsIRequestObserver,
nsIStreamListener,
nsIInterfaceRequestor,
nsIProgressEventSink);
NS_IMPL_ISUPPORTS1(HttpChannelParent,
nsIProgressEventSink)
//-----------------------------------------------------------------------------
// HttpChannelParent::PHttpChannelParent
@ -145,7 +144,9 @@ HttpChannelParent::RecvAsyncOpen(const IPC::URI& aURI,
requestHeaders[i].mMerge);
}
httpChan->SetNotificationCallbacks(this);
mChannelListener = new HttpChannelParentListener(this);
httpChan->SetNotificationCallbacks(mChannelListener);
httpChan->SetRequestMethod(nsDependentCString(requestMethod.get()));
@ -167,7 +168,7 @@ HttpChannelParent::RecvAsyncOpen(const IPC::URI& aURI,
httpChan->SetAllowPipelining(allowPipelining);
httpChan->SetForceAllowThirdPartyCookie(forceAllowThirdPartyCookie);
rv = httpChan->AsyncOpen(this, nsnull);
rv = httpChan->AsyncOpen(mChannelListener, nsnull);
if (NS_FAILED(rv))
return false; // TODO: cancel request (bug 536317), return true
@ -191,15 +192,28 @@ HttpChannelParent::RecvSetCacheTokenCachedCharset(const nsCString& charset)
return true;
}
bool
HttpChannelParent::RecvRedirect2Result(const nsresult& result,
const RequestHeaderTuples& changedHeaders)
{
if (mChannelListener)
mChannelListener->OnContentRedirectResultReceived(result, changedHeaders);
return true;
}
//-----------------------------------------------------------------------------
// HttpChannelParent::nsIRequestObserver
// nsIRequestObserver and nsIStreamListener methods equivalents
//-----------------------------------------------------------------------------
NS_IMETHODIMP
nsresult
HttpChannelParent::OnStartRequest(nsIRequest *aRequest, nsISupports *aContext)
{
LOG(("HttpChannelParent::OnStartRequest [this=%x]\n", this));
// We need this member only to call OnContentRedirectResultReceived on it,
// that will for sure not happen when we get here. Throw it away ASAP.
mChannelListener = nsnull;
nsHttpChannel *chan = static_cast<nsHttpChannel *>(aRequest);
nsHttpResponseHead *responseHead = chan->GetResponseHead();
@ -224,7 +238,7 @@ HttpChannelParent::OnStartRequest(nsIRequest *aRequest, nsISupports *aContext)
return NS_OK;
}
NS_IMETHODIMP
nsresult
HttpChannelParent::OnStopRequest(nsIRequest *aRequest,
nsISupports *aContext,
nsresult aStatusCode)
@ -237,11 +251,7 @@ HttpChannelParent::OnStopRequest(nsIRequest *aRequest,
return NS_OK;
}
//-----------------------------------------------------------------------------
// HttpChannelParent::nsIStreamListener
//-----------------------------------------------------------------------------
NS_IMETHODIMP
nsresult
HttpChannelParent::OnDataAvailable(nsIRequest *aRequest,
nsISupports *aContext,
nsIInputStream *aInputStream,
@ -267,63 +277,10 @@ HttpChannelParent::OnDataAvailable(nsIRequest *aRequest,
return NS_OK;
}
//-----------------------------------------------------------------------------
// HttpChannelParent::nsIInterfaceRequestor
//-----------------------------------------------------------------------------
NS_IMETHODIMP
HttpChannelParent::GetInterface(const nsIID& aIID, void **result)
{
if (aIID.Equals(NS_GET_IID(nsIAuthPromptProvider))) {
if (!mTabParent)
return NS_NOINTERFACE;
return mTabParent->QueryInterface(aIID, result);
}
// TODO: 575494: once we're confident we're handling all needed interfaces,
// remove all code below and simply "return QueryInterface(aIID, result)"
if (// Known interface calls:
// FIXME: HTTP Authorization (bug 537782):
// nsHttpChannel first tries to get this as an nsIAuthPromptProvider; if that
// fails, it tries as an nsIAuthPrompt2, and if that fails, an nsIAuthPrompt.
// See nsHttpChannel::GetAuthPrompt(). So if we can return any one of these,
// HTTP auth should be all set. The other two if checks can be eventually
// deleted.
aIID.Equals(NS_GET_IID(nsIAuthPrompt2)) ||
aIID.Equals(NS_GET_IID(nsIAuthPrompt)) ||
// FIXME: redirects (bug 536294):
// The likely solution here is for this class to implement nsIChannelEventSink
// and nsIHttpEventSink (and forward calls to any real sinks in the child), in
// which case QueryInterface() will do the work here and these if statements
// can be eventually discarded.
aIID.Equals(NS_GET_IID(nsIChannelEventSink)) ||
aIID.Equals(NS_GET_IID(nsIHttpEventSink)) ||
// FIXME: application cache (bug 536295):
aIID.Equals(NS_GET_IID(nsIApplicationCacheContainer)) ||
aIID.Equals(NS_GET_IID(nsIProgressEventSink)) ||
// FIXME: bug 561830: when fixed, we shouldn't be asked for this interface
aIID.Equals(NS_GET_IID(nsIDocShellTreeItem)) ||
// Let this return NS_ERROR_NO_INTERFACE: it's OK to not provide it.
aIID.Equals(NS_GET_IID(nsIBadCertListener2)))
{
return QueryInterface(aIID, result);
} else {
nsPrintfCString msg(2000,
"HttpChannelParent::GetInterface: interface UUID=%s not yet supported! "
"Use 'grep -ri UUID <mozilla_src>' to find the name of the interface, "
"check http://tinyurl.com/255ojvu to see if a bug has already been "
"filed, and if not, add one and make it block bug 516730. Thanks!",
aIID.ToString());
NECKO_MAYBE_ABORT(msg);
return NS_NOINTERFACE;
}
}
//-----------------------------------------------------------------------------
// HttpChannelParent::nsIProgressEventSink
//-----------------------------------------------------------------------------
NS_IMETHODIMP
HttpChannelParent::OnProgress(nsIRequest *aRequest,
nsISupports *aContext,
@ -346,6 +303,5 @@ HttpChannelParent::OnStatus(nsIRequest *aRequest,
return NS_OK;
}
}} // mozilla::net

View File

@ -23,6 +23,7 @@
*
* Contributor(s):
* Jason Duell <jduell.mcbugs@gmail.com>
* Honza Bambas <honzab@firemni.cz>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
@ -45,8 +46,6 @@
#include "mozilla/dom/PBrowserParent.h"
#include "mozilla/net/PHttpChannelParent.h"
#include "mozilla/net/NeckoCommon.h"
#include "nsIStreamListener.h"
#include "nsIInterfaceRequestor.h"
#include "nsIProgressEventSink.h"
#include "nsITabParent.h"
@ -57,19 +56,27 @@ class nsICacheEntryDescriptor;
namespace mozilla {
namespace net {
// Header file contents
class HttpChannelParentListener;
class HttpChannelParent : public PHttpChannelParent
, public nsIStreamListener
, public nsIInterfaceRequestor
, public nsIProgressEventSink
{
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIREQUESTOBSERVER
NS_DECL_NSISTREAMLISTENER
NS_DECL_NSIINTERFACEREQUESTOR
NS_DECL_NSIPROGRESSEVENTSINK
// Make these non-virtual for a little performance benefit
nsresult OnStartRequest(nsIRequest *aRequest,
nsISupports *aContext);
nsresult OnStopRequest(nsIRequest *aRequest,
nsISupports *aContext,
nsresult aStatusCode);
nsresult OnDataAvailable(nsIRequest *aRequest,
nsISupports *aContext,
nsIInputStream *aInputStream,
PRUint32 aOffset,
PRUint32 aCount);
HttpChannelParent(PBrowserParent* iframeEmbedding);
virtual ~HttpChannelParent();
@ -90,12 +97,18 @@ protected:
virtual bool RecvSetPriority(const PRUint16& priority);
virtual bool RecvSetCacheTokenCachedCharset(const nsCString& charset);
virtual bool RecvRedirect2Result(const nsresult& result,
const RequestHeaderTuples& changedHeaders);
virtual void ActorDestroy(ActorDestroyReason why);
private:
protected:
friend class mozilla::net::HttpChannelParentListener;
nsCOMPtr<nsITabParent> mTabParent;
private:
nsCOMPtr<nsIChannel> mChannel;
nsRefPtr<HttpChannelParentListener> mChannelListener;
nsCOMPtr<nsICacheEntryDescriptor> mCacheDescriptor;
bool mIPCClosed; // PHttpChannel actor has been Closed()
};

View File

@ -0,0 +1,289 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set sw=2 ts=8 et tw=80 : */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is
* The Mozilla Foundation
* Portions created by the Initial Developer are Copyright (C) 2009
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Jason Duell <jduell.mcbugs@gmail.com>
* Honza Bambas <honzab@firemni.cz>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#include "HttpChannelParentListener.h"
#include "mozilla/net/HttpChannelParent.h"
#include "mozilla/dom/TabParent.h"
#include "mozilla/net/NeckoParent.h"
#include "nsHttpChannel.h"
#include "nsHttpHandler.h"
#include "nsNetUtil.h"
#include "nsISupportsPriority.h"
#include "nsIAuthPromptProvider.h"
#include "nsIDocShellTreeItem.h"
#include "nsIBadCertListener2.h"
#include "nsICacheEntryDescriptor.h"
#include "nsSerializationHelper.h"
#include "nsISerializable.h"
#include "nsIAssociatedContentSecurity.h"
#include "nsISecureBrowserUI.h"
namespace mozilla {
namespace net {
HttpChannelParentListener::HttpChannelParentListener(HttpChannelParent* aInitialChannel)
: mActiveChannel(aInitialChannel)
{
}
HttpChannelParentListener::~HttpChannelParentListener()
{
}
//-----------------------------------------------------------------------------
// HttpChannelParentListener::nsISupports
//-----------------------------------------------------------------------------
NS_IMPL_ISUPPORTS5(HttpChannelParentListener,
nsIInterfaceRequestor,
nsIStreamListener,
nsIRequestObserver,
nsIChannelEventSink,
nsIRedirectResultListener)
//-----------------------------------------------------------------------------
// HttpChannelParentListener::nsIRequestObserver
//-----------------------------------------------------------------------------
NS_IMETHODIMP
HttpChannelParentListener::OnStartRequest(nsIRequest *aRequest, nsISupports *aContext)
{
if (!mActiveChannel)
return NS_ERROR_UNEXPECTED;
LOG(("HttpChannelParentListener::OnStartRequest [this=%x]\n", this));
return mActiveChannel->OnStartRequest(aRequest, aContext);
}
NS_IMETHODIMP
HttpChannelParentListener::OnStopRequest(nsIRequest *aRequest,
nsISupports *aContext,
nsresult aStatusCode)
{
if (!mActiveChannel)
return NS_ERROR_UNEXPECTED;
LOG(("HttpChannelParentListener::OnStopRequest: [this=%x status=%ul]\n",
this, aStatusCode));
nsresult rv = mActiveChannel->OnStopRequest(aRequest, aContext, aStatusCode);
mActiveChannel = nsnull;
return rv;
}
//-----------------------------------------------------------------------------
// HttpChannelParentListener::nsIStreamListener
//-----------------------------------------------------------------------------
NS_IMETHODIMP
HttpChannelParentListener::OnDataAvailable(nsIRequest *aRequest,
nsISupports *aContext,
nsIInputStream *aInputStream,
PRUint32 aOffset,
PRUint32 aCount)
{
if (!mActiveChannel)
return NS_ERROR_UNEXPECTED;
LOG(("HttpChannelParentListener::OnDataAvailable [this=%x]\n", this));
return mActiveChannel->OnDataAvailable(aRequest, aContext, aInputStream, aOffset, aCount);
}
//-----------------------------------------------------------------------------
// HttpChannelParentListener::nsIInterfaceRequestor
//-----------------------------------------------------------------------------
NS_IMETHODIMP
HttpChannelParentListener::GetInterface(const nsIID& aIID, void **result)
{
if (aIID.Equals(NS_GET_IID(nsIAuthPromptProvider))) {
if (!mActiveChannel || !mActiveChannel->mTabParent)
return NS_NOINTERFACE;
return mActiveChannel->mTabParent->QueryInterface(aIID, result);
}
if (aIID.Equals(NS_GET_IID(nsIProgressEventSink))) {
if (!mActiveChannel)
return NS_NOINTERFACE;
return mActiveChannel->QueryInterface(aIID, result);
}
// TODO: 575494: once we're confident we're handling all needed interfaces,
// remove all code below and simply "return QueryInterface(aIID, result)"
if (// Known interface calls:
// FIXME: HTTP Authorization (bug 537782):
// nsHttpChannel first tries to get this as an nsIAuthPromptProvider; if that
// fails, it tries as an nsIAuthPrompt2, and if that fails, an nsIAuthPrompt.
// See nsHttpChannel::GetAuthPrompt(). So if we can return any one of these,
// HTTP auth should be all set. The other two if checks can be eventually
// deleted.
aIID.Equals(NS_GET_IID(nsIAuthPrompt2)) ||
aIID.Equals(NS_GET_IID(nsIAuthPrompt)) ||
// FIXME: redirects (bug 536294):
// The likely solution here is for this class to implement nsIChannelEventSink
// and nsIHttpEventSink (and forward calls to any real sinks in the child), in
// which case QueryInterface() will do the work here and these if statements
// can be eventually discarded.
aIID.Equals(NS_GET_IID(nsIChannelEventSink)) ||
aIID.Equals(NS_GET_IID(nsIHttpEventSink)) ||
aIID.Equals(NS_GET_IID(nsIRedirectResultListener)) ||
// FIXME: application cache (bug 536295):
aIID.Equals(NS_GET_IID(nsIApplicationCacheContainer)) ||
// FIXME: bug 561830: when fixed, we shouldn't be asked for this interface
aIID.Equals(NS_GET_IID(nsIDocShellTreeItem)) ||
// Let this return NS_ERROR_NO_INTERFACE: it's OK to not provide it.
aIID.Equals(NS_GET_IID(nsIBadCertListener2)))
{
return QueryInterface(aIID, result);
} else {
nsPrintfCString msg(2000,
"HttpChannelParentListener::GetInterface: interface UUID=%s not yet supported! "
"Use 'grep -ri UUID <mozilla_src>' to find the name of the interface, "
"check http://tinyurl.com/255ojvu to see if a bug has already been "
"filed, and if not, add one and make it block bug 516730. Thanks!",
aIID.ToString());
NECKO_MAYBE_ABORT(msg);
return NS_NOINTERFACE;
}
}
//-----------------------------------------------------------------------------
// HttpChannelParentListener::nsIChannelEventSink
//-----------------------------------------------------------------------------
NS_IMETHODIMP
HttpChannelParentListener::AsyncOnChannelRedirect(
nsIChannel *oldChannel,
nsIChannel *newChannel,
PRUint32 redirectFlags,
nsIAsyncVerifyRedirectCallback* callback)
{
if (mActiveChannel->mIPCClosed)
return NS_BINDING_ABORTED;
// Create new PHttpChannel
PBrowserParent* browser = mActiveChannel->mTabParent ?
static_cast<TabParent*>(mActiveChannel->mTabParent.get()) : nsnull;
mRedirectChannel = static_cast<HttpChannelParent *>
(mActiveChannel->Manager()->SendPHttpChannelConstructor(browser));
// Join it with the correct channel
mRedirectChannel->mChannel = newChannel;
// Let the new channel also keep the wrapper in case we get another redirect
// response, it wouldn't be able to send back the redirect result.
mRedirectChannel->mChannelListener = this;
// And finally, let the content process decide to redirect or not.
mRedirectCallback = callback;
nsCOMPtr<nsIURI> newURI;
newChannel->GetURI(getter_AddRefs(newURI));
nsHttpChannel *oldHttpChannel = static_cast<nsHttpChannel *>(oldChannel);
// TODO: check mActiveChannel->mIPCClosed and return val from Send function
mActiveChannel->SendRedirect1Begin(mRedirectChannel,
IPC::URI(newURI),
redirectFlags,
*oldHttpChannel->GetResponseHead());
// mActiveChannel gets the response in RecvRedirect2Result and forwards it
// to this wrapper through OnContentRedirectResultReceived
return NS_OK;
}
void
HttpChannelParentListener::OnContentRedirectResultReceived(
const nsresult result,
const RequestHeaderTuples& changedHeaders)
{
nsHttpChannel* newHttpChannel =
static_cast<nsHttpChannel*>(mRedirectChannel->mChannel.get());
if (NS_SUCCEEDED(result)) {
for (PRUint32 i = 0; i < changedHeaders.Length(); i++) {
newHttpChannel->SetRequestHeader(changedHeaders[i].mHeader,
changedHeaders[i].mValue,
changedHeaders[i].mMerge);
}
}
mRedirectCallback->OnRedirectVerifyCallback(result);
mRedirectCallback = nsnull;
}
//-----------------------------------------------------------------------------
// HttpChannelParentListener::nsIRedirectResultListener
//-----------------------------------------------------------------------------
NS_IMETHODIMP
HttpChannelParentListener::OnRedirectResult(PRBool succeeded)
{
if (!mRedirectChannel) {
// Redirect might get canceled before we got AsyncOnChannelRedirect
return NS_OK;
}
if (succeeded && !mActiveChannel->mIPCClosed) {
// TODO: check return value: assume child dead if failed
mActiveChannel->SendRedirect3Complete();
}
HttpChannelParent* channelToDelete;
if (succeeded) {
// Switch to redirect channel and delete the old one.
channelToDelete = mActiveChannel;
mActiveChannel = mRedirectChannel;
} else {
// Delete the redirect target channel: continue using old channel
channelToDelete = mRedirectChannel;
}
if (!channelToDelete->mIPCClosed)
HttpChannelParent::Send__delete__(channelToDelete);
mRedirectChannel = nsnull;
return NS_OK;
}
}} // mozilla::net

View File

@ -0,0 +1,94 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set sw=2 ts=8 et tw=80 : */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is
* The Mozilla Foundation
* Portions created by the Initial Developer are Copyright (C) 2009
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Jason Duell <jduell.mcbugs@gmail.com>
* Honza Bambas <honzab@firemni.cz>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#ifndef mozilla_net_HttpChannelCallbackWrapper_h
#define mozilla_net_HttpChannelCallbackWrapper_h
#include "nsHttp.h"
#include "mozilla/net/NeckoCommon.h"
#include "PHttpChannelParams.h"
#include "nsIStreamListener.h"
#include "nsIInterfaceRequestor.h"
#include "nsIChannelEventSink.h"
#include "nsIRedirectResultListener.h"
#include "nsIProgressEventSink.h"
using namespace mozilla::dom;
class nsICacheEntryDescriptor;
namespace mozilla {
namespace net {
class HttpChannelParent;
class HttpChannelParentListener : public nsIInterfaceRequestor
, public nsIChannelEventSink
, public nsIRedirectResultListener
, public nsIStreamListener
{
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIINTERFACEREQUESTOR
NS_DECL_NSICHANNELEVENTSINK
NS_DECL_NSIREDIRECTRESULTLISTENER
NS_DECL_NSIREQUESTOBSERVER
NS_DECL_NSISTREAMLISTENER
HttpChannelParentListener(HttpChannelParent* aInitialChannel);
virtual ~HttpChannelParentListener();
protected:
friend class HttpChannelParent;
void OnContentRedirectResultReceived(
const nsresult result,
const RequestHeaderTuples& changedHeaders);
private:
nsRefPtr<HttpChannelParent> mActiveChannel;
nsRefPtr<HttpChannelParent> mRedirectChannel;
nsCOMPtr<nsIAsyncVerifyRedirectCallback> mRedirectCallback;
};
} // namespace net
} // namespace mozilla
#endif // mozilla_net_HttpChannelParent_h

View File

@ -114,6 +114,7 @@ ifdef MOZ_IPC
CPPSRCS += \
HttpChannelParent.cpp \
HttpChannelChild.cpp \
HttpChannelParentListener.cpp \
$(NULL)
endif

View File

@ -23,6 +23,7 @@
*
* Contributor(s):
* Jason Duell <jduell.mcbugs@gmail.com>
* Honza Bambas <honzab@firemni.cz>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
@ -57,8 +58,6 @@ protocol PHttpChannel
manager PNecko;
parent:
__delete__();
AsyncOpen(URI uri,
// - TODO: bug 571161: unclear if any HTTP channel clients ever
// set originalURI != uri (about:credits?); also not clear if
@ -80,6 +79,9 @@ parent:
SetCacheTokenCachedCharset(nsCString charset);
// Reports approval/veto of redirect by child process redirect observers
Redirect2Result(nsresult result, RequestHeaderTuples changedHeaders);
child:
OnStartRequest(nsHttpResponseHead responseHead,
PRBool useResponseHead,
@ -97,6 +99,18 @@ child:
OnProgress(PRUint64 progress, PRUint64 progressMax);
OnStatus(nsresult status, nsString statusArg);
// Called to initiate content channel redirect, starts talking to sinks
// on the content process and reports result via OnRedirect2Result above
Redirect1Begin(PHttpChannel newChannel,
URI newUri,
PRUint32 redirectFlags,
nsHttpResponseHead responseHead);
// Called if redirect successful so that child can complete setup.
Redirect3Complete();
both:
__delete__();
};

View File

@ -69,6 +69,7 @@
#include "nsICacheService.h"
#include "nsDNSPrefetch.h"
#include "nsChannelClassifier.h"
#include "nsIRedirectResultListener.h"
// True if the local cache should be bypassed when processing a request.
#define BYPASS_LOCAL_CACHE(loadFlags) \
@ -77,6 +78,34 @@
static NS_DEFINE_CID(kStreamListenerTeeCID, NS_STREAMLISTENERTEE_CID);
class AutoRedirectVetoNotifier
{
public:
AutoRedirectVetoNotifier(nsHttpChannel* channel) : mChannel(channel) {}
~AutoRedirectVetoNotifier() {ReportRedirectResult(false);}
void DontReport() {mChannel = nsnull;}
void RedirectSucceeded() {ReportRedirectResult(true);}
private:
nsHttpChannel* mChannel;
void ReportRedirectResult(bool succeeded);
};
void
AutoRedirectVetoNotifier::ReportRedirectResult(bool succeeded)
{
if (!mChannel)
return;
nsCOMPtr<nsIRedirectResultListener> vetoHook;
NS_QueryNotificationCallbacks(mChannel,
NS_GET_IID(nsIRedirectResultListener),
getter_AddRefs(vetoHook));
mChannel = nsnull;
if (vetoHook)
vetoHook->OnRedirectResult(succeeded);
}
//-----------------------------------------------------------------------------
// nsHttpChannel <public>
//-----------------------------------------------------------------------------
@ -99,9 +128,6 @@ nsHttpChannel::nsHttpChannel()
, mCacheForOfflineUse(PR_FALSE)
, mCachingOpportunistically(PR_FALSE)
, mFallbackChannel(PR_FALSE)
, mInheritApplicationCache(PR_TRUE)
, mChooseApplicationCache(PR_FALSE)
, mLoadedFromApplicationCache(PR_FALSE)
, mTracingEnabled(PR_TRUE)
, mCustomConditionalRequest(PR_FALSE)
, mFallingBack(PR_FALSE)
@ -1230,6 +1256,7 @@ nsHttpChannel::AsyncDoReplaceWithProxy(nsIProxyInfo* pi)
rv = WaitForRedirectCallback();
if (NS_FAILED(rv)) {
AutoRedirectVetoNotifier notifier(this);
PopRedirectAsyncFunc(&nsHttpChannel::ContinueDoReplaceWithProxy);
mRedirectChannel = nsnull;
}
@ -1240,6 +1267,8 @@ nsHttpChannel::AsyncDoReplaceWithProxy(nsIProxyInfo* pi)
nsresult
nsHttpChannel::ContinueDoReplaceWithProxy(nsresult rv)
{
AutoRedirectVetoNotifier notifier(this);
if (NS_FAILED(rv))
return rv;
@ -1256,6 +1285,8 @@ nsHttpChannel::ContinueDoReplaceWithProxy(nsresult rv)
mStatus = NS_BINDING_REDIRECTED;
notifier.RedirectSucceeded();
// disconnect from the old listeners...
mListener = nsnull;
mListenerContext = nsnull;
@ -1593,6 +1624,7 @@ nsHttpChannel::ProcessFallback(PRBool *waitingForRedirectCallback)
rv = WaitForRedirectCallback();
if (NS_FAILED(rv)) {
AutoRedirectVetoNotifier notifier(this);
PopRedirectAsyncFunc(&nsHttpChannel::ContinueProcessFallback);
mRedirectChannel = nsnull;
return rv;
@ -1607,6 +1639,8 @@ nsHttpChannel::ProcessFallback(PRBool *waitingForRedirectCallback)
nsresult
nsHttpChannel::ContinueProcessFallback(nsresult rv)
{
AutoRedirectVetoNotifier notifier(this);
if (NS_FAILED(rv))
return rv;
@ -1617,14 +1651,18 @@ nsHttpChannel::ContinueProcessFallback(nsresult rv)
rv = mRedirectChannel->AsyncOpen(mListener, mListenerContext);
mRedirectChannel = nsnull;
NS_ENSURE_SUCCESS(rv, rv);
if (NS_FAILED(rv))
return rv;
// close down this channel
Cancel(NS_BINDING_REDIRECTED);
notifier.RedirectSucceeded();
// disconnect from our listener
mListener = 0;
mListenerContext = 0;
// and from our callbacks
mCallbacks = nsnull;
mProgressSink = nsnull;
@ -2752,15 +2790,6 @@ nsHttpChannel::ClearBogusContentEncodingIfNeeded()
// nsHttpChannel <redirect>
//-----------------------------------------------------------------------------
static PLDHashOperator
CopyProperties(const nsAString& aKey, nsIVariant *aData, void *aClosure)
{
nsIWritablePropertyBag* bag = static_cast<nsIWritablePropertyBag*>
(aClosure);
bag->SetProperty(aKey, aData);
return PL_DHASH_NEXT;
}
nsresult
nsHttpChannel::SetupReplacementChannel(nsIURI *newURI,
nsIChannel *newChannel,
@ -2769,105 +2798,19 @@ nsHttpChannel::SetupReplacementChannel(nsIURI *newURI,
LOG(("nsHttpChannel::SetupReplacementChannel "
"[this=%p newChannel=%p preserveMethod=%d]",
this, newChannel, preserveMethod));
PRUint32 newLoadFlags = mLoadFlags | LOAD_REPLACE;
// if the original channel was using SSL and this channel is not using
// SSL, then no need to inhibit persistent caching. however, if the
// original channel was not using SSL and has INHIBIT_PERSISTENT_CACHING
// set, then allow the flag to apply to the redirected channel as well.
// since we force set INHIBIT_PERSISTENT_CACHING on all HTTPS channels,
// we only need to check if the original channel was using SSL.
if (mConnectionInfo->UsingSSL())
newLoadFlags &= ~INHIBIT_PERSISTENT_CACHING;
// Do not pass along LOAD_CHECK_OFFLINE_CACHE
newLoadFlags &= ~LOAD_CHECK_OFFLINE_CACHE;
newChannel->SetLoadGroup(mLoadGroup);
newChannel->SetNotificationCallbacks(mCallbacks);
newChannel->SetLoadFlags(newLoadFlags);
nsresult rv = HttpBaseChannel::SetupReplacementChannel(newURI, newChannel, preserveMethod);
if (NS_FAILED(rv))
return rv;
nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(newChannel);
if (!httpChannel)
return NS_OK; // no other options to set
if (preserveMethod) {
nsCOMPtr<nsIUploadChannel> uploadChannel =
do_QueryInterface(httpChannel);
nsCOMPtr<nsIUploadChannel2> uploadChannel2 =
do_QueryInterface(httpChannel);
if (mUploadStream && (uploadChannel2 || uploadChannel)) {
// rewind upload stream
nsCOMPtr<nsISeekableStream> seekable = do_QueryInterface(mUploadStream);
if (seekable)
seekable->Seek(nsISeekableStream::NS_SEEK_SET, 0);
// replicate original call to SetUploadStream...
if (uploadChannel2) {
const char *ctype = mRequestHead.PeekHeader(nsHttp::Content_Type);
if (!ctype)
ctype = "";
const char *clen = mRequestHead.PeekHeader(nsHttp::Content_Length);
PRInt64 len = clen ? nsCRT::atoll(clen) : -1;
uploadChannel2->ExplicitSetUploadStream(
mUploadStream,
nsDependentCString(ctype),
len,
nsDependentCString(mRequestHead.Method()),
mUploadStreamHasHeaders);
}
else {
if (mUploadStreamHasHeaders)
uploadChannel->SetUploadStream(mUploadStream, EmptyCString(),
-1);
else {
const char *ctype =
mRequestHead.PeekHeader(nsHttp::Content_Type);
const char *clen =
mRequestHead.PeekHeader(nsHttp::Content_Length);
if (!ctype) {
ctype = "application/octet-stream";
}
if (clen) {
uploadChannel->SetUploadStream(mUploadStream,
nsDependentCString(ctype),
atoi(clen));
}
}
}
}
// since preserveMethod is true, we need to ensure that the appropriate
// request method gets set on the channel, regardless of whether or not
// we set the upload stream above. This means SetRequestMethod() will
// be called twice if ExplicitSetUploadStream() gets called above.
httpChannel->SetRequestMethod(nsDependentCString(mRequestHead.Method()));
}
// convey the referrer if one was used for this channel to the next one
if (mReferrer)
httpChannel->SetReferrer(mReferrer);
// convey the mAllowPipelining flag
httpChannel->SetAllowPipelining(mAllowPipelining);
// convey the new redirection limit
httpChannel->SetRedirectionLimit(mRedirectionLimit - 1);
// transfer the remote flag
nsHttpChannel *httpChannelImpl = static_cast<nsHttpChannel*>(httpChannel.get());
httpChannelImpl->SetRemoteChannel(mRemoteChannel);
nsCOMPtr<nsIHttpChannelInternal> httpInternal = do_QueryInterface(newChannel);
if (httpInternal) {
// convey the mForceAllowThirdPartyCookie flag
httpInternal->SetForceAllowThirdPartyCookie(mForceAllowThirdPartyCookie);
// update the DocumentURI indicator since we are being redirected.
// if this was a top-level document channel, then the new channel
// should have its mDocumentURI point to newURI; otherwise, we
// just need to pass along our mDocumentURI to the new channel.
if (newURI && (mURI == mDocumentURI))
httpInternal->SetDocumentURI(newURI);
else
httpInternal->SetDocumentURI(mDocumentURI);
}
// convey the mApplyConversion flag (bug 91862)
nsCOMPtr<nsIEncodedChannel> encodedChannel = do_QueryInterface(httpChannel);
if (encodedChannel)
@ -2883,20 +2826,6 @@ nsHttpChannel::SetupReplacementChannel(nsIURI *newURI,
resumableChannel->ResumeAt(mStartPos, mEntityID);
}
// transfer application cache information
nsCOMPtr<nsIApplicationCacheChannel> appCacheChannel =
do_QueryInterface(newChannel);
if (appCacheChannel) {
appCacheChannel->SetApplicationCache(mApplicationCache);
appCacheChannel->SetInheritApplicationCache(mInheritApplicationCache);
// We purposely avoid transfering mChooseApplicationCache.
}
// transfer any properties
nsCOMPtr<nsIWritablePropertyBag> bag(do_QueryInterface(newChannel));
if (bag)
mPropertyHash.EnumerateRead(CopyProperties, bag.get());
return NS_OK;
}
@ -3034,6 +2963,7 @@ nsHttpChannel::ContinueProcessRedirectionAfterFallback(nsresult rv)
rv = WaitForRedirectCallback();
if (NS_FAILED(rv)) {
AutoRedirectVetoNotifier notifier(this);
PopRedirectAsyncFunc(&nsHttpChannel::ContinueProcessRedirection);
mRedirectChannel = nsnull;
}
@ -3044,6 +2974,8 @@ nsHttpChannel::ContinueProcessRedirectionAfterFallback(nsresult rv)
nsresult
nsHttpChannel::ContinueProcessRedirection(nsresult rv)
{
AutoRedirectVetoNotifier notifier(this);
LOG(("ContinueProcessRedirection [rv=%x]\n", rv));
if (NS_FAILED(rv))
return rv;
@ -3076,9 +3008,12 @@ nsHttpChannel::ContinueProcessRedirection(nsresult rv)
// close down this channel
Cancel(NS_BINDING_REDIRECTED);
notifier.RedirectSucceeded();
// disconnect from our listener
mListener = 0;
mListenerContext = 0;
// and from our callbacks
mCallbacks = nsnull;
mProgressSink = nsnull;

View File

@ -54,7 +54,6 @@
#include "nsICachingChannel.h"
#include "nsICacheEntryDescriptor.h"
#include "nsICacheListener.h"
#include "nsIApplicationCache.h"
#include "nsIApplicationCacheChannel.h"
#include "nsIEncodedChannel.h"
#include "nsIStringEnumerator.h"
@ -206,7 +205,7 @@ private:
void HandleAsyncFallback();
nsresult ContinueHandleAsyncFallback(nsresult);
nsresult PromptTempRedirect();
nsresult SetupReplacementChannel(nsIURI *, nsIChannel *, PRBool preserveMethod);
virtual nsresult SetupReplacementChannel(nsIURI *, nsIChannel *, PRBool preserveMethod);
// proxy specific methods
nsresult ProxyFailover();
@ -269,8 +268,6 @@ private:
nsCacheAccessMode mOfflineCacheAccess;
nsCString mOfflineCacheClientID;
nsCOMPtr<nsIApplicationCache> mApplicationCache;
// auth specific data
nsCOMPtr<nsIHttpChannelAuthProvider> mAuthProvider;
@ -314,9 +311,6 @@ private:
// True if we are loading a fallback cache entry from the
// application cache.
PRUint32 mFallbackChannel : 1;
PRUint32 mInheritApplicationCache : 1;
PRUint32 mChooseApplicationCache : 1;
PRUint32 mLoadedFromApplicationCache : 1;
PRUint32 mTracingEnabled : 1;
// True if consumer added its own If-None-Match or If-Modified-Since
// headers. In such a case we must not override them in the cache code

View File

@ -0,0 +1,7 @@
//
// Run test script in content process instead of chrome (xpcshell's default)
//
function run_test() {
run_test_in_child("../unit/test_event_sink.js");
}

View File

@ -0,0 +1,7 @@
//
// Run test script in content process instead of chrome (xpcshell's default)
//
//
function run_test() {
run_test_in_child("../unit/test_redirect-caching_canceled.js");
}

View File

@ -0,0 +1,7 @@
//
// Run test script in content process instead of chrome (xpcshell's default)
//
//
function run_test() {
run_test_in_child("../unit/test_redirect-caching_failure.js");
}

View File

@ -0,0 +1,7 @@
//
// Run test script in content process instead of chrome (xpcshell's default)
//
//
function run_test() {
run_test_in_child("../unit/test_redirect-caching_passing.js");
}

View File

@ -0,0 +1,7 @@
//
// Run test script in content process instead of chrome (xpcshell's default)
//
//
function run_test() {
run_test_in_child("../unit/test_redirect_canceled.js");
}

View File

@ -0,0 +1,7 @@
//
// Run test script in content process instead of chrome (xpcshell's default)
//
function run_test() {
run_test_in_child("../unit/test_redirect_failure.js");
}

View File

@ -0,0 +1,7 @@
//
// Run test script in content process instead of chrome (xpcshell's default)
//
function run_test() {
run_test_in_child("../unit/test_redirect_passing.js");
}