diff --git a/netwerk/build/nsNetModule.cpp b/netwerk/build/nsNetModule.cpp index e0e7e0cbc9b..fd845ef2ae2 100644 --- a/netwerk/build/nsNetModule.cpp +++ b/netwerk/build/nsNetModule.cpp @@ -38,6 +38,7 @@ #include "necko-config.h" #ifdef MOZ_IPC +#define ALLOW_LATE_NSHTTP_H_INCLUDE 1 #include "base/basictypes.h" #endif diff --git a/netwerk/ipc/Makefile.in b/netwerk/ipc/Makefile.in index ce0ab05cb24..32cb6d860ec 100644 --- a/netwerk/ipc/Makefile.in +++ b/netwerk/ipc/Makefile.in @@ -53,6 +53,7 @@ EXPORTS_NAMESPACES = mozilla/net EXPORTS_mozilla/net = \ NeckoParent.h \ NeckoChild.h \ + NeckoCommon.h \ $(NULL) CPPSRCS = \ @@ -60,6 +61,11 @@ CPPSRCS = \ NeckoParent.cpp \ $(NULL) +LOCAL_INCLUDES += \ + -I$(srcdir)/../protocol/http/src \ + -I$(srcdir)/../base/src \ + $(NULL) + include $(topsrcdir)/config/config.mk include $(topsrcdir)/ipc/chromium/chromium-config.mk include $(topsrcdir)/config/rules.mk diff --git a/netwerk/ipc/NeckoChild.cpp b/netwerk/ipc/NeckoChild.cpp index e2fc78ddaa0..20dd315e2fa 100644 --- a/netwerk/ipc/NeckoChild.cpp +++ b/netwerk/ipc/NeckoChild.cpp @@ -38,6 +38,7 @@ * * ***** END LICENSE BLOCK ***** */ +#include "nsHttp.h" #include "mozilla/net/NeckoChild.h" #include "mozilla/dom/ContentProcessChild.h" #include "mozilla/net/HttpChannelChild.h" @@ -58,7 +59,9 @@ NeckoChild::~NeckoChild() void NeckoChild::InitNeckoChild() { - if (XRE_GetProcessType() == GeckoProcessType_Content) { + NS_ABORT_IF_FALSE(IsNeckoChild(), "InitNeckoChild called by non-child!"); + + if (!gNeckoChild) { mozilla::dom::ContentProcessChild * cpc = mozilla::dom::ContentProcessChild::GetSingleton(); NS_ASSERTION(cpc, "Content Protocol is NULL!"); @@ -67,16 +70,36 @@ void NeckoChild::InitNeckoChild() } } +// Note: not actually called; has some lifespan as child process, so +// automatically destroyed at exit. +void NeckoChild::DestroyNeckoChild() +{ + NS_ABORT_IF_FALSE(IsNeckoChild(), "DestroyNeckoChild called by non-child!"); + static bool alreadyDestroyed = false; + NS_ABORT_IF_FALSE(!alreadyDestroyed, "DestroyNeckoChild already called!"); + + if (!alreadyDestroyed) { + Send__delete__(gNeckoChild); + gNeckoChild = nsnull; + alreadyDestroyed = true; + } +} + PHttpChannelChild* NeckoChild::AllocPHttpChannel() { - return new HttpChannelChild(); + // We don't allocate here: see HttpChannelChild::AsyncOpen() + NS_RUNTIMEABORT("AllocPHttpChannel should not be called"); + return nsnull; } bool NeckoChild::DeallocPHttpChannel(PHttpChannelChild* channel) { - delete channel; + NS_ABORT_IF_FALSE(IsNeckoChild(), "DeallocPHttpChannel called by non-child!"); + + HttpChannelChild *p = static_cast(channel); + p->Release(); return true; } diff --git a/netwerk/ipc/NeckoChild.h b/netwerk/ipc/NeckoChild.h index 9de4e9e918e..df34c6661fb 100644 --- a/netwerk/ipc/NeckoChild.h +++ b/netwerk/ipc/NeckoChild.h @@ -42,8 +42,7 @@ #define mozilla_net_NeckoChild_h #include "mozilla/net/PNeckoChild.h" -#include "mozilla/net/HttpChannelChild.h" -#include "nsXULAppAPI.h" +#include "mozilla/net/NeckoCommon.h" namespace mozilla { namespace net { @@ -57,11 +56,11 @@ public: virtual ~NeckoChild(); static void InitNeckoChild(); - - virtual PHttpChannelChild* AllocPHttpChannel(); - virtual bool DeallocPHttpChannel(PHttpChannelChild*); + static void DestroyNeckoChild(); protected: + virtual PHttpChannelChild* AllocPHttpChannel(); + virtual bool DeallocPHttpChannel(PHttpChannelChild*); }; /** @@ -70,12 +69,6 @@ protected: */ extern PNeckoChild *gNeckoChild; -static inline PRBool -IsNeckoChild() -{ - return XRE_GetProcessType() == GeckoProcessType_Content; -} - } // namespace net } // namespace mozilla diff --git a/netwerk/ipc/NeckoCommon.h b/netwerk/ipc/NeckoCommon.h new file mode 100644 index 00000000000..15d82eddecf --- /dev/null +++ b/netwerk/ipc/NeckoCommon.h @@ -0,0 +1,87 @@ +/* -*- 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 + * + * 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_NeckoCommon_h +#define mozilla_net_NeckoCommon_h + +#include "nsXULAppAPI.h" + +// Temporary: use while we figure out which XPCOM interfaces (from list +// copied from nsHttpChannel) HttpChannel{Child|Parent}, etc., actually need to +// implement. I.e., implement interfaces as we need them, and if we never hit a +// given interface, figure out if we can stop advertising it. + +#define DROP_DEAD() \ + do { \ + fprintf(stderr, \ + "*&*&*&*&*&*&*&**&*&&*& FATAL ERROR: '%s' UNIMPLEMENTED: %s +%d", \ + __FUNCTION__, __FILE__, __LINE__); \ + NS_ABORT(); \ + return NS_ERROR_NOT_IMPLEMENTED; \ + } while (0) + + +namespace mozilla { +namespace net { + +inline bool +IsNeckoChild() +{ + // TODO: remove env var check eventually. + // - For now: if unset, necko works with full stack in each process, + // i.e. no IPC. + static bool didCheck = false; + static bool amChild = false; + + if (!didCheck) { + const char * e = PR_GetEnv("NECKO_E10S_HTTP"); + if (e && *e) + amChild = (XRE_GetProcessType() == GeckoProcessType_Content); + didCheck = true; + } + return amChild; +} + + +} // namespace net +} // namespace mozilla + +#endif // mozilla_net_NeckoCommon_h + diff --git a/netwerk/ipc/NeckoParent.cpp b/netwerk/ipc/NeckoParent.cpp index d2ebc0bc8d2..8af6a1fa416 100644 --- a/netwerk/ipc/NeckoParent.cpp +++ b/netwerk/ipc/NeckoParent.cpp @@ -38,6 +38,7 @@ * * ***** END LICENSE BLOCK ***** */ +#include "nsHttp.h" #include "mozilla/net/NeckoParent.h" #include "mozilla/net/HttpChannelParent.h" @@ -56,13 +57,16 @@ NeckoParent::~NeckoParent() PHttpChannelParent* NeckoParent::AllocPHttpChannel() { - return new HttpChannelParent(); + HttpChannelParent *p = new HttpChannelParent(); + p->AddRef(); + return p; } bool NeckoParent::DeallocPHttpChannel(PHttpChannelParent* channel) { - delete channel; + HttpChannelParent *p = static_cast(channel); + p->Release(); return true; } diff --git a/netwerk/ipc/NeckoParent.h b/netwerk/ipc/NeckoParent.h index c5e38482106..67b0ff9636a 100644 --- a/netwerk/ipc/NeckoParent.h +++ b/netwerk/ipc/NeckoParent.h @@ -39,7 +39,7 @@ * ***** END LICENSE BLOCK ***** */ #include "mozilla/net/PNeckoParent.h" -#include "mozilla/net/HttpChannelChild.h" +#include "mozilla/net/NeckoCommon.h" #ifndef mozilla_net_NeckoParent_h #define mozilla_net_NeckoParent_h diff --git a/netwerk/protocol/http/src/HttpChannelChild.cpp b/netwerk/protocol/http/src/HttpChannelChild.cpp index 7a16050dbbe..4d5ec319af1 100644 --- a/netwerk/protocol/http/src/HttpChannelChild.cpp +++ b/netwerk/protocol/http/src/HttpChannelChild.cpp @@ -38,20 +38,1086 @@ * * ***** END LICENSE BLOCK ***** */ +#include "nsHttp.h" +#include "mozilla/net/NeckoChild.h" #include "mozilla/net/HttpChannelChild.h" -#include "mozilla/dom/ContentProcessChild.h" + +#include "nsStringStream.h" +#include "nsHttpHandler.h" +#include "nsMimeTypes.h" +#include "nsNetUtil.h" + +// - TODO: Can we add these checks to nsHttpChannel.cpp too? +#define ENSURE_CALLED_BEFORE_ASYNC_OPEN() \ + if (mIsPending) \ + DROP_DEAD(); \ + if (mWasOpened) \ + DROP_DEAD(); \ + NS_ENSURE_TRUE(!mIsPending, NS_ERROR_IN_PROGRESS); \ + NS_ENSURE_TRUE(!mWasOpened, NS_ERROR_ALREADY_OPENED); + namespace mozilla { namespace net { // C++ file contents HttpChannelChild::HttpChannelChild() + : mState(HCC_NEW) + // FIELDS COPIED FROM nsHttpChannel.h + , mLoadFlags(LOAD_NORMAL) + , mStatus(NS_OK) + , mIsPending(PR_FALSE) + , mWasOpened(PR_FALSE) { + LOG(("Creating HttpChannelChild @%x\n", this)); + + // grab a reference to the handler to ensure that it doesn't go away. + NS_ADDREF(gHttpHandler); } HttpChannelChild::~HttpChannelChild() { + LOG(("Destroying HttpChannelChild @%x\n", this)); + + // release our reference to the handler + NS_RELEASE(gHttpHandler); } +nsresult +HttpChannelChild::Init(nsIURI *uri) +{ + /** + * COPIED from nsHttpChannel and tweaked: merge into base class? + */ + LOG(("HttpChannelChild::Init [this=%x]\n", this)); + + NS_PRECONDITION(uri, "null uri"); + + nsresult rv = nsHashPropertyBag::Init(); + if (NS_FAILED(rv)) + return rv; + + mURI = uri; + mOriginalURI = uri; + mDocumentURI = nsnull; +// mCaps = caps; + + // + // Construct connection info object + // + nsCAutoString host; + PRInt32 port = -1; + PRBool usingSSL = PR_FALSE; + + rv = mURI->SchemeIs("https", &usingSSL); + if (NS_FAILED(rv)) return rv; + + rv = mURI->GetAsciiHost(host); + if (NS_FAILED(rv)) return rv; + + // reject the URL if it doesn't specify a host + if (host.IsEmpty()) + return NS_ERROR_MALFORMED_URI; + + rv = mURI->GetPort(&port); + if (NS_FAILED(rv)) return rv; + + LOG(("host=%s port=%d\n", host.get(), port)); + + rv = mURI->GetAsciiSpec(mSpec); + if (NS_FAILED(rv)) return rv; + LOG(("uri=%s\n", mSpec.get())); + +#if 0 + // Not yet clear that we need this in child + mConnectionInfo = new nsHttpConnectionInfo(host, port, + proxyInfo, usingSSL); + if (!mConnectionInfo) + return NS_ERROR_OUT_OF_MEMORY; + NS_ADDREF(mConnectionInfo); +#endif + + // Set default request method + mRequestHead.SetMethod(nsHttp::Get); + +#if 0 + // FIXME (bug 541017): split this out into a separate function so we can share + // with nsHttpChannel. + // - Make sure not to set any headers twice on parent. + + // + // Set request headers + // + nsCAutoString hostLine; + if (strchr(host.get(), ':')) { + // host is an IPv6 address literal and must be encapsulated in []'s + hostLine.Assign('['); + // scope id is not needed for Host header. + int scopeIdPos = host.FindChar('%'); + if (scopeIdPos == kNotFound) + hostLine.Append(host); + else if (scopeIdPos > 0) + hostLine.Append(Substring(host, 0, scopeIdPos)); + else + return NS_ERROR_MALFORMED_URI; + hostLine.Append(']'); + } + else + hostLine.Assign(host); + if (port != -1) { + hostLine.Append(':'); + hostLine.AppendInt(port); + } + + rv = mRequestHead.SetHeader(nsHttp::Host, hostLine); + if (NS_FAILED(rv)) return rv; + + rv = gHttpHandler-> + AddStandardRequestHeaders(&mRequestHead.Headers(), caps, + !mConnectionInfo->UsingSSL() && + mConnectionInfo->UsingHttpProxy()); +#endif /* 0 */ + + return rv; +} + +//----------------------------------------------------------------------------- +// HttpChannelChild::nsISupports +//----------------------------------------------------------------------------- + +NS_IMPL_ADDREF_INHERITED(HttpChannelChild, nsHashPropertyBag) +NS_IMPL_RELEASE_INHERITED(HttpChannelChild, nsHashPropertyBag) + +NS_INTERFACE_MAP_BEGIN(HttpChannelChild) + NS_INTERFACE_MAP_ENTRY(nsIRequest) + NS_INTERFACE_MAP_ENTRY(nsIChannel) + NS_INTERFACE_MAP_ENTRY(nsIHttpChannel) + NS_INTERFACE_MAP_ENTRY(nsIHttpChannelInternal) + NS_INTERFACE_MAP_ENTRY(nsIRequestObserver) + NS_INTERFACE_MAP_ENTRY(nsIStreamListener) + NS_INTERFACE_MAP_ENTRY(nsICachingChannel) + NS_INTERFACE_MAP_ENTRY(nsIUploadChannel) + NS_INTERFACE_MAP_ENTRY(nsIUploadChannel2) + NS_INTERFACE_MAP_ENTRY(nsICacheListener) + NS_INTERFACE_MAP_ENTRY(nsIEncodedChannel) + NS_INTERFACE_MAP_ENTRY(nsIResumableChannel) + NS_INTERFACE_MAP_ENTRY(nsITransportEventSink) + NS_INTERFACE_MAP_ENTRY(nsISupportsPriority) + NS_INTERFACE_MAP_ENTRY(nsIProtocolProxyCallback) + NS_INTERFACE_MAP_ENTRY(nsIProxiedChannel) + NS_INTERFACE_MAP_ENTRY(nsITraceableChannel) + NS_INTERFACE_MAP_ENTRY(nsIApplicationCacheContainer) + NS_INTERFACE_MAP_ENTRY(nsIApplicationCacheChannel) + NS_INTERFACE_MAP_ENTRY(nsIAuthPromptCallback) +NS_INTERFACE_MAP_END_INHERITING(nsHashPropertyBag) + +//----------------------------------------------------------------------------- +// HttpChannelChild::PHttpChannelChild +//----------------------------------------------------------------------------- + +bool +HttpChannelChild::RecvOnStartRequest(const PRInt32& HACK_ContentLength, + const nsCString& HACK_ContentType, + const PRUint32& HACK_Status, + const nsCString& HACK_StatusText) +{ + LOG(("HttpChannelChild::RecvOnStartRequest [this=%x]\n", this)); + + mState = HCC_ONSTART; + + mContentLength_HACK = HACK_ContentLength; + mContentType_HACK = HACK_ContentType; + mResponseStatus_HACK = HACK_Status; + mResponseStatusText_HACK = HACK_StatusText; + + nsresult rv = mChildListener->OnStartRequest(this, mChildListenerContext); + if (!NS_SUCCEEDED(rv)) { + // TODO: Cancel request: + // - Send Cancel msg to parent + // - drop any in flight OnDataAvail msgs we receive + // - make sure we do call OnStopRequest eventually + // - return true here, not false + return false; + } + return true; +} + +bool +HttpChannelChild::RecvOnDataAvailable(const nsCString& data, + const PRUint32& offset, + const PRUint32& count) +{ + LOG(("HttpChannelChild::RecvOnDataAvailable [this=%x]\n", this)); + + mState = HCC_ONDATA; + + // NOTE: the OnDataAvailable contract requires the client to read all the data + // in the inputstream. This code relies on that ('data' will go away after + // this function). Apparently the previous, non-e10s behavior was to actually + // support only reading part of the data, allowing later calls to read the + // rest. + nsCOMPtr stringStream; + nsresult rv = NS_NewByteInputStream(getter_AddRefs(stringStream), + data.get(), + count, + NS_ASSIGNMENT_DEPEND); + if (!NS_SUCCEEDED(rv)) { + // TODO: what to do here? Cancel request? Very unlikely to fail. + return false; + } + rv = mChildListener->OnDataAvailable(this, mChildListenerContext, + stringStream, offset, count); + stringStream->Close(); + if (!NS_SUCCEEDED(rv)) { + // TODO: Cancel request: see notes in OnStartRequest + return false; + } + return true; +} + +bool +HttpChannelChild::RecvOnStopRequest(const nsresult& statusCode) +{ + LOG(("HttpChannelChild::RecvOnStopRequest [this=%x status=%u]\n", + this, statusCode)); + + mState = HCC_ONSTOP; + + mIsPending = PR_FALSE; + mStatus = statusCode; + nsresult rv = mChildListener->OnStopRequest(this, mChildListenerContext, + statusCode); + mChildListener = 0; + mChildListenerContext = 0; + if (!NS_SUCCEEDED(rv)) { + // TODO: Cancel request: see notes in OnStartRequest + return false; + } + return true; +} + +//----------------------------------------------------------------------------- +// HttpChannelChild::nsIRequest +//----------------------------------------------------------------------------- + +NS_IMETHODIMP +HttpChannelChild::GetName(nsACString& aName) +{ + DROP_DEAD(); +} + +NS_IMETHODIMP +HttpChannelChild::IsPending(PRBool *retval) +{ + /** + * COPIED from nsHttpChannel.cpp: move to shared base class? + */ + NS_ENSURE_ARG_POINTER(retval); + *retval = mIsPending; + return NS_OK; +} + +NS_IMETHODIMP +HttpChannelChild::GetStatus(nsresult *aStatus) +{ + /** + * COPIED from nsHttpChannel.cpp: move to shared base class? + */ + NS_ENSURE_ARG_POINTER(aStatus); + *aStatus = mStatus; + return NS_OK; +} + +NS_IMETHODIMP +HttpChannelChild::Cancel(nsresult aStatus) +{ + DROP_DEAD(); +} + +NS_IMETHODIMP +HttpChannelChild::Suspend() +{ + DROP_DEAD(); +} + +NS_IMETHODIMP +HttpChannelChild::Resume() +{ + DROP_DEAD(); +} + +NS_IMETHODIMP +HttpChannelChild::GetLoadGroup(nsILoadGroup **aLoadGroup) +{ + DROP_DEAD(); +} +NS_IMETHODIMP +HttpChannelChild::SetLoadGroup(nsILoadGroup *aLoadGroup) +{ + DROP_DEAD(); +} + +NS_IMETHODIMP +HttpChannelChild::GetLoadFlags(nsLoadFlags *aLoadFlags) +{ + /** + * COPIED from nsHttpChannel.cpp: move to shared base class? + */ + NS_ENSURE_ARG_POINTER(aLoadFlags); + *aLoadFlags = mLoadFlags; + return NS_OK; +} + +NS_IMETHODIMP +HttpChannelChild::SetLoadFlags(nsLoadFlags aLoadFlags) +{ + ENSURE_CALLED_BEFORE_ASYNC_OPEN(); + /** + * COPIED from nsHttpChannel.cpp: move to shared base class? + */ + mLoadFlags = aLoadFlags; + return NS_OK; +} + +//----------------------------------------------------------------------------- +// HttpChannelChild::nsIChannel +//----------------------------------------------------------------------------- + +NS_IMETHODIMP +HttpChannelChild::GetOriginalURI(nsIURI **originalURI) +{ + /** + * COPIED from nsHttpChannel.cpp: move to shared base class? + */ + NS_ENSURE_ARG_POINTER(originalURI); + *originalURI = mOriginalURI; + NS_ADDREF(*originalURI); + return NS_OK; +} + +NS_IMETHODIMP +HttpChannelChild::SetOriginalURI(nsIURI *originalURI) +{ + ENSURE_CALLED_BEFORE_ASYNC_OPEN(); + /** + * COPIED from nsHttpChannel.cpp: move to shared base class? + */ + NS_ENSURE_ARG_POINTER(originalURI); + mOriginalURI = originalURI; + return NS_OK; +} + +NS_IMETHODIMP +HttpChannelChild::GetURI(nsIURI **URI) +{ + /** + * COPIED from nsHttpChannel.cpp: move to shared base class? + */ + NS_ENSURE_ARG_POINTER(URI); + *URI = mURI; + NS_IF_ADDREF(*URI); + return NS_OK; +} + +NS_IMETHODIMP +HttpChannelChild::GetOwner(nsISupports **aOwner) +{ + DROP_DEAD(); +} +NS_IMETHODIMP +HttpChannelChild::SetOwner(nsISupports *aOwner) +{ + DROP_DEAD(); +} + +NS_IMETHODIMP +HttpChannelChild::GetNotificationCallbacks(nsIInterfaceRequestor **callbacks) +{ + /** + * COPIED from nsHttpChannel.cpp: move to shared base class? + */ + NS_IF_ADDREF(*callbacks = mCallbacks); + return NS_OK; +} +NS_IMETHODIMP +HttpChannelChild::SetNotificationCallbacks(nsIInterfaceRequestor *callbacks) +{ + /** + * COPIED from nsHttpChannel.cpp: move to shared base class? + */ + mCallbacks = callbacks; + mProgressSink = nsnull; + return NS_OK; +} + +NS_IMETHODIMP +HttpChannelChild::GetSecurityInfo(nsISupports **aSecurityInfo) +{ + DROP_DEAD(); +} + +NS_IMETHODIMP +HttpChannelChild::GetContentType(nsACString& value) +{ + if (mState < HCC_ONSTART) { + value.Truncate(); + return NS_ERROR_NOT_AVAILABLE; + } + if (mContentType_HACK.IsEmpty()) { + value.AssignLiteral(UNKNOWN_CONTENT_TYPE); + } else { + value = mContentType_HACK; + } + return NS_OK; +} +NS_IMETHODIMP +HttpChannelChild::SetContentType(const nsACString& aContentType) +{ + DROP_DEAD(); +} + +NS_IMETHODIMP +HttpChannelChild::GetContentCharset(nsACString& aContentCharset) +{ + DROP_DEAD(); +} +NS_IMETHODIMP +HttpChannelChild::SetContentCharset(const nsACString& aContentCharset) +{ + DROP_DEAD(); +} + +NS_IMETHODIMP +HttpChannelChild::GetContentLength(PRInt32 *aContentLength) +{ + *aContentLength = mContentLength_HACK; + return NS_OK; +} + +NS_IMETHODIMP +HttpChannelChild::SetContentLength(PRInt32 aContentLength) +{ + DROP_DEAD(); +} + +NS_IMETHODIMP +HttpChannelChild::Open(nsIInputStream **retval) +{ + NS_ENSURE_TRUE(!mWasOpened, NS_ERROR_IN_PROGRESS); + return NS_ImplementChannelOpen(this, retval); +} + +NS_IMETHODIMP +HttpChannelChild::AsyncOpen(nsIStreamListener *listener, nsISupports *aContext) +{ + LOG(("HttpChannelChild::AsyncOpen [this=%x uri=%s]\n", this, mSpec.get())); + + NS_ENSURE_TRUE(gNeckoChild != nsnull, NS_ERROR_FAILURE); + NS_ENSURE_ARG_POINTER(listener); + NS_ENSURE_TRUE(!mIsPending, NS_ERROR_IN_PROGRESS); + NS_ENSURE_TRUE(!mWasOpened, NS_ERROR_ALREADY_OPENED); + + // Port checked in parent, but duplicate here so we can return with error + // immediately, as we've done since before e10s. + nsresult rv; + rv = NS_CheckPortSafety(mURI); + if (NS_FAILED(rv)) + return rv; + + // This corresponds to Release() in DeallocPHttpChannel + this->AddRef(); + + // TODO: Combine constructor and AsyncOpen to save one IPC msg + if (!gNeckoChild->SendPHttpChannelConstructor(this)) { + // TODO: currently means "this" has been deleted! bug 529693 + DROP_DEAD(); + } + mChildListener = listener; + mChildListenerContext = aContext; + + // TODO: need to dupe cookies logic from nsHttpChannel.cpp? + + // TODO: need to notify (child-side) http-on-modify-req observers + + // TODO: add self to loadgroup? + + // TODO: smartest way to pass nsURI == (spec, charset)? + nsCAutoString charset; + mURI->GetOriginCharset(charset); + nsCAutoString originalSpec; + mOriginalURI->GetSpec(originalSpec); + nsCAutoString originalCharset; + mOriginalURI->GetOriginCharset(originalCharset); + + nsCAutoString docSpec; + nsCAutoString docCharset; + if (mDocumentURI) { + mDocumentURI->GetSpec(docSpec); + mDocumentURI->GetOriginCharset(docCharset); + } + + if (!SendAsyncOpen(mSpec, charset, originalSpec, originalCharset, + docSpec, docCharset, mLoadFlags)) { + // IPDL error: our destructor will be called automatically + // -- TODO: verify that that's the case :) + mChildListener = 0; + mChildListenerContext = 0; + return NS_ERROR_FAILURE; + } + + mIsPending = PR_TRUE; + mWasOpened = PR_TRUE; + mState = HCC_OPENED; + + return NS_OK; +} + +//----------------------------------------------------------------------------- +// HttpChannelChild::nsIHttpChannel +//----------------------------------------------------------------------------- + +NS_IMETHODIMP +HttpChannelChild::GetRequestMethod(nsACString& method) +{ + /** + * COPIED from nsHttpChannel.cpp: move to shared base class? + */ + method = mRequestHead.Method(); + return NS_OK; +} +NS_IMETHODIMP +HttpChannelChild::SetRequestMethod(const nsACString& method) +{ + /** + * COPIED from nsHttpChannel.cpp: move to shared base class? + * - TODO: pass along to parent in AsyncOpen + */ + NS_ENSURE_TRUE(!mIsPending, NS_ERROR_IN_PROGRESS); + + const nsCString& flatMethod = PromiseFlatCString(method); + + // Method names are restricted to valid HTTP tokens. + if (!nsHttp::IsValidToken(flatMethod)) + return NS_ERROR_INVALID_ARG; + + nsHttpAtom atom = nsHttp::ResolveAtom(flatMethod.get()); + if (!atom) + return NS_ERROR_FAILURE; + + mRequestHead.SetMethod(atom); + return NS_OK; +} + +NS_IMETHODIMP +HttpChannelChild::GetReferrer(nsIURI **aReferrer) +{ + DROP_DEAD(); +} +NS_IMETHODIMP +HttpChannelChild::SetReferrer(nsIURI *aReferrer) +{ + DROP_DEAD(); +} + +NS_IMETHODIMP +HttpChannelChild::GetRequestHeader(const nsACString& hdr, nsACString& val) +{ + DROP_DEAD(); +} + +NS_IMETHODIMP +HttpChannelChild::SetRequestHeader(const nsACString& aHeader, + const nsACString& aValue, + PRBool aMerge) +{ + DROP_DEAD(); +} + +NS_IMETHODIMP +HttpChannelChild::VisitRequestHeaders(nsIHttpHeaderVisitor *aVisitor) +{ + DROP_DEAD(); +} + +NS_IMETHODIMP +HttpChannelChild::GetAllowPipelining(PRBool *aAllowPipelining) +{ + DROP_DEAD(); +} +NS_IMETHODIMP +HttpChannelChild::SetAllowPipelining(PRBool aAllowPipelining) +{ + DROP_DEAD(); +} + +NS_IMETHODIMP +HttpChannelChild::GetRedirectionLimit(PRUint32 *aRedirectionLimit) +{ + DROP_DEAD(); +} +NS_IMETHODIMP +HttpChannelChild::SetRedirectionLimit(PRUint32 aRedirectionLimit) +{ + DROP_DEAD(); +} + +NS_IMETHODIMP +HttpChannelChild::GetResponseStatus(PRUint32 *value) +{ + NS_ENSURE_ARG_POINTER(value); + if (mState < HCC_ONSTART) + return NS_ERROR_NOT_AVAILABLE; + *value = mResponseStatus_HACK; + return NS_OK; +} + +NS_IMETHODIMP +HttpChannelChild::GetResponseStatusText(nsACString& value) +{ + if (mState < HCC_ONSTART) + return NS_ERROR_NOT_AVAILABLE; + value = mResponseStatusText_HACK; + return NS_OK; +} + +NS_IMETHODIMP +HttpChannelChild::GetRequestSucceeded(PRBool *value) +{ + NS_PRECONDITION(value, "Don't ever pass a null arg to this function"); + if (mState < HCC_ONSTART) + return NS_ERROR_NOT_AVAILABLE; + PRUint32 status = mResponseStatus_HACK; + *value = (status / 100 == 2); + return NS_OK; +} + +NS_IMETHODIMP +HttpChannelChild::GetResponseHeader(const nsACString& header, nsACString& val) +{ + DROP_DEAD(); +} + +NS_IMETHODIMP +HttpChannelChild::SetResponseHeader(const nsACString& header, + const nsACString& value, + PRBool merge) +{ + DROP_DEAD(); +} + +NS_IMETHODIMP +HttpChannelChild::VisitResponseHeaders(nsIHttpHeaderVisitor *aVisitor) +{ + DROP_DEAD(); +} + +NS_IMETHODIMP +HttpChannelChild::IsNoStoreResponse(PRBool *retval) +{ + DROP_DEAD(); +} + +NS_IMETHODIMP +HttpChannelChild::IsNoCacheResponse(PRBool *retval) +{ + DROP_DEAD(); +} + +//----------------------------------------------------------------------------- +// HttpChannelChild::nsIHttpChannelInternal +//----------------------------------------------------------------------------- + +NS_IMETHODIMP +HttpChannelChild::GetDocumentURI(nsIURI **aDocumentURI) +{ + /** + * COPIED from nsHttpChannel.cpp: move to shared base class? + */ + NS_ENSURE_ARG_POINTER(aDocumentURI); + *aDocumentURI = mDocumentURI; + NS_IF_ADDREF(*aDocumentURI); + return NS_OK; +} +NS_IMETHODIMP +HttpChannelChild::SetDocumentURI(nsIURI *aDocumentURI) +{ + ENSURE_CALLED_BEFORE_ASYNC_OPEN(); + /** + * COPIED from nsHttpChannel.cpp: move to shared base class? + */ + mDocumentURI = aDocumentURI; + return NS_OK; +} + +NS_IMETHODIMP +HttpChannelChild::GetRequestVersion(PRUint32 *major, PRUint32 *minor) +{ + DROP_DEAD(); +} + +NS_IMETHODIMP +HttpChannelChild::GetResponseVersion(PRUint32 *major, PRUint32 *minor) +{ + DROP_DEAD(); +} + +NS_IMETHODIMP +HttpChannelChild::SetCookie(const char *aCookieHeader) +{ + DROP_DEAD(); +} + +NS_IMETHODIMP +HttpChannelChild::SetupFallbackChannel(const char *aFallbackKey) +{ + DROP_DEAD(); +} + +NS_IMETHODIMP +HttpChannelChild::GetForceAllowThirdPartyCookie(PRBool *force) +{ + DROP_DEAD(); +} + +NS_IMETHODIMP +HttpChannelChild::SetForceAllowThirdPartyCookie(PRBool force) +{ + DROP_DEAD(); +} + + +//----------------------------------------------------------------------------- +// HttpChannelChild::nsIRequestObserver +//----------------------------------------------------------------------------- + +NS_IMETHODIMP +HttpChannelChild::OnStartRequest(nsIRequest *aRequest, nsISupports *aContext) +{ + DROP_DEAD(); +} + +NS_IMETHODIMP +HttpChannelChild::OnStopRequest(nsIRequest *aRequest, + nsISupports *aContext, + nsresult aStatusCode) +{ + DROP_DEAD(); +} + +//----------------------------------------------------------------------------- +// HttpChannelChild::nsIStreamListener +//----------------------------------------------------------------------------- + +NS_IMETHODIMP +HttpChannelChild::OnDataAvailable(nsIRequest *aRequest, + nsISupports *aContext, + nsIInputStream *aInputStream, + PRUint32 aOffset, + PRUint32 aCount) +{ + DROP_DEAD(); +} + +//----------------------------------------------------------------------------- +// HttpChannelChild::nsICachingChannel +//----------------------------------------------------------------------------- + +NS_IMETHODIMP +HttpChannelChild::GetCacheToken(nsISupports **aCacheToken) +{ + DROP_DEAD(); +} +NS_IMETHODIMP +HttpChannelChild::SetCacheToken(nsISupports *aCacheToken) +{ + DROP_DEAD(); +} + +NS_IMETHODIMP +HttpChannelChild::GetOfflineCacheToken(nsISupports **aOfflineCacheToken) +{ + DROP_DEAD(); +} +NS_IMETHODIMP +HttpChannelChild::SetOfflineCacheToken(nsISupports *aOfflineCacheToken) +{ + DROP_DEAD(); +} + +NS_IMETHODIMP +HttpChannelChild::GetCacheKey(nsISupports **aCacheKey) +{ + DROP_DEAD(); +} +NS_IMETHODIMP +HttpChannelChild::SetCacheKey(nsISupports *aCacheKey) +{ + DROP_DEAD(); +} + +NS_IMETHODIMP +HttpChannelChild::GetCacheAsFile(PRBool *aCacheAsFile) +{ + DROP_DEAD(); +} +NS_IMETHODIMP +HttpChannelChild::SetCacheAsFile(PRBool aCacheAsFile) +{ + DROP_DEAD(); +} + +NS_IMETHODIMP +HttpChannelChild::GetCacheForOfflineUse(PRBool *aCacheForOfflineUse) +{ + DROP_DEAD(); +} +NS_IMETHODIMP +HttpChannelChild::SetCacheForOfflineUse(PRBool aCacheForOfflineUse) +{ + DROP_DEAD(); +} + +NS_IMETHODIMP +HttpChannelChild::GetOfflineCacheClientID(nsACString& id) +{ + DROP_DEAD(); +} +NS_IMETHODIMP +HttpChannelChild::SetOfflineCacheClientID(const nsACString& id) +{ + DROP_DEAD(); +} + +NS_IMETHODIMP +HttpChannelChild::GetCacheFile(nsIFile **aCacheFile) +{ + DROP_DEAD(); +} + +NS_IMETHODIMP +HttpChannelChild::IsFromCache(PRBool *retval) +{ + DROP_DEAD(); +} + +//----------------------------------------------------------------------------- +// HttpChannelChild::nsIUploadChannel +//----------------------------------------------------------------------------- + +NS_IMETHODIMP +HttpChannelChild::SetUploadStream(nsIInputStream *aStream, + const nsACString& aContentType, + PRInt32 aContentLength) +{ + DROP_DEAD(); +} + +NS_IMETHODIMP +HttpChannelChild::GetUploadStream(nsIInputStream **aUploadStream) +{ + DROP_DEAD(); +} + +//----------------------------------------------------------------------------- +// HttpChannelChild::nsIUploadChannel2 +//----------------------------------------------------------------------------- + +NS_IMETHODIMP +HttpChannelChild::ExplicitSetUploadStream(nsIInputStream *aStream, + const nsACString& aContentType, + PRInt64 aContentLength, + const nsACString& aMethod, + PRBool aStreamHasHeaders) +{ + DROP_DEAD(); +} + +//----------------------------------------------------------------------------- +// HttpChannelChild::nsICacheListener +//----------------------------------------------------------------------------- + +NS_IMETHODIMP +HttpChannelChild::OnCacheEntryAvailable(nsICacheEntryDescriptor *descriptor, + nsCacheAccessMode accessGranted, + nsresult status) +{ + DROP_DEAD(); +} + +//----------------------------------------------------------------------------- +// HttpChannelChild::nsIEncodedChannel +//----------------------------------------------------------------------------- + +NS_IMETHODIMP +HttpChannelChild::GetContentEncodings(nsIUTF8StringEnumerator **result) +{ + DROP_DEAD(); +} + +/* attribute boolean applyConversion; */ +NS_IMETHODIMP +HttpChannelChild::GetApplyConversion(PRBool *aApplyConversion) +{ + DROP_DEAD(); +} + +NS_IMETHODIMP +HttpChannelChild::SetApplyConversion(PRBool aApplyConversion) +{ + DROP_DEAD(); +} + +//----------------------------------------------------------------------------- +// HttpChannelChild::nsITransportEventSink +//----------------------------------------------------------------------------- + +NS_IMETHODIMP +HttpChannelChild::OnTransportStatus(nsITransport *aTransport, + nsresult aStatus, + PRUint64 aProgress, + PRUint64 aProgressMax) +{ + DROP_DEAD(); +} + +//----------------------------------------------------------------------------- +// HttpChannelChild::nsIResumableChannel +//----------------------------------------------------------------------------- + +NS_IMETHODIMP +HttpChannelChild::ResumeAt(PRUint64 startPos, const nsACString& entityID) +{ + DROP_DEAD(); +} + +NS_IMETHODIMP +HttpChannelChild::GetEntityID(nsACString& aEntityID) +{ + DROP_DEAD(); +} + +//----------------------------------------------------------------------------- +// HttpChannelChild::nsISupportsPriority +//----------------------------------------------------------------------------- + +NS_IMETHODIMP +HttpChannelChild::GetPriority(PRInt32 *aPriority) +{ + DROP_DEAD(); +} +NS_IMETHODIMP +HttpChannelChild::SetPriority(PRInt32 aPriority) +{ + DROP_DEAD(); +} + +NS_IMETHODIMP +HttpChannelChild::AdjustPriority(PRInt32 delta) +{ + DROP_DEAD(); +} + +//----------------------------------------------------------------------------- +// HttpChannelChild::nsIProtocolProxyCallback +//----------------------------------------------------------------------------- + +NS_IMETHODIMP +HttpChannelChild::OnProxyAvailable(nsICancelable *aRequest, + nsIURI *aURI, + nsIProxyInfo *aProxyInfo, + nsresult aStatus) +{ + DROP_DEAD(); +} + +//----------------------------------------------------------------------------- +// HttpChannelChild::nsIProxiedChannel +//----------------------------------------------------------------------------- + +NS_IMETHODIMP +HttpChannelChild::GetProxyInfo(nsIProxyInfo **aProxyInfo) +{ + DROP_DEAD(); +} + +//----------------------------------------------------------------------------- +// HttpChannelChild::nsITraceableChannel +//----------------------------------------------------------------------------- + +NS_IMETHODIMP +HttpChannelChild::SetNewListener(nsIStreamListener *listener, + nsIStreamListener **oldListener) +{ + DROP_DEAD(); +} + +//----------------------------------------------------------------------------- +// HttpChannelChild::nsIApplicationCacheContainer +//----------------------------------------------------------------------------- + +NS_IMETHODIMP +HttpChannelChild::GetApplicationCache(nsIApplicationCache **aApplicationCache) +{ + DROP_DEAD(); +} +NS_IMETHODIMP +HttpChannelChild::SetApplicationCache(nsIApplicationCache *aApplicationCache) +{ + DROP_DEAD(); +} + +//----------------------------------------------------------------------------- +// HttpChannelChild::nsIApplicationCacheChannel +//----------------------------------------------------------------------------- + +NS_IMETHODIMP +HttpChannelChild::GetLoadedFromApplicationCache(PRBool *retval) +{ + DROP_DEAD(); +} + +NS_IMETHODIMP +HttpChannelChild::GetInheritApplicationCache(PRBool *aInheritApplicationCache) +{ + DROP_DEAD(); +} +NS_IMETHODIMP +HttpChannelChild::SetInheritApplicationCache(PRBool aInheritApplicationCache) +{ + // FIXME: Browser calls this early, so stub OK for now. Fix in bug 536295. + return NS_OK; +} + +NS_IMETHODIMP +HttpChannelChild::GetChooseApplicationCache(PRBool *aChooseApplicationCache) +{ + DROP_DEAD(); +} +NS_IMETHODIMP +HttpChannelChild::SetChooseApplicationCache(PRBool aChooseApplicationCache) +{ + // FIXME: Browser calls this early, so stub OK for now. Fix in bug 536295. + return NS_OK; +} + +//----------------------------------------------------------------------------- +// HttpChannelChild::nsIAuthPromptCallback +//----------------------------------------------------------------------------- + +NS_IMETHODIMP +HttpChannelChild::OnAuthAvailable(nsISupports *context, + nsIAuthInformation *aAuthInfo) +{ + DROP_DEAD(); +} + +NS_IMETHODIMP +HttpChannelChild::OnAuthCancelled(nsISupports *aContext, PRBool userCancel) +{ + DROP_DEAD(); +} + + +//------------------------------------------------------------------------------ }} // mozilla::net diff --git a/netwerk/protocol/http/src/HttpChannelChild.h b/netwerk/protocol/http/src/HttpChannelChild.h index 8bc71e8fe6c..fac01a8db30 100644 --- a/netwerk/protocol/http/src/HttpChannelChild.h +++ b/netwerk/protocol/http/src/HttpChannelChild.h @@ -42,20 +42,138 @@ #define mozilla_net_HttpChannelChild_h #include "mozilla/net/PHttpChannelChild.h" -#include "nsXULAppAPI.h" +#include "mozilla/net/NeckoCommon.h" + +#include "nsHttpRequestHead.h" +#include "nsHashPropertyBag.h" +#include "nsIHttpChannel.h" +#include "nsIHttpChannelInternal.h" +#include "nsIStreamListener.h" +#include "nsIURI.h" +#include "nsILoadGroup.h" +#include "nsIInterfaceRequestor.h" +#include "nsIInterfaceRequestorUtils.h" +#include "nsIProgressEventSink.h" +#include "nsICachingChannel.h" +#include "nsICacheListener.h" +#include "nsIApplicationCache.h" +#include "nsIApplicationCacheChannel.h" +#include "nsIEncodedChannel.h" +#include "nsITransport.h" +#include "nsIUploadChannel.h" +#include "nsIUploadChannel2.h" +#include "nsIResumableChannel.h" +#include "nsISupportsPriority.h" +#include "nsIProtocolProxyCallback.h" +#include "nsIProxiedChannel.h" +#include "nsITraceableChannel.h" +#include "nsIAuthPromptCallback.h" + namespace mozilla { namespace net { +// TODO: replace with IPDL states +enum HttpChannelChildState { + HCC_NEW, + HCC_OPENED, + HCC_ONSTART, + HCC_ONDATA, + HCC_ONSTOP +}; + // Header file contents -class HttpChannelChild : - public PHttpChannelChild +class HttpChannelChild : public PHttpChannelChild + , public nsIHttpChannel + , public nsHashPropertyBag + , public nsIHttpChannelInternal + , public nsIStreamListener + , public nsICachingChannel + , public nsIUploadChannel + , public nsIUploadChannel2 + , public nsICacheListener + , public nsIEncodedChannel + , public nsITransportEventSink + , public nsIResumableChannel + , public nsISupportsPriority + , public nsIProtocolProxyCallback + , public nsIProxiedChannel + , public nsITraceableChannel + , public nsIApplicationCacheChannel + , public nsIAuthPromptCallback { public: + NS_DECL_ISUPPORTS_INHERITED + NS_DECL_NSIREQUEST + NS_DECL_NSICHANNEL + NS_DECL_NSIHTTPCHANNEL + NS_DECL_NSIHTTPCHANNELINTERNAL + NS_DECL_NSIREQUESTOBSERVER + NS_DECL_NSISTREAMLISTENER + NS_DECL_NSICACHINGCHANNEL + NS_DECL_NSIUPLOADCHANNEL + NS_DECL_NSIUPLOADCHANNEL2 + NS_DECL_NSICACHELISTENER + NS_DECL_NSIENCODEDCHANNEL + NS_DECL_NSITRANSPORTEVENTSINK + NS_DECL_NSIRESUMABLECHANNEL + NS_DECL_NSISUPPORTSPRIORITY + NS_DECL_NSIPROTOCOLPROXYCALLBACK + NS_DECL_NSIPROXIEDCHANNEL + NS_DECL_NSITRACEABLECHANNEL + NS_DECL_NSIAPPLICATIONCACHECONTAINER + NS_DECL_NSIAPPLICATIONCACHECHANNEL + NS_DECL_NSIAUTHPROMPTCALLBACK + HttpChannelChild(); virtual ~HttpChannelChild(); + nsresult Init(nsIURI *uri); + protected: + bool RecvOnStartRequest(const PRInt32& HACK_ContentLength, + const nsCString& HACK_ContentType, + const PRUint32& HACK_Status, + const nsCString& HACK_StatusText); + bool RecvOnDataAvailable(const nsCString& data, + const PRUint32& offset, + const PRUint32& count); + bool RecvOnStopRequest(const nsresult& statusCode); + +private: + nsCOMPtr mChildListener; + nsCOMPtr mChildListenerContext; + + // FIXME: copy full ResponseHead (bug 536283) + PRInt32 mContentLength_HACK; + nsCString mContentType_HACK; + PRUint32 mResponseStatus_HACK; + nsCString mResponseStatusText_HACK; + + // FIXME: replace with IPDL states (bug 536319) + enum HttpChannelChildState mState; + + /** + * fields copied from nsHttpChannel.h + */ + nsCOMPtr mOriginalURI; + nsCOMPtr mURI; + nsCOMPtr mDocumentURI; + + nsCOMPtr mCallbacks; + nsCOMPtr mProgressSink; + + nsHttpRequestHead mRequestHead; + + nsCString mSpec; // ASCII encoded URL spec + + PRUint32 mLoadFlags; + PRUint32 mStatus; + + // state flags + PRUint32 mIsPending : 1; + PRUint32 mWasOpened : 1; + }; diff --git a/netwerk/protocol/http/src/HttpChannelParent.cpp b/netwerk/protocol/http/src/HttpChannelParent.cpp index e063229ed5d..1d8d57d0f58 100644 --- a/netwerk/protocol/http/src/HttpChannelParent.cpp +++ b/netwerk/protocol/http/src/HttpChannelParent.cpp @@ -38,7 +38,10 @@ * * ***** END LICENSE BLOCK ***** */ +#include "nsHttp.h" #include "mozilla/net/HttpChannelParent.h" +#include "nsHttpChannel.h" +#include "nsNetUtil.h" namespace mozilla { namespace net { @@ -53,12 +56,176 @@ HttpChannelParent::~HttpChannelParent() } //----------------------------------------------------------------------------- -// -bool HttpChannelParent::RecvasyncOpen(const nsCString& uri) +// HttpChannelParent::nsISupports +//----------------------------------------------------------------------------- + +NS_IMPL_ISUPPORTS3(HttpChannelParent, + nsIRequestObserver, + nsIStreamListener, + nsIInterfaceRequestor); + +//----------------------------------------------------------------------------- +// HttpChannelParent::PHttpChannelParent +//----------------------------------------------------------------------------- + +bool +HttpChannelParent::RecvAsyncOpen(const nsCString& uriSpec, + const nsCString& charset, + const nsCString& originalUriSpec, + const nsCString& originalCharset, + const nsCString& docUriSpec, + const nsCString& docCharset, + const PRUint32& loadFlags) { - puts("[HttpChannelParent] got asyncOpen msg"); + nsresult rv; + + nsCOMPtr ios(do_GetIOService(&rv)); + if (NS_FAILED(rv)) + return false; // TODO: send fail msg to child, return true + + nsCOMPtr uri; + rv = NS_NewURI(getter_AddRefs(uri), uriSpec, charset.get(), nsnull, ios); + if (NS_FAILED(rv)) + return false; // TODO: send fail msg to child, return true + + // Delay log to here, as gHttpLog may not exist in parent until we init + // gHttpHandler via above call to NS_NewURI. Avoids segfault :) + LOG(("HttpChannelParent RecvAsyncOpen [this=%x uri=%s (%s)]\n", + this, uriSpec.get(), charset.get())); + + nsCOMPtr chan; + rv = NS_NewChannel(getter_AddRefs(chan), uri, ios, nsnull, nsnull, loadFlags); + if (NS_FAILED(rv)) + return false; // TODO: send fail msg to child, return true + + if (!originalUriSpec.IsEmpty()) { + nsCOMPtr originalUri; + rv = NS_NewURI(getter_AddRefs(originalUri), originalUriSpec, + originalCharset.get(), nsnull, ios); + if (!NS_FAILED(rv)) + chan->SetOriginalURI(originalUri); + } + if (!docUriSpec.IsEmpty()) { + nsCOMPtr docUri; + rv = NS_NewURI(getter_AddRefs(docUri), docUriSpec, + docCharset.get(), nsnull, ios); + if (!NS_FAILED(rv)) { + nsCOMPtr iChan(do_QueryInterface(chan)); + if (iChan) + iChan->SetDocumentURI(docUri); + } + } + if (loadFlags != nsIRequest::LOAD_NORMAL) + chan->SetLoadFlags(loadFlags); + + // TODO: implement needed interfaces, and either proxy calls back to child + // process, or rig up appropriate hacks. +// chan->SetNotificationCallbacks(this); + + rv = chan->AsyncOpen(this, nsnull); + if (NS_FAILED(rv)) + return false; // TODO: send fail msg to child, return true + return true; } + +//----------------------------------------------------------------------------- +// HttpChannelParent::nsIRequestObserver +//----------------------------------------------------------------------------- + +NS_IMETHODIMP +HttpChannelParent::OnStartRequest(nsIRequest *aRequest, nsISupports *aContext) +{ + LOG(("HttpChannelParent::OnStartRequest [this=%x]\n", this)); + + nsCOMPtr chan(do_QueryInterface(aRequest)); + NS_ENSURE_TRUE(chan, NS_ERROR_FAILURE); + + /* + * - TODO: Need to send all or most of mResponseHead + * - TODO: if getting vals fails, still need to call OnStartRequest on child, + * not just fail here? + */ + PRInt32 contentLength_HACK; + chan->GetContentLength(&contentLength_HACK); + nsCAutoString contentType_HACK; + chan->GetContentType(contentType_HACK); + PRUint32 status_HACK; + chan->GetResponseStatus(&status_HACK); + nsCAutoString statusText_HACK; + chan->GetResponseStatusText(statusText_HACK); + + if (!SendOnStartRequest(contentLength_HACK, contentType_HACK, + status_HACK, statusText_HACK)) + { + // IPDL error--child dead/dying & our own destructor will be called + // automatically + // -- TODO: verify that that's the case :) + return NS_ERROR_UNEXPECTED; + } + return NS_OK; +} + +NS_IMETHODIMP +HttpChannelParent::OnStopRequest(nsIRequest *aRequest, + nsISupports *aContext, + nsresult aStatusCode) +{ + LOG(("HttpChannelParent::OnStopRequest: [this=%x status=%ul]\n", + this, aStatusCode)); + + if (!SendOnStopRequest(aStatusCode)) { + // IPDL error--child dead/dying & our own destructor will be called + // automatically + return NS_ERROR_UNEXPECTED; + } + return NS_OK; +} + +//----------------------------------------------------------------------------- +// HttpChannelParent::nsIStreamListener +//----------------------------------------------------------------------------- + +NS_IMETHODIMP +HttpChannelParent::OnDataAvailable(nsIRequest *aRequest, + nsISupports *aContext, + nsIInputStream *aInputStream, + PRUint32 aOffset, + PRUint32 aCount) +{ + LOG(("HttpChannelParent::OnDataAvailable [this=%x]\n", this)); + + nsresult rv; + + nsCString data; + data.SetLength(aCount); + char * p = data.BeginWriting(); + PRUint32 bytesRead; + rv = aInputStream->Read(p, aCount, &bytesRead); + data.EndWriting(); + if (!NS_SUCCEEDED(rv) || bytesRead != aCount) { + return rv; // TODO: figure out error handling + } + + if (!SendOnDataAvailable(data, aOffset, bytesRead)) { + // IPDL error--child dead/dying & our own destructor will be called + // automatically + return NS_ERROR_UNEXPECTED; + } + return NS_OK; +} + +//----------------------------------------------------------------------------- +// HttpChannelParent::nsIInterfaceRequestor +//----------------------------------------------------------------------------- + +NS_IMETHODIMP +HttpChannelParent::GetInterface(const nsIID& uuid, void **result) +{ + DROP_DEAD(); +} + + }} // mozilla::net diff --git a/netwerk/protocol/http/src/HttpChannelParent.h b/netwerk/protocol/http/src/HttpChannelParent.h index b8972e15985..ac26f7d8218 100644 --- a/netwerk/protocol/http/src/HttpChannelParent.h +++ b/netwerk/protocol/http/src/HttpChannelParent.h @@ -41,21 +41,37 @@ #ifndef mozilla_net_HttpChannelParent_h #define mozilla_net_HttpChannelParent_h +#include "nsHttp.h" #include "mozilla/net/PHttpChannelParent.h" +#include "mozilla/net/NeckoCommon.h" +#include "nsIStreamListener.h" +#include "nsIInterfaceRequestor.h" namespace mozilla { namespace net { // Header file contents -class HttpChannelParent : - public PHttpChannelParent +class HttpChannelParent : public PHttpChannelParent + , public nsIStreamListener + , public nsIInterfaceRequestor { public: + NS_DECL_ISUPPORTS + NS_DECL_NSIREQUESTOBSERVER + NS_DECL_NSISTREAMLISTENER + NS_DECL_NSIINTERFACEREQUESTOR + HttpChannelParent(); virtual ~HttpChannelParent(); protected: - virtual bool RecvasyncOpen(const nsCString& uri); + virtual bool RecvAsyncOpen(const nsCString& uriSpec, + const nsCString& originCharset, + const nsCString& originalUriSpec, + const nsCString& originalCharset, + const nsCString& docUriSpec, + const nsCString& docCharset, + const PRUint32& loadFlags); }; } // namespace net diff --git a/netwerk/protocol/http/src/Makefile.in b/netwerk/protocol/http/src/Makefile.in index 5bab0bc7709..5c191829a04 100644 --- a/netwerk/protocol/http/src/Makefile.in +++ b/netwerk/protocol/http/src/Makefile.in @@ -83,7 +83,10 @@ CPPSRCS += \ $(NULL) endif -LOCAL_INCLUDES=-I$(srcdir)/../../../base/src -I$(topsrcdir)/xpcom/ds +LOCAL_INCLUDES += \ + -I$(srcdir)/../../../base/src \ + -I$(topsrcdir)/xpcom/ds \ + $(NULL) # we don't want the shared lib, but we want to force the creation of a # static lib. diff --git a/netwerk/protocol/http/src/PHttpChannel.ipdl b/netwerk/protocol/http/src/PHttpChannel.ipdl index a1823b4883e..38fa08284d8 100644 --- a/netwerk/protocol/http/src/PHttpChannel.ipdl +++ b/netwerk/protocol/http/src/PHttpChannel.ipdl @@ -43,7 +43,6 @@ include protocol "PNecko.ipdl"; namespace mozilla { namespace net { - //------------------------------------------------------------------- protocol PHttpChannel { @@ -52,7 +51,29 @@ protocol PHttpChannel parent: __delete__(); - asyncOpen(nsCString uri); + AsyncOpen(nsCString uriSpec, + nsCString originCharset, + // - TODO: unclear if any HTTP channel clients ever set + // originalURI != uri (about:credits?); also not clear if chrome + // channel would ever need to know. Can we get rid of next two + // args? + nsCString originalUriSpec, + nsCString originalCharset, + nsCString documentUriSpec, + nsCString documentCharset, + PRUint32 loadFlags); + +child: + OnStartRequest(PRInt32 HACK_ContentLength, + nsCString HACK_ContentType, + PRUint32 HACK_Status, + nsCString HACK_StatusText); + + OnDataAvailable(nsCString data, + PRUint32 offset, + PRUint32 count); + + OnStopRequest(nsresult statusCode); }; diff --git a/netwerk/protocol/http/src/nsHttp.h b/netwerk/protocol/http/src/nsHttp.h index 4e07083215a..4cdfbeef087 100644 --- a/netwerk/protocol/http/src/nsHttp.h +++ b/netwerk/protocol/http/src/nsHttp.h @@ -45,8 +45,22 @@ #endif #ifdef MOZ_IPC +// e10s mess: IPDL-generatd headers include chromium which both #includes +// prlog.h, and #defines LOG in conflict with this file. +// Solution: (as described in bug 545995) +// 1) ensure that this file is #included before any IPDL-generated files and +// anything else that #includes prlog.h, so that we can make sure prlog.h +// sees FORCE_PR_LOG if needed. +// 2) #include IPDL boilerplate, and then undef LOG so our LOG wins. +// 3) nsNetModule.cpp does its own crazy stuff with #including prlog.h +// multiple times; allow it to define ALLOW_LATE_NSHTTP_H_INCLUDE to bypass +// check. +#if defined(PR_LOG) && !defined(ALLOW_LATE_NSHTTP_H_INCLUDE) +#error "If nsHttp.h #included it must come before any IPDL-generated files or other files that #include prlog.h" +#endif #include "mozilla/net/NeckoChild.h" -#endif +#undef LOG +#endif // MOZ_IPC #include "plstr.h" #include "prlog.h" @@ -71,7 +85,6 @@ extern PRLogModuleInfo *gHttpLog; #endif -#undef LOG // http logging #define LOG1(args) PR_LOG(gHttpLog, 1, args) #define LOG2(args) PR_LOG(gHttpLog, 2, args) diff --git a/netwerk/protocol/http/src/nsHttpHandler.cpp b/netwerk/protocol/http/src/nsHttpHandler.cpp index 2b5e9862856..f42684bdd48 100644 --- a/netwerk/protocol/http/src/nsHttpHandler.cpp +++ b/netwerk/protocol/http/src/nsHttpHandler.cpp @@ -77,6 +77,10 @@ #include "nsIXULAppInfo.h" +#ifdef MOZ_IPC +#include "mozilla/net/NeckoChild.h" +#endif + #if defined(XP_UNIX) || defined(XP_BEOS) #include #endif @@ -97,6 +101,7 @@ //----------------------------------------------------------------------------- #ifdef MOZ_IPC using namespace mozilla::net; +#include "mozilla/net/HttpChannelChild.h" #endif #ifdef DEBUG @@ -208,6 +213,9 @@ nsHttpHandler::~nsHttpHandler() NS_RELEASE(mConnMgr); } + // Note: don't call NeckoChild::DestroyNeckoChild() here, as it's too late + // and it'll segfault. NeckoChild will get cleaned up by process exit. + nsHttp::DestroyAtomTable(); gHttpHandler = nsnull; @@ -231,7 +239,7 @@ nsHttpHandler::Init() } #ifdef MOZ_IPC - if (IsNeckoChild() && !gNeckoChild) + if (IsNeckoChild()) NeckoChild::InitNeckoChild(); #endif // MOZ_IPC @@ -1497,6 +1505,32 @@ nsHttpHandler::NewProxiedChannel(nsIURI *uri, if (NS_FAILED(rv)) return rv; +#if MOZ_IPC + if (IsNeckoChild()) { + LOG(("NECKO_E10S_HTTP set: using experimental interprocess HTTP\n")); + // TODO_JCD: + // - Create a common BaseHttpChannel so can share logic? + HttpChannelChild *childChannel = nsnull; + NS_NEWXPCOM(childChannel, HttpChannelChild); + if (!childChannel) + return NS_ERROR_OUT_OF_MEMORY; + NS_ADDREF(childChannel); + // TODO: Just ignore HTTPS and proxying for now + if (https) + DROP_DEAD(); + if (givenProxyInfo) + DROP_DEAD(); + // TODO: Init caps, etc, as below? + rv = childChannel->Init(uri); + if (NS_FAILED(rv)) { + NS_RELEASE(childChannel); + return rv; + } + *result = childChannel; + return NS_OK; + } +#endif + NS_NEWXPCOM(httpChannel, nsHttpChannel); if (!httpChannel) return NS_ERROR_OUT_OF_MEMORY;