Bug 541174 - e10s HTTP: Improve how URIs are serialized (part1). r=dwitte
authorJosh Matthews <josh@joshmatthews.net>
Fri, 09 Apr 2010 18:26:36 +1200
changeset 46809 7b2da3a79e359028a82ee7e2ceb8bbdf849ea853
parent 46808 bc5c9b9f6eee3ce5a9e57a0f71d3e284333de581
child 46810 cc46a878de23d87416637072d56b81e53eca39e5
push idunknown
push userunknown
push dateunknown
reviewersdwitte
bugs541174
milestone1.9.3a5pre
Bug 541174 - e10s HTTP: Improve how URIs are serialized (part1). r=dwitte
netwerk/base/public/Makefile.in
netwerk/base/public/nsIIPCSerializable.idl
netwerk/base/src/Makefile.in
netwerk/base/src/nsStandardURL.cpp
netwerk/base/src/nsStandardURL.h
netwerk/ipc/Makefile.in
netwerk/ipc/NeckoMessageUtils.h
--- a/netwerk/base/public/Makefile.in
+++ b/netwerk/base/public/Makefile.in
@@ -79,16 +79,17 @@ XPIDLSRCS	= \
 		nsICryptoHMAC.idl \
 		nsIDownloader.idl \
 		nsIEncodedChannel.idl \
 		nsIFileStreams.idl \
 		nsIIncrementalDownload.idl \
 		nsIInputStreamPump.idl \
 		nsIInputStreamChannel.idl \
                 nsIIOService2.idl \
+                nsIIPCSerializable.idl \
 		nsIMIMEInputStream.idl \
                 nsINetworkLinkService.idl \
 		nsIPermission.idl \
 		nsIPermissionManager.idl \
 		nsIPrivateBrowsingService.idl \
 		nsIProgressEventSink.idl \
 		nsIPrompt.idl \
 		nsIProtocolProxyService.idl \
new file mode 100644
--- /dev/null
+++ b/netwerk/base/public/nsIIPCSerializable.idl
@@ -0,0 +1,57 @@
+/* -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 8 -*- */
+/* vim: set sw=2 ts=8 et tw=80 ft=cpp : */
+/* ***** 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.
+ *
+ * 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):
+ *   Josh Matthews <josh@joshmatthews.net>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "nsISupports.idl"
+
+%{C++
+namespace IPC {
+class Message;
+}
+%}
+
+[ptr] native ConstMessage(const IPC::Message);
+[ptr] native Message(IPC::Message);
+[ptr] native Iterator(void*);
+
+[noscript, uuid(1f605ac7-666b-471f-9864-1a21a95f11c4)]
+interface nsIIPCSerializable : nsISupports
+{
+  [notxpcom] boolean read(in ConstMessage msg, in Iterator iter);
+  [notxpcom] void write(in Message msg);
+};
--- a/netwerk/base/src/Makefile.in
+++ b/netwerk/base/src/Makefile.in
@@ -124,15 +124,17 @@ EXTRA_COMPONENTS = \
 EXTRA_JS_MODULES = \
 		NetUtil.jsm \
 		$(NULL)
 
 # we don't want the shared lib, but we want to force the creation of a
 # static lib.
 FORCE_STATIC_LIB = 1
 
+include $(topsrcdir)/config/config.mk
+include $(topsrcdir)/ipc/chromium/chromium-config.mk
 include $(topsrcdir)/config/rules.mk
 
 DEFINES += -DIMPL_NS_NET
 
 ifdef MOZ_ENABLE_LIBCONIC
 	OS_INCLUDES += $(GLIB_CFLAGS) $(LIBCONIC_CFLAGS)
 endif
--- a/netwerk/base/src/nsStandardURL.cpp
+++ b/netwerk/base/src/nsStandardURL.cpp
@@ -33,16 +33,20 @@
  * 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 ***** */
 
+#ifdef MOZ_IPC
+#include "IPCMessageUtils.h"
+#endif
+
 #include "nsStandardURL.h"
 #include "nsDependentSubstring.h"
 #include "nsReadableUtils.h"
 #include "nsCRT.h"
 #include "nsEscape.h"
 #include "nsILocalFile.h"
 #include "nsIObjectInputStream.h"
 #include "nsIObjectOutputStream.h"
@@ -68,16 +72,19 @@ PRBool nsStandardURL::gAlwaysEncodeInUTF
 PRBool nsStandardURL::gEncodeQueryInUTF8 = PR_TRUE;
 
 #if defined(PR_LOGGING)
 //
 // setenv NSPR_LOG_MODULES nsStandardURL:5
 //
 static PRLogModuleInfo *gStandardURLLog;
 #endif
+
+// The Chromium code defines its own LOG macro which we don't want
+#undef LOG
 #define LOG(args)     PR_LOG(gStandardURLLog, PR_LOG_DEBUG, args)
 #define LOG_ENABLED() PR_LOG_TEST(gStandardURLLog, PR_LOG_DEBUG)
 
 //----------------------------------------------------------------------------
 
 #define ENSURE_MUTABLE() \
   PR_BEGIN_MACRO \
     if (!mMutable) { \
@@ -847,16 +854,32 @@ nsStandardURL::WriteSegment(nsIBinaryOut
     if (NS_FAILED(rv)) return rv;
 
     rv = stream->Write32(PRUint32(seg.mLen));
     if (NS_FAILED(rv)) return rv;
 
     return NS_OK;
 }
 
+#ifdef MOZ_IPC
+bool
+nsStandardURL::ReadSegment(const IPC::Message *aMsg, void **aIter, URLSegment &seg)
+{
+    return (IPC::ReadParam(aMsg, aIter, &seg.mPos) &&
+            IPC::ReadParam(aMsg, aIter, &seg.mLen));
+}
+
+void
+nsStandardURL::WriteSegment(IPC::Message *aMsg, const URLSegment &seg)
+{
+    IPC::WriteParam(aMsg, seg.mPos);
+    IPC::WriteParam(aMsg, seg.mLen);
+}
+#endif
+
 /* static */ void
 nsStandardURL::PrefsChanged(nsIPrefBranch *prefs, const char *pref)
 {
     PRBool val;
 
     LOG(("nsStandardURL::PrefsChanged [pref=%s]\n", pref));
 
 #define PREF_CHANGED(p) ((pref == nsnull) || !strcmp(pref, p))
@@ -903,16 +926,17 @@ NS_IMPL_RELEASE(nsStandardURL)
 
 NS_INTERFACE_MAP_BEGIN(nsStandardURL)
     NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIStandardURL)
     NS_INTERFACE_MAP_ENTRY(nsIURI)
     NS_INTERFACE_MAP_ENTRY(nsIURL)
     NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsIFileURL, mSupportsFileURL)
     NS_INTERFACE_MAP_ENTRY(nsIStandardURL)
     NS_INTERFACE_MAP_ENTRY(nsISerializable)
+    NS_INTERFACE_MAP_ENTRY(nsIIPCSerializable)
     NS_INTERFACE_MAP_ENTRY(nsIClassInfo)
     NS_INTERFACE_MAP_ENTRY(nsIMutable)
     // see nsStandardURL::Equals
     if (aIID.Equals(kThisImplCID))
         foundInterface = static_cast<nsIURI *>(this);
     else
 NS_INTERFACE_MAP_END
 
@@ -2776,16 +2800,122 @@ nsStandardURL::Write(nsIObjectOutputStre
     rv = stream->Write32(mHostEncoding);
     if (NS_FAILED(rv)) return rv;
 
     // mSpecEncoding and mHostA are just caches that can be recovered as needed.
 
     return NS_OK;
 }
 
+//---------------------------------------------------------------------------
+// nsStandardURL::nsIIPCSerializable
+//---------------------------------------------------------------------------
+
+PRBool
+nsStandardURL::Read(const IPC::Message *aMsg, void **aIter)
+{
+#ifdef MOZ_IPC
+    using IPC::ReadParam;
+    
+    NS_PRECONDITION(!mHostA, "Shouldn't have cached ASCII host");
+    NS_PRECONDITION(mSpecEncoding == eEncoding_Unknown,
+                    "Shouldn't have spec encoding here");
+    NS_PRECONDITION(!mFile, "Shouldn't have cached file");
+    
+    PRUint32 urlType;
+    if (!ReadParam(aMsg, aIter, &urlType))
+        return PR_FALSE;
+    
+    mURLType = urlType;
+    switch (mURLType) {
+        case URLTYPE_STANDARD:
+            mParser = net_GetStdURLParser();
+            break;
+        case URLTYPE_AUTHORITY:
+            mParser = net_GetAuthURLParser();
+            break;
+        case URLTYPE_NO_AUTHORITY:
+            mParser = net_GetNoAuthURLParser();
+            break;
+        default:
+            NS_NOTREACHED("bad urlType");
+            return PR_FALSE;
+    }
+
+    PRUint32 hostEncoding;
+    bool isMutable, supportsFileURL;
+    if (!ReadParam(aMsg, aIter, &mPort) ||
+        !ReadParam(aMsg, aIter, &mDefaultPort) ||
+        !ReadParam(aMsg, aIter, &mSpec) ||
+        !ReadSegment(aMsg, aIter, mScheme) ||
+        !ReadSegment(aMsg, aIter, mAuthority) ||
+        !ReadSegment(aMsg, aIter, mUsername) ||
+        !ReadSegment(aMsg, aIter, mPassword) ||
+        !ReadSegment(aMsg, aIter, mHost) ||
+        !ReadSegment(aMsg, aIter, mPath) ||
+        !ReadSegment(aMsg, aIter, mFilepath) ||
+        !ReadSegment(aMsg, aIter, mDirectory) ||
+        !ReadSegment(aMsg, aIter, mBasename) ||
+        !ReadSegment(aMsg, aIter, mExtension) ||
+        !ReadSegment(aMsg, aIter, mParam) ||
+        !ReadSegment(aMsg, aIter, mQuery) ||
+        !ReadSegment(aMsg, aIter, mRef) ||
+        !ReadParam(aMsg, aIter, &mOriginCharset) ||
+        !ReadParam(aMsg, aIter, &isMutable) ||
+        !ReadParam(aMsg, aIter, &supportsFileURL) ||
+        !ReadParam(aMsg, aIter, &hostEncoding))
+        return PR_FALSE;
+
+    if (hostEncoding != eEncoding_ASCII && hostEncoding != eEncoding_UTF8) {
+        NS_WARNING("Unexpected host encoding");
+        return PR_FALSE;
+    }
+    mHostEncoding = hostEncoding;
+    mMutable = isMutable;
+    mSupportsFileURL = supportsFileURL;
+
+    // mSpecEncoding and mHostA are just caches that can be recovered as needed.
+
+    return PR_TRUE;
+#else
+    return PR_FALSE;
+#endif
+}
+
+void
+nsStandardURL::Write(IPC::Message *aMsg)
+{
+#ifdef MOZ_IPC
+    using IPC::WriteParam;
+    
+    WriteParam(aMsg, mURLType);
+    WriteParam(aMsg, mPort);
+    WriteParam(aMsg, mDefaultPort);
+    WriteParam(aMsg, mSpec);
+    WriteSegment(aMsg, mScheme);
+    WriteSegment(aMsg, mAuthority);
+    WriteSegment(aMsg, mUsername);
+    WriteSegment(aMsg, mPassword);
+    WriteSegment(aMsg, mHost);
+    WriteSegment(aMsg, mPath);
+    WriteSegment(aMsg, mFilepath);
+    WriteSegment(aMsg, mDirectory);
+    WriteSegment(aMsg, mBasename);
+    WriteSegment(aMsg, mExtension);
+    WriteSegment(aMsg, mParam);
+    WriteSegment(aMsg, mQuery);
+    WriteSegment(aMsg, mRef);
+    WriteParam(aMsg, mOriginCharset);
+    WriteParam(aMsg, bool(mMutable));
+    WriteParam(aMsg, bool(mSupportsFileURL));
+    WriteParam(aMsg, mHostEncoding);
+    // mSpecEncoding and mHostA are just caches that can be recovered as needed.
+#endif
+}
+
 //----------------------------------------------------------------------------
 // nsStandardURL::nsIClassInfo
 //----------------------------------------------------------------------------
 
 NS_IMETHODIMP 
 nsStandardURL::GetInterfaces(PRUint32 *count, nsIID * **array)
 {
     *count = 0;
--- a/netwerk/base/src/nsStandardURL.h
+++ b/netwerk/base/src/nsStandardURL.h
@@ -38,16 +38,17 @@
 
 #ifndef nsStandardURL_h__
 #define nsStandardURL_h__
 
 #include "nsString.h"
 #include "nsDependentString.h"
 #include "nsDependentSubstring.h"
 #include "nsISerializable.h"
+#include "nsIIPCSerializable.h"
 #include "nsIFileURL.h"
 #include "nsIStandardURL.h"
 #include "nsIFile.h"
 #include "nsIURLParser.h"
 #include "nsIUnicodeEncoder.h"
 #include "nsIObserver.h"
 #include "nsIIOService.h"
 #include "nsCOMPtr.h"
@@ -67,25 +68,27 @@ class nsIPrefBranch;
 
 //-----------------------------------------------------------------------------
 // standard URL implementation
 //-----------------------------------------------------------------------------
 
 class nsStandardURL : public nsIFileURL
                     , public nsIStandardURL
                     , public nsISerializable
+                    , public nsIIPCSerializable
                     , public nsIClassInfo
 {
 public:
     NS_DECL_ISUPPORTS
     NS_DECL_NSIURI
     NS_DECL_NSIURL
     NS_DECL_NSIFILEURL
     NS_DECL_NSISTANDARDURL
     NS_DECL_NSISERIALIZABLE
+    NS_DECL_NSIIPCSERIALIZABLE
     NS_DECL_NSICLASSINFO
     NS_DECL_NSIMUTABLE
 
     nsStandardURL(PRBool aSupportsFileURL = PR_FALSE);
     virtual ~nsStandardURL();
 
     static void InitGlobalObjects();
     static void ShutdownGlobalObjects();
@@ -220,16 +223,22 @@ private:
     void ShiftFromParam(PRInt32 diff)     { mParam.mPos += diff; ShiftFromQuery(diff); }
     void ShiftFromQuery(PRInt32 diff)     { mQuery.mPos += diff; ShiftFromRef(diff); }
     void ShiftFromRef(PRInt32 diff)       { mRef.mPos += diff; }
 
     // fastload helper functions
     nsresult ReadSegment(nsIBinaryInputStream *, URLSegment &);
     nsresult WriteSegment(nsIBinaryOutputStream *, const URLSegment &);
 
+#ifdef MOZ_IPC
+    // ipc helper functions
+    bool ReadSegment(const IPC::Message *, void **, URLSegment &);
+    void WriteSegment(IPC::Message *, const URLSegment &);
+#endif
+
     static void PrefsChanged(nsIPrefBranch *prefs, const char *pref);
 
     // mSpec contains the normalized version of the URL spec (UTF-8 encoded).
     nsCString mSpec;
     PRInt32   mDefaultPort;
     PRInt32   mPort;
 
     // url parts (relative to mSpec)
--- a/netwerk/ipc/Makefile.in
+++ b/netwerk/ipc/Makefile.in
@@ -49,16 +49,17 @@ FORCE_STATIC_LIB = 1
 EXPORT_LIBRARY = 1
 
 EXPORTS_NAMESPACES = mozilla/net
 
 EXPORTS_mozilla/net = \
   NeckoParent.h       \
   NeckoChild.h        \
   NeckoCommon.h       \
+  NeckoMessageUtils.h \
   $(NULL)
 
 CPPSRCS =               \
   NeckoChild.cpp        \
   NeckoParent.cpp       \
   $(NULL)
 
 LOCAL_INCLUDES +=                  \
new file mode 100644
--- /dev/null
+++ b/netwerk/ipc/NeckoMessageUtils.h
@@ -0,0 +1,138 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** 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):
+ *   Josh Matthews <josh@joshmatthews.net> (Initial Developer)
+ *
+ * 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_NeckoMessageUtils_h
+#define mozilla_net_NeckoMessageUtils_h
+
+#include "IPC/IPCMessageUtils.h"
+#include "nsStringGlue.h"
+#include "nsIURI.h"
+#include "nsIIPCSerializable.h"
+#include "nsIClassInfo.h"
+#include "nsComponentManagerUtils.h"
+
+namespace IPC {
+
+// Since IPDL doesn't have any knowledge of pointers, there's no easy way to
+// pass around nsIURI pointers.  This is a very thin wrapper that IPDL can
+// easily work with, allowing for conversion to and from an nsIURI pointer.
+
+class URI {
+ public:
+  URI() : mURI(nsnull) {}
+  URI(nsIURI* aURI) : mURI(aURI) {}
+  // The contained URI is already addrefed on creation. We don't want another
+  // addref when passing it off to its actual owner.
+  operator nsCOMPtr<nsIURI>() const { return already_AddRefed<nsIURI>(mURI); }
+
+  friend struct ParamTraits<URI>;
+  
+ private:
+  URI& operator=(URI&);
+  nsIURI* mURI;
+};
+  
+template<>
+struct ParamTraits<URI>
+{
+  typedef URI paramType;
+  
+  static void Write(Message* aMsg, const paramType& aParam)
+  {
+    bool isNull = !aParam.mURI;
+    WriteParam(aMsg, isNull);
+    if (isNull)
+      return;
+    
+    nsCOMPtr<nsIIPCSerializable> serializable = do_QueryInterface(aParam.mURI);
+    NS_ABORT_IF_FALSE(serializable, "All IPDL URIs must be serializable");
+    nsCOMPtr<nsIClassInfo> classInfo = do_QueryInterface(aParam.mURI);
+    char cidStr[NSID_LENGTH];
+    nsCID cid;
+    nsresult rv = classInfo->GetClassIDNoAlloc(&cid);
+    NS_ABORT_IF_FALSE(NS_SUCCEEDED(rv), "All IPDL URIs must report a valid class ID");
+    
+    cid.ToProvidedString(cidStr);
+    WriteParam(aMsg, nsCAutoString(cidStr));
+    serializable->Write(aMsg);
+  }
+
+  static bool Read(const Message* aMsg, void** aIter, paramType* aResult)
+  {
+    bool isNull;
+    if (!ReadParam(aMsg, aIter, &isNull))
+      return false;
+    if (isNull) {
+      aResult->mURI = nsnull;
+      return true;
+    }
+    
+    nsCAutoString cidStr;
+    nsCID cid;
+    if (!ReadParam(aMsg, aIter, &cidStr) ||
+        !cid.Parse(cidStr.get()))
+      return false;
+
+    nsCOMPtr<nsIURI> uri = do_CreateInstance(cid);
+    if (!uri)
+      return false;
+    nsCOMPtr<nsIIPCSerializable> serializable = do_QueryInterface(uri);
+    if (!serialiable || !serializable->Read(aMsg, aIter))
+      return false;
+
+    uri.forget(&aResult->mURI);
+    return true;
+  }
+
+  static void Log(const paramType& aParam, std::wstring* aLog)
+  {
+    nsIURI* uri = aParam.mURI;
+    if (uri) {
+      nsCString spec;
+      uri->GetSpec(spec);
+      aLog->append(StringPrintf(L"[%s]", spec.get()));
+    }
+    else {
+      aLog->append(L"[]");
+    }
+  }
+};
+
+}
+
+#endif // mozilla_net_NeckoMessageUtils_h