author | Honza Bambas <honzab.moz@firemni.cz> |
Tue, 23 Nov 2010 23:56:06 +0100 | |
changeset 58111 | 33c8fcb13a996977987bc9e6f505c8fae2a5ca8c |
parent 58110 | 3492dbd5ff507a0dbb3f318f61717ef752d6e1f4 |
child 58112 | cf61e6916004b57f47ad001034757fe3a7df6d53 |
push id | 17160 |
push user | honzab.moz@firemni.cz |
push date | Tue, 23 Nov 2010 22:57:29 +0000 |
treeherder | mozilla-central@33c8fcb13a99 [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | jduell, blocking-fennec2.0b3 |
bugs | 591707 |
milestone | 2.0b8pre |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
--- a/netwerk/base/public/Makefile.in +++ b/netwerk/base/public/Makefile.in @@ -140,16 +140,24 @@ XPIDLSRCS = \ nsIStrictTransportSecurityService.idl \ nsIURIWithPrincipal.idl \ nsIURIClassifier.idl \ nsIRedirectResultListener.idl \ mozIThirdPartyUtil.idl \ nsISerializationHelper.idl \ $(NULL) +ifdef MOZ_IPC +XPIDLSRCS += \ + nsIChildChannel.idl \ + nsIParentChannel.idl \ + nsIParentRedirectingChannel.idl \ + nsIRedirectChannelRegistrar.idl +endif + ifdef MOZ_TOOLKIT_SEARCH XPIDLSRCS += nsIBrowserSearchService.idl endif EXPORTS = \ netCore.h \ nsNetError.h \ nsNetUtil.h \
new file mode 100644 --- /dev/null +++ b/netwerk/base/public/nsIChildChannel.idl @@ -0,0 +1,67 @@ +/* ***** 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 Mozilla Foundation + * 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" + +interface nsIStreamListener; + +/** + * Implemented by content side of IPC protocols. + */ + +[scriptable, uuid(c45b92ae-4f07-41dd-b0ef-aa044eeabb1e)] +interface nsIChildChannel : nsISupports +{ + /** + * Create the chrome side of the IPC protocol and join an existing 'real' + * channel on the parent process. The id is provided by + * nsIRedirectChannelRegistrar on the chrome process and pushed to the child + * protocol as an argument to event starting a redirect. + * + * Primarilly used in HttpChannelChild::Redirect1Begin on a newly created + * child channel, where the new channel is intended to be created on the + * child process. + */ + void connectParent(in PRUint32 id); + + /** + * As AsyncOpen is called on the chrome process for redirect target channels, + * we have to inform the child side of the protocol of that fact by a special + * method. + */ + void completeRedirectSetup(in nsIStreamListener aListener, + in nsISupports aContext); +};
new file mode 100644 --- /dev/null +++ b/netwerk/base/public/nsIParentChannel.idl @@ -0,0 +1,52 @@ +/* ***** 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 Mozilla Foundation + * 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 "nsIStreamListener.idl" + +interface nsITabParent; + +/** + * Implemented by chrome side of IPC protocols. + */ + +[scriptable, uuid(723188c3-fff8-4d27-b657-a256e7209be0)] +interface nsIParentChannel : nsIStreamListener +{ + /** + * Called to invoke deletion of the IPC protocol. + */ + void delete(); +};
new file mode 100644 --- /dev/null +++ b/netwerk/base/public/nsIParentRedirectingChannel.idl @@ -0,0 +1,78 @@ +/* ***** 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 Mozilla Foundation + * 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 "nsIParentChannel.idl" + +interface nsITabParent; +interface nsIChannel; +interface nsIAsyncVerifyRedirectCallback; + +/** + * Implemented by chrome side of IPC protocols that support redirect responses. + */ + +[scriptable, uuid(cb7edc1c-096f-44de-957c-cb93de1545f6)] +interface nsIParentRedirectingChannel : nsIParentChannel +{ + /** + * Called when the channel got a response that redirects it to a different + * URI. The implementation is responsible for calling the redirect observers + * on the child process and provide the decision result to the callback. + * + * @param newChannelId + * id of the redirect channel obtained from nsIRedirectChannelRegistrar. + * @param newURI + * the URI we redirect to + * @param callback + * redirect result callback, usage is compatible with how + * nsIChannelEventSink defines it + */ + void startRedirect(in PRUint32 newChannelId, + in nsIChannel newChannel, + in PRUint32 redirectFlags, + in nsIAsyncVerifyRedirectCallback callback); + + /** + * Called after we are done with redirecting process and we know if to + * redirect or not. Forward the redirect result to the child process. From + * that moment the nsIParentChannel implementation expects it will be + * forwarded all notifications from the 'real' channel. + * + * Primarilly used by HttpChannelParentListener::OnRedirectResult and kept + * as mActiveChannel and mRedirectChannel in that class. + */ + void completeRedirect(in PRBool succeeded); +};
new file mode 100644 --- /dev/null +++ b/netwerk/base/public/nsIRedirectChannelRegistrar.idl @@ -0,0 +1,104 @@ +/* ***** 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 Mozilla Foundation + * 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" + +interface nsIChannel; +interface nsIParentChannel; + +/** + * Used on the chrome process as a service to join channel implementation + * and parent IPC protocol side under a unique id. Provides this way a generic + * communication while redirecting to various protocols. + * + * See also nsIChildChannel and nsIParentChannel. + */ + +[scriptable, uuid (efa36ea2-5b07-46fc-9534-a5acb8b77b72)] +interface nsIRedirectChannelRegistrar : nsISupports +{ + /** + * Register the redirect target channel and obtain a unique ID for that + * channel. + * + * Primarily used in HttpChannelParentListener::AsyncOnChannelRedirect to get + * a channel id sent to the HttpChannelChild being redirected. + */ + PRUint32 registerChannel(in nsIChannel channel); + + /** + * First, search for the channel registered under the id. If found return + * it. Then, register under the same id the parent side of IPC protocol + * to let it be later grabbed back by the originator of the redirect and + * notifications from the real channel could be forwarded to this parent + * channel. + * + * Primarily used in parent side of an IPC protocol implementation + * in reaction to nsIChildChannel.connectParent(id) called from the child + * process. + */ + nsIChannel linkChannels(in PRUint32 id, in nsIParentChannel channel); + + /** + * Returns back the channel previously registered under the ID with + * registerChannel method. + * + * Primarilly used in chrome IPC side of protocols when attaching a redirect + * target channel to an existing 'real' channel implementation. + */ + nsIChannel getRegisteredChannel(in PRUint32 id); + + /** + * Returns the stream listener that shall be attached to the redirect target + * channel, all notification from the redirect target channel will be + * forwarded to this stream listener. + * + * Primarilly used in HttpChannelParentListener::OnRedirectResult callback + * to grab the created parent side of the channel and forward notifications + * to it. + */ + nsIParentChannel getParentChannel(in PRUint32 id); + + /** + * To not force all channel implementations to support weak reference + * consumers of this service must ensure release of registered channels them + * self. This releases both the real and parent channel registered under + * the id. + * + * Primarilly used in HttpChannelParentListener::OnRedirectResult callback. + */ + void deregisterChannels(in PRUint32 id); +};
--- a/netwerk/base/public/nsNetUtil.h +++ b/netwerk/base/public/nsNetUtil.h @@ -102,16 +102,17 @@ #include "nsIMutable.h" #include "nsIPropertyBag2.h" #include "nsIWritablePropertyBag2.h" #include "nsIIDNService.h" #include "nsIChannelEventSink.h" #include "nsIChannelPolicy.h" #include "nsISocketProviderService.h" #include "nsISocketProvider.h" +#include "nsIRedirectChannelRegistrar.h" #include "mozilla/Services.h" #ifdef MOZILLA_INTERNAL_API inline already_AddRefed<nsIIOService> do_GetIOService(nsresult* error = 0) { already_AddRefed<nsIIOService> ret = mozilla::services::GetIOService(); @@ -1775,16 +1776,32 @@ NS_IsInternalSameURIRedirect(nsIChannel if (!oldURI || !newURI) { return PR_FALSE; } PRBool res; return NS_SUCCEEDED(oldURI->Equals(newURI, &res)) && res; } +inline nsresult +NS_LinkRedirectChannels(PRUint32 channelId, + nsIParentChannel *parentChannel, + nsIChannel** _result) +{ + nsresult rv; + + nsCOMPtr<nsIRedirectChannelRegistrar> registrar = + do_GetService("@mozilla.org/redirectchannelregistrar;1", &rv); + NS_ENSURE_SUCCESS(rv, rv); + + return registrar->LinkChannels(channelId, + parentChannel, + _result); +} + /** * Helper function to create a random URL string that's properly formed * but guaranteed to be invalid. */ #define NS_FAKE_SCHEME "http://" #define NS_FAKE_TLD ".invalid" inline nsresult NS_MakeRandomInvalidURLString(nsCString& result)
--- a/netwerk/base/src/Makefile.in +++ b/netwerk/base/src/Makefile.in @@ -89,16 +89,20 @@ CPPSRCS = \ nsURLHelper.cpp \ nsURLParsers.cpp \ nsNetStrings.cpp \ nsBase64Encoder.cpp \ nsSerializationHelper.cpp \ nsDNSPrefetch.cpp \ $(NULL) +ifdef MOZ_IPC + CPPSRCS += RedirectChannelRegistrar.cpp +endif + ifeq ($(MOZ_WIDGET_TOOLKIT),os2) CPPSRCS += nsURLHelperOS2.cpp else ifeq ($(MOZ_WIDGET_TOOLKIT),windows) CPPSRCS += nsURLHelperWin.cpp CPPSRCS += nsNativeConnectionHelper.cpp ifneq ($(OS_ARCH), WINCE) CPPSRCS += nsAutodialWin.cpp
new file mode 100644 --- /dev/null +++ b/netwerk/base/src/RedirectChannelRegistrar.cpp @@ -0,0 +1,127 @@ +/* ***** 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 Mozilla Foundation + * 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 "RedirectChannelRegistrar.h" + +namespace mozilla { +namespace net { + +template<class KeyClass, class T> +PRBool +RedirectChannelRegistrar::nsCOMPtrHashtable<KeyClass,T>::Get(KeyType aKey, T** retVal) const +{ + typename base_type::EntryType* ent = this->GetEntry(aKey); + + if (ent) { + if (retVal) + NS_IF_ADDREF(*retVal = ent->mData); + + return PR_TRUE; + } + + if (retVal) + *retVal = nsnull; + + return PR_FALSE; +} + +NS_IMPL_ISUPPORTS1(RedirectChannelRegistrar, nsIRedirectChannelRegistrar) + +RedirectChannelRegistrar::RedirectChannelRegistrar() + : mId(1) +{ + mRealChannels.Init(64); + mParentChannels.Init(64); +} + +NS_IMETHODIMP +RedirectChannelRegistrar::RegisterChannel(nsIChannel *channel, + PRUint32 *_retval NS_OUTPARAM) +{ + mRealChannels.Put(mId, channel); + *_retval = mId; + + ++mId; + + // Ensure we always provide positive ids + if (!mId) + mId = 1; + + return NS_OK; +} + +NS_IMETHODIMP +RedirectChannelRegistrar::GetRegisteredChannel(PRUint32 id, + nsIChannel **_retval NS_OUTPARAM) +{ + if (!mRealChannels.Get(id, _retval)) + return NS_ERROR_NOT_AVAILABLE; + + return NS_OK; +} + +NS_IMETHODIMP +RedirectChannelRegistrar::LinkChannels(PRUint32 id, + nsIParentChannel *channel, + nsIChannel** _retval) +{ + if (!mRealChannels.Get(id, _retval)) + return NS_ERROR_NOT_AVAILABLE; + + mParentChannels.Put(id, channel); + return NS_OK; +} + +NS_IMETHODIMP +RedirectChannelRegistrar::GetParentChannel(PRUint32 id, + nsIParentChannel **_retval NS_OUTPARAM) +{ + if (!mParentChannels.Get(id, _retval)) + return NS_ERROR_NOT_AVAILABLE; + + return NS_OK; +} + +NS_IMETHODIMP +RedirectChannelRegistrar::DeregisterChannels(PRUint32 id) +{ + mRealChannels.Remove(id); + mParentChannels.Remove(id); + return NS_OK; +} + +} +}
new file mode 100644 --- /dev/null +++ b/netwerk/base/src/RedirectChannelRegistrar.h @@ -0,0 +1,82 @@ +/* ***** 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 Mozilla Foundation + * 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 ***** */ + +#ifndef RedirectChannelRegistrar_h__ +#define RedirectChannelRegistrar_h__ + +#include "nsIRedirectChannelRegistrar.h" + +#include "nsIChannel.h" +#include "nsIParentChannel.h" +#include "nsClassHashtable.h" + +namespace mozilla { +namespace net { + +class RedirectChannelRegistrar : public nsIRedirectChannelRegistrar +{ + NS_DECL_ISUPPORTS + NS_DECL_NSIREDIRECTCHANNELREGISTRAR + + RedirectChannelRegistrar(); + +protected: + template<class KeyClass, class T> + class nsCOMPtrHashtable : + public nsBaseHashtable< KeyClass, nsCOMPtr<T>, T* > + { + public: + typedef typename KeyClass::KeyType KeyType; + typedef T* UserDataType; + typedef nsBaseHashtable< KeyClass, nsCOMPtr<T>, T* > base_type; + + PRBool Get(KeyType aKey, UserDataType* pData) const; + }; + + typedef nsCOMPtrHashtable<nsUint32HashKey, nsIChannel> + ChannelHashtable; + typedef nsCOMPtrHashtable<nsUint32HashKey, nsIParentChannel> + ParentChannelHashtable; + + ChannelHashtable mRealChannels; + ParentChannelHashtable mParentChannels; + PRUint32 mId; +}; + +} +} + +#endif
--- a/netwerk/build/nsNetCID.h +++ b/netwerk/build/nsNetCID.h @@ -478,16 +478,27 @@ /** * Contract ID for a service implementing nsIURIClassifier that identifies * phishing and malware sites. */ #define NS_URICLASSIFIERSERVICE_CONTRACTID \ "@mozilla.org/uriclassifierservice" +// Redirect channel registrar used for redirect to various protocols +#define NS_REDIRECTCHANNELREGISTRAR_CONTRACTID \ + "@mozilla.org/redirectchannelregistrar;1" +#define NS_REDIRECTCHANNELREGISTRAR_CID \ +{ /* {b69043a6-8929-4d60-8d17-a27e44a8393e} */ \ + 0xb69043a6, \ + 0x8929, \ + 0x4d60, \ + { 0x8d, 0x17, 0xa2, 0x7e, 0x44, 0xa8, 0x39, 0x3e } \ +} + /****************************************************************************** * netwerk/cache/ classes */ // service implementing nsICacheService. #define NS_CACHESERVICE_CLASSNAME \ "nsCacheService" #define NS_CACHESERVICE_CONTRACTID \
--- a/netwerk/build/nsNetModule.cpp +++ b/netwerk/build/nsNetModule.cpp @@ -122,16 +122,22 @@ NS_GENERIC_FACTORY_CONSTRUCTOR(nsSafeFil NS_GENERIC_AGGREGATED_CONSTRUCTOR_INIT(nsLoadGroup, Init) #include "nsEffectiveTLDService.h" NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsEffectiveTLDService, Init) #include "nsSerializationHelper.h" NS_GENERIC_FACTORY_CONSTRUCTOR(nsSerializationHelper) +#ifdef MOZ_IPC +#include "RedirectChannelRegistrar.h" +typedef mozilla::net::RedirectChannelRegistrar RedirectChannelRegistrar; +NS_GENERIC_FACTORY_CONSTRUCTOR(RedirectChannelRegistrar) +#endif + /////////////////////////////////////////////////////////////////////////////// extern nsresult net_NewIncrementalDownload(nsISupports *, const nsIID &, void **); #define NS_INCREMENTALDOWNLOAD_CLASSNAME \ "nsIncrementalDownload" #define NS_INCREMENTALDOWNLOAD_CID \ @@ -740,16 +746,19 @@ NS_DEFINE_NAMED_CID(NS_NETWORK_LINK_SERV #elif defined(MOZ_WIDGET_COCOA) NS_DEFINE_NAMED_CID(NS_NETWORK_LINK_SERVICE_CID); #elif defined(MOZ_ENABLE_LIBCONIC) NS_DEFINE_NAMED_CID(NS_NETWORK_LINK_SERVICE_CID); #elif defined(MOZ_ENABLE_QTNETWORK) NS_DEFINE_NAMED_CID(NS_NETWORK_LINK_SERVICE_CID); #endif NS_DEFINE_NAMED_CID(NS_SERIALIZATION_HELPER_CID); +#ifdef MOZ_IPC +NS_DEFINE_NAMED_CID(NS_REDIRECTCHANNELREGISTRAR_CID); +#endif static const mozilla::Module::CIDEntry kNeckoCIDs[] = { { &kNS_IOSERVICE_CID, false, NULL, nsIOServiceConstructor }, { &kNS_STREAMTRANSPORTSERVICE_CID, false, NULL, nsStreamTransportServiceConstructor }, { &kNS_SOCKETTRANSPORTSERVICE_CID, false, NULL, nsSocketTransportServiceConstructor }, { &kNS_SERVERSOCKET_CID, false, NULL, nsServerSocketConstructor }, { &kNS_SOCKETPROVIDERSERVICE_CID, false, NULL, nsSocketProviderService::Create }, { &kNS_DNSSERVICE_CID, false, NULL, nsDNSServiceConstructor }, @@ -866,16 +875,19 @@ static const mozilla::Module::CIDEntry k #elif defined(MOZ_WIDGET_COCOA) { &kNS_NETWORK_LINK_SERVICE_CID, false, NULL, nsNetworkLinkServiceConstructor }, #elif defined(MOZ_ENABLE_LIBCONIC) { &kNS_NETWORK_LINK_SERVICE_CID, false, NULL, nsMaemoNetworkLinkServiceConstructor }, #elif defined(MOZ_ENABLE_QTNETWORK) { &kNS_NETWORK_LINK_SERVICE_CID, false, NULL, nsQtNetworkLinkServiceConstructor }, #endif { &kNS_SERIALIZATION_HELPER_CID, false, NULL, nsSerializationHelperConstructor }, +#ifdef MOZ_IPC + { &kNS_REDIRECTCHANNELREGISTRAR_CID, false, NULL, RedirectChannelRegistrarConstructor }, +#endif { NULL } }; static const mozilla::Module::ContractIDEntry kNeckoContracts[] = { { NS_IOSERVICE_CONTRACTID, &kNS_IOSERVICE_CID }, { NS_NETUTIL_CONTRACTID, &kNS_IOSERVICE_CID }, { NS_STREAMTRANSPORTSERVICE_CONTRACTID, &kNS_STREAMTRANSPORTSERVICE_CID }, { NS_SOCKETTRANSPORTSERVICE_CONTRACTID, &kNS_SOCKETTRANSPORTSERVICE_CID }, @@ -999,16 +1011,19 @@ static const mozilla::Module::ContractID #elif defined(MOZ_WIDGET_COCOA) { NS_NETWORK_LINK_SERVICE_CONTRACTID, &kNS_NETWORK_LINK_SERVICE_CID }, #elif defined(MOZ_ENABLE_LIBCONIC) { NS_NETWORK_LINK_SERVICE_CONTRACTID, &kNS_NETWORK_LINK_SERVICE_CID }, #elif defined(MOZ_ENABLE_QTNETWORK) { NS_NETWORK_LINK_SERVICE_CONTRACTID, &kNS_NETWORK_LINK_SERVICE_CID }, #endif { NS_SERIALIZATION_HELPER_CONTRACTID, &kNS_SERIALIZATION_HELPER_CID }, +#ifdef MOZ_IPC + { NS_REDIRECTCHANNELREGISTRAR_CONTRACTID, &kNS_REDIRECTCHANNELREGISTRAR_CID }, +#endif { NULL } }; static const mozilla::Module kNeckoModule = { mozilla::Module::kVersion, kNeckoCIDs, kNeckoContracts, kNeckoCategories,
--- a/netwerk/protocol/ftp/FTPChannelChild.cpp +++ b/netwerk/protocol/ftp/FTPChannelChild.cpp @@ -92,22 +92,23 @@ FTPChannelChild::ReleaseIPDLReference() mIPCOpen = false; Release(); } //----------------------------------------------------------------------------- // FTPChannelChild::nsISupports //----------------------------------------------------------------------------- -NS_IMPL_ISUPPORTS_INHERITED4(FTPChannelChild, +NS_IMPL_ISUPPORTS_INHERITED5(FTPChannelChild, nsBaseChannel, nsIFTPChannel, nsIUploadChannel, nsIResumableChannel, - nsIProxiedChannel) + nsIProxiedChannel, + nsIChildChannel) //----------------------------------------------------------------------------- NS_IMETHODIMP FTPChannelChild::GetLastModifiedTime(PRTime* lastModifiedTime) { *lastModifiedTime = mLastModifiedTime; return NS_OK; @@ -434,16 +435,44 @@ FTPChannelChild::DoCancelEarly(const nsr mListener = nsnull; mListenerContext = nsnull; if (mIPCOpen) Send__delete__(this); } +class FTPDeleteSelfEvent : public ChannelEvent +{ + public: + FTPDeleteSelfEvent(FTPChannelChild* aChild) + : mChild(aChild) {} + void Run() { mChild->DoDeleteSelf(); } + private: + FTPChannelChild* mChild; +}; + +bool +FTPChannelChild::RecvDeleteSelf() +{ + if (ShouldEnqueue()) { + EnqueueEvent(new FTPDeleteSelfEvent(this)); + } else { + DoDeleteSelf(); + } + return true; +} + +void +FTPChannelChild::DoDeleteSelf() +{ + if (mIPCOpen) + Send__delete__(this); +} + NS_IMETHODIMP FTPChannelChild::Cancel(nsresult status) { if (mCanceled) return NS_OK; mCanceled = true; mStatus = status; @@ -470,11 +499,55 @@ FTPChannelChild::Resume() if (!mSuspendCount) { if (mQueuePhase == PHASE_UNQUEUED) mQueuePhase = PHASE_FINISHED_QUEUEING; FlushEventQueue(); } return NS_OK; } +//----------------------------------------------------------------------------- +// FTPChannelChild::nsIChildChannel +//----------------------------------------------------------------------------- + +NS_IMETHODIMP +FTPChannelChild::ConnectParent(PRUint32 id) +{ + // 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(); + + if (!gNeckoChild->SendPFTPChannelConstructor(this)) + return NS_ERROR_FAILURE; + + if (!SendConnectChannel(id)) + return NS_ERROR_FAILURE; + + return NS_OK; +} + +NS_IMETHODIMP +FTPChannelChild::CompleteRedirectSetup(nsIStreamListener *listener, + nsISupports *aContext) +{ + LOG(("FTPChannelChild::CompleteRedirectSetup [this=%x]\n", this)); + + NS_ENSURE_TRUE(!mIsPending, NS_ERROR_IN_PROGRESS); + NS_ENSURE_TRUE(!mWasOpened, NS_ERROR_ALREADY_OPENED); + + mIsPending = PR_TRUE; + mWasOpened = PR_TRUE; + mListener = listener; + mListenerContext = aContext; + + // add ourselves to the load group. + if (mLoadGroup) + mLoadGroup->AddRequest(this, nsnull); + + // We already have an open IPDL connection to the parent. If on-modify-request + // listeners or load group observers canceled us, let the parent handle it + // and send it back to us naturally. + return NS_OK; +} + } // namespace net } // namespace mozilla
--- a/netwerk/protocol/ftp/FTPChannelChild.h +++ b/netwerk/protocol/ftp/FTPChannelChild.h @@ -44,16 +44,17 @@ #include "mozilla/net/PFTPChannelChild.h" #include "mozilla/net/ChannelEventQueue.h" #include "nsBaseChannel.h" #include "nsIFTPChannel.h" #include "nsIUploadChannel.h" #include "nsIProxiedChannel.h" #include "nsIResumableChannel.h" +#include "nsIChildChannel.h" #include "nsIStreamListener.h" namespace mozilla { namespace net { // This class inherits logic from nsBaseChannel that is not needed for an // e10s child channel, but it works. At some point we could slice up @@ -61,36 +62,40 @@ namespace net { // nsFTPChannel/FTPChannelChild. class FTPChannelChild : public PFTPChannelChild , public nsBaseChannel , public nsIFTPChannel , public nsIUploadChannel , public nsIResumableChannel , public nsIProxiedChannel + , public nsIChildChannel , public ChannelEventQueue<FTPChannelChild> { public: + typedef ::nsIStreamListener nsIStreamListener; + NS_DECL_ISUPPORTS_INHERITED NS_DECL_NSIFTPCHANNEL NS_DECL_NSIUPLOADCHANNEL NS_DECL_NSIRESUMABLECHANNEL NS_DECL_NSIPROXIEDCHANNEL + NS_DECL_NSICHILDCHANNEL NS_IMETHOD Cancel(nsresult status); NS_IMETHOD Suspend(); NS_IMETHOD Resume(); FTPChannelChild(nsIURI* uri); virtual ~FTPChannelChild(); void AddIPDLReference(); void ReleaseIPDLReference(); - NS_IMETHOD AsyncOpen(::nsIStreamListener* listener, nsISupports* aContext); + NS_IMETHOD AsyncOpen(nsIStreamListener* listener, nsISupports* aContext); // Note that we handle this ourselves, overriding the nsBaseChannel // default behavior, in order to be e10s-friendly. NS_IMETHOD IsPending(PRBool* result); NS_OVERRIDE nsresult OpenContentStream(PRBool async, nsIInputStream** stream, nsIChannel** channel); @@ -103,32 +108,35 @@ protected: const PRTime& aLastModified, const nsCString& aEntityID, const IPC::URI& aURI); NS_OVERRIDE bool RecvOnDataAvailable(const nsCString& data, const PRUint32& offset, const PRUint32& count); NS_OVERRIDE bool RecvOnStopRequest(const nsresult& statusCode); NS_OVERRIDE bool RecvCancelEarly(const nsresult& statusCode); + NS_OVERRIDE bool RecvDeleteSelf(); void DoOnStartRequest(const PRInt32& aContentLength, const nsCString& aContentType, const PRTime& aLastModified, const nsCString& aEntityID, const IPC::URI& aURI); void DoOnDataAvailable(const nsCString& data, const PRUint32& offset, const PRUint32& count); void DoOnStopRequest(const nsresult& statusCode); void DoCancelEarly(const nsresult& statusCode); + void DoDeleteSelf(); friend class FTPStartRequestEvent; friend class FTPDataAvailableEvent; friend class FTPStopRequestEvent; friend class FTPCancelEarlyEvent; + friend class FTPDeleteSelfEvent; private: nsCOMPtr<nsIInputStream> mUploadStream; bool mIPCOpen; bool mCanceled; PRUint32 mSuspendCount; PRPackedBool mIsPending;
--- a/netwerk/protocol/ftp/FTPChannelParent.cpp +++ b/netwerk/protocol/ftp/FTPChannelParent.cpp @@ -38,16 +38,17 @@ * the terms of any one of the MPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** */ #include "mozilla/net/FTPChannelParent.h" #include "nsFTPChannel.h" #include "nsNetUtil.h" #include "nsISupportsPriority.h" +#include "nsIRedirectChannelRegistrar.h" #include "nsFtpProtocolHandler.h" #undef LOG #define LOG(args) PR_LOG(gFTPLog, PR_LOG_DEBUG, args) namespace mozilla { namespace net { @@ -71,18 +72,19 @@ FTPChannelParent::ActorDestroy(ActorDest // yet, but we must not send any more msgs to child. mIPCClosed = true; } //----------------------------------------------------------------------------- // FTPChannelParent::nsISupports //----------------------------------------------------------------------------- -NS_IMPL_ISUPPORTS3(FTPChannelParent, +NS_IMPL_ISUPPORTS4(FTPChannelParent, nsIStreamListener, + nsIParentChannel, nsIInterfaceRequestor, nsIRequestObserver); //----------------------------------------------------------------------------- // FTPChannelParent::PFTPChannelParent //----------------------------------------------------------------------------- bool @@ -127,16 +129,33 @@ FTPChannelParent::RecvAsyncOpen(const IP rv = mChannel->AsyncOpen(this, nsnull); if (NS_FAILED(rv)) return SendCancelEarly(rv); return true; } bool +FTPChannelParent::RecvConnectChannel(const PRUint32& channelId) +{ + nsresult rv; + + LOG(("Looking for a registered channel [this=%p, id=%d]", this, channelId)); + + nsCOMPtr<nsIChannel> channel; + rv = NS_LinkRedirectChannels(channelId, this, getter_AddRefs(channel)); + if (NS_SUCCEEDED(rv)) + mChannel = static_cast<nsFtpChannel*>(channel.get()); + + LOG((" found channel %p, rv=%08x", mChannel.get(), rv)); + + return true; +} + +bool FTPChannelParent::RecvCancel(const nsresult& status) { mChannel->Cancel(status); return true; } bool FTPChannelParent::RecvSuspend() @@ -214,20 +233,33 @@ FTPChannelParent::OnDataAvailable(nsIReq if (mIPCClosed || !SendOnDataAvailable(data, aOffset, aCount)) return NS_ERROR_UNEXPECTED; return NS_OK; } //----------------------------------------------------------------------------- +// FTPChannelParent::nsIParentChannel +//----------------------------------------------------------------------------- + +NS_IMETHODIMP +FTPChannelParent::Delete() +{ + if (mIPCClosed || !SendDeleteSelf()) + return NS_ERROR_UNEXPECTED; + + return NS_OK; +} + +//----------------------------------------------------------------------------- // FTPChannelParent::nsIInterfaceRequestor //----------------------------------------------------------------------------- NS_IMETHODIMP FTPChannelParent::GetInterface(const nsIID& uuid, void** result) { - DROP_DEAD(); + return QueryInterface(uuid, result); } } // namespace net } // namespace mozilla
--- a/netwerk/protocol/ftp/FTPChannelParent.h +++ b/netwerk/protocol/ftp/FTPChannelParent.h @@ -39,42 +39,44 @@ * * ***** END LICENSE BLOCK ***** */ #ifndef mozilla_net_FTPChannelParent_h #define mozilla_net_FTPChannelParent_h #include "mozilla/net/PFTPChannelParent.h" #include "mozilla/net/NeckoCommon.h" -#include "nsIStreamListener.h" +#include "nsIParentChannel.h" #include "nsIInterfaceRequestor.h" class nsFtpChannel; namespace mozilla { namespace net { class FTPChannelParent : public PFTPChannelParent - , public nsIStreamListener + , public nsIParentChannel , public nsIInterfaceRequestor { public: NS_DECL_ISUPPORTS NS_DECL_NSIREQUESTOBSERVER NS_DECL_NSISTREAMLISTENER + NS_DECL_NSIPARENTCHANNEL NS_DECL_NSIINTERFACEREQUESTOR FTPChannelParent(); virtual ~FTPChannelParent(); protected: NS_OVERRIDE virtual bool RecvAsyncOpen(const IPC::URI& uri, const PRUint64& startPos, const nsCString& entityID, const IPC::InputStream& uploadStream); + NS_OVERRIDE virtual bool RecvConnectChannel(const PRUint32& channelId); NS_OVERRIDE virtual bool RecvCancel(const nsresult& status); NS_OVERRIDE virtual bool RecvSuspend(); NS_OVERRIDE virtual bool RecvResume(); NS_OVERRIDE virtual void ActorDestroy(ActorDestroyReason why); nsRefPtr<nsFtpChannel> mChannel;
--- a/netwerk/protocol/ftp/PFTPChannel.ipdl +++ b/netwerk/protocol/ftp/PFTPChannel.ipdl @@ -54,23 +54,25 @@ async protocol PFTPChannel { manager PNecko; parent: __delete__(); AsyncOpen(URI uri, PRUint64 startPos, nsCString entityID, InputStream uploadStream); + ConnectChannel(PRUint32 channelId); Cancel(nsresult status); Suspend(); Resume(); child: OnStartRequest(PRInt32 aContentLength, nsCString aContentType, PRTime aLastModified, nsCString aEntityID, URI aURI); OnDataAvailable(nsCString data, PRUint32 offset, PRUint32 count); OnStopRequest(nsresult statusCode); CancelEarly(nsresult statusCode); + DeleteSelf(); }; } // namespace net } // namespace mozilla
--- a/netwerk/protocol/http/HttpChannelChild.cpp +++ b/netwerk/protocol/http/HttpChannelChild.cpp @@ -114,16 +114,18 @@ NS_INTERFACE_MAP_BEGIN(HttpChannelChild) NS_INTERFACE_MAP_ENTRY(nsICacheInfoChannel) NS_INTERFACE_MAP_ENTRY(nsIResumableChannel) NS_INTERFACE_MAP_ENTRY(nsISupportsPriority) NS_INTERFACE_MAP_ENTRY(nsIProxiedChannel) NS_INTERFACE_MAP_ENTRY(nsITraceableChannel) NS_INTERFACE_MAP_ENTRY(nsIApplicationCacheContainer) NS_INTERFACE_MAP_ENTRY(nsIApplicationCacheChannel) NS_INTERFACE_MAP_ENTRY(nsIAsyncVerifyRedirectCallback) + NS_INTERFACE_MAP_ENTRY(nsIChildChannel) + NS_INTERFACE_MAP_ENTRY(nsIHttpChannelChild) NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsIAssociatedContentSecurity, GetAssociatedContentSecurity()) NS_INTERFACE_MAP_END_INHERITING(HttpBaseChannel) //----------------------------------------------------------------------------- // HttpChannelChild::PHttpChannelChild //----------------------------------------------------------------------------- void @@ -584,89 +586,101 @@ HttpChannelChild::DeleteSelf() { Send__delete__(this); } class Redirect1Event : public ChannelEvent { public: Redirect1Event(HttpChannelChild* child, - PHttpChannelChild* newChannel, + const PRUint32& newChannelId, const IPC::URI& newURI, const PRUint32& redirectFlags, const nsHttpResponseHead& responseHead) : mChild(child) - , mNewChannel(newChannel) + , mNewChannelId(newChannelId) , mNewURI(newURI) , mRedirectFlags(redirectFlags) , mResponseHead(responseHead) {} void Run() { - mChild->Redirect1Begin(mNewChannel, mNewURI, mRedirectFlags, + mChild->Redirect1Begin(mNewChannelId, mNewURI, mRedirectFlags, mResponseHead); } private: HttpChannelChild* mChild; - PHttpChannelChild* mNewChannel; + PRUint32 mNewChannelId; IPC::URI mNewURI; PRUint32 mRedirectFlags; nsHttpResponseHead mResponseHead; }; bool -HttpChannelChild::RecvRedirect1Begin(PHttpChannelChild* newChannel, - const IPC::URI& newURI, +HttpChannelChild::RecvRedirect1Begin(const PRUint32& newChannelId, + const URI& newUri, const PRUint32& redirectFlags, const nsHttpResponseHead& responseHead) { if (ShouldEnqueue()) { - EnqueueEvent(new Redirect1Event(this, newChannel, newURI, redirectFlags, + EnqueueEvent(new Redirect1Event(this, newChannelId, newUri, redirectFlags, responseHead)); } else { - Redirect1Begin(newChannel, newURI, redirectFlags, responseHead); + Redirect1Begin(newChannelId, newUri, redirectFlags, responseHead); } return true; } void -HttpChannelChild::Redirect1Begin(PHttpChannelChild* newChannel, +HttpChannelChild::Redirect1Begin(const PRUint32& newChannelId, const IPC::URI& newURI, const PRUint32& redirectFlags, const nsHttpResponseHead& responseHead) { - HttpChannelChild* - newHttpChannelChild = static_cast<HttpChannelChild*>(newChannel); + nsresult rv; + + nsCOMPtr<nsIIOService> ioService; + rv = gHttpHandler->GetIOService(getter_AddRefs(ioService)); + if (NS_FAILED(rv)) { + // Veto redirect. nsHttpChannel decides to cancel or continue. + OnRedirectVerifyCallback(rv); + return; + } + nsCOMPtr<nsIURI> uri(newURI); - nsresult rv = - newHttpChannelChild->HttpBaseChannel::Init(uri, mCaps, - mConnectionInfo->ProxyInfo()); + nsCOMPtr<nsIChannel> newChannel; + rv = ioService->NewChannelFromURI(uri, getter_AddRefs(newChannel)); if (NS_FAILED(rv)) { - // Veto redirect. nsHttpChannel decides to cancel or continue. - SendRedirect2Verify(rv, newHttpChannelChild->mRequestHeaders); + // Veto redirect. nsHttpChannel decides to cancel or continue. + OnRedirectVerifyCallback(rv); return; } // 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); + rv = SetupReplacementChannel(uri, newChannel, preserveMethod); if (NS_FAILED(rv)) { // Veto redirect. nsHttpChannel decides to cancel or continue. - SendRedirect2Verify(rv, newHttpChannelChild->mRequestHeaders); + OnRedirectVerifyCallback(rv); return; } - mRedirectChannelChild = newHttpChannelChild; + mRedirectChannelChild = do_QueryInterface(newChannel); + if (mRedirectChannelChild) { + mRedirectChannelChild->ConnectParent(newChannelId); + } else { + NS_ERROR("Redirecting to a protocol that doesn't support universal protocol redirect"); + } rv = gHttpHandler->AsyncOnChannelRedirect(this, - newHttpChannelChild, + newChannel, redirectFlags); if (NS_FAILED(rv)) OnRedirectVerifyCallback(rv); } class Redirect3Event : public ChannelEvent { public: @@ -685,33 +699,62 @@ HttpChannelChild::RecvRedirect3Complete( Redirect3Complete(); } return true; } void HttpChannelChild::Redirect3Complete() { - nsresult rv; + nsresult rv = NS_OK; + + // Chrome channel has been AsyncOpen'd. Reflect this in child. + if (mRedirectChannelChild) + rv = mRedirectChannelChild->CompleteRedirectSetup(mListener, + mListenerContext); // 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)) NS_WARNING("CompleteRedirectSetup failed, HttpChannelChild already open?"); // Release ref to new channel. mRedirectChannelChild = nsnull; } -nsresult +//----------------------------------------------------------------------------- +// HttpChannelChild::nsIChildChannel +//----------------------------------------------------------------------------- + +NS_IMETHODIMP +HttpChannelChild::ConnectParent(PRUint32 id) +{ + mozilla::dom::TabChild* tabChild = nsnull; + nsCOMPtr<nsITabChild> iTabChild; + GetCallback(iTabChild); + if (iTabChild) { + tabChild = static_cast<mozilla::dom::TabChild*>(iTabChild.get()); + } + + // 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(); + + if (!gNeckoChild->SendPHttpChannelConstructor(this, tabChild)) + return NS_ERROR_FAILURE; + + if (!SendConnectChannel(id)) + return NS_ERROR_FAILURE; + + return NS_OK; +} + +NS_IMETHODIMP 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); @@ -739,27 +782,40 @@ HttpChannelChild::CompleteRedirectSetup( //----------------------------------------------------------------------------- // 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); + nsCOMPtr<nsIHttpChannel> newHttpChannel = + do_QueryInterface(mRedirectChannelChild); + + if (newHttpChannel) { + // Must not be called until after redirect observers called. + newHttpChannel->SetOriginalURI(mRedirectOriginalURI); + } + + RequestHeaderTuples emptyHeaders; + RequestHeaderTuples* headerTuples = &emptyHeaders; + + nsCOMPtr<nsIHttpChannelChild> newHttpChannelChild = + do_QueryInterface(mRedirectChannelChild); + if (newHttpChannelChild && NS_SUCCEEDED(result)) { + newHttpChannelChild->AddCookiesToRequest(); + newHttpChannelChild->GetHeaderTuples(&headerTuples); + } // After we verify redirect, nsHttpChannel may hit the network: must give // "http-on-modify-request" observers the chance to cancel before that. if (NS_SUCCEEDED(result)) - gHttpHandler->OnModifyRequest(mRedirectChannelChild); + gHttpHandler->OnModifyRequest(newHttpChannel); - return SendRedirect2Verify(result, mRedirectChannelChild->mRequestHeaders); + return SendRedirect2Verify(result, *headerTuples); } //----------------------------------------------------------------------------- // HttpChannelChild::nsIRequest //----------------------------------------------------------------------------- NS_IMETHODIMP HttpChannelChild::Cancel(nsresult status) @@ -1241,12 +1297,27 @@ HttpChannelChild::Flush() NS_ENSURE_SUCCESS(rv, rv); if (mIPCOpen) SendUpdateAssociatedContentSecurity(hi, low, broken, no); return NS_OK; } +//----------------------------------------------------------------------------- +// HttpChannelChild::nsIHttpChannelChild +//----------------------------------------------------------------------------- + +NS_IMETHODIMP HttpChannelChild::AddCookiesToRequest() +{ + HttpBaseChannel::AddCookiesToRequest(); + return NS_OK; +} + +NS_IMETHODIMP HttpChannelChild::GetHeaderTuples(RequestHeaderTuples **aHeaderTuples) +{ + *aHeaderTuples = &mRequestHeaders; + return NS_OK; +} + //------------------------------------------------------------------------------ }} // mozilla::net -
--- a/netwerk/protocol/http/HttpChannelChild.h +++ b/netwerk/protocol/http/HttpChannelChild.h @@ -56,39 +56,45 @@ #include "nsIApplicationCache.h" #include "nsIApplicationCacheChannel.h" #include "nsIUploadChannel2.h" #include "nsIResumableChannel.h" #include "nsIProxiedChannel.h" #include "nsITraceableChannel.h" #include "nsIAsyncVerifyRedirectCallback.h" #include "nsIAssociatedContentSecurity.h" +#include "nsIChildChannel.h" +#include "nsIHttpChannelChild.h" namespace mozilla { namespace net { class HttpChannelChild : public PHttpChannelChild , public HttpBaseChannel , public nsICacheInfoChannel , public nsIProxiedChannel , public nsITraceableChannel , public nsIApplicationCacheChannel , public nsIAsyncVerifyRedirectCallback , public nsIAssociatedContentSecurity + , public nsIChildChannel + , public nsIHttpChannelChild , public ChannelEventQueue<HttpChannelChild> { public: NS_DECL_ISUPPORTS_INHERITED NS_DECL_NSICACHEINFOCHANNEL NS_DECL_NSIPROXIEDCHANNEL NS_DECL_NSITRACEABLECHANNEL NS_DECL_NSIAPPLICATIONCACHECONTAINER NS_DECL_NSIAPPLICATIONCACHECHANNEL NS_DECL_NSIASYNCVERIFYREDIRECTCALLBACK NS_DECL_NSIASSOCIATEDCONTENTSECURITY + NS_DECL_NSICHILDCHANNEL + NS_DECL_NSIHTTPCHANNELCHILD HttpChannelChild(); virtual ~HttpChannelChild(); // Methods HttpBaseChannel didn't implement for us or that we override. // // nsIRequest NS_IMETHOD Cancel(nsresult status); @@ -103,20 +109,16 @@ public: PRBool aMerge); // nsIHttpChannelInternal NS_IMETHOD SetupFallbackChannel(const char *aFallbackKey); // nsISupportsPriority NS_IMETHOD SetPriority(PRInt32 value); // nsIResumableChannel NS_IMETHOD ResumeAt(PRUint64 startPos, const nsACString& entityID); - // 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()). void AddIPDLReference(); void ReleaseIPDLReference(); bool IsSuspended(); @@ -131,30 +133,30 @@ protected: const nsCString& securityInfoSerialization); bool RecvOnDataAvailable(const nsCString& data, const PRUint32& offset, const PRUint32& count); bool RecvOnStopRequest(const nsresult& statusCode); bool RecvOnProgress(const PRUint64& progress, const PRUint64& progressMax); bool RecvOnStatus(const nsresult& status, const nsString& statusArg); bool RecvCancelEarly(const nsresult& status); - bool RecvRedirect1Begin(PHttpChannelChild* newChannel, + bool RecvRedirect1Begin(const PRUint32& newChannel, const URI& newURI, const PRUint32& redirectFlags, const nsHttpResponseHead& responseHead); bool RecvRedirect3Complete(); bool RecvAssociateApplicationCache(const nsCString& groupID, const nsCString& clientID); bool RecvDeleteSelf(); bool GetAssociatedContentSecurity(nsIAssociatedContentSecurity** res = nsnull); private: RequestHeaderTuples mRequestHeaders; - nsRefPtr<HttpChannelChild> mRedirectChannelChild; + nsCOMPtr<nsIChildChannel> mRedirectChannelChild; nsCOMPtr<nsIURI> mRedirectOriginalURI; nsCOMPtr<nsISupports> mSecurityInfo; PRPackedBool mIsFromCache; PRPackedBool mCacheEntryAvailable; PRUint32 mCacheExpirationTime; nsCString mCachedCharset; @@ -176,17 +178,18 @@ private: const nsCString& securityInfoSerialization); void OnDataAvailable(const nsCString& data, const PRUint32& offset, const PRUint32& count); void OnStopRequest(const nsresult& statusCode); void OnProgress(const PRUint64& progress, const PRUint64& progressMax); void OnStatus(const nsresult& status, const nsString& statusArg); void OnCancel(const nsresult& status); - void Redirect1Begin(PHttpChannelChild* newChannel, const URI& newURI, + void Redirect1Begin(const PRUint32& newChannelId, + const URI& newUri, const PRUint32& redirectFlags, const nsHttpResponseHead& responseHead); void Redirect3Complete(); void DeleteSelf(); friend class StartRequestEvent; friend class StopRequestEvent; friend class DataAvailableEvent;
--- a/netwerk/protocol/http/HttpChannelParent.cpp +++ b/netwerk/protocol/http/HttpChannelParent.cpp @@ -37,30 +37,32 @@ * 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 "mozilla/net/HttpChannelParent.h" #include "mozilla/dom/TabParent.h" #include "mozilla/net/NeckoParent.h" +#include "mozilla/unused.h" #include "HttpChannelParentListener.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 "nsIApplicationCacheService.h" #include "nsIOfflineCacheUpdate.h" +#include "nsIRedirectChannelRegistrar.h" namespace mozilla { namespace net { HttpChannelParent::HttpChannelParent(PBrowserParent* iframeEmbedding) : mIPCClosed(false) { // Ensure gHttpHandler is initialized: we need the atom table up and running. @@ -84,18 +86,41 @@ HttpChannelParent::ActorDestroy(ActorDes // yet, but we must not send any more msgs to child. mIPCClosed = true; } //----------------------------------------------------------------------------- // HttpChannelParent::nsISupports //----------------------------------------------------------------------------- -NS_IMPL_ISUPPORTS1(HttpChannelParent, - nsIProgressEventSink) +NS_IMPL_ISUPPORTS6(HttpChannelParent, + nsIInterfaceRequestor, + nsIProgressEventSink, + nsIRequestObserver, + nsIStreamListener, + nsIParentChannel, + nsIParentRedirectingChannel) + +//----------------------------------------------------------------------------- +// HttpChannelParent::nsIInterfaceRequestor +//----------------------------------------------------------------------------- + +NS_IMETHODIMP +HttpChannelParent::GetInterface(const nsIID& aIID, void **result) +{ + if (aIID.Equals(NS_GET_IID(nsIAuthPromptProvider)) || + aIID.Equals(NS_GET_IID(nsISecureBrowserUI))) { + if (!mTabParent) + return NS_NOINTERFACE; + + return mTabParent->QueryInterface(aIID, result); + } + + return QueryInterface(aIID, result); +} //----------------------------------------------------------------------------- // HttpChannelParent::PHttpChannelParent //----------------------------------------------------------------------------- bool HttpChannelParent::RecvAsyncOpen(const IPC::URI& aURI, const IPC::URI& aOriginalURI, @@ -151,19 +176,20 @@ HttpChannelParent::RecvAsyncOpen(const I httpChan->SetLoadFlags(loadFlags); for (PRUint32 i = 0; i < requestHeaders.Length(); i++) { httpChan->SetRequestHeader(requestHeaders[i].mHeader, requestHeaders[i].mValue, requestHeaders[i].mMerge); } - mChannelListener = new HttpChannelParentListener(this); + nsRefPtr<HttpChannelParentListener> channelListener = + new HttpChannelParentListener(this); - httpChan->SetNotificationCallbacks(mChannelListener); + httpChan->SetNotificationCallbacks(channelListener); httpChan->SetRequestMethod(nsDependentCString(requestMethod.get())); nsCOMPtr<nsIInputStream> stream(uploadStream); if (stream) { httpChan->InternalSetUploadStream(stream); httpChan->SetUploadStreamHasHeaders(uploadStreamHasHeaders); } @@ -204,33 +230,46 @@ HttpChannelParent::RecvAsyncOpen(const I &setChooseApplicationCache); if (setChooseApplicationCache && NS_SUCCEEDED(rv)) appCacheChan->SetChooseApplicationCache(PR_TRUE); } } } - rv = httpChan->AsyncOpen(mChannelListener, nsnull); + rv = httpChan->AsyncOpen(channelListener, nsnull); if (NS_FAILED(rv)) return SendCancelEarly(rv); return true; } +bool +HttpChannelParent::RecvConnectChannel(const PRUint32& channelId) +{ + nsresult rv; + + LOG(("Looking for a registered channel [this=%p, id=%d]", this, channelId)); + rv = NS_LinkRedirectChannels(channelId, this, getter_AddRefs(mChannel)); + LOG((" found channel %p, rv=%08x", mChannel.get(), rv)); + + return true; +} + bool HttpChannelParent::RecvSetPriority(const PRUint16& priority) { nsHttpChannel *httpChan = static_cast<nsHttpChannel *>(mChannel.get()); httpChan->SetPriority(priority); - if (mChannelListener && mChannelListener->mRedirectChannel && - mChannelListener->mRedirectChannel != this) - return mChannelListener->mRedirectChannel->RecvSetPriority(priority); - + nsCOMPtr<nsISupportsPriority> priorityRedirectChannel = + do_QueryInterface(mRedirectChannel); + if (priorityRedirectChannel) + priorityRedirectChannel->SetPriority(priority); + return true; } bool HttpChannelParent::RecvSuspend() { mChannel->Suspend(); return true; @@ -286,18 +325,31 @@ HttpChannelParent::RecvUpdateAssociatedC return true; } bool HttpChannelParent::RecvRedirect2Verify(const nsresult& result, const RequestHeaderTuples& changedHeaders) { - if (mChannelListener) - mChannelListener->OnContentRedirectResultReceived(result, changedHeaders); + if (NS_SUCCEEDED(result)) { + nsCOMPtr<nsIHttpChannel> newHttpChannel = + do_QueryInterface(mRedirectChannel); + + if (newHttpChannel) { + for (PRUint32 i = 0; i < changedHeaders.Length(); i++) { + newHttpChannel->SetRequestHeader(changedHeaders[i].mHeader, + changedHeaders[i].mValue, + changedHeaders[i].mMerge); + } + } + } + + mRedirectCallback->OnRedirectVerifyCallback(result); + mRedirectCallback = nsnull; return true; } bool HttpChannelParent::RecvDocumentChannelCleanup() { // We must clear the cache entry here, else we'll block other channels from // reading it if we've got it open for writing. @@ -310,28 +362,24 @@ bool HttpChannelParent::RecvMarkOfflineCacheEntryAsForeign() { nsHttpChannel *httpChan = static_cast<nsHttpChannel *>(mChannel.get()); httpChan->MarkOfflineCacheEntryAsForeign(); return true; } //----------------------------------------------------------------------------- -// nsIRequestObserver and nsIStreamListener methods equivalents +// HttpChannelParent::nsIRequestObserver //----------------------------------------------------------------------------- -nsresult +NS_IMETHODIMP 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(); nsHttpRequestHead *requestHead = chan->GetRequestHead(); PRBool isFromCache = false; chan->IsFromCache(&isFromCache); PRUint32 expirationTime = nsICache::NO_EXPIRATION_TIME; chan->GetCacheTokenExpirationTime(&expirationTime); nsCString cachedCharset; @@ -388,30 +436,34 @@ HttpChannelParent::OnStartRequest(nsIReq mCacheDescriptor ? PR_TRUE : PR_FALSE, expirationTime, cachedCharset, secInfoSerialization)) { return NS_ERROR_UNEXPECTED; } return NS_OK; } -nsresult +NS_IMETHODIMP HttpChannelParent::OnStopRequest(nsIRequest *aRequest, nsISupports *aContext, nsresult aStatusCode) { LOG(("HttpChannelParent::OnStopRequest: [this=%x status=%ul]\n", this, aStatusCode)); if (mIPCClosed || !SendOnStopRequest(aStatusCode)) return NS_ERROR_UNEXPECTED; return NS_OK; } -nsresult +//----------------------------------------------------------------------------- +// HttpChannelParent::nsIStreamListener +//----------------------------------------------------------------------------- + +NS_IMETHODIMP HttpChannelParent::OnDataAvailable(nsIRequest *aRequest, nsISupports *aContext, nsIInputStream *aInputStream, PRUint32 aOffset, PRUint32 aCount) { LOG(("HttpChannelParent::OnDataAvailable [this=%x]\n", this)); @@ -447,10 +499,67 @@ HttpChannelParent::OnStatus(nsIRequest * nsresult aStatus, const PRUnichar *aStatusArg) { if (mIPCClosed || !SendOnStatus(aStatus, nsString(aStatusArg))) return NS_ERROR_UNEXPECTED; return NS_OK; } +//----------------------------------------------------------------------------- +// HttpChannelParent::nsIParentChannel +//----------------------------------------------------------------------------- + +NS_IMETHODIMP +HttpChannelParent::Delete() +{ + if (!mIPCClosed) + SendDeleteSelf(); + + return NS_OK; +} + +//----------------------------------------------------------------------------- +// HttpChannelParent::nsIParentRedirectingChannel +//----------------------------------------------------------------------------- + +NS_IMETHODIMP +HttpChannelParent::StartRedirect(PRUint32 newChannelId, + nsIChannel* newChannel, + PRUint32 redirectFlags, + nsIAsyncVerifyRedirectCallback* callback) +{ + if (mIPCClosed) + return NS_BINDING_ABORTED; + + nsCOMPtr<nsIURI> newURI; + newChannel->GetURI(getter_AddRefs(newURI)); + + nsHttpChannel *httpChan = static_cast<nsHttpChannel *>(mChannel.get()); + nsHttpResponseHead *responseHead = httpChan->GetResponseHead(); + bool result = SendRedirect1Begin(newChannelId, + IPC::URI(newURI), + redirectFlags, + responseHead ? *responseHead + : nsHttpResponseHead()); + if (!result) + return NS_BINDING_ABORTED; + + // Result is handled in RecvRedirect2Verify above + + mRedirectChannel = newChannel; + mRedirectCallback = callback; + return NS_OK; +} + +NS_IMETHODIMP +HttpChannelParent::CompleteRedirect(PRBool succeeded) +{ + if (succeeded && !mIPCClosed) { + // TODO: check return value: assume child dead if failed + unused << SendRedirect3Complete(); + } + + mRedirectChannel = nsnull; + return NS_OK; +} + }} // mozilla::net -
--- a/netwerk/protocol/http/HttpChannelParent.h +++ b/netwerk/protocol/http/HttpChannelParent.h @@ -41,47 +41,43 @@ #ifndef mozilla_net_HttpChannelParent_h #define mozilla_net_HttpChannelParent_h #include "nsHttp.h" #include "mozilla/dom/PBrowserParent.h" #include "mozilla/net/PHttpChannelParent.h" #include "mozilla/net/NeckoCommon.h" +#include "nsIParentRedirectingChannel.h" #include "nsIProgressEventSink.h" #include "nsITabParent.h" using namespace mozilla::dom; class nsICacheEntryDescriptor; namespace mozilla { namespace net { class HttpChannelParentListener; class HttpChannelParent : public PHttpChannelParent + , public nsIParentRedirectingChannel , public nsIProgressEventSink + , public nsIInterfaceRequestor { public: NS_DECL_ISUPPORTS + NS_DECL_NSIREQUESTOBSERVER + NS_DECL_NSISTREAMLISTENER + NS_DECL_NSIPARENTCHANNEL + NS_DECL_NSIPARENTREDIRECTINGCHANNEL NS_DECL_NSIPROGRESSEVENTSINK + NS_DECL_NSIINTERFACEREQUESTOR - // 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(); protected: virtual bool RecvAsyncOpen(const IPC::URI& uri, const IPC::URI& originalUri, const IPC::URI& docUri, const IPC::URI& referrerUri, @@ -95,16 +91,17 @@ protected: const PRBool& allowPipelining, const PRBool& forceAllowThirdPartyCookie, const bool& doResumeAt, const PRUint64& startPos, const nsCString& entityID, const bool& chooseApplicationCache, const nsCString& appCacheClientID); + virtual bool RecvConnectChannel(const PRUint32& channelId); virtual bool RecvSetPriority(const PRUint16& priority); virtual bool RecvSetCacheTokenCachedCharset(const nsCString& charset); virtual bool RecvSuspend(); virtual bool RecvResume(); virtual bool RecvCancel(const nsresult& status); virtual bool RecvRedirect2Verify(const nsresult& result, const RequestHeaderTuples& changedHeaders); virtual bool RecvUpdateAssociatedContentSecurity(const PRInt32& high, @@ -117,17 +114,19 @@ protected: virtual void ActorDestroy(ActorDestroyReason why); 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() + + nsCOMPtr<nsIChannel> mRedirectChannel; + nsCOMPtr<nsIAsyncVerifyRedirectCallback> mRedirectCallback; }; } // namespace net } // namespace mozilla #endif // mozilla_net_HttpChannelParent_h
--- a/netwerk/protocol/http/HttpChannelParentListener.cpp +++ b/netwerk/protocol/http/HttpChannelParentListener.cpp @@ -51,24 +51,28 @@ #include "nsIAuthPromptProvider.h" #include "nsIDocShellTreeItem.h" #include "nsIBadCertListener2.h" #include "nsICacheEntryDescriptor.h" #include "nsSerializationHelper.h" #include "nsISerializable.h" #include "nsIAssociatedContentSecurity.h" #include "nsISecureBrowserUI.h" +#include "nsIRedirectChannelRegistrar.h" + +#include "nsIFTPChannel.h" using mozilla::unused; namespace mozilla { namespace net { HttpChannelParentListener::HttpChannelParentListener(HttpChannelParent* aInitialChannel) : mActiveChannel(aInitialChannel) + , mRedirectChannelId(0) { } HttpChannelParentListener::~HttpChannelParentListener() { } //----------------------------------------------------------------------------- @@ -132,171 +136,120 @@ HttpChannelParentListener::OnDataAvailab //----------------------------------------------------------------------------- // 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(nsISecureBrowserUI))) { - 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); + if (aIID.Equals(NS_GET_IID(nsIChannelEventSink)) || + aIID.Equals(NS_GET_IID(nsIHttpEventSink)) || + aIID.Equals(NS_GET_IID(nsIRedirectResultListener))) + { + return 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: + nsCOMPtr<nsIInterfaceRequestor> ir; + if (mActiveChannel && + NS_SUCCEEDED(CallQueryInterface(mActiveChannel.get(), + getter_AddRefs(ir)))) + { + return ir->GetInterface(aIID, result); + } - // 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; - } + 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; + nsresult rv; - // 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); - nsHttpResponseHead *responseHead = oldHttpChannel->GetResponseHead(); + // Register the new channel and obtain id for it + nsCOMPtr<nsIRedirectChannelRegistrar> registrar = + do_GetService("@mozilla.org/redirectchannelregistrar;1", &rv); + NS_ENSURE_SUCCESS(rv, rv); - // TODO: check mActiveChannel->mIPCClosed and return val from Send function - - unused << mActiveChannel->SendRedirect1Begin(mRedirectChannel, - IPC::URI(newURI), - redirectFlags, - responseHead ? *responseHead - : nsHttpResponseHead()); + rv = registrar->RegisterChannel(newChannel, &mRedirectChannelId); + NS_ENSURE_SUCCESS(rv, rv); - // mActiveChannel gets the response in RecvRedirect2Verify and forwards it - // to this wrapper through OnContentRedirectResultReceived - - return NS_OK; -} + LOG(("Registered %p channel under id=%d", newChannel, mRedirectChannelId)); -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); - } + nsCOMPtr<nsIParentRedirectingChannel> activeRedirectingChannel = + do_QueryInterface(mActiveChannel); + if (!activeRedirectingChannel) { + NS_RUNTIMEABORT("Channel got a redirect response, but doesn't implement " + "nsIParentRedirectingChannel to handle it."); } - mRedirectCallback->OnRedirectVerifyCallback(result); - mRedirectCallback = nsnull; + return activeRedirectingChannel->StartRedirect(mRedirectChannelId, + newChannel, + redirectFlags, + callback); } //----------------------------------------------------------------------------- // HttpChannelParentListener::nsIRedirectResultListener //----------------------------------------------------------------------------- NS_IMETHODIMP HttpChannelParentListener::OnRedirectResult(PRBool succeeded) { - if (!mRedirectChannel) { - // Redirect might get canceled before we got AsyncOnChannelRedirect - return NS_OK; - } + nsresult rv; + + nsCOMPtr<nsIParentChannel> redirectChannel; + if (mRedirectChannelId) { + nsCOMPtr<nsIRedirectChannelRegistrar> registrar = + do_GetService("@mozilla.org/redirectchannelregistrar;1", &rv); + NS_ENSURE_SUCCESS(rv, rv); + + rv = registrar->GetParentChannel(mRedirectChannelId, + getter_AddRefs(redirectChannel)); + if (NS_FAILED(rv) || !redirectChannel) { + // Redirect might get canceled before we got AsyncOnChannelRedirect + LOG(("Registered parent channel not found under id=%d", mRedirectChannelId)); - if (succeeded && !mActiveChannel->mIPCClosed) { - // TODO: check return value: assume child dead if failed - unused << mActiveChannel->SendRedirect3Complete(); + nsCOMPtr<nsIChannel> newChannel; + rv = registrar->GetRegisteredChannel(mRedirectChannelId, + getter_AddRefs(newChannel)); + NS_ASSERTION(newChannel, "Already registered channel not found"); + + if (NS_SUCCEEDED(rv)) + newChannel->Cancel(NS_BINDING_ABORTED); + } + + // Release all previously registered channels, they are no longer need to be + // kept in the registrar from this moment. + registrar->DeregisterChannels(mRedirectChannelId); + + mRedirectChannelId = 0; } - HttpChannelParent* channelToDelete; + nsCOMPtr<nsIParentRedirectingChannel> activeRedirectingChannel = + do_QueryInterface(mActiveChannel); + NS_ABORT_IF_FALSE(activeRedirectingChannel, + "Channel finished a redirect response, but doesn't implement " + "nsIParentRedirectingChannel to complete it."); + + activeRedirectingChannel->CompleteRedirect(succeeded); + if (succeeded) { // Switch to redirect channel and delete the old one. - channelToDelete = mActiveChannel; - mActiveChannel = mRedirectChannel; - } else { + mActiveChannel->Delete(); + mActiveChannel = redirectChannel; + } else if (redirectChannel) { // Delete the redirect target channel: continue using old channel - channelToDelete = mRedirectChannel; + redirectChannel->Delete(); } - if (!channelToDelete->mIPCClosed) - unused << channelToDelete->SendDeleteSelf(); - mRedirectChannel = nsnull; - return NS_OK; } }} // mozilla::net
--- a/netwerk/protocol/http/HttpChannelParentListener.h +++ b/netwerk/protocol/http/HttpChannelParentListener.h @@ -40,17 +40,17 @@ * ***** 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 "nsIParentChannel.h" #include "nsIInterfaceRequestor.h" #include "nsIChannelEventSink.h" #include "nsIRedirectResultListener.h" #include "nsIProgressEventSink.h" using namespace mozilla::dom; class nsICacheEntryDescriptor; @@ -71,24 +71,17 @@ public: 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; + nsCOMPtr<nsIParentChannel> mActiveChannel; + PRUint32 mRedirectChannelId; }; } // namespace net } // namespace mozilla #endif // mozilla_net_HttpChannelParent_h
--- a/netwerk/protocol/http/Makefile.in +++ b/netwerk/protocol/http/Makefile.in @@ -61,16 +61,17 @@ XPIDLSRCS = \ nsIHttpActivityObserver.idl \ nsIHttpAuthManager.idl \ nsIHttpAuthenticator.idl \ nsIHttpChannelInternal.idl \ nsIHttpEventSink.idl \ nsIHttpProtocolHandler.idl \ nsIHttpChannelAuthProvider.idl \ nsIHttpAuthenticableChannel.idl \ + nsIHttpChannelChild.idl \ $(NULL) EXPORTS_mozilla/net = \ HttpBaseChannel.h \ $(NULL) ifdef MOZ_IPC EXPORTS_mozilla/net += \
--- a/netwerk/protocol/http/PHttpChannel.ipdl +++ b/netwerk/protocol/http/PHttpChannel.ipdl @@ -76,16 +76,18 @@ parent: PRBool allowPipelining, PRBool forceAllowThirdPartyCookie, bool resumeAt, PRUint64 startPos, nsCString entityID, bool chooseApplicationCache, nsCString appCacheClientID); + ConnectChannel(PRUint32 channelId); + SetPriority(PRUint16 priority); SetCacheTokenCachedCharset(nsCString charset); UpdateAssociatedContentSecurity(PRInt32 high, PRInt32 low, PRInt32 broken, PRInt32 no); @@ -140,17 +142,17 @@ child: OnStatus(nsresult status, nsString statusArg); // Used to cancel child channel if we hit errors during creating and // AsyncOpen of nsHttpChannel on the parent. CancelEarly(nsresult status); // Called to initiate content channel redirect, starts talking to sinks // on the content process and reports result via Redirect2Verify above - Redirect1Begin(PHttpChannel newChannel, + Redirect1Begin(PRUint32 newChannelId, URI newUri, PRUint32 redirectFlags, nsHttpResponseHead responseHead); // Called if redirect successful so that child can complete setup. Redirect3Complete(); // Associte the child with an application ids
new file mode 100644 --- /dev/null +++ b/netwerk/protocol/http/nsIHttpChannelChild.idl @@ -0,0 +1,48 @@ +/* -*- Mode: C++; 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 Mozilla. + * + * The Initial Developer of the Original Code is + * Netscape Communications. + * Portions created by the Initial Developer are Copyright (C) 2001 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Honza Bambas <honzab.moz@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" + +[ptr] native RequestHeaderTuples(mozilla::net::RequestHeaderTuples); + +[uuid(40192377-f83c-4b31-92c6-dbc6c767c860)] +interface nsIHttpChannelChild : nsISupports +{ + void addCookiesToRequest(); + readonly attribute RequestHeaderTuples headerTuples; +};