Bug 546581: e10s HTTP: create common base class for HttpChannelChild and nsHttpChannel. a=dwitte, r=jae-seong, r=jduell
authorJason Duell <jduell.mcbugs@gmail.com>
Wed, 07 Apr 2010 01:43:09 -0700
changeset 46790 f5972978cb6e41d39b4d6642fe767d4c3f097593
parent 46789 c23610cf63c904b94274d39a0dc5f0dac29a063f
child 46791 e0be6af79c76656ae3de099bf2fa147fc54bede1
push idunknown
push userunknown
push dateunknown
reviewersdwitte, jae-seong, jduell
bugs546581
milestone1.9.3a4pre
Bug 546581: e10s HTTP: create common base class for HttpChannelChild and nsHttpChannel. a=dwitte, r=jae-seong, r=jduell
netwerk/protocol/http/src/HttpBaseChannel.cpp
netwerk/protocol/http/src/HttpBaseChannel.h
netwerk/protocol/http/src/HttpChannelChild.cpp
netwerk/protocol/http/src/HttpChannelChild.h
netwerk/protocol/http/src/HttpChannelParent.cpp
netwerk/protocol/http/src/HttpChannelParent.h
netwerk/protocol/http/src/Makefile.in
netwerk/protocol/http/src/PHttpChannel.ipdl
netwerk/protocol/http/src/PHttpChannelParams.h
netwerk/protocol/http/src/nsHttpChannel.cpp
netwerk/protocol/http/src/nsHttpChannel.h
netwerk/protocol/http/src/nsHttpHandler.cpp
netwerk/test/unit_ipc/test_bug528292_wrap.js
new file mode 100644
--- /dev/null
+++ b/netwerk/protocol/http/src/HttpBaseChannel.cpp
@@ -0,0 +1,816 @@
+/* -*- 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) 2010
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Daniel Witte <dwitte@mozilla.com>
+ *
+ * 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 "mozilla/net/HttpBaseChannel.h"
+
+#include "nsHttpHandler.h"
+#include "nsMimeTypes.h"
+#include "nsNetUtil.h"
+
+#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 {
+
+HttpBaseChannel::HttpBaseChannel()
+  : mStatus(NS_OK)
+  , mLoadFlags(LOAD_NORMAL)
+  , mCaps(0)
+  , mRedirectionLimit(gHttpHandler->RedirectionLimit())
+  , mIsPending(PR_FALSE)
+  , mWasOpened(PR_FALSE)
+  , mResponseHeadersModified(PR_FALSE)
+  , mAllowPipelining(PR_TRUE)
+  , mForceAllowThirdPartyCookie(PR_FALSE)
+{
+  LOG(("Creating HttpBaseChannel @%x\n", this));
+
+  // grab a reference to the handler to ensure that it doesn't go away.
+  NS_ADDREF(gHttpHandler);
+}
+
+HttpBaseChannel::~HttpBaseChannel()
+{
+  LOG(("Destroying HttpBaseChannel @%x\n", this));
+
+  nsHttpHandler* handler = gHttpHandler;
+  NS_RELEASE(handler);
+}
+
+nsresult
+HttpBaseChannel::Init(nsIURI *aURI,
+                      PRUint8 aCaps,
+                      nsProxyInfo *aProxyInfo)
+{
+  LOG(("HttpBaseChannel::Init [this=%p]\n", this));
+
+  NS_PRECONDITION(aURI, "null uri");
+
+  nsresult rv = nsHashPropertyBag::Init();
+  if (NS_FAILED(rv)) return rv;
+
+  mURI = aURI;
+  mOriginalURI = aURI;
+  mDocumentURI = nsnull;
+  mCaps = aCaps;
+
+  // 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()));
+
+  mConnectionInfo = new nsHttpConnectionInfo(host, port,
+                                             aProxyInfo, usingSSL);
+  if (!mConnectionInfo)
+    return NS_ERROR_OUT_OF_MEMORY;
+
+  // Set default request method
+  mRequestHead.SetMethod(nsHttp::Get);
+
+  // Set request headers
+  nsCAutoString hostLine;
+  rv = nsHttpHandler::GenerateHostPort(host, port, hostLine);
+  if (NS_FAILED(rv)) return rv;
+
+  rv = mRequestHead.SetHeader(nsHttp::Host, hostLine);
+  if (NS_FAILED(rv)) return rv;
+
+  rv = gHttpHandler->
+      AddStandardRequestHeaders(&mRequestHead.Headers(), aCaps,
+                                !mConnectionInfo->UsingSSL() &&
+                                mConnectionInfo->UsingHttpProxy());
+
+  return rv;
+}
+
+//-----------------------------------------------------------------------------
+// HttpBaseChannel::nsISupports
+//-----------------------------------------------------------------------------
+
+NS_IMPL_ISUPPORTS_INHERITED4(HttpBaseChannel,
+                             nsHashPropertyBag, 
+                             nsIRequest,
+                             nsIChannel,
+                             nsIHttpChannel,
+                             nsIHttpChannelInternal)
+
+//-----------------------------------------------------------------------------
+// HttpBaseChannel::nsIRequest
+//-----------------------------------------------------------------------------
+
+NS_IMETHODIMP
+HttpBaseChannel::GetName(nsACString& aName)
+{
+  aName = mSpec;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+HttpBaseChannel::IsPending(PRBool *aIsPending)
+{
+  NS_ENSURE_ARG_POINTER(aIsPending);
+  *aIsPending = mIsPending;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+HttpBaseChannel::GetStatus(nsresult *aStatus)
+{
+  NS_ENSURE_ARG_POINTER(aStatus);
+  *aStatus = mStatus;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+HttpBaseChannel::GetLoadGroup(nsILoadGroup **aLoadGroup)
+{
+  NS_ENSURE_ARG_POINTER(aLoadGroup);
+  *aLoadGroup = mLoadGroup;
+  NS_IF_ADDREF(*aLoadGroup);
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+HttpBaseChannel::SetLoadGroup(nsILoadGroup *aLoadGroup)
+{
+  mLoadGroup = aLoadGroup;
+  mProgressSink = nsnull;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+HttpBaseChannel::GetLoadFlags(nsLoadFlags *aLoadFlags)
+{
+  NS_ENSURE_ARG_POINTER(aLoadFlags);
+  *aLoadFlags = mLoadFlags;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+HttpBaseChannel::SetLoadFlags(nsLoadFlags aLoadFlags)
+{
+  mLoadFlags = aLoadFlags;
+  return NS_OK;
+}
+
+//-----------------------------------------------------------------------------
+// HttpBaseChannel::nsIChannel
+//-----------------------------------------------------------------------------
+
+NS_IMETHODIMP
+HttpBaseChannel::GetOriginalURI(nsIURI **aOriginalURI)
+{
+  NS_ENSURE_ARG_POINTER(aOriginalURI);
+  *aOriginalURI = mOriginalURI;
+  NS_ADDREF(*aOriginalURI);
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+HttpBaseChannel::SetOriginalURI(nsIURI *aOriginalURI)
+{
+  ENSURE_CALLED_BEFORE_ASYNC_OPEN();
+
+  NS_ENSURE_ARG_POINTER(aOriginalURI);
+  mOriginalURI = aOriginalURI;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+HttpBaseChannel::GetURI(nsIURI **aURI)
+{
+  NS_ENSURE_ARG_POINTER(aURI);
+  *aURI = mURI;
+  NS_ADDREF(*aURI);
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+HttpBaseChannel::GetNotificationCallbacks(nsIInterfaceRequestor **aCallbacks)
+{
+  *aCallbacks = mCallbacks;
+  NS_IF_ADDREF(*aCallbacks);
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+HttpBaseChannel::SetNotificationCallbacks(nsIInterfaceRequestor *aCallbacks)
+{
+  mCallbacks = aCallbacks;
+  mProgressSink = nsnull;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+HttpBaseChannel::GetContentType(nsACString& aContentType)
+{
+  if (!mResponseHead) {
+    aContentType.Truncate();
+    return NS_ERROR_NOT_AVAILABLE;
+  }
+
+  if (!mResponseHead->ContentType().IsEmpty()) {
+    aContentType = mResponseHead->ContentType();
+    return NS_OK;
+  }
+
+  aContentType.AssignLiteral(UNKNOWN_CONTENT_TYPE);
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+HttpBaseChannel::SetContentType(const nsACString& aContentType)
+{
+  if (mListener || mWasOpened) {
+    if (!mResponseHead)
+      return NS_ERROR_NOT_AVAILABLE;
+
+    nsCAutoString contentTypeBuf, charsetBuf;
+    PRBool hadCharset;
+    net_ParseContentType(aContentType, contentTypeBuf, charsetBuf, &hadCharset);
+
+    mResponseHead->SetContentType(contentTypeBuf);
+
+    // take care not to stomp on an existing charset
+    if (hadCharset)
+      mResponseHead->SetContentCharset(charsetBuf);
+
+  } else {
+    // We are being given a content-type hint.
+    PRBool dummy;
+    net_ParseContentType(aContentType, mContentTypeHint, mContentCharsetHint,
+                         &dummy);
+  }
+  
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+HttpBaseChannel::GetContentCharset(nsACString& aContentCharset)
+{
+  if (!mResponseHead)
+    return NS_ERROR_NOT_AVAILABLE;
+
+  aContentCharset = mResponseHead->ContentCharset();
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+HttpBaseChannel::SetContentCharset(const nsACString& aContentCharset)
+{
+  if (mListener) {
+    if (!mResponseHead)
+      return NS_ERROR_NOT_AVAILABLE;
+
+    mResponseHead->SetContentCharset(aContentCharset);
+  } else {
+    // Charset hint
+    mContentCharsetHint = aContentCharset;
+  }
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+HttpBaseChannel::GetContentLength(PRInt32 *aContentLength)
+{
+  NS_ENSURE_ARG_POINTER(aContentLength);
+
+  if (!mResponseHead)
+    return NS_ERROR_NOT_AVAILABLE;
+
+  // XXX truncates to 32 bit
+  *aContentLength = mResponseHead->ContentLength();
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+HttpBaseChannel::SetContentLength(PRInt32 value)
+{
+  NS_NOTYETIMPLEMENTED("nsHttpChannel::SetContentLength");
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
+HttpBaseChannel::Open(nsIInputStream **aResult)
+{
+  NS_ENSURE_TRUE(!mWasOpened, NS_ERROR_IN_PROGRESS);
+  return NS_ImplementChannelOpen(this, aResult);
+}
+
+//-----------------------------------------------------------------------------
+// HttpBaseChannel::nsIHttpChannel
+//-----------------------------------------------------------------------------
+
+NS_IMETHODIMP
+HttpBaseChannel::GetRequestMethod(nsACString& aMethod)
+{
+  aMethod = mRequestHead.Method();
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+HttpBaseChannel::SetRequestMethod(const nsACString& aMethod)
+{
+  ENSURE_CALLED_BEFORE_ASYNC_OPEN();
+
+  const nsCString& flatMethod = PromiseFlatCString(aMethod);
+
+  // 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
+HttpBaseChannel::GetReferrer(nsIURI **referrer)
+{
+  NS_ENSURE_ARG_POINTER(referrer);
+  *referrer = mReferrer;
+  NS_IF_ADDREF(*referrer);
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+HttpBaseChannel::SetReferrer(nsIURI *referrer)
+{
+  ENSURE_CALLED_BEFORE_ASYNC_OPEN();
+
+  // clear existing referrer, if any
+  mReferrer = nsnull;
+  mRequestHead.ClearHeader(nsHttp::Referer);
+
+  if (!referrer)
+      return NS_OK;
+
+  // check referrer blocking pref
+  PRUint32 referrerLevel;
+  if (mLoadFlags & LOAD_INITIAL_DOCUMENT_URI)
+    referrerLevel = 1; // user action
+  else
+    referrerLevel = 2; // inline content
+  if (gHttpHandler->ReferrerLevel() < referrerLevel)
+    return NS_OK;
+
+  nsCOMPtr<nsIURI> referrerGrip;
+  nsresult rv;
+  PRBool match;
+
+  //
+  // Strip off "wyciwyg://123/" from wyciwyg referrers.
+  //
+  // XXX this really belongs elsewhere since wyciwyg URLs aren't part of necko.
+  //     perhaps some sort of generic nsINestedURI could be used.  then, if an URI
+  //     fails the whitelist test, then we could check for an inner URI and try
+  //     that instead.  though, that might be too automatic.
+  // 
+  rv = referrer->SchemeIs("wyciwyg", &match);
+  if (NS_FAILED(rv)) return rv;
+  if (match) {
+    nsCAutoString path;
+    rv = referrer->GetPath(path);
+    if (NS_FAILED(rv)) return rv;
+
+    PRUint32 pathLength = path.Length();
+    if (pathLength <= 2) return NS_ERROR_FAILURE;
+
+    // Path is of the form "//123/http://foo/bar", with a variable number of digits.
+    // To figure out where the "real" URL starts, search path for a '/', starting at 
+    // the third character.
+    PRInt32 slashIndex = path.FindChar('/', 2);
+    if (slashIndex == kNotFound) return NS_ERROR_FAILURE;
+
+    // Get the charset of the original URI so we can pass it to our fixed up URI.
+    nsCAutoString charset;
+    referrer->GetOriginCharset(charset);
+
+    // Replace |referrer| with a URI without wyciwyg://123/.
+    rv = NS_NewURI(getter_AddRefs(referrerGrip),
+                   Substring(path, slashIndex + 1, pathLength - slashIndex - 1),
+                   charset.get());
+    if (NS_FAILED(rv)) return rv;
+
+    referrer = referrerGrip.get();
+  }
+
+  //
+  // block referrer if not on our white list...
+  //
+  static const char *const referrerWhiteList[] = {
+    "http",
+    "https",
+    "ftp",
+    "gopher",
+    nsnull
+  };
+  match = PR_FALSE;
+  const char *const *scheme = referrerWhiteList;
+  for (; *scheme && !match; ++scheme) {
+    rv = referrer->SchemeIs(*scheme, &match);
+    if (NS_FAILED(rv)) return rv;
+  }
+  if (!match)
+    return NS_OK; // kick out....
+
+  //
+  // Handle secure referrals.
+  //
+  // Support referrals from a secure server if this is a secure site
+  // and (optionally) if the host names are the same.
+  //
+  rv = referrer->SchemeIs("https", &match);
+  if (NS_FAILED(rv)) return rv;
+  if (match) {
+    rv = mURI->SchemeIs("https", &match);
+    if (NS_FAILED(rv)) return rv;
+    if (!match)
+      return NS_OK;
+
+    if (!gHttpHandler->SendSecureXSiteReferrer()) {
+      nsCAutoString referrerHost;
+      nsCAutoString host;
+
+      rv = referrer->GetAsciiHost(referrerHost);
+      if (NS_FAILED(rv)) return rv;
+
+      rv = mURI->GetAsciiHost(host);
+      if (NS_FAILED(rv)) return rv;
+
+      // GetAsciiHost returns lowercase hostname.
+      if (!referrerHost.Equals(host))
+        return NS_OK;
+    }
+  }
+
+  nsCOMPtr<nsIURI> clone;
+  //
+  // we need to clone the referrer, so we can:
+  //  (1) modify it
+  //  (2) keep a reference to it after returning from this function
+  //
+  rv = referrer->Clone(getter_AddRefs(clone));
+  if (NS_FAILED(rv)) return rv;
+
+  // strip away any userpass; we don't want to be giving out passwords ;-)
+  clone->SetUserPass(EmptyCString());
+
+  // strip away any fragment per RFC 2616 section 14.36
+  nsCOMPtr<nsIURL> url = do_QueryInterface(clone);
+  if (url)
+    url->SetRef(EmptyCString());
+
+  nsCAutoString spec;
+  rv = clone->GetAsciiSpec(spec);
+  if (NS_FAILED(rv)) return rv;
+
+  // finally, remember the referrer URI and set the Referer header.
+  mReferrer = clone;
+  mRequestHead.SetHeader(nsHttp::Referer, spec);
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+HttpBaseChannel::GetRequestHeader(const nsACString& aHeader,
+                                  nsACString& aValue)
+{
+  // XXX might be better to search the header list directly instead of
+  // hitting the http atom hash table.
+  nsHttpAtom atom = nsHttp::ResolveAtom(aHeader);
+  if (!atom)
+    return NS_ERROR_NOT_AVAILABLE;
+
+  return mRequestHead.GetHeader(atom, aValue);
+}
+
+NS_IMETHODIMP
+HttpBaseChannel::SetRequestHeader(const nsACString& aHeader,
+                                  const nsACString& aValue,
+                                  PRBool aMerge)
+{
+  ENSURE_CALLED_BEFORE_ASYNC_OPEN();
+
+  const nsCString &flatHeader = PromiseFlatCString(aHeader);
+  const nsCString &flatValue  = PromiseFlatCString(aValue);
+
+  LOG(("HttpBaseChannel::SetRequestHeader [this=%p header=\"%s\" value=\"%s\" merge=%u]\n",
+      this, flatHeader.get(), flatValue.get(), aMerge));
+
+  // Header names are restricted to valid HTTP tokens.
+  if (!nsHttp::IsValidToken(flatHeader))
+    return NS_ERROR_INVALID_ARG;
+  
+  // Header values MUST NOT contain line-breaks.  RFC 2616 technically
+  // permits CTL characters, including CR and LF, in header values provided
+  // they are quoted.  However, this can lead to problems if servers do not
+  // interpret quoted strings properly.  Disallowing CR and LF here seems
+  // reasonable and keeps things simple.  We also disallow a null byte.
+  if (flatValue.FindCharInSet("\r\n") != kNotFound ||
+      flatValue.Length() != strlen(flatValue.get()))
+    return NS_ERROR_INVALID_ARG;
+
+  nsHttpAtom atom = nsHttp::ResolveAtom(flatHeader.get());
+  if (!atom) {
+    NS_WARNING("failed to resolve atom");
+    return NS_ERROR_NOT_AVAILABLE;
+  }
+
+  return mRequestHead.SetHeader(atom, flatValue, aMerge);
+}
+
+NS_IMETHODIMP
+HttpBaseChannel::VisitRequestHeaders(nsIHttpHeaderVisitor *visitor)
+{
+  return mRequestHead.Headers().VisitHeaders(visitor);
+}
+
+NS_IMETHODIMP
+HttpBaseChannel::GetResponseHeader(const nsACString &header, nsACString &value)
+{
+  if (!mResponseHead)
+    return NS_ERROR_NOT_AVAILABLE;
+
+  nsHttpAtom atom = nsHttp::ResolveAtom(header);
+  if (!atom)
+    return NS_ERROR_NOT_AVAILABLE;
+
+  return mResponseHead->GetHeader(atom, value);
+}
+
+NS_IMETHODIMP
+HttpBaseChannel::SetResponseHeader(const nsACString& header, 
+                                   const nsACString& value, 
+                                   PRBool merge)
+{
+  LOG(("HttpBaseChannel::SetResponseHeader [this=%p header=\"%s\" value=\"%s\" merge=%u]\n",
+      this, PromiseFlatCString(header).get(), PromiseFlatCString(value).get(), merge));
+
+  if (!mResponseHead)
+    return NS_ERROR_NOT_AVAILABLE;
+
+  nsHttpAtom atom = nsHttp::ResolveAtom(header);
+  if (!atom)
+    return NS_ERROR_NOT_AVAILABLE;
+
+  // these response headers must not be changed 
+  if (atom == nsHttp::Content_Type ||
+      atom == nsHttp::Content_Length ||
+      atom == nsHttp::Content_Encoding ||
+      atom == nsHttp::Trailer ||
+      atom == nsHttp::Transfer_Encoding)
+    return NS_ERROR_ILLEGAL_VALUE;
+
+  mResponseHeadersModified = PR_TRUE;
+
+  return mResponseHead->SetHeader(atom, value, merge);
+}
+
+NS_IMETHODIMP
+HttpBaseChannel::VisitResponseHeaders(nsIHttpHeaderVisitor *visitor)
+{
+  if (!mResponseHead)
+    return NS_ERROR_NOT_AVAILABLE;
+  return mResponseHead->Headers().VisitHeaders(visitor);
+}
+
+NS_IMETHODIMP
+HttpBaseChannel::GetAllowPipelining(PRBool *value)
+{
+  NS_ENSURE_ARG_POINTER(value);
+  *value = mAllowPipelining;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+HttpBaseChannel::SetAllowPipelining(PRBool value)
+{
+  ENSURE_CALLED_BEFORE_ASYNC_OPEN();
+
+  mAllowPipelining = value;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+HttpBaseChannel::GetRedirectionLimit(PRUint32 *value)
+{
+  NS_ENSURE_ARG_POINTER(value);
+  *value = mRedirectionLimit;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+HttpBaseChannel::SetRedirectionLimit(PRUint32 value)
+{
+  ENSURE_CALLED_BEFORE_ASYNC_OPEN();
+
+  mRedirectionLimit = PR_MIN(value, 0xff);
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+HttpBaseChannel::IsNoStoreResponse(PRBool *value)
+{
+  if (!mResponseHead)
+    return NS_ERROR_NOT_AVAILABLE;
+  *value = mResponseHead->NoStore();
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+HttpBaseChannel::IsNoCacheResponse(PRBool *value)
+{
+  if (!mResponseHead)
+    return NS_ERROR_NOT_AVAILABLE;
+  *value = mResponseHead->NoCache();
+  if (!*value)
+    *value = mResponseHead->ExpiresInPast();
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+HttpBaseChannel::GetResponseStatus(PRUint32 *aValue)
+{
+  if (!mResponseHead)
+    return NS_ERROR_NOT_AVAILABLE;
+  *aValue = mResponseHead->Status();
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+HttpBaseChannel::GetResponseStatusText(nsACString& aValue)
+{
+  if (!mResponseHead)
+    return NS_ERROR_NOT_AVAILABLE;
+  aValue = mResponseHead->StatusText();
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+HttpBaseChannel::GetRequestSucceeded(PRBool *aValue)
+{
+  if (!mResponseHead)
+    return NS_ERROR_NOT_AVAILABLE;
+  PRUint32 status = mResponseHead->Status();
+  *aValue = (status / 100 == 2);
+  return NS_OK;
+}
+
+//-----------------------------------------------------------------------------
+// HttpBaseChannel::nsIHttpChannelInternal
+//-----------------------------------------------------------------------------
+
+NS_IMETHODIMP
+HttpBaseChannel::GetDocumentURI(nsIURI **aDocumentURI)
+{
+  NS_ENSURE_ARG_POINTER(aDocumentURI);
+  *aDocumentURI = mDocumentURI;
+  NS_IF_ADDREF(*aDocumentURI);
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+HttpBaseChannel::SetDocumentURI(nsIURI *aDocumentURI)
+{
+  ENSURE_CALLED_BEFORE_ASYNC_OPEN();
+
+  mDocumentURI = aDocumentURI;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+HttpBaseChannel::GetRequestVersion(PRUint32 *major, PRUint32 *minor)
+{
+  nsHttpVersion version = mRequestHead.Version();
+
+  if (major) { *major = version / 10; }
+  if (minor) { *minor = version % 10; }
+
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+HttpBaseChannel::GetResponseVersion(PRUint32 *major, PRUint32 *minor)
+{
+  if (!mResponseHead)
+  {
+    *major = *minor = 0; // we should at least be kind about it
+    return NS_ERROR_NOT_AVAILABLE;
+  }
+
+  nsHttpVersion version = mResponseHead->Version();
+
+  if (major) { *major = version / 10; }
+  if (minor) { *minor = version % 10; }
+
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+HttpBaseChannel::SetCookie(const char *aCookieHeader)
+{
+  if (mLoadFlags & LOAD_ANONYMOUS)
+    return NS_OK;
+
+  // empty header isn't an error
+  if (!(aCookieHeader && *aCookieHeader))
+    return NS_OK;
+
+  nsICookieService *cs = gHttpHandler->GetCookieService();
+  NS_ENSURE_TRUE(cs, NS_ERROR_FAILURE);
+
+  return cs->SetCookieStringFromHttp(mURI,
+                                     nsnull,
+                                     nsnull,
+                                     aCookieHeader,
+                                     mResponseHead->PeekHeader(nsHttp::Date),
+                                     this);
+}
+
+NS_IMETHODIMP
+HttpBaseChannel::GetForceAllowThirdPartyCookie(PRBool *aForce)
+{
+  *aForce = mForceAllowThirdPartyCookie;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+HttpBaseChannel::SetForceAllowThirdPartyCookie(PRBool aForce)
+{
+  ENSURE_CALLED_BEFORE_ASYNC_OPEN();
+
+  mForceAllowThirdPartyCookie = aForce;
+  return NS_OK;
+}
+
+//------------------------------------------------------------------------------
+
+}
+}
+
new file mode 100644
--- /dev/null
+++ b/netwerk/protocol/http/src/HttpBaseChannel.h
@@ -0,0 +1,186 @@
+/* -*- 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) 2010
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Daniel Witte <dwitte@mozilla.com>
+ *
+ * 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_HttpBaseChannel_h
+#define mozilla_net_HttpBaseChannel_h
+
+#include "nsHttp.h"
+#include "nsAutoPtr.h"
+#include "nsHashPropertyBag.h"
+#include "nsProxyInfo.h"
+#include "nsHttpRequestHead.h"
+#include "nsHttpResponseHead.h"
+#include "nsHttpConnectionInfo.h"
+#include "nsIHttpChannel.h"
+#include "nsIHttpChannelInternal.h"
+#include "nsIProgressEventSink.h"
+#include "nsIURI.h"
+
+#define DIE_WITH_ASYNC_OPEN_MSG()                                              \
+  do {                                                                         \
+    fprintf(stderr,                                                            \
+            "*&*&*&*&*&*&*&**&*&&*& FATAL ERROR: '%s' "                        \
+            "called after AsyncOpen: %s +%d",                                  \
+            __FUNCTION__, __FILE__, __LINE__);                                 \
+    NS_ABORT();                                                                \
+    return NS_ERROR_NOT_IMPLEMENTED;                                           \
+  } while (0)
+
+#define ENSURE_CALLED_BEFORE_ASYNC_OPEN()                                      \
+  if (mIsPending)                                                              \
+    DIE_WITH_ASYNC_OPEN_MSG();                                                 \
+  if (mWasOpened)                                                              \
+    DIE_WITH_ASYNC_OPEN_MSG();                                                 \
+  NS_ENSURE_TRUE(!mIsPending, NS_ERROR_IN_PROGRESS);                           \
+  NS_ENSURE_TRUE(!mWasOpened, NS_ERROR_ALREADY_OPENED);
+
+namespace mozilla {
+namespace net {
+
+/*
+ * This class is a partial implementation of nsIHttpChannel.  It contains code
+ * shared by nsHttpChannel and HttpChannelChild. 
+ * - Note that this class has nothing to do with nsBaseChannel, which is an
+ *   earlier effort at a base class for channels that somehow never made it all
+ *   the way to the HTTP channel.
+ */
+class HttpBaseChannel : public nsHashPropertyBag
+                      , public nsIHttpChannel
+                      , public nsIHttpChannelInternal
+{
+public:
+  NS_DECL_ISUPPORTS_INHERITED
+
+  HttpBaseChannel();
+  virtual ~HttpBaseChannel();
+
+  nsresult Init(nsIURI *aURI, PRUint8 aCaps, nsProxyInfo *aProxyInfo);
+
+  // nsIRequest
+  NS_IMETHOD GetName(nsACString& aName);
+  NS_IMETHOD IsPending(PRBool *aIsPending);
+  NS_IMETHOD GetStatus(nsresult *aStatus);
+  NS_IMETHOD GetLoadGroup(nsILoadGroup **aLoadGroup);
+  NS_IMETHOD SetLoadGroup(nsILoadGroup *aLoadGroup);
+  NS_IMETHOD GetLoadFlags(nsLoadFlags *aLoadFlags);
+  NS_IMETHOD SetLoadFlags(nsLoadFlags aLoadFlags);
+
+  // nsIChannel
+  NS_IMETHOD GetOriginalURI(nsIURI **aOriginalURI);
+  NS_IMETHOD SetOriginalURI(nsIURI *aOriginalURI);
+  NS_IMETHOD GetURI(nsIURI **aURI);
+  NS_IMETHOD GetNotificationCallbacks(nsIInterfaceRequestor **aCallbacks);
+  NS_IMETHOD SetNotificationCallbacks(nsIInterfaceRequestor *aCallbacks);
+  NS_IMETHOD GetContentType(nsACString& aContentType);
+  NS_IMETHOD SetContentType(const nsACString& aContentType);
+  NS_IMETHOD GetContentCharset(nsACString& aContentCharset);
+  NS_IMETHOD SetContentCharset(const nsACString& aContentCharset);
+  NS_IMETHOD GetContentLength(PRInt32 *aContentLength);
+  NS_IMETHOD SetContentLength(PRInt32 aContentLength);
+  NS_IMETHOD Open(nsIInputStream **aResult);
+
+  // HttpBaseChannel::nsIHttpChannel
+  NS_IMETHOD GetRequestMethod(nsACString& aMethod);
+  NS_IMETHOD SetRequestMethod(const nsACString& aMethod);
+  NS_IMETHOD GetReferrer(nsIURI **referrer);
+  NS_IMETHOD SetReferrer(nsIURI *referrer);
+  NS_IMETHOD GetRequestHeader(const nsACString& aHeader, nsACString& aValue);
+  NS_IMETHOD SetRequestHeader(const nsACString& aHeader, 
+                              const nsACString& aValue, PRBool aMerge);
+  NS_IMETHOD VisitRequestHeaders(nsIHttpHeaderVisitor *visitor);
+  NS_IMETHOD GetResponseHeader(const nsACString &header, nsACString &value);
+  NS_IMETHOD SetResponseHeader(const nsACString& header, 
+                               const nsACString& value, PRBool merge);
+  NS_IMETHOD VisitResponseHeaders(nsIHttpHeaderVisitor *visitor);
+  NS_IMETHOD GetAllowPipelining(PRBool *value);
+  NS_IMETHOD SetAllowPipelining(PRBool value);
+  NS_IMETHOD GetRedirectionLimit(PRUint32 *value);
+  NS_IMETHOD SetRedirectionLimit(PRUint32 value);
+  NS_IMETHOD IsNoStoreResponse(PRBool *value);
+  NS_IMETHOD IsNoCacheResponse(PRBool *value);
+  NS_IMETHOD GetResponseStatus(PRUint32 *aValue);
+  NS_IMETHOD GetResponseStatusText(nsACString& aValue);
+  NS_IMETHOD GetRequestSucceeded(PRBool *aValue);
+
+  // nsIHttpChannelInternal
+  NS_IMETHOD GetDocumentURI(nsIURI **aDocumentURI);
+  NS_IMETHOD SetDocumentURI(nsIURI *aDocumentURI);
+  NS_IMETHOD GetRequestVersion(PRUint32 *major, PRUint32 *minor);
+  NS_IMETHOD GetResponseVersion(PRUint32 *major, PRUint32 *minor);
+  NS_IMETHOD SetCookie(const char *aCookieHeader);
+  NS_IMETHOD GetForceAllowThirdPartyCookie(PRBool *aForce);
+  NS_IMETHOD SetForceAllowThirdPartyCookie(PRBool aForce);
+
+protected:
+  nsCOMPtr<nsIURI>                  mURI;
+  nsCOMPtr<nsIURI>                  mOriginalURI;
+  nsCOMPtr<nsIURI>                  mDocumentURI;
+  nsCOMPtr<nsIStreamListener>       mListener;
+  nsCOMPtr<nsISupports>             mListenerContext;
+  nsCOMPtr<nsILoadGroup>            mLoadGroup;
+  nsCOMPtr<nsIInterfaceRequestor>   mCallbacks;
+  nsCOMPtr<nsIProgressEventSink>    mProgressSink;
+  nsCOMPtr<nsIURI>                  mReferrer;
+
+  nsHttpRequestHead                 mRequestHead;
+  nsAutoPtr<nsHttpResponseHead>     mResponseHead;
+  nsRefPtr<nsHttpConnectionInfo>    mConnectionInfo;
+
+  nsCString                         mSpec; // ASCII encoded URL spec
+  nsCString                         mContentTypeHint;
+  nsCString                         mContentCharsetHint;
+
+  nsresult                          mStatus;
+  PRUint32                          mLoadFlags;
+  PRUint8                           mCaps;
+  PRUint8                           mRedirectionLimit;
+
+  PRUint8                           mIsPending                  : 1;
+  PRUint8                           mWasOpened                  : 1;
+  PRUint8                           mResponseHeadersModified    : 1;
+  PRUint8                           mAllowPipelining            : 1;
+  PRUint8                           mForceAllowThirdPartyCookie : 1;
+};
+
+
+} // namespace net
+} // namespace mozilla
+
+#endif // mozilla_net_HttpBaseChannel_h
--- a/netwerk/protocol/http/src/HttpChannelChild.cpp
+++ b/netwerk/protocol/http/src/HttpChannelChild.cpp
@@ -18,16 +18,17 @@
  *
  * The Initial Developer of the Original Code is
  *  The Mozilla Foundation
  * Portions created by the Initial Developer are Copyright (C) 2009
  * the Initial Developer. All Rights Reserved.
  *
  * Contributor(s):
  *   Jason Duell <jduell.mcbugs@gmail.com>
+ *   Daniel Witte <dwitte@mozilla.com>
  *
  * 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
@@ -42,188 +43,69 @@
 #include "mozilla/net/NeckoChild.h"
 #include "mozilla/net/HttpChannelChild.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_IMPL_ADDREF_INHERITED(HttpChannelChild, HttpBaseChannel)
+NS_IMPL_RELEASE_INHERITED(HttpChannelChild, HttpBaseChannel)
 
 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(nsICachingChannel)
   NS_INTERFACE_MAP_ENTRY(nsIUploadChannel)
   NS_INTERFACE_MAP_ENTRY(nsIUploadChannel2)
   NS_INTERFACE_MAP_ENTRY(nsIEncodedChannel)
   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_END_INHERITING(nsHashPropertyBag)
+NS_INTERFACE_MAP_END_INHERITING(HttpBaseChannel)
 
 //-----------------------------------------------------------------------------
 // HttpChannelChild::PHttpChannelChild
 //-----------------------------------------------------------------------------
 
 bool 
 HttpChannelChild::RecvOnStartRequest(const nsHttpResponseHead& responseHead)
 {
   LOG(("HttpChannelChild::RecvOnStartRequest [this=%x]\n", this));
 
   mState = HCC_ONSTART;
 
   mResponseHead = new nsHttpResponseHead(responseHead);
 
-  nsresult rv = mChildListener->OnStartRequest(this, mChildListenerContext);
+  nsresult rv = mListener->OnStartRequest(this, mListenerContext);
   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;  
   }
@@ -248,18 +130,18 @@ HttpChannelChild::RecvOnDataAvailable(co
   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);
+  rv = mListener->OnDataAvailable(this, mListenerContext,
+                                  stringStream, offset, count);
   stringStream->Close();
   if (!NS_SUCCEEDED(rv)) {
     // TODO: Cancel request: see notes in OnStartRequest
     return false; 
   }
   return true;
 }
 
@@ -268,283 +150,70 @@ HttpChannelChild::RecvOnStopRequest(cons
 {
   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;
+  nsresult rv = mListener->OnStopRequest(this, mListenerContext, statusCode);
+  mListener = 0;
+  mListenerContext = 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)
+HttpChannelChild::Cancel(nsresult status)
 {
   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 (!mResponseHead) {
-    value.Truncate();
-    return NS_ERROR_NOT_AVAILABLE;
-  }
-  if (mResponseHead->ContentType().IsEmpty()) {
-    value.AssignLiteral(UNKNOWN_CONTENT_TYPE);
-  } else {
-    value = mResponseHead->ContentType();
-  }
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-HttpChannelChild::SetContentType(const nsACString& aContentType)
-{
-  return BaseClassSetContentType_HACK(aContentType);
-}
-
-nsresult
-HttpChannelChild::BaseClassSetContentType_HACK(const nsACString &value)
-{
-  if (mChildListener || mWasOpened) {
-    if (!mResponseHead)
-      return NS_ERROR_NOT_AVAILABLE;
-
-    nsCAutoString contentTypeBuf, charsetBuf;
-    PRBool hadCharset;
-    net_ParseContentType(value, contentTypeBuf, charsetBuf, &hadCharset);
-
-    mResponseHead->SetContentType(contentTypeBuf);
-
-    // take care not to stomp on an existing charset
-    if (hadCharset)
-      mResponseHead->SetContentCharset(charsetBuf);
-  }
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-HttpChannelChild::GetContentCharset(nsACString& aContentCharset)
-{
-  return BaseClassGetContentCharset_HACK(aContentCharset);
-}
-
-nsresult
-HttpChannelChild::BaseClassGetContentCharset_HACK(nsACString &value)
-{
-  if (!mResponseHead)
-    return NS_ERROR_NOT_AVAILABLE;
-
-  value = mResponseHead->ContentCharset();
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-HttpChannelChild::SetContentCharset(const nsACString& aContentCharset)
-{
-  return BaseClassSetContentCharset_HACK(aContentCharset);
-}
-
-nsresult
-HttpChannelChild::BaseClassSetContentCharset_HACK(const nsACString &value)
-{
-  if (mChildListener) {
-    if (!mResponseHead)
-      return NS_ERROR_NOT_AVAILABLE;
-
-    mResponseHead->SetContentCharset(value);
-  }
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-HttpChannelChild::GetContentLength(PRInt32 *aContentLength)
-{
-  *aContentLength = mResponseHead->ContentLength();
-  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);
@@ -559,18 +228,24 @@ HttpChannelChild::AsyncOpen(nsIStreamLis
   // 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;
+  mListener = listener;
+  mListenerContext = aContext;
+
+  // TODO: serialize mConnectionInfo across to the parent, and set it on
+  // the new channel somehow?
+
+  // TODO: serialize mCaps across to the parent, and set it on
+  // the new channel somehow?
 
   // 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)? 
@@ -584,342 +259,66 @@ HttpChannelChild::AsyncOpen(nsIStreamLis
   nsCAutoString docSpec;
   nsCAutoString docCharset;
   if (mDocumentURI) {
     mDocumentURI->GetSpec(docSpec);
     mDocumentURI->GetOriginCharset(docCharset);
   }
 
   if (!SendAsyncOpen(mSpec, charset, originalSpec, originalCharset, 
-                     docSpec, docCharset, mLoadFlags, mRequestHeaders)) {
+                     docSpec, docCharset, mLoadFlags, mRequestHeaders,
+                     mRequestHead.Method(), mRedirectionLimit, mAllowPipelining,
+                     mForceAllowThirdPartyCookie)) {
     // IPDL error: our destructor will be called automatically
     // -- TODO: verify that that's the case :)
-    mChildListener = 0;
-    mChildListenerContext = 0;
+    mListener = 0;
+    mListenerContext = 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)
-{
-  return BaseClassGetRequestHeader_HACK(hdr, val);
-}
-
-nsresult
-HttpChannelChild::BaseClassGetRequestHeader_HACK(const nsACString &header,
-                                                 nsACString &value)
-{
-  // XXX might be better to search the header list directly instead of
-  // hitting the http atom hash table.
-
-  nsHttpAtom atom = nsHttp::ResolveAtom(header);
-  if (!atom)
-    return NS_ERROR_NOT_AVAILABLE;
-
-  return mRequestHead.GetHeader(atom, value);
-}
-
-NS_IMETHODIMP
 HttpChannelChild::SetRequestHeader(const nsACString& aHeader, 
                                    const nsACString& aValue, 
                                    PRBool aMerge)
 {
-  ENSURE_CALLED_BEFORE_ASYNC_OPEN();
-
-  nsresult rv = BaseClassSetRequestHeader_HACK(aHeader, aValue, aMerge);
+  nsresult rv = HttpBaseChannel::SetRequestHeader(aHeader, aValue, aMerge);
   if (NS_FAILED(rv))
     return rv;
 
   RequestHeaderTuple* tuple = mRequestHeaders.AppendElement();
   if (!tuple)
     return NS_ERROR_OUT_OF_MEMORY;
 
   tuple->mHeader = aHeader;
   tuple->mValue = aValue;
   tuple->mMerge = aMerge;
   return NS_OK;
 }
 
-nsresult
-HttpChannelChild::BaseClassSetRequestHeader_HACK(const nsACString &header,
-                                                 const nsACString &value,
-                                                 PRBool merge)
-{
-  NS_ENSURE_TRUE(!mIsPending, NS_ERROR_IN_PROGRESS);
-
-  const nsCString &flatHeader = PromiseFlatCString(header);
-  const nsCString &flatValue  = PromiseFlatCString(value);
-
-  LOG(("nsHttpChannel::SetRequestHeader [this=%x header=\"%s\" value=\"%s\" merge=%u]\n",
-       this, flatHeader.get(), flatValue.get(), merge));
-
-  // Header names are restricted to valid HTTP tokens.
-  if (!nsHttp::IsValidToken(flatHeader))
-    return NS_ERROR_INVALID_ARG;
-
-  // Header values MUST NOT contain line-breaks.  RFC 2616 technically
-  // permits CTL characters, including CR and LF, in header values provided
-  // they are quoted.  However, this can lead to problems if servers do not
-  // interpret quoted strings properly.  Disallowing CR and LF here seems
-  // reasonable and keeps things simple.  We also disallow a null byte.
-  if (flatValue.FindCharInSet("\r\n") != kNotFound ||
-      flatValue.Length() != strlen(flatValue.get()))
-    return NS_ERROR_INVALID_ARG;
-
-  nsHttpAtom atom = nsHttp::ResolveAtom(flatHeader.get());
-  if (!atom) {
-    NS_WARNING("failed to resolve atom");
-    return NS_ERROR_NOT_AVAILABLE;
-  }
-
-  return mRequestHead.SetHeader(atom, flatValue, merge);
-}
-
-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 (!mResponseHead)
-    return NS_ERROR_NOT_AVAILABLE;
-  *value = mResponseHead->Status();
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-HttpChannelChild::GetResponseStatusText(nsACString& value)
-{
-  if (!mResponseHead)
-    return NS_ERROR_NOT_AVAILABLE;
-  value = mResponseHead->StatusText();
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-HttpChannelChild::GetRequestSucceeded(PRBool *value)
-{
-  NS_PRECONDITION(value, "Don't ever pass a null arg to this function");
-  if (!mResponseHead)
-    return NS_ERROR_NOT_AVAILABLE;
-  PRUint32 status = mResponseHead->Status();
-  *value = (status / 100 == 2);
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-HttpChannelChild::GetResponseHeader(const nsACString& header, nsACString& val)
-{
-  return BaseClassGetResponseHeader_HACK(header, val);
-}
-
-nsresult
-HttpChannelChild::BaseClassGetResponseHeader_HACK(const nsACString &header,
-                                                  nsACString &value)
-{
-  if (!mResponseHead)
-    return NS_ERROR_NOT_AVAILABLE;
-  nsHttpAtom atom = nsHttp::ResolveAtom(header);
-  if (!atom)
-    return NS_ERROR_NOT_AVAILABLE;
-  return mResponseHead->GetHeader(atom, value);
-}
-
-NS_IMETHODIMP
-HttpChannelChild::SetResponseHeader(const nsACString& header, 
-                                    const nsACString& value, 
-                                    PRBool merge)
-{
-  return BaseClassSetResponseHeader_HACK(header, value, merge);
-}
-
-nsresult
-HttpChannelChild::BaseClassSetResponseHeader_HACK(const nsACString &header,
-                                                  const nsACString &value,
-                                                  PRBool merge)
-{
-  LOG(("nsHttpChannel::SetResponseHeader [this=%x header=\"%s\" value=\"%s\" merge=%u]\n",
-       this, PromiseFlatCString(header).get(), PromiseFlatCString(value).get(), merge));
-
-  if (!mResponseHead)
-    return NS_ERROR_NOT_AVAILABLE;
-  nsHttpAtom atom = nsHttp::ResolveAtom(header);
-  if (!atom)
-    return NS_ERROR_NOT_AVAILABLE;
-
-  // these response headers must not be changed 
-  if (atom == nsHttp::Content_Type ||
-      atom == nsHttp::Content_Length ||
-      atom == nsHttp::Content_Encoding ||
-      atom == nsHttp::Trailer ||
-      atom == nsHttp::Transfer_Encoding)
-    return NS_ERROR_ILLEGAL_VALUE;
-
-  return mResponseHead->SetHeader(atom, value, merge);
-}
-
-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::nsICachingChannel
 //-----------------------------------------------------------------------------
 
 NS_IMETHODIMP
 HttpChannelChild::GetCacheToken(nsISupports **aCacheToken)
 {
--- a/netwerk/protocol/http/src/HttpChannelChild.h
+++ b/netwerk/protocol/http/src/HttpChannelChild.h
@@ -18,16 +18,17 @@
  *
  * The Initial Developer of the Original Code is
  *  The Mozilla Foundation
  * Portions created by the Initial Developer are Copyright (C) 2009
  * the Initial Developer. All Rights Reserved.
  *
  * Contributor(s):
  *   Jason Duell <jduell.mcbugs@gmail.com>
+ *   Daniel Witte <dwitte@mozilla.com>
  *
  * 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
@@ -36,142 +37,106 @@
  * 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_HttpChannelChild_h
 #define mozilla_net_HttpChannelChild_h
 
+#include "mozilla/net/HttpBaseChannel.h"
 #include "mozilla/net/PHttpChannelChild.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 "nsIApplicationCache.h"
 #include "nsIApplicationCacheChannel.h"
 #include "nsIEncodedChannel.h"
 #include "nsIUploadChannel.h"
 #include "nsIUploadChannel2.h"
 #include "nsIResumableChannel.h"
 #include "nsISupportsPriority.h"
 #include "nsIProxiedChannel.h"
 #include "nsITraceableChannel.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
-                       , public nsIHttpChannel
-                       , public nsHashPropertyBag
-                       , public nsIHttpChannelInternal
+                       , public HttpBaseChannel
                        , public nsICachingChannel
                        , public nsIUploadChannel
                        , public nsIUploadChannel2
                        , public nsIEncodedChannel
                        , public nsIResumableChannel
                        , public nsISupportsPriority
                        , public nsIProxiedChannel
                        , public nsITraceableChannel
                        , public nsIApplicationCacheChannel
 {
 public:
   NS_DECL_ISUPPORTS_INHERITED
-  NS_DECL_NSIREQUEST
-  NS_DECL_NSICHANNEL
-  NS_DECL_NSIHTTPCHANNEL
-  NS_DECL_NSIHTTPCHANNELINTERNAL
   NS_DECL_NSICACHINGCHANNEL
   NS_DECL_NSIUPLOADCHANNEL
   NS_DECL_NSIUPLOADCHANNEL2
   NS_DECL_NSIENCODEDCHANNEL
   NS_DECL_NSIRESUMABLECHANNEL
   NS_DECL_NSISUPPORTSPRIORITY
   NS_DECL_NSIPROXIEDCHANNEL
   NS_DECL_NSITRACEABLECHANNEL
   NS_DECL_NSIAPPLICATIONCACHECONTAINER
   NS_DECL_NSIAPPLICATIONCACHECHANNEL
 
   HttpChannelChild();
   virtual ~HttpChannelChild();
 
   nsresult Init(nsIURI *uri);
 
+  // Methods HttpBaseChannel didn't implement for us or that we override.
+  //
+  // nsIRequest
+  NS_IMETHOD Cancel(nsresult status);
+  NS_IMETHOD Suspend();
+  NS_IMETHOD Resume();
+  // nsIChannel
+  NS_IMETHOD GetOwner(nsISupports **aOwner);
+  NS_IMETHOD SetOwner(nsISupports *aOwner);
+  NS_IMETHOD GetSecurityInfo(nsISupports **aSecurityInfo);
+  NS_IMETHOD AsyncOpen(nsIStreamListener *listener, nsISupports *aContext);
+  // HttpBaseChannel::nsIHttpChannel
+  NS_IMETHOD SetRequestHeader(const nsACString& aHeader, 
+                              const nsACString& aValue, 
+                              PRBool aMerge);
+  // nsIHttpChannelInternal
+  NS_IMETHOD SetupFallbackChannel(const char *aFallbackKey);
+
 protected:
   bool RecvOnStartRequest(const nsHttpResponseHead& responseHead);
   bool RecvOnDataAvailable(const nsCString& data, 
                            const PRUint32& offset,
                            const PRUint32& count);
   bool RecvOnStopRequest(const nsresult& statusCode);
 
 private:
-  nsresult BaseClassSetContentType_HACK(const nsACString &value);
-  nsresult BaseClassGetContentCharset_HACK(nsACString &value);
-  nsresult BaseClassSetContentCharset_HACK(const nsACString &value);
-  nsresult BaseClassSetRequestHeader_HACK(const nsACString &header,
-                                          const nsACString &value,
-                                          PRBool merge);
-  nsresult BaseClassGetRequestHeader_HACK(const nsACString &header,
-                                          nsACString &value);
-  nsresult BaseClassGetResponseHeader_HACK(const nsACString &header,
-                                           nsACString &value);
-  nsresult BaseClassSetResponseHeader_HACK(const nsACString &header,
-                                           const nsACString &value,
-                                           PRBool merge);
-
-  nsCOMPtr<nsIStreamListener>         mChildListener;
-  nsCOMPtr<nsISupports>               mChildListenerContext;
-
-  RequestHeaderTuples                 mRequestHeaders;
-
-  nsAutoPtr<nsHttpResponseHead>       mResponseHead;
+  RequestHeaderTuples mRequestHeaders;
 
   // FIXME: replace with IPDL states (bug 536319) 
   enum HttpChannelChildState mState;
-
-  /**
-   * fields copied from nsHttpChannel.h
-   */
-  nsCOMPtr<nsIURI>                  mOriginalURI;
-  nsCOMPtr<nsIURI>                  mURI;
-  nsCOMPtr<nsIURI>                  mDocumentURI;
-
-  nsCOMPtr<nsIInterfaceRequestor>   mCallbacks;
-  nsCOMPtr<nsIProgressEventSink>    mProgressSink;
-
-  nsHttpRequestHead                 mRequestHead;
-
-  nsCString                         mSpec; // ASCII encoded URL spec
-
-  PRUint32                          mLoadFlags;
-  PRUint32                          mStatus;
-
-  // state flags
-  PRUint32                          mIsPending                : 1;
-  PRUint32                          mWasOpened                : 1;
-
 };
 
-
 } // namespace net
 } // namespace mozilla
 
 #endif // mozilla_net_HttpChannelChild_h
--- a/netwerk/protocol/http/src/HttpChannelParent.cpp
+++ b/netwerk/protocol/http/src/HttpChannelParent.cpp
@@ -33,31 +33,36 @@
  * 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 "nsHttp.h"
 #include "mozilla/net/HttpChannelParent.h"
 #include "nsHttpChannel.h"
+#include "nsHttpHandler.h"
 #include "nsNetUtil.h"
 
 namespace mozilla {
 namespace net {
 
 // C++ file contents
 HttpChannelParent::HttpChannelParent()
 {
+  // Ensure gHttpHandler is initialized: we need the atom table up and running.
+  nsIHttpProtocolHandler* handler;
+  CallGetService(NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX "http", &handler);
+  NS_ASSERTION(handler, "no http handler");
 }
 
 HttpChannelParent::~HttpChannelParent()
 {
+  NS_RELEASE(gHttpHandler);
 }
 
 //-----------------------------------------------------------------------------
 // HttpChannelParent::nsISupports
 //-----------------------------------------------------------------------------
 
 NS_IMPL_ISUPPORTS3(HttpChannelParent, 
                    nsIRequestObserver, 
@@ -71,69 +76,76 @@ NS_IMPL_ISUPPORTS3(HttpChannelParent,
 bool 
 HttpChannelParent::RecvAsyncOpen(const nsCString&           uriSpec, 
                                  const nsCString&           charset,
                                  const nsCString&           originalUriSpec, 
                                  const nsCString&           originalCharset,
                                  const nsCString&           docUriSpec, 
                                  const nsCString&           docCharset,
                                  const PRUint32&            loadFlags,
-                                 const RequestHeaderTuples& requestHeaders)
+                                 const RequestHeaderTuples& requestHeaders,
+                                 const nsHttpAtom&          requestMethod,
+                                 const PRUint8&             redirectionLimit,
+                                 const PRBool&              allowPipelining,
+                                 const PRBool&              forceAllowThirdPartyCookie)
 {
+  LOG(("HttpChannelParent RecvAsyncOpen [this=%x uri=%s (%s)]\n", 
+       this, uriSpec.get(), charset.get()));
+
   nsresult rv;
 
   nsCOMPtr<nsIIOService> ios(do_GetIOService(&rv));
   if (NS_FAILED(rv))
     return false;       // TODO: send fail msg to child, return true
 
   nsCOMPtr<nsIURI> 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<nsIChannel> 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
 
+  nsCOMPtr<nsIHttpChannel> httpChan(do_QueryInterface(chan));
+  nsCOMPtr<nsIHttpChannelInternal> httpChanInt(do_QueryInterface(chan));
+
   if (!originalUriSpec.IsEmpty()) {
     nsCOMPtr<nsIURI> originalUri;
     rv = NS_NewURI(getter_AddRefs(originalUri), originalUriSpec, 
                    originalCharset.get(), nsnull, ios);
     if (!NS_FAILED(rv))
       chan->SetOriginalURI(originalUri);
   }
   if (!docUriSpec.IsEmpty()) {
     nsCOMPtr<nsIURI> docUri;
     rv = NS_NewURI(getter_AddRefs(docUri), docUriSpec, 
                    docCharset.get(), nsnull, ios);
     if (!NS_FAILED(rv)) {
-      nsCOMPtr<nsIHttpChannelInternal> iChan(do_QueryInterface(chan));
-      if (iChan) 
-        iChan->SetDocumentURI(docUri);
+      httpChanInt->SetDocumentURI(docUri);
     }
   }
   if (loadFlags != nsIRequest::LOAD_NORMAL)
     chan->SetLoadFlags(loadFlags);
 
-  nsCOMPtr<nsIHttpChannel> httpChan(do_QueryInterface(chan));
   for (PRUint32 i = 0; i < requestHeaders.Length(); i++)
     httpChan->SetRequestHeader(requestHeaders[i].mHeader,
                                requestHeaders[i].mValue,
                                requestHeaders[i].mMerge);
 
   // TODO: implement needed interfaces, and either proxy calls back to child
   // process, or rig up appropriate hacks.
 //  chan->SetNotificationCallbacks(this);
 
+  httpChan->SetRequestMethod(nsDependentCString(requestMethod.get()));
+  httpChan->SetRedirectionLimit(redirectionLimit);
+  httpChan->SetAllowPipelining(allowPipelining);
+  httpChanInt->SetForceAllowThirdPartyCookie(forceAllowThirdPartyCookie);
+
   rv = chan->AsyncOpen(this, nsnull);
   if (NS_FAILED(rv))
     return false;       // TODO: send fail msg to child, return true
 
   return true;
 }
 
 
--- a/netwerk/protocol/http/src/HttpChannelParent.h
+++ b/netwerk/protocol/http/src/HttpChannelParent.h
@@ -67,15 +67,19 @@ public:
 protected:
   virtual bool RecvAsyncOpen(const nsCString&           uriSpec, 
                              const nsCString&           charset,
                              const nsCString&           originalUriSpec, 
                              const nsCString&           originalCharset,
                              const nsCString&           docUriSpec, 
                              const nsCString&           docCharset,
                              const PRUint32&            loadFlags,
-                             const RequestHeaderTuples& requestHeaders);
+                             const RequestHeaderTuples& requestHeaders,
+                             const nsHttpAtom&          requestMethod,
+                             const PRUint8&             redirectionLimit,
+                             const PRBool&              allowPipelining,
+                             const PRBool&              forceAllowThirdPartyCookie);
 };
 
 } // namespace net
 } // namespace mozilla
 
 #endif // mozilla_net_HttpChannelParent_h
--- a/netwerk/protocol/http/src/Makefile.in
+++ b/netwerk/protocol/http/src/Makefile.in
@@ -41,20 +41,24 @@ srcdir		= @srcdir@
 VPATH		= @srcdir@
 
 include $(DEPTH)/config/autoconf.mk
 
 MODULE		= necko
 LIBRARY_NAME = nkhttp_s
 LIBXUL_LIBRARY  = 1
 
-ifdef MOZ_IPC
 EXPORTS_NAMESPACES = mozilla/net
 
 EXPORTS_mozilla/net = \
+  HttpBaseChannel.h \
+  $(NULL)
+
+ifdef MOZ_IPC
+EXPORTS_mozilla/net += \
   HttpChannelParent.h \
   HttpChannelChild.h  \
   PHttpChannelParams.h \
   $(NULL)
 
 EXPORTS = \
   nsHttpResponseHead.h \
   nsHttpHeaderArray.h \
@@ -74,16 +78,17 @@ CPPSRCS		= \
 		nsHttpChunkedDecoder.cpp \
 		nsHttpAuthCache.cpp \
 		nsHttpAuthManager.cpp \
 		nsHttpBasicAuth.cpp \
 		nsHttpDigestAuth.cpp \
 		nsHttpNTLMAuth.cpp \
 		nsHttpTransaction.cpp \
 		nsHttpHandler.cpp \
+		HttpBaseChannel.cpp \
 		nsHttpChannel.cpp \
 		nsHttpPipeline.cpp \
 		nsHttpActivityDistributor.cpp \
 		$(NULL)
 
 ifdef MOZ_IPC
 CPPSRCS += \
   HttpChannelParent.cpp \
--- a/netwerk/protocol/http/src/PHttpChannel.ipdl
+++ b/netwerk/protocol/http/src/PHttpChannel.ipdl
@@ -39,16 +39,17 @@
  * ***** END LICENSE BLOCK ***** */
 
 include protocol "PNecko.ipdl";
 
 include "mozilla/net/PHttpChannelParams.h";
 
 using RequestHeaderTuples;
 using nsHttpResponseHead;
+using nsHttpAtom;
 
 namespace mozilla {
 namespace net {
 
 //-------------------------------------------------------------------
 protocol PHttpChannel
 {
   manager PNecko;
@@ -62,17 +63,21 @@ parent:
             // 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           docUriSpec, 
             nsCString           docCharset, 
             PRUint32            loadFlags,
-            RequestHeaderTuples requestHeaders);
+            RequestHeaderTuples requestHeaders,
+            nsHttpAtom          requestMethod,
+            PRUint8             redirectionLimit,
+            PRBool              allowPipelining,
+            PRBool              forceAllowThirdPartyCookie);
 
 child:
   OnStartRequest(nsHttpResponseHead responseHead);
 
   OnDataAvailable(nsCString data, 
                   PRUint32  offset, 
                   PRUint32  count);
 
--- a/netwerk/protocol/http/src/PHttpChannelParams.h
+++ b/netwerk/protocol/http/src/PHttpChannelParams.h
@@ -103,16 +103,17 @@ struct ParamTraits<nsHttpAtom>
 
   static bool Read(const Message* aMsg, void** aIter, paramType* aResult)
   {
     nsCAutoString value;
     if (!ReadParam(aMsg, aIter, &value))
       return false;
 
     *aResult = nsHttp::ResolveAtom(value.get());
+    NS_ASSERTION(aResult->get(), "atom table not initialized");
     return true;
   }
 };
 
 template<>
 struct ParamTraits<nsHttpHeaderArray::nsEntry>
 {
   typedef nsHttpHeaderArray::nsEntry paramType;
--- a/netwerk/protocol/http/src/nsHttpChannel.cpp
+++ b/netwerk/protocol/http/src/nsHttpChannel.cpp
@@ -23,68 +23,51 @@
  * Contributor(s):
  *   Darin Fisher <darin@meer.net> (original author)
  *   Christian Biesinger <cbiesinger@web.de>
  *   Google Inc.
  *   Jan Wrobel <wrobel@blues.ath.cx>
  *   Jan Odvarko <odvarko@gmail.com>
  *   Dave Camp <dcamp@mozilla.com>
  *   Honza Bambas <honzab@firemni.cz>
+ *   Daniel Witte <dwitte@mozilla.com>
  *
  * 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 "nsHttpChannel.h"
-#include "nsHttpTransaction.h"
-#include "nsHttpConnection.h"
 #include "nsHttpHandler.h"
-#include "nsHttpAuthCache.h"
-#include "nsHttpResponseHead.h"
-#include "nsHttp.h"
 #include "nsIHttpAuthenticator.h"
 #include "nsIApplicationCacheService.h"
 #include "nsIApplicationCacheContainer.h"
 #include "nsIAuthInformation.h"
 #include "nsIAuthPrompt2.h"
 #include "nsIAuthPromptProvider.h"
 #include "nsIStringBundle.h"
-#include "nsXPCOM.h"
-#include "nsISupportsPrimitives.h"
-#include "nsIURL.h"
 #include "nsIIDNService.h"
 #include "nsIStreamListenerTee.h"
 #include "nsISeekableStream.h"
 #include "nsMimeTypes.h"
+#include "nsPrintfCString.h"
 #include "nsNetUtil.h"
-#include "nsString.h"
-#include "nsPrintfCString.h"
-#include "nsReadableUtils.h"
-#include "nsUnicharUtils.h"
-#include "nsAutoPtr.h"
-#include "plstr.h"
 #include "prprf.h"
 #include "nsEscape.h"
-#include "nsICookieService.h"
-#include "nsIResumableChannel.h"
 #include "nsInt64.h"
-#include "nsIVariant.h"
-#include "nsChannelProperties.h"
 #include "nsStreamUtils.h"
-#include "nsIOService.h"
 #include "nsAuthInformationHolder.h"
 #include "nsICacheService.h"
 #include "nsDNSPrefetch.h"
 #include "nsNetSegmentUtils.h"
 
 // True if the local cache should be bypassed when processing a request.
 #define BYPASS_LOCAL_CACHE(loadFlags) \
         (loadFlags & (nsIRequest::LOAD_BYPASS_CACHE | \
@@ -92,41 +75,29 @@
 
 static NS_DEFINE_CID(kStreamListenerTeeCID, NS_STREAMLISTENERTEE_CID);
 
 //-----------------------------------------------------------------------------
 // nsHttpChannel <public>
 //-----------------------------------------------------------------------------
 
 nsHttpChannel::nsHttpChannel()
-    : mResponseHead(nsnull)
-    , mTransaction(nsnull)
-    , mConnectionInfo(nsnull)
-    , mLoadFlags(LOAD_NORMAL)
-    , mStatus(NS_OK)
-    , mLogicalOffset(0)
-    , mCaps(0)
+    : mLogicalOffset(0)
     , mPriority(PRIORITY_NORMAL)
-    , mCachedResponseHead(nsnull)
     , mCacheAccess(0)
     , mPostID(0)
     , mRequestTime(0)
     , mProxyAuthContinuationState(nsnull)
     , mAuthContinuationState(nsnull)
     , mStartPos(LL_MAXUINT)
     , mPendingAsyncCallOnResume(nsnull)
     , mSuspendCount(0)
-    , mRedirectionLimit(gHttpHandler->RedirectionLimit())
-    , mIsPending(PR_FALSE)
-    , mWasOpened(PR_FALSE)
     , mApplyConversion(PR_TRUE)
-    , mAllowPipelining(PR_TRUE)
     , mCachedContentIsValid(PR_FALSE)
     , mCachedContentIsPartial(PR_FALSE)
-    , mResponseHeadersModified(PR_FALSE)
     , mCanceled(PR_FALSE)
     , mTransactionReplaced(PR_FALSE)
     , mUploadStreamHasHeaders(PR_FALSE)
     , mAuthRetryPending(PR_FALSE)
     , mProxyAuth(PR_FALSE)
     , mTriedProxyAuth(PR_FALSE)
     , mTriedHostAuth(PR_FALSE)
     , mSuppressDefensiveAuth(PR_FALSE)
@@ -134,115 +105,27 @@ nsHttpChannel::nsHttpChannel()
     , mInitedCacheEntry(PR_FALSE)
     , mCacheForOfflineUse(PR_FALSE)
     , mCachingOpportunistically(PR_FALSE)
     , mFallbackChannel(PR_FALSE)
     , mInheritApplicationCache(PR_TRUE)
     , mChooseApplicationCache(PR_FALSE)
     , mLoadedFromApplicationCache(PR_FALSE)
     , mTracingEnabled(PR_TRUE)
-    , mForceAllowThirdPartyCookie(PR_FALSE)
     , mCustomConditionalRequest(PR_FALSE)
 {
     LOG(("Creating nsHttpChannel [this=%p]\n", this));
-
-    // grab a reference to the handler to ensure that it doesn't go away.
-    nsHttpHandler *handler = gHttpHandler;
-    NS_ADDREF(handler);
 }
 
 nsHttpChannel::~nsHttpChannel()
 {
     LOG(("Destroying nsHttpChannel [this=%p]\n", this));
 
-    NS_IF_RELEASE(mConnectionInfo);
-    NS_IF_RELEASE(mTransaction);
-
     NS_IF_RELEASE(mProxyAuthContinuationState);
     NS_IF_RELEASE(mAuthContinuationState);
-
-    delete mResponseHead;
-    delete mCachedResponseHead;
-
-    // release our reference to the handler
-    nsHttpHandler *handler = gHttpHandler;
-    NS_RELEASE(handler);
-}
-
-nsresult
-nsHttpChannel::Init(nsIURI *uri,
-                    PRUint8 caps,
-                    nsProxyInfo *proxyInfo)
-{
-    LOG(("nsHttpChannel::Init [this=%p]\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()));
-
-    mConnectionInfo = new nsHttpConnectionInfo(host, port,
-                                               proxyInfo, usingSSL);
-    if (!mConnectionInfo)
-        return NS_ERROR_OUT_OF_MEMORY;
-    NS_ADDREF(mConnectionInfo);
-
-    // Set default request method
-    mRequestHead.SetMethod(nsHttp::Get);
-
-    //
-    // Set request headers
-    //
-    nsCAutoString hostLine;
-    rv = nsHttpHandler::GenerateHostPort(host, port, hostLine);
-    if (NS_FAILED(rv))
-        return rv;
-
-    rv = mRequestHead.SetHeader(nsHttp::Host, hostLine);
-    if (NS_FAILED(rv)) return rv;
-
-    rv = gHttpHandler->
-        AddStandardRequestHeaders(&mRequestHead.Headers(), caps,
-                                  !mConnectionInfo->UsingSSL() &&
-                                  mConnectionInfo->UsingHttpProxy());
-
-    return rv;
 }
 
 //-----------------------------------------------------------------------------
 // nsHttpChannel <private>
 //-----------------------------------------------------------------------------
 
 nsresult
 nsHttpChannel::AsyncCall(nsAsyncCallback funcPtr,
@@ -645,31 +528,30 @@ nsHttpChannel::SetupTransaction()
                                            getter_AddRefs(callbacks));
     if (!callbacks)
         return NS_ERROR_OUT_OF_MEMORY;
 
     // create the transaction object
     mTransaction = new nsHttpTransaction();
     if (!mTransaction)
         return NS_ERROR_OUT_OF_MEMORY;
-    NS_ADDREF(mTransaction);
 
     // See bug #466080. Transfer LOAD_ANONYMOUS flag to socket-layer.
     if (mLoadFlags & LOAD_ANONYMOUS)
         mCaps |= NS_HTTP_LOAD_ANONYMOUS;
 
     mConnectionInfo->SetAnonymous((mLoadFlags & LOAD_ANONYMOUS) != 0);
 
     nsCOMPtr<nsIAsyncInputStream> responseStream;
     rv = mTransaction->Init(mCaps, mConnectionInfo, &mRequestHead,
                             mUploadStream, mUploadStreamHasHeaders,
                             NS_GetCurrentThread(), callbacks, this,
                             getter_AddRefs(responseStream));
     if (NS_FAILED(rv)) {
-        NS_RELEASE(mTransaction);
+        mTransaction = nsnull;
         return rv;
     }
 
     rv = nsInputStreamPump::Create(getter_AddRefs(mTransactionPump),
                                    responseStream);
     return rv;
 }
 
@@ -1409,19 +1291,17 @@ nsHttpChannel::ProcessPartialContent()
 
     // update the cached response head
     nsCAutoString head;
     mCachedResponseHead->Flatten(head, PR_TRUE);
     rv = mCacheEntry->SetMetaDataElement("response-head", head.get());
     if (NS_FAILED(rv)) return rv;
 
     // make the cached response be the current response
-    delete mResponseHead;
     mResponseHead = mCachedResponseHead;
-    mCachedResponseHead = 0;
 
     rv = UpdateExpirationTime();
     if (NS_FAILED(rv)) return rv;
 
     // notify observers interested in looking at a response that has been
     // merged with any cached headers (http-on-examine-merged-response).
     gHttpHandler->OnExamineMergedResponse(this);
 
@@ -1492,19 +1372,17 @@ nsHttpChannel::ProcessNotModified()
 
     // update the cached response head
     nsCAutoString head;
     mCachedResponseHead->Flatten(head, PR_TRUE);
     rv = mCacheEntry->SetMetaDataElement("response-head", head.get());
     if (NS_FAILED(rv)) return rv;
 
     // make the cached response be the current response
-    delete mResponseHead;
     mResponseHead = mCachedResponseHead;
-    mCachedResponseHead = 0;
 
     rv = UpdateExpirationTime();
     if (NS_FAILED(rv)) return rv;
 
     // notify observers interested in looking at a reponse that has been
     // merged with any cached headers
     gHttpHandler->OnExamineMergedResponse(this);
 
@@ -2022,17 +1900,16 @@ nsHttpChannel::CheckCache()
     PRBool fromPreviousSession =
             (gHttpHandler->SessionStartTime() > lastModifiedTime);
 
     // Get the cached HTTP response headers
     rv = mCacheEntry->GetMetaDataElement("response-head", getter_Copies(buf));
     NS_ENSURE_SUCCESS(rv, rv);
 
     // Parse the cached HTTP response headers
-    NS_ASSERTION(!mCachedResponseHead, "memory leak detected");
     mCachedResponseHead = new nsHttpResponseHead();
     if (!mCachedResponseHead)
         return NS_ERROR_OUT_OF_MEMORY;
     rv = mCachedResponseHead->Parse((char *) buf.get());
     NS_ENSURE_SUCCESS(rv, rv);
     buf.Adopt(0);
 
     // Don't bother to validate items that are read-only,
@@ -2317,21 +2194,18 @@ nsHttpChannel::ReadFromCache()
     nsresult rv;
 
     NS_ENSURE_TRUE(mCacheEntry, NS_ERROR_FAILURE);
     NS_ENSURE_TRUE(mCachedContentIsValid, NS_ERROR_FAILURE);
 
     LOG(("nsHttpChannel::ReadFromCache [this=%p] "
          "Using cached copy of: %s\n", this, mSpec.get()));
 
-    if (mCachedResponseHead) {
-        NS_ASSERTION(!mResponseHead, "memory leak");
+    if (mCachedResponseHead)
         mResponseHead = mCachedResponseHead;
-        mCachedResponseHead = 0;
-    }
 
     // if we don't already have security info, try to get it from the cache 
     // entry. there are two cases to consider here: 1) we are just reading
     // from the cache, or 2) this may be due to a 304 not modified response,
     // in which case we could have security info from a socket transport.
     if (!mSecurityInfo)
         mCacheEntry->GetSecurityInfo(getter_AddRefs(mSecurityInfo));
 
@@ -2403,20 +2277,17 @@ nsHttpChannel::CloseCacheEntry(PRBool do
     else if (mCacheAccess == nsICache::ACCESS_WRITE)
         doom = PR_TRUE;
 
     if (doom) {
         LOG(("  dooming cache entry!!"));
         mCacheEntry->Doom();
     }
 
-    if (mCachedResponseHead) {
-        delete mCachedResponseHead;
-        mCachedResponseHead = 0;
-    }
+    mCachedResponseHead = nsnull;
 
     mCachePump = 0;
     mCacheEntry = 0;
     mCacheAccess = 0;
     mInitedCacheEntry = PR_FALSE;
 }
 
 
@@ -4112,18 +3983,18 @@ nsHttpChannel::GetCurrentPath(nsACString
         rv = mURI->GetPath(path);
     return rv;
 }
 
 //-----------------------------------------------------------------------------
 // nsHttpChannel::nsISupports
 //-----------------------------------------------------------------------------
 
-NS_IMPL_ADDREF_INHERITED(nsHttpChannel, nsHashPropertyBag)
-NS_IMPL_RELEASE_INHERITED(nsHttpChannel, nsHashPropertyBag)
+NS_IMPL_ADDREF_INHERITED(nsHttpChannel, HttpBaseChannel)
+NS_IMPL_RELEASE_INHERITED(nsHttpChannel, HttpBaseChannel)
 
 NS_INTERFACE_MAP_BEGIN(nsHttpChannel)
     NS_INTERFACE_MAP_ENTRY(nsIRequest)
     NS_INTERFACE_MAP_ENTRY(nsIChannel)
     NS_INTERFACE_MAP_ENTRY(nsIRequestObserver)
     NS_INTERFACE_MAP_ENTRY(nsIStreamListener)
     NS_INTERFACE_MAP_ENTRY(nsIHttpChannel)
     NS_INTERFACE_MAP_ENTRY(nsICachingChannel)
@@ -4136,46 +4007,23 @@ NS_INTERFACE_MAP_BEGIN(nsHttpChannel)
     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)
+NS_INTERFACE_MAP_END_INHERITING(HttpBaseChannel)
 
 //-----------------------------------------------------------------------------
 // nsHttpChannel::nsIRequest
 //-----------------------------------------------------------------------------
 
 NS_IMETHODIMP
-nsHttpChannel::GetName(nsACString &aName)
-{
-    aName = mSpec;
-    return NS_OK;
-}
-
-NS_IMETHODIMP
-nsHttpChannel::IsPending(PRBool *value)
-{
-    NS_ENSURE_ARG_POINTER(value);
-    *value = mIsPending;
-    return NS_OK;
-}
-
-NS_IMETHODIMP
-nsHttpChannel::GetStatus(nsresult *aStatus)
-{
-    NS_ENSURE_ARG_POINTER(aStatus);
-    *aStatus = mStatus;
-    return NS_OK;
-}
-
-NS_IMETHODIMP
 nsHttpChannel::Cancel(nsresult status)
 {
     LOG(("nsHttpChannel::Cancel [this=%p status=%x]\n", this, status));
     if (mCanceled) {
         LOG(("  ignoring; already canceled\n"));
         return NS_OK;
     }
     mCanceled = PR_TRUE;
@@ -4226,211 +4074,46 @@ nsHttpChannel::Resume()
     if (mTransactionPump)
         return mTransactionPump->Resume();
     if (mCachePump)
         return mCachePump->Resume();
 
     return NS_OK;
 }
 
-NS_IMETHODIMP
-nsHttpChannel::GetLoadGroup(nsILoadGroup **aLoadGroup)
-{
-    NS_ENSURE_ARG_POINTER(aLoadGroup);
-    *aLoadGroup = mLoadGroup;
-    NS_IF_ADDREF(*aLoadGroup);
-    return NS_OK;
-}
-NS_IMETHODIMP
-nsHttpChannel::SetLoadGroup(nsILoadGroup *aLoadGroup)
-{
-    mLoadGroup = aLoadGroup;
-    mProgressSink = nsnull;
-    return NS_OK;
-}
-
-NS_IMETHODIMP
-nsHttpChannel::GetLoadFlags(nsLoadFlags *aLoadFlags)
-{
-    NS_ENSURE_ARG_POINTER(aLoadFlags);
-    *aLoadFlags = mLoadFlags;
-    return NS_OK;
-}
-NS_IMETHODIMP
-nsHttpChannel::SetLoadFlags(nsLoadFlags aLoadFlags)
-{
-    mLoadFlags = aLoadFlags;
-    return NS_OK;
-}
-
 //-----------------------------------------------------------------------------
 // nsHttpChannel::nsIChannel
 //-----------------------------------------------------------------------------
 
 NS_IMETHODIMP
-nsHttpChannel::GetOriginalURI(nsIURI **originalURI)
-{
-    NS_ENSURE_ARG_POINTER(originalURI);
-    *originalURI = mOriginalURI;
-    NS_ADDREF(*originalURI);
-    return NS_OK;
-}
-NS_IMETHODIMP
-nsHttpChannel::SetOriginalURI(nsIURI *originalURI)
-{
-    NS_ENSURE_ARG_POINTER(originalURI);
-    mOriginalURI = originalURI;
-    return NS_OK;
-}
-
-NS_IMETHODIMP
-nsHttpChannel::GetURI(nsIURI **URI)
-{
-    NS_ENSURE_ARG_POINTER(URI);
-    *URI = mURI;
-    NS_IF_ADDREF(*URI);
-    return NS_OK;
-}
-
-NS_IMETHODIMP
 nsHttpChannel::GetOwner(nsISupports **owner)
 {
     NS_ENSURE_ARG_POINTER(owner);
     *owner = mOwner;
     NS_IF_ADDREF(*owner);
     return NS_OK;
 }
+
 NS_IMETHODIMP
 nsHttpChannel::SetOwner(nsISupports *owner)
 {
     mOwner = owner;
     return NS_OK;
 }
 
 NS_IMETHODIMP
-nsHttpChannel::GetNotificationCallbacks(nsIInterfaceRequestor **callbacks)
-{
-    NS_IF_ADDREF(*callbacks = mCallbacks);
-    return NS_OK;
-}
-NS_IMETHODIMP
-nsHttpChannel::SetNotificationCallbacks(nsIInterfaceRequestor *callbacks)
-{
-    mCallbacks = callbacks;
-    mProgressSink = nsnull;
-    return NS_OK;
-}
-
-NS_IMETHODIMP
 nsHttpChannel::GetSecurityInfo(nsISupports **securityInfo)
 {
     NS_ENSURE_ARG_POINTER(securityInfo);
     *securityInfo = mSecurityInfo;
     NS_IF_ADDREF(*securityInfo);
     return NS_OK;
 }
 
 NS_IMETHODIMP
-nsHttpChannel::GetContentType(nsACString &value)
-{
-    if (!mResponseHead) {
-        // We got no data, we got no headers, we got nothing
-        value.Truncate();
-        return NS_ERROR_NOT_AVAILABLE;
-    }
-
-    if (!mResponseHead->ContentType().IsEmpty()) {
-        value = mResponseHead->ContentType();
-        return NS_OK;
-    }
-
-    
-    value.AssignLiteral(UNKNOWN_CONTENT_TYPE);
-    return NS_OK;
-}
-
-NS_IMETHODIMP
-nsHttpChannel::SetContentType(const nsACString &value)
-{
-    if (mListener || mWasOpened) {
-        if (!mResponseHead)
-            return NS_ERROR_NOT_AVAILABLE;
-
-        nsCAutoString contentTypeBuf, charsetBuf;
-        PRBool hadCharset;
-        net_ParseContentType(value, contentTypeBuf, charsetBuf, &hadCharset);
-
-        mResponseHead->SetContentType(contentTypeBuf);
-
-        // take care not to stomp on an existing charset
-        if (hadCharset)
-            mResponseHead->SetContentCharset(charsetBuf);
-    } else {
-        // We are being given a content-type hint.
-        PRBool dummy;
-        net_ParseContentType(value, mContentTypeHint, mContentCharsetHint,
-                             &dummy);
-    }
-    
-    return NS_OK;
-}
-
-NS_IMETHODIMP
-nsHttpChannel::GetContentCharset(nsACString &value)
-{
-    if (!mResponseHead)
-        return NS_ERROR_NOT_AVAILABLE;
-
-    value = mResponseHead->ContentCharset();
-    return NS_OK;
-}
-
-NS_IMETHODIMP
-nsHttpChannel::SetContentCharset(const nsACString &value)
-{
-    if (mListener) {
-        if (!mResponseHead)
-            return NS_ERROR_NOT_AVAILABLE;
-
-        mResponseHead->SetContentCharset(value);
-    } else {
-        // Charset hint
-        mContentCharsetHint = value;
-    }
-    return NS_OK;
-}
-
-NS_IMETHODIMP
-nsHttpChannel::GetContentLength(PRInt32 *value)
-{
-    NS_ENSURE_ARG_POINTER(value);
-
-    if (!mResponseHead)
-        return NS_ERROR_NOT_AVAILABLE;
-
-    // XXX truncates to 32 bit
-    LL_L2I(*value, mResponseHead->ContentLength());
-    return NS_OK;
-}
-
-NS_IMETHODIMP
-nsHttpChannel::SetContentLength(PRInt32 value)
-{
-    NS_NOTYETIMPLEMENTED("nsHttpChannel::SetContentLength");
-    return NS_ERROR_NOT_IMPLEMENTED;
-}
-
-NS_IMETHODIMP
-nsHttpChannel::Open(nsIInputStream **_retval)
-{
-    NS_ENSURE_TRUE(!mWasOpened, NS_ERROR_IN_PROGRESS);
-    return NS_ImplementChannelOpen(this, _retval);
-}
-
-NS_IMETHODIMP
 nsHttpChannel::AsyncOpen(nsIStreamListener *listener, nsISupports *context)
 {
     LOG(("nsHttpChannel::AsyncOpen [this=%p]\n", this));
 
     NS_ENSURE_ARG_POINTER(listener);
     NS_ENSURE_TRUE(!mIsPending, NS_ERROR_IN_PROGRESS);
     NS_ENSURE_TRUE(!mWasOpened, NS_ERROR_ALREADY_OPENED);
 
@@ -4491,245 +4174,35 @@ nsHttpChannel::AsyncOpen(nsIStreamListen
         rv = Connect();
     if (NS_FAILED(rv)) {
         LOG(("Calling AsyncAbort [rv=%x mCanceled=%i]\n", rv, mCanceled));
         CloseCacheEntry(PR_TRUE);
         AsyncAbort(rv);
     }
     return NS_OK;
 }
+
 //-----------------------------------------------------------------------------
-// nsHttpChannel::nsIHttpChannel
+// nsHttpChannel::nsIHttpChannelInternal
 //-----------------------------------------------------------------------------
 
 NS_IMETHODIMP
-nsHttpChannel::GetRequestMethod(nsACString &method)
-{
-    method = mRequestHead.Method();
-    return NS_OK;
-}
-NS_IMETHODIMP
-nsHttpChannel::SetRequestMethod(const nsACString &method)
+nsHttpChannel::SetupFallbackChannel(const char *aFallbackKey)
 {
-    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
-nsHttpChannel::GetReferrer(nsIURI **referrer)
-{
-    NS_ENSURE_ARG_POINTER(referrer);
-    *referrer = mReferrer;
-    NS_IF_ADDREF(*referrer);
+    LOG(("nsHttpChannel::SetupFallbackChannel [this=%x, key=%s]",
+         this, aFallbackKey));
+    mFallbackChannel = PR_TRUE;
+    mFallbackKey = aFallbackKey;
+
     return NS_OK;
 }
-
-NS_IMETHODIMP
-nsHttpChannel::SetReferrer(nsIURI *referrer)
-{
-    NS_ENSURE_TRUE(!mIsPending, NS_ERROR_IN_PROGRESS);
-
-    // clear existing referrer, if any
-    mReferrer = nsnull;
-    mRequestHead.ClearHeader(nsHttp::Referer);
-
-    if (!referrer)
-        return NS_OK;
-
-    // check referrer blocking pref
-    PRUint32 referrerLevel;
-    if (mLoadFlags & LOAD_INITIAL_DOCUMENT_URI)
-        referrerLevel = 1; // user action
-    else
-        referrerLevel = 2; // inline content
-    if (gHttpHandler->ReferrerLevel() < referrerLevel)
-        return NS_OK;
-
-    nsCOMPtr<nsIURI> referrerGrip;
-    nsresult rv;
-    PRBool match;
-
-    //
-    // Strip off "wyciwyg://123/" from wyciwyg referrers.
-    //
-    // XXX this really belongs elsewhere since wyciwyg URLs aren't part of necko.
-    //     perhaps some sort of generic nsINestedURI could be used.  then, if an URI
-    //     fails the whitelist test, then we could check for an inner URI and try
-    //     that instead.  though, that might be too automatic.
-    // 
-    rv = referrer->SchemeIs("wyciwyg", &match);
-    if (NS_FAILED(rv)) return rv;
-    if (match) {
-        nsCAutoString path;
-        rv = referrer->GetPath(path);
-        if (NS_FAILED(rv)) return rv;
-
-        PRUint32 pathLength = path.Length();
-        if (pathLength <= 2) return NS_ERROR_FAILURE;
-
-        // Path is of the form "//123/http://foo/bar", with a variable number of digits.
-        // To figure out where the "real" URL starts, search path for a '/', starting at 
-        // the third character.
-        PRInt32 slashIndex = path.FindChar('/', 2);
-        if (slashIndex == kNotFound) return NS_ERROR_FAILURE;
-
-        // Get the charset of the original URI so we can pass it to our fixed up URI.
-        nsCAutoString charset;
-        referrer->GetOriginCharset(charset);
-
-        // Replace |referrer| with a URI without wyciwyg://123/.
-        rv = NS_NewURI(getter_AddRefs(referrerGrip),
-                       Substring(path, slashIndex + 1, pathLength - slashIndex - 1),
-                       charset.get());
-        if (NS_FAILED(rv)) return rv;
-
-        referrer = referrerGrip.get();
-    }
-
-    //
-    // block referrer if not on our white list...
-    //
-    static const char *const referrerWhiteList[] = {
-        "http",
-        "https",
-        "ftp",
-        "gopher",
-        nsnull
-    };
-    match = PR_FALSE;
-    const char *const *scheme = referrerWhiteList;
-    for (; *scheme && !match; ++scheme) {
-        rv = referrer->SchemeIs(*scheme, &match);
-        if (NS_FAILED(rv)) return rv;
-    }
-    if (!match)
-        return NS_OK; // kick out....
-
-    //
-    // Handle secure referrals.
-    //
-    // Support referrals from a secure server if this is a secure site
-    // and (optionally) if the host names are the same.
-    //
-    rv = referrer->SchemeIs("https", &match);
-    if (NS_FAILED(rv)) return rv;
-    if (match) {
-        rv = mURI->SchemeIs("https", &match);
-        if (NS_FAILED(rv)) return rv;
-        if (!match)
-            return NS_OK;
-
-        if (!gHttpHandler->SendSecureXSiteReferrer()) {
-            nsCAutoString referrerHost;
-            nsCAutoString host;
-
-            rv = referrer->GetAsciiHost(referrerHost);
-            if (NS_FAILED(rv)) return rv;
-
-            rv = mURI->GetAsciiHost(host);
-            if (NS_FAILED(rv)) return rv;
-
-            // GetAsciiHost returns lowercase hostname.
-            if (!referrerHost.Equals(host))
-                return NS_OK;
-        }
-    }
-
-    nsCOMPtr<nsIURI> clone;
-    //
-    // we need to clone the referrer, so we can:
-    //  (1) modify it
-    //  (2) keep a reference to it after returning from this function
-    //
-    rv = referrer->Clone(getter_AddRefs(clone));
-    if (NS_FAILED(rv)) return rv;
-
-    // strip away any userpass; we don't want to be giving out passwords ;-)
-    clone->SetUserPass(EmptyCString());
-
-    // strip away any fragment per RFC 2616 section 14.36
-    nsCOMPtr<nsIURL> url = do_QueryInterface(clone);
-    if (url)
-        url->SetRef(EmptyCString());
-
-    nsCAutoString spec;
-    rv = clone->GetAsciiSpec(spec);
-    if (NS_FAILED(rv)) return rv;
-
-    // finally, remember the referrer URI and set the Referer header.
-    mReferrer = clone;
-    mRequestHead.SetHeader(nsHttp::Referer, spec);
-    return NS_OK;
-}
-
-NS_IMETHODIMP
-nsHttpChannel::GetRequestHeader(const nsACString &header, nsACString &value)
-{
-    // XXX might be better to search the header list directly instead of
-    // hitting the http atom hash table.
-
-    nsHttpAtom atom = nsHttp::ResolveAtom(header);
-    if (!atom)
-        return NS_ERROR_NOT_AVAILABLE;
-
-    return mRequestHead.GetHeader(atom, value);
-}
-
-NS_IMETHODIMP
-nsHttpChannel::SetRequestHeader(const nsACString &header,
-                                const nsACString &value,
-                                PRBool merge)
-{
-    NS_ENSURE_TRUE(!mIsPending, NS_ERROR_IN_PROGRESS);
-
-    const nsCString &flatHeader = PromiseFlatCString(header);
-    const nsCString &flatValue  = PromiseFlatCString(value);
-
-    LOG(("nsHttpChannel::SetRequestHeader [this=%p header=\"%s\" value=\"%s\" merge=%u]\n",
-        this, flatHeader.get(), flatValue.get(), merge));
-
-    // Header names are restricted to valid HTTP tokens.
-    if (!nsHttp::IsValidToken(flatHeader))
-        return NS_ERROR_INVALID_ARG;
-    
-    // Header values MUST NOT contain line-breaks.  RFC 2616 technically
-    // permits CTL characters, including CR and LF, in header values provided
-    // they are quoted.  However, this can lead to problems if servers do not
-    // interpret quoted strings properly.  Disallowing CR and LF here seems
-    // reasonable and keeps things simple.  We also disallow a null byte.
-    if (flatValue.FindCharInSet("\r\n") != kNotFound ||
-        flatValue.Length() != strlen(flatValue.get()))
-        return NS_ERROR_INVALID_ARG;
-
-    nsHttpAtom atom = nsHttp::ResolveAtom(flatHeader.get());
-    if (!atom) {
-        NS_WARNING("failed to resolve atom");
-        return NS_ERROR_NOT_AVAILABLE;
-    }
-
-    return mRequestHead.SetHeader(atom, flatValue, merge);
-}
-
-NS_IMETHODIMP
-nsHttpChannel::VisitRequestHeaders(nsIHttpHeaderVisitor *visitor)
-{
-    return mRequestHead.Headers().VisitHeaders(visitor);
-}
+ 
+//-----------------------------------------------------------------------------
+// nsHttpChannel::nsIUploadChannel
+//-----------------------------------------------------------------------------
 
 NS_IMETHODIMP
 nsHttpChannel::GetUploadStream(nsIInputStream **stream)
 {
     NS_ENSURE_ARG_POINTER(stream);
     *stream = mUploadStream;
     NS_IF_ADDREF(*stream);
     return NS_OK;
@@ -4770,16 +4243,20 @@ nsHttpChannel::SetUploadStream(nsIInputS
     else {
         mUploadStreamHasHeaders = PR_FALSE;
         mRequestHead.SetMethod(nsHttp::Get); // revert to GET request
     }
     mUploadStream = stream;
     return NS_OK;
 }
 
+//-----------------------------------------------------------------------------
+// nsHttpChannel::nsIUploadChannel2
+//-----------------------------------------------------------------------------
+
 NS_IMETHODIMP
 nsHttpChannel::ExplicitSetUploadStream(nsIInputStream *aStream,
                                        const nsACString &aContentType,
                                        PRInt64 aContentLength,
                                        const nsACString &aMethod,
                                        PRBool aStreamHasHeaders)
 {
     // Ensure stream is set and method is valid 
@@ -4804,111 +4281,19 @@ nsHttpChannel::ExplicitSetUploadStream(n
         mRequestHead.SetHeader(nsHttp::Content_Type, aContentType);
     }
 
     mUploadStreamHasHeaders = aStreamHasHeaders;
     mUploadStream = aStream;
     return NS_OK;
 }
 
-NS_IMETHODIMP
-nsHttpChannel::GetResponseStatus(PRUint32 *value)
-{
-    NS_ENSURE_ARG_POINTER(value);
-    if (!mResponseHead)
-        return NS_ERROR_NOT_AVAILABLE;
-    *value = mResponseHead->Status();
-    return NS_OK;
-}
-
-NS_IMETHODIMP
-nsHttpChannel::GetResponseStatusText(nsACString &value)
-{
-    if (!mResponseHead)
-        return NS_ERROR_NOT_AVAILABLE;
-    value = mResponseHead->StatusText();
-    return NS_OK;
-}
-
-NS_IMETHODIMP
-nsHttpChannel::GetRequestSucceeded(PRBool *value)
-{
-    NS_PRECONDITION(value, "Don't ever pass a null arg to this function");
-    if (!mResponseHead)
-        return NS_ERROR_NOT_AVAILABLE;
-    PRUint32 status = mResponseHead->Status();
-    *value = (status / 100 == 2);
-    return NS_OK;
-}
-
-NS_IMETHODIMP
-nsHttpChannel::GetResponseHeader(const nsACString &header, nsACString &value)
-{
-    if (!mResponseHead)
-        return NS_ERROR_NOT_AVAILABLE;
-    nsHttpAtom atom = nsHttp::ResolveAtom(header);
-    if (!atom)
-        return NS_ERROR_NOT_AVAILABLE;
-    return mResponseHead->GetHeader(atom, value);
-}
-
-NS_IMETHODIMP
-nsHttpChannel::SetResponseHeader(const nsACString &header,
-                                 const nsACString &value,
-                                 PRBool merge)
-{
-    LOG(("nsHttpChannel::SetResponseHeader [this=%p header=\"%s\" value=\"%s\" merge=%u]\n",
-        this, PromiseFlatCString(header).get(), PromiseFlatCString(value).get(), merge));
-
-    if (!mResponseHead)
-        return NS_ERROR_NOT_AVAILABLE;
-    nsHttpAtom atom = nsHttp::ResolveAtom(header);
-    if (!atom)
-        return NS_ERROR_NOT_AVAILABLE;
-
-    // these response headers must not be changed 
-    if (atom == nsHttp::Content_Type ||
-        atom == nsHttp::Content_Length ||
-        atom == nsHttp::Content_Encoding ||
-        atom == nsHttp::Trailer ||
-        atom == nsHttp::Transfer_Encoding)
-        return NS_ERROR_ILLEGAL_VALUE;
-
-    mResponseHeadersModified = PR_TRUE;
-
-    return mResponseHead->SetHeader(atom, value, merge);
-}
-
-NS_IMETHODIMP
-nsHttpChannel::VisitResponseHeaders(nsIHttpHeaderVisitor *visitor)
-{
-    if (!mResponseHead)
-        return NS_ERROR_NOT_AVAILABLE;
-    return mResponseHead->Headers().VisitHeaders(visitor);
-}
-
-NS_IMETHODIMP
-nsHttpChannel::IsNoStoreResponse(PRBool *value)
-{
-    if (!mResponseHead)
-        return NS_ERROR_NOT_AVAILABLE;
-    *value = mResponseHead->NoStore();
-    return NS_OK;
-}
-
-NS_IMETHODIMP
-nsHttpChannel::IsNoCacheResponse(PRBool *value)
-{
-    if (!mResponseHead)
-        return NS_ERROR_NOT_AVAILABLE;
-    *value = mResponseHead->NoCache();
-    if (!*value)
-        *value = mResponseHead->ExpiresInPast();
-    return NS_OK;
-}
+//-----------------------------------------------------------------------------
+// nsHttpChannel::nsIEncodedChannel
+//-----------------------------------------------------------------------------
 
 NS_IMETHODIMP
 nsHttpChannel::GetApplyConversion(PRBool *value)
 {
     NS_ENSURE_ARG_POINTER(value);
     *value = mApplyConversion;
     return NS_OK;
 }
@@ -4917,48 +4302,16 @@ NS_IMETHODIMP
 nsHttpChannel::SetApplyConversion(PRBool value)
 {
     LOG(("nsHttpChannel::SetApplyConversion [this=%p value=%d]\n", this, value));
     mApplyConversion = value;
     return NS_OK;
 }
 
 NS_IMETHODIMP
-nsHttpChannel::GetAllowPipelining(PRBool *value)
-{
-    NS_ENSURE_ARG_POINTER(value);
-    *value = mAllowPipelining;
-    return NS_OK;
-}
-
-NS_IMETHODIMP
-nsHttpChannel::SetAllowPipelining(PRBool value)
-{
-    if (mIsPending)
-        return NS_ERROR_FAILURE;
-    mAllowPipelining = value;
-    return NS_OK;
-}
-
-NS_IMETHODIMP
-nsHttpChannel::GetRedirectionLimit(PRUint32 *value)
-{
-    NS_ENSURE_ARG_POINTER(value);
-    *value = PRUint32(mRedirectionLimit);
-    return NS_OK;
-}
-
-NS_IMETHODIMP
-nsHttpChannel::SetRedirectionLimit(PRUint32 value)
-{
-    mRedirectionLimit = PR_MIN(value, 0xff);
-    return NS_OK;
-}
-
-NS_IMETHODIMP
 nsHttpChannel::GetContentEncodings(nsIUTF8StringEnumerator** aEncodings)
 {
     NS_PRECONDITION(aEncodings, "Null out param");
     if (!mResponseHead) {
         *aEncodings = nsnull;
         return NS_OK;
     }
     
@@ -4971,114 +4324,16 @@ nsHttpChannel::GetContentEncodings(nsIUT
     if (!enumerator)
         return NS_ERROR_OUT_OF_MEMORY;
 
     NS_ADDREF(*aEncodings = enumerator);
     return NS_OK;
 }
 
 //-----------------------------------------------------------------------------
-// nsHttpChannel::nsIHttpChannelInternal
-//-----------------------------------------------------------------------------
-
-NS_IMETHODIMP
-nsHttpChannel::GetDocumentURI(nsIURI **aDocumentURI)
-{
-    NS_ENSURE_ARG_POINTER(aDocumentURI);
-    *aDocumentURI = mDocumentURI;
-    NS_IF_ADDREF(*aDocumentURI);
-    return NS_OK;
-}
-
-NS_IMETHODIMP
-nsHttpChannel::SetDocumentURI(nsIURI *aDocumentURI)
-{
-    mDocumentURI = aDocumentURI;
-    return NS_OK;
-}
-
-NS_IMETHODIMP
-nsHttpChannel::GetForceAllowThirdPartyCookie(PRBool *aForceAllowThirdPartyCookie)
-{
-    *aForceAllowThirdPartyCookie = mForceAllowThirdPartyCookie;
-    return NS_OK;
-}
-
-NS_IMETHODIMP
-nsHttpChannel::SetForceAllowThirdPartyCookie(PRBool aForceAllowThirdPartyCookie)
-{
-    mForceAllowThirdPartyCookie = aForceAllowThirdPartyCookie;
-    return NS_OK;
-}
-
-NS_IMETHODIMP
-nsHttpChannel::GetRequestVersion(PRUint32 *major, PRUint32 *minor)
-{
-  int version = mRequestHead.Version();
-
-  if (major) { *major = version / 10; }
-  if (minor) { *minor = version % 10; }
-
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-nsHttpChannel::GetResponseVersion(PRUint32 *major, PRUint32 *minor)
-{
-  if (!mResponseHead)
-  {
-    *major = *minor = 0;                   // we should at least be kind about it
-    return NS_ERROR_NOT_AVAILABLE;
-  }
-
-  int version = mResponseHead->Version();
-
-  if (major) { *major = version / 10; }
-  if (minor) { *minor = version % 10; }
-
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-nsHttpChannel::SetCookie(const char *aCookieHeader)
-{
-    if (mLoadFlags & LOAD_ANONYMOUS) {
-      return NS_OK;
-    }
-
-    // empty header isn't an error
-    if (!(aCookieHeader && *aCookieHeader))
-        return NS_OK;
-
-    nsICookieService *cs = gHttpHandler->GetCookieService();
-    NS_ENSURE_TRUE(cs, NS_ERROR_FAILURE);
-
-    nsCOMPtr<nsIPrompt> prompt;
-    GetCallback(prompt);
-
-    return cs->SetCookieStringFromHttp(mURI,
-                                       mDocumentURI ? mDocumentURI : mOriginalURI,
-                                       prompt,
-                                       aCookieHeader,
-                                       mResponseHead->PeekHeader(nsHttp::Date),
-                                       this);
-}
-
-NS_IMETHODIMP
-nsHttpChannel::SetupFallbackChannel(const char *aFallbackKey)
-{
-    LOG(("nsHttpChannel::SetupFallbackChannel [this=%p, key=%s]",
-         this, aFallbackKey));
-    mFallbackChannel = PR_TRUE;
-    mFallbackKey = aFallbackKey;
-
-    return NS_OK;
-}
-
-//-----------------------------------------------------------------------------
 // nsHttpChannel::nsISupportsPriority
 //-----------------------------------------------------------------------------
 
 NS_IMETHODIMP
 nsHttpChannel::GetPriority(PRInt32 *value)
 {
     *value = mPriority;
     return NS_OK;
@@ -5166,18 +4421,16 @@ nsHttpChannel::OnStartRequest(nsIRequest
     if (!mSecurityInfo && !mCachePump && mTransaction) {
         // grab the security info from the connection object; the transaction
         // is guaranteed to own a reference to the connection.
         mSecurityInfo = mTransaction->SecurityInfo();
     }
 
     // don't enter this block if we're reading from the cache...
     if (NS_SUCCEEDED(mStatus) && !mCachePump && mTransaction) {
-        NS_ASSERTION(mResponseHead == nsnull, "leaking mResponseHead");
-
         // all of the response headers have been acquired, so we can take ownership
         // of them from the transaction.
         mResponseHead = mTransaction->TakeResponseHead();
         // the response head may be null if the transaction was cancelled.  in
         // which case we just need to call OnStartRequest/OnStopRequest.
         if (mResponseHead)
             return ProcessResponse();
 
@@ -5262,17 +4515,17 @@ nsHttpChannel::OnStopRequest(nsIRequest 
             // This is so far a workaround to fix leak when reusing unpersistent
             // connection for authentication retry. See bug 459620 comment 4
             // for details.
             if (conn && !conn->IsPersistent())
                 conn = nsnull;
         }
 
         // at this point, we're done with the transaction
-        NS_RELEASE(mTransaction);
+        mTransaction = nsnull;
         mTransactionPump = 0;
 
         // handle auth retry...
         if (authRetry) {
             mAuthRetryPending = PR_FALSE;
             status = DoAuthRetry(conn);
             if (NS_SUCCEEDED(status))
                 return NS_OK;
@@ -5708,17 +4961,16 @@ nsHttpChannel::DoAuthRetry(nsAHttpConnec
     AddCookiesToRequest();
 
     // notify "http-on-modify-request" observers
     gHttpHandler->OnModifyRequest(this);
 
     mIsPending = PR_TRUE;
 
     // get rid of the old response headers
-    delete mResponseHead;
     mResponseHead = nsnull;
 
     // set sticky connection flag and disable pipelining.
     mCaps |=  NS_HTTP_STICKY_CONNECTION;
     mCaps &= ~NS_HTTP_ALLOW_PIPELINING;
    
     // and create a new one...
     rv = SetupTransaction();
--- a/netwerk/protocol/http/src/nsHttpChannel.h
+++ b/netwerk/protocol/http/src/nsHttpChannel.h
@@ -18,16 +18,17 @@
  * 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):
  *   Darin Fisher <darin@netscape.com> (original author)
  *   Christian Biesinger <cbiesinger@web.de>
+ *   Daniel Witte <dwitte@mozilla.com>
  *
  * 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
@@ -36,74 +37,52 @@
  * 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 nsHttpChannel_h__
 #define nsHttpChannel_h__
 
+#include "HttpBaseChannel.h"
+
 #include "nsHttpTransaction.h"
-#include "nsHttpRequestHead.h"
 #include "nsHttpAuthCache.h"
-#include "nsHashPropertyBag.h"
 #include "nsInputStreamPump.h"
 #include "nsThreadUtils.h"
-#include "nsString.h"
-#include "nsAutoPtr.h"
-#include "nsCOMPtr.h"
-#include "nsInt64.h"
 
-#include "nsIHttpChannel.h"
-#include "nsIHttpChannelInternal.h"
-#include "nsIHttpHeaderVisitor.h"
 #include "nsIHttpEventSink.h"
-#include "nsIChannelEventSink.h"
-#include "nsIStreamListener.h"
-#include "nsIIOService.h"
-#include "nsIURI.h"
-#include "nsILoadGroup.h"
-#include "nsIInterfaceRequestor.h"
-#include "nsIInterfaceRequestorUtils.h"
-#include "nsIInputStream.h"
-#include "nsIProgressEventSink.h"
 #include "nsICachingChannel.h"
-#include "nsICacheSession.h"
 #include "nsICacheEntryDescriptor.h"
 #include "nsICacheListener.h"
 #include "nsIApplicationCache.h"
 #include "nsIApplicationCacheChannel.h"
 #include "nsIEncodedChannel.h"
-#include "nsITransport.h"
 #include "nsIUploadChannel.h"
 #include "nsIUploadChannel2.h"
 #include "nsIStringEnumerator.h"
-#include "nsIOutputStream.h"
-#include "nsIAsyncInputStream.h"
 #include "nsIPrompt.h"
 #include "nsIResumableChannel.h"
 #include "nsISupportsPriority.h"
 #include "nsIProtocolProxyCallback.h"
 #include "nsICancelable.h"
 #include "nsIProxiedChannel.h"
 #include "nsITraceableChannel.h"
 #include "nsIAuthPromptCallback.h"
 
-class nsHttpResponseHead;
 class nsAHttpConnection;
 class nsIHttpAuthenticator;
-class nsProxyInfo;
+
+using namespace mozilla::net;
 
 //-----------------------------------------------------------------------------
 // nsHttpChannel
 //-----------------------------------------------------------------------------
 
-class nsHttpChannel : public nsHashPropertyBag
-                    , public nsIHttpChannel
-                    , public nsIHttpChannelInternal
+class nsHttpChannel : public HttpBaseChannel
                     , public nsIStreamListener
                     , public nsICachingChannel
                     , public nsIUploadChannel
                     , public nsIUploadChannel2
                     , public nsICacheListener
                     , public nsIEncodedChannel
                     , public nsITransportEventSink
                     , public nsIResumableChannel
@@ -111,45 +90,53 @@ class nsHttpChannel : public nsHashPrope
                     , 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_NSIREQUESTOBSERVER
     NS_DECL_NSISTREAMLISTENER
     NS_DECL_NSICACHINGCHANNEL
     NS_DECL_NSIUPLOADCHANNEL
     NS_DECL_NSIUPLOADCHANNEL2
     NS_DECL_NSICACHELISTENER
     NS_DECL_NSIENCODEDCHANNEL
-    NS_DECL_NSIHTTPCHANNELINTERNAL
     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
 
     nsHttpChannel();
     virtual ~nsHttpChannel();
 
-    nsresult Init(nsIURI *uri,
-                  PRUint8 capabilities,
-                  nsProxyInfo* proxyInfo);
+    // Methods HttpBaseChannel didn't implement for us or that we override.
+    //
+    // nsIRequest
+    NS_IMETHOD Cancel(nsresult status);
+    NS_IMETHOD Suspend();
+    NS_IMETHOD Resume();
+    // nsIChannel
+    NS_IMETHOD GetOwner(nsISupports **aOwner);
+    NS_IMETHOD SetOwner(nsISupports *aOwner);
+    NS_IMETHOD GetSecurityInfo(nsISupports **aSecurityInfo);
+    NS_IMETHOD AsyncOpen(nsIStreamListener *listener, nsISupports *aContext);
+    // nsIHttpChannelInternal
+    NS_IMETHOD SetupFallbackChannel(const char *aFallbackKey);
 
-public: /* internal; workaround lame compilers */ 
+
+
+public: /* internal necko use only */ 
     typedef void (nsHttpChannel:: *nsAsyncCallback)(void);
     nsHttpResponseHead * GetResponseHead() const { return mResponseHead; }
 private:
 
     // Helper function to simplify getting notification callbacks.
     template <class T>
     void GetCallback(nsCOMPtr<T> &aResult)
     {
@@ -258,53 +245,33 @@ private:
     /**
      * Method called to resume suspended transaction after we got credentials
      * from the user. Called from OnAuthAvailable callback or OnAuthCancelled
      * when credentials for next challenge were obtained synchronously.
      */
     nsresult ContinueOnAuthAvailable(const nsCSubstring& creds);
 
 private:
-    nsCOMPtr<nsIURI>                  mOriginalURI;
-    nsCOMPtr<nsIURI>                  mURI;
-    nsCOMPtr<nsIURI>                  mDocumentURI;
-    nsCOMPtr<nsIStreamListener>       mListener;
-    nsCOMPtr<nsISupports>             mListenerContext;
-    nsCOMPtr<nsILoadGroup>            mLoadGroup;
     nsCOMPtr<nsISupports>             mOwner;
-    nsCOMPtr<nsIInterfaceRequestor>   mCallbacks;
-    nsCOMPtr<nsIProgressEventSink>    mProgressSink;
     nsCOMPtr<nsIInputStream>          mUploadStream;
-    nsCOMPtr<nsIURI>                  mReferrer;
     nsCOMPtr<nsISupports>             mSecurityInfo;
     nsCOMPtr<nsICancelable>           mProxyRequest;
 
-    nsHttpRequestHead                 mRequestHead;
-    nsHttpResponseHead               *mResponseHead;
-
     nsRefPtr<nsInputStreamPump>       mTransactionPump;
-    nsHttpTransaction                *mTransaction;     // hard ref
-    nsHttpConnectionInfo             *mConnectionInfo;  // hard ref
+    nsRefPtr<nsHttpTransaction>       mTransaction;
 
-    nsCString                         mSpec; // ASCII encoded URL spec
-
-    PRUint32                          mLoadFlags;
-    PRUint32                          mStatus;
     PRUint64                          mLogicalOffset;
-    PRUint8                           mCaps;
     PRInt16                           mPriority;
 
-    nsCString                         mContentTypeHint;
-    nsCString                         mContentCharsetHint;
     nsCString                         mUserSetCookieHeader;
 
     // cache specific data
     nsCOMPtr<nsICacheEntryDescriptor> mCacheEntry;
     nsRefPtr<nsInputStreamPump>       mCachePump;
-    nsHttpResponseHead               *mCachedResponseHead;
+    nsAutoPtr<nsHttpResponseHead>     mCachedResponseHead;
     nsCacheAccessMode                 mCacheAccess;
     PRUint32                          mPostID;
     PRUint32                          mRequestTime;
 
     nsCOMPtr<nsICacheEntryDescriptor> mOfflineCacheEntry;
     nsCacheAccessMode                 mOfflineCacheAccess;
     nsCString                         mOfflineCacheClientID;
 
@@ -342,32 +309,25 @@ private:
 
     // Proxy info to replace with
     nsCOMPtr<nsIProxyInfo>            mTargetProxyInfo;
 
     // Suspend counter.  This is used if someone tries to suspend/resume us
     // before we have either a cache pump or a transaction pump.
     PRUint32                          mSuspendCount;
 
-    // redirection specific data.
-    PRUint8                           mRedirectionLimit;
-
     // If the channel is associated with a cache, and the URI matched
     // a fallback namespace, this will hold the key for the fallback
     // cache entry.
     nsCString                         mFallbackKey;
 
     // state flags
-    PRUint32                          mIsPending                : 1;
-    PRUint32                          mWasOpened                : 1;
     PRUint32                          mApplyConversion          : 1;
-    PRUint32                          mAllowPipelining          : 1;
     PRUint32                          mCachedContentIsValid     : 1;
     PRUint32                          mCachedContentIsPartial   : 1;
-    PRUint32                          mResponseHeadersModified  : 1;
     PRUint32                          mCanceled                 : 1;
     PRUint32                          mTransactionReplaced      : 1;
     PRUint32                          mUploadStreamHasHeaders   : 1;
     PRUint32                          mAuthRetryPending         : 1;
     // True when we need to authenticate to proxy, i.e. when we get 407
     // response. Used in OnAuthAvailable and OnAuthCancelled callbacks.
     PRUint32                          mProxyAuth                : 1;
     PRUint32                          mTriedProxyAuth           : 1;
@@ -381,17 +341,16 @@ private:
     PRUint32                          mCachingOpportunistically : 1;
     // True if we are loading a fallback cache entry from the
     // application cache.
     PRUint32                          mFallbackChannel          : 1;
     PRUint32                          mInheritApplicationCache  : 1;
     PRUint32                          mChooseApplicationCache   : 1;
     PRUint32                          mLoadedFromApplicationCache : 1;
     PRUint32                          mTracingEnabled           : 1;
-    PRUint32                          mForceAllowThirdPartyCookie : 1;
     // True if consumer added its own If-None-Match or If-Modified-Since
     // headers. In such a case we must not override them in the cache code
     // and also we want to pass possible 304 code response through.
     PRUint32                          mCustomConditionalRequest : 1;
 
     class nsContentEncodings : public nsIUTF8StringEnumerator
     {
     public:
--- a/netwerk/protocol/http/src/nsHttpHandler.cpp
+++ b/netwerk/protocol/http/src/nsHttpHandler.cpp
@@ -94,18 +94,18 @@
 #endif
 
 #if defined(XP_OS2)
 #define INCL_DOSMISC
 #include <os2.h>
 #endif
 
 //-----------------------------------------------------------------------------
+using namespace mozilla::net;
 #ifdef MOZ_IPC
-using namespace mozilla::net;
 #include "mozilla/net/HttpChannelChild.h"
 #endif 
 
 #ifdef DEBUG
 // defined by the socket transport service while active
 extern PRThread *gSocketThread;
 #endif
 
@@ -1519,62 +1519,48 @@ nsHttpHandler::AllowPort(PRInt32 port, c
 // nsHttpHandler::nsIProxiedProtocolHandler
 //-----------------------------------------------------------------------------
 
 NS_IMETHODIMP
 nsHttpHandler::NewProxiedChannel(nsIURI *uri,
                                  nsIProxyInfo* givenProxyInfo,
                                  nsIChannel **result)
 {
-    nsHttpChannel *httpChannel = nsnull;
+    nsRefPtr<HttpBaseChannel> httpChannel;
 
     LOG(("nsHttpHandler::NewProxiedChannel [proxyInfo=%p]\n",
         givenProxyInfo));
     
     nsCOMPtr<nsProxyInfo> proxyInfo;
     if (givenProxyInfo) {
         proxyInfo = do_QueryInterface(givenProxyInfo);
         NS_ENSURE_ARG(proxyInfo);
     }
 
     PRBool https;
     nsresult rv = uri->SchemeIs("https", &https);
     if (NS_FAILED(rv))
         return rv;
 
-#if MOZ_IPC
+#ifdef 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;
+
+        httpChannel = new HttpChannelChild();
+    } else
+#endif
+    {
+        httpChannel = new nsHttpChannel();
     }
-#endif
-
-    NS_NEWXPCOM(httpChannel, nsHttpChannel);
-    if (!httpChannel)
-        return NS_ERROR_OUT_OF_MEMORY;
-    NS_ADDREF(httpChannel);
 
     // select proxy caps if using a non-transparent proxy.  SSL tunneling
     // should not use proxy settings.
     PRInt8 caps;
     if (proxyInfo && !nsCRT::strcmp(proxyInfo->Type(), "http") && !https)
         caps = mProxyCapabilities;
     else
         caps = mCapabilities;
@@ -1589,23 +1575,20 @@ nsHttpHandler::NewProxiedChannel(nsIURI 
                 do_GetService(NS_SOCKETPROVIDERSERVICE_CONTRACTID);
         if (spserv) {
             nsCOMPtr<nsISocketProvider> provider;
             spserv->GetSocketProvider("ssl", getter_AddRefs(provider));
         }
     }
 
     rv = httpChannel->Init(uri, caps, proxyInfo);
-
-    if (NS_FAILED(rv)) {
-        NS_RELEASE(httpChannel);
+    if (NS_FAILED(rv))
         return rv;
-    }
 
-    *result = httpChannel;
+    httpChannel.forget(result);
     return NS_OK;
 }
 
 //-----------------------------------------------------------------------------
 // nsHttpHandler::nsIHttpProtocolHandler
 //-----------------------------------------------------------------------------
 
 NS_IMETHODIMP
new file mode 100644
--- /dev/null
+++ b/netwerk/test/unit_ipc/test_bug528292_wrap.js
@@ -0,0 +1,3 @@
+function run_test() {
+  run_test_in_child("../unit/test_bug528292.js");
+}