Bug 1345094 - make http redirects to file:// uris work under e10s. r=mayhemer
authorNicholas Hurley <hurley@mozilla.com>
Wed, 12 Apr 2017 11:43:50 -0700
changeset 353513 a3953fb9958d9118fd4802c93f160b15888fea0e
parent 353512 eef59bccf1c7730fd478d5fc6d53d626c32bd571
child 353514 1b277ae21ba5774735109df4b719a6e992e296e6
push id31670
push usercbook@mozilla.com
push dateTue, 18 Apr 2017 08:20:28 +0000
treeherdermozilla-central@92f94fc0993b [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmayhemer
bugs1345094
milestone55.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1345094 - make http redirects to file:// uris work under e10s. r=mayhemer MozReview-Commit-ID: J4IheswoeMZ
netwerk/ipc/NeckoChild.cpp
netwerk/ipc/NeckoChild.h
netwerk/ipc/NeckoParent.cpp
netwerk/ipc/NeckoParent.h
netwerk/ipc/PFileChannel.ipdl
netwerk/ipc/PNecko.ipdl
netwerk/ipc/moz.build
netwerk/protocol/file/FileChannelChild.cpp
netwerk/protocol/file/FileChannelChild.h
netwerk/protocol/file/FileChannelParent.cpp
netwerk/protocol/file/FileChannelParent.h
netwerk/protocol/file/moz.build
netwerk/protocol/file/nsFileProtocolHandler.cpp
--- a/netwerk/ipc/NeckoChild.cpp
+++ b/netwerk/ipc/NeckoChild.cpp
@@ -228,16 +228,30 @@ NeckoChild::AllocPDataChannelChild(const
 
 bool
 NeckoChild::DeallocPDataChannelChild(PDataChannelChild* child)
 {
   // NB: See DataChannelChild::ActorDestroy.
   return true;
 }
 
+PFileChannelChild*
+NeckoChild::AllocPFileChannelChild(const uint32_t& channelId)
+{
+  MOZ_ASSERT_UNREACHABLE("Should never get here");
+  return nullptr;
+}
+
+bool
+NeckoChild::DeallocPFileChannelChild(PFileChannelChild* child)
+{
+  // NB: See FileChannelChild::ActorDestroy.
+  return true;
+}
+
 PRtspControllerChild*
 NeckoChild::AllocPRtspControllerChild()
 {
   NS_NOTREACHED("AllocPRtspController should not be called");
   return nullptr;
 }
 
 bool
--- a/netwerk/ipc/NeckoChild.h
+++ b/netwerk/ipc/NeckoChild.h
@@ -64,16 +64,18 @@ protected:
   virtual bool DeallocPUDPSocketChild(PUDPSocketChild*) override;
   virtual PDNSRequestChild* AllocPDNSRequestChild(const nsCString& aHost,
                                                   const OriginAttributes& aOriginAttributes,
                                                   const uint32_t& aFlags,
                                                   const nsCString& aNetworkInterface) override;
   virtual bool DeallocPDNSRequestChild(PDNSRequestChild*) override;
   virtual PDataChannelChild* AllocPDataChannelChild(const uint32_t& channelId) override;
   virtual bool DeallocPDataChannelChild(PDataChannelChild* child) override;
+  virtual PFileChannelChild* AllocPFileChannelChild(const uint32_t& channelId) override;
+  virtual bool DeallocPFileChannelChild(PFileChannelChild* child) override;
   virtual PRtspControllerChild* AllocPRtspControllerChild() override;
   virtual bool DeallocPRtspControllerChild(PRtspControllerChild*) override;
   virtual PRtspChannelChild*
     AllocPRtspChannelChild(const RtspChannelConnectArgs& aArgs)
                            override;
   virtual bool DeallocPRtspChannelChild(PRtspChannelChild*) override;
   virtual PChannelDiverterChild*
   AllocPChannelDiverterChild(const ChannelDiverterArgs& channel) override;
--- a/netwerk/ipc/NeckoParent.cpp
+++ b/netwerk/ipc/NeckoParent.cpp
@@ -13,16 +13,17 @@
 #include "mozilla/net/CookieServiceParent.h"
 #include "mozilla/net/WyciwygChannelParent.h"
 #include "mozilla/net/FTPChannelParent.h"
 #include "mozilla/net/WebSocketChannelParent.h"
 #include "mozilla/net/WebSocketEventListenerParent.h"
 #include "mozilla/net/DataChannelParent.h"
 #include "mozilla/net/AltDataOutputStreamParent.h"
 #include "mozilla/Unused.h"
+#include "mozilla/net/FileChannelParent.h"
 #ifdef NECKO_PROTOCOL_rtsp
 #include "mozilla/net/RtspControllerParent.h"
 #include "mozilla/net/RtspChannelParent.h"
 #endif
 #include "mozilla/net/DNSRequestParent.h"
 #include "mozilla/net/ChannelDiverterParent.h"
 #include "mozilla/net/IPCTransportProvider.h"
 #ifdef MOZ_WEBRTC
@@ -520,16 +521,40 @@ NeckoParent::RecvPDataChannelConstructor
                                          const uint32_t& channelId)
 {
   DataChannelParent* p = static_cast<DataChannelParent*>(actor);
   DebugOnly<bool> rv = p->Init(channelId);
   MOZ_ASSERT(rv);
   return IPC_OK();
 }
 
+PFileChannelParent*
+NeckoParent::AllocPFileChannelParent(const uint32_t &channelId)
+{
+  RefPtr<FileChannelParent> p = new FileChannelParent();
+  return p.forget().take();
+}
+
+bool
+NeckoParent::DeallocPFileChannelParent(PFileChannelParent* actor)
+{
+  RefPtr<FileChannelParent> p = dont_AddRef(static_cast<FileChannelParent*>(actor));
+  return true;
+}
+
+mozilla::ipc::IPCResult
+NeckoParent::RecvPFileChannelConstructor(PFileChannelParent* actor,
+                                         const uint32_t& channelId)
+{
+  FileChannelParent* p = static_cast<FileChannelParent*>(actor);
+  DebugOnly<bool> rv = p->Init(channelId);
+  MOZ_ASSERT(rv);
+  return IPC_OK();
+}
+
 PRtspControllerParent*
 NeckoParent::AllocPRtspControllerParent()
 {
 #ifdef NECKO_PROTOCOL_rtsp
   RtspControllerParent* p = new RtspControllerParent();
   p->AddRef();
   return p;
 #else
--- a/netwerk/ipc/NeckoParent.h
+++ b/netwerk/ipc/NeckoParent.h
@@ -178,16 +178,23 @@ protected:
 
   virtual PDataChannelParent*
     AllocPDataChannelParent(const uint32_t& channelId) override;
   virtual bool DeallocPDataChannelParent(PDataChannelParent* parent) override;
 
   virtual mozilla::ipc::IPCResult RecvPDataChannelConstructor(PDataChannelParent* aActor,
                                                               const uint32_t& channelId) override;
 
+  virtual PFileChannelParent*
+    AllocPFileChannelParent(const uint32_t& channelId) override;
+  virtual bool DeallocPFileChannelParent(PFileChannelParent* parent) override;
+
+  virtual mozilla::ipc::IPCResult RecvPFileChannelConstructor(PFileChannelParent* aActor,
+                                                              const uint32_t& channelId) override;
+
   virtual PRtspControllerParent* AllocPRtspControllerParent() override;
   virtual bool DeallocPRtspControllerParent(PRtspControllerParent*) override;
 
   virtual PRtspChannelParent*
     AllocPRtspChannelParent(const RtspChannelConnectArgs& aArgs)
                             override;
   virtual mozilla::ipc::IPCResult
     RecvPRtspChannelConstructor(PRtspChannelParent* aActor,
new file mode 100644
--- /dev/null
+++ b/netwerk/ipc/PFileChannel.ipdl
@@ -0,0 +1,28 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set sw=2 ts=2 sts=2 et tw=80 ft=cpp : */
+
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+include protocol PNecko;
+include URIParams;
+
+namespace mozilla {
+namespace net {
+
+/* Used to facilitate http redirects to file:// - see
+ * https://bugzilla.mozilla.org/show_bug.cgi?id=1345094
+ */
+async protocol PFileChannel
+{
+  manager PNecko;
+
+parent:
+  // Note: channels are opened during construction, so no open method here:
+  // see PNecko.ipdl
+  async __delete__();
+};
+
+} // namespace net
+} // namespace mozilla
--- a/netwerk/ipc/PNecko.ipdl
+++ b/netwerk/ipc/PNecko.ipdl
@@ -20,16 +20,17 @@ include protocol PDNSRequest;
 include protocol PChannelDiverter;
 include protocol PBlob; //FIXME: bug #792908
 include protocol PFileDescriptorSet;
 include protocol PDataChannel;
 include protocol PTransportProvider;
 include protocol PChildToParentStream; //FIXME: bug #792908
 include protocol PParentToChildStream; //FIXME: bug #792908
 include protocol PStunAddrsRequest;
+include protocol PFileChannel;
 
 include protocol PRtspController;
 include protocol PRtspChannel;
 include URIParams;
 include NeckoChannelParams;
 include PBrowserOrId;
 include protocol PAltDataOutputStream;
 
@@ -50,16 +51,17 @@ nested(upto inside_cpow) sync protocol P
   manages PFTPChannel;
   manages PWebSocket;
   manages PWebSocketEventListener;
   manages PTCPSocket;
   manages PTCPServerSocket;
   manages PUDPSocket;
   manages PDNSRequest;
   manages PDataChannel;
+  manages PFileChannel;
   manages PRtspController;
   manages PRtspChannel;
   manages PChannelDiverter;
   manages PTransportProvider;
   manages PAltDataOutputStream;
   manages PStunAddrsRequest;
 
 parent:
@@ -98,16 +100,18 @@ parent:
                               uint16_t flags, nsresult reason);
 
   /**
    * channelId is used to establish a connection between redirect channels in
    * the parent and the child when we're redirecting to a data: URI.
    */
   async PDataChannel(uint32_t channelId);
 
+  async PFileChannel(uint32_t channelId);
+
   async PRtspController();
   async PRtspChannel(RtspChannelConnectArgs args);
   async PChannelDiverter(ChannelDiverterArgs channel);
 
   /**
    * These are called from the child with the results of the auth prompt.
    * callbackId is the id that was passed in PBrowser::AsyncAuthPrompt,
    * corresponding to an nsIAuthPromptCallback
--- a/netwerk/ipc/moz.build
+++ b/netwerk/ipc/moz.build
@@ -18,16 +18,17 @@ UNIFIED_SOURCES += [
     'NeckoCommon.cpp',
     'NeckoParent.cpp',
 ]
 
 IPDL_SOURCES = [
     'NeckoChannelParams.ipdlh',
     'PChannelDiverter.ipdl',
     'PDataChannel.ipdl',
+    'PFileChannel.ipdl',
     'PNecko.ipdl',
     'PRtspChannel.ipdl',
     'PRtspController.ipdl',
 ]
 
 # needed so --disable-webrtc builds work (yes, a bit messy)
 if not CONFIG['MOZ_WEBRTC']:
   IPDL_SOURCES += [
new file mode 100644
--- /dev/null
+++ b/netwerk/protocol/file/FileChannelChild.cpp
@@ -0,0 +1,74 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=2 sw=2 sts=2 et tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "FileChannelChild.h"
+
+#include "mozilla/Unused.h"
+#include "mozilla/net/NeckoChild.h"
+
+namespace mozilla {
+namespace net {
+
+NS_IMPL_ISUPPORTS_INHERITED(FileChannelChild, nsFileChannel, nsIChildChannel)
+
+FileChannelChild::FileChannelChild(nsIURI *uri)
+  : nsFileChannel(uri)
+  , mIPCOpen(false)
+{
+}
+
+NS_IMETHODIMP
+FileChannelChild::ConnectParent(uint32_t id)
+{
+  if (!gNeckoChild->SendPFileChannelConstructor(this, id)) {
+    return NS_ERROR_FAILURE;
+  }
+
+  AddIPDLReference();
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+FileChannelChild::CompleteRedirectSetup(nsIStreamListener *listener,
+                                        nsISupports *ctx)
+{
+  nsresult rv;
+
+  if (mLoadInfo && mLoadInfo->GetEnforceSecurity()) {
+    MOZ_ASSERT(!ctx, "Context should be null");
+    rv = AsyncOpen2(listener);
+  } else {
+    rv = AsyncOpen(listener, ctx);
+  }
+
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+
+  if (mIPCOpen) {
+    Unused << Send__delete__(this);
+  }
+
+  return NS_OK;
+}
+
+void
+FileChannelChild::AddIPDLReference()
+{
+  AddRef();
+  mIPCOpen = true;
+}
+
+void
+FileChannelChild::ActorDestroy(ActorDestroyReason why)
+{
+  MOZ_ASSERT(mIPCOpen);
+  mIPCOpen = false;
+  Release();
+}
+
+} // namespace net
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/netwerk/protocol/file/FileChannelChild.h
@@ -0,0 +1,43 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=2 sw=2 sts=2 et tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla__net__FileChannelChild_h
+#define mozilla__net__FileChannelChild_h
+
+#include "nsFileChannel.h"
+#include "nsIChildChannel.h"
+#include "nsISupportsImpl.h"
+
+#include "mozilla/net/PFileChannelChild.h"
+
+namespace mozilla {
+namespace net {
+
+class FileChannelChild : public nsFileChannel
+                       , public nsIChildChannel
+                       , public PFileChannelChild
+{
+public:
+  explicit FileChannelChild(nsIURI *uri);
+
+  NS_DECL_ISUPPORTS_INHERITED
+  NS_DECL_NSICHILDCHANNEL
+
+protected:
+  virtual void ActorDestroy(ActorDestroyReason why) override;
+
+private:
+  ~FileChannelChild() { };
+
+  void AddIPDLReference();
+
+  bool mIPCOpen;
+};
+
+} // namespace net
+} // namespace mozilla
+
+#endif /* mozilla__net__FileChannelChild_h */
new file mode 100644
--- /dev/null
+++ b/netwerk/protocol/file/FileChannelParent.cpp
@@ -0,0 +1,105 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=2 sw=2 sts=2 et tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "FileChannelParent.h"
+#include "mozilla/Assertions.h"
+#include "nsNetUtil.h"
+#include "nsIChannel.h"
+
+namespace mozilla {
+namespace net {
+
+NS_IMPL_ISUPPORTS(FileChannelParent, nsIParentChannel, nsIStreamListener)
+
+FileChannelParent::~FileChannelParent()
+{
+}
+
+bool
+FileChannelParent::Init(const uint32_t &channelId)
+{
+  nsCOMPtr<nsIChannel> channel;
+  MOZ_ALWAYS_SUCCEEDS(
+      NS_LinkRedirectChannels(channelId, this, getter_AddRefs(channel)));
+
+  return true;
+}
+
+NS_IMETHODIMP
+FileChannelParent::SetParentListener(HttpChannelParentListener* aListener)
+{
+  // Nothing to do.
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+FileChannelParent::NotifyTrackingProtectionDisabled()
+{
+  // Nothing to do.
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+FileChannelParent::NotifyTrackingResource()
+{
+  // Nothing to do.
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+FileChannelParent::SetClassifierMatchedInfo(const nsACString& aList,
+                                            const nsACString& aProvider,
+                                            const nsACString& aPrefix)
+{
+  // nothing to do
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+FileChannelParent::Delete()
+{
+  // Nothing to do.
+  return NS_OK;
+}
+
+void
+FileChannelParent::ActorDestroy(ActorDestroyReason why)
+{
+}
+
+NS_IMETHODIMP
+FileChannelParent::OnStartRequest(nsIRequest *aRequest,
+                                  nsISupports *aContext)
+{
+  // We don't have a way to prevent nsBaseChannel from calling AsyncOpen on
+  // the created nsDataChannel. We don't have anywhere to send the data in the
+  // parent, so abort the binding.
+  return NS_BINDING_ABORTED;
+}
+
+NS_IMETHODIMP
+FileChannelParent::OnStopRequest(nsIRequest *aRequest,
+                                 nsISupports *aContext,
+                                 nsresult aStatusCode)
+{
+  // See above.
+  MOZ_ASSERT(NS_FAILED(aStatusCode));
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+FileChannelParent::OnDataAvailable(nsIRequest *aRequest,
+                                   nsISupports *aContext,
+                                   nsIInputStream *aInputStream,
+                                   uint64_t aOffset,
+                                   uint32_t aCount)
+{
+  // See above.
+  MOZ_CRASH("Should never be called");
+}
+
+} // namespace net
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/netwerk/protocol/file/FileChannelParent.h
@@ -0,0 +1,41 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* vim: set ts=4 sw=4 sts=4 et tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla__net__FileChannelParent_h
+#define mozilla__net__FileChannelParent_h
+
+#include "nsIParentChannel.h"
+#include "nsISupportsImpl.h"
+
+#include "mozilla/net/PFileChannelParent.h"
+
+namespace mozilla {
+namespace net {
+
+// In order to support HTTP redirects to file:, we need to implement the HTTP
+// redirection API, which requires a class that implements nsIParentChannel
+// and which calls NS_LinkRedirectChannels.
+class FileChannelParent : public nsIParentChannel
+                        , public PFileChannelParent
+{
+public:
+  NS_DECL_ISUPPORTS
+  NS_DECL_NSIPARENTCHANNEL
+  NS_DECL_NSIREQUESTOBSERVER
+  NS_DECL_NSISTREAMLISTENER
+
+  MOZ_MUST_USE bool Init(const uint32_t& aArgs);
+
+private:
+  ~FileChannelParent();
+
+  virtual void ActorDestroy(ActorDestroyReason why) override;
+};
+
+} // namespace net
+} // namespace mozilla
+
+#endif /* mozilla__net__FileChannelParent_h */
--- a/netwerk/protocol/file/moz.build
+++ b/netwerk/protocol/file/moz.build
@@ -3,31 +3,36 @@
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 with Files('**'):
     BUG_COMPONENT = ('Core', 'Networking: File')
 
 EXPORTS.mozilla.net += [
+    'FileChannelParent.h',
     'nsFileProtocolHandler.h',
 ]
 
 XPIDL_SOURCES += [
     'nsIFileChannel.idl',
     'nsIFileProtocolHandler.idl',
 ]
 
 XPIDL_MODULE = 'necko_file'
 
 UNIFIED_SOURCES += [
+    'FileChannelChild.cpp',
+    'FileChannelParent.cpp',
     'nsFileChannel.cpp',
     'nsFileProtocolHandler.cpp',
 ]
 
+include('/ipc/chromium/chromium-config.mozbuild')
+
 FINAL_LIBRARY = 'xul'
 
 LOCAL_INCLUDES += [
     '/netwerk/base',
 ]
 
 if CONFIG['GNU_CXX']:
     CXXFLAGS += ['-Wno-error=shadow']
--- a/netwerk/protocol/file/nsFileProtocolHandler.cpp
+++ b/netwerk/protocol/file/nsFileProtocolHandler.cpp
@@ -7,16 +7,18 @@
 #include "nsIFile.h"
 #include "nsFileProtocolHandler.h"
 #include "nsFileChannel.h"
 #include "nsStandardURL.h"
 #include "nsURLHelper.h"
 
 #include "nsNetUtil.h"
 
+#include "FileChannelChild.h"
+
 // URL file handling, copied and modified from xpfe/components/bookmarks/src/nsBookmarksService.cpp
 #ifdef XP_WIN
 #include <shlobj.h>
 #include <intshcut.h>
 #include "nsIFileURL.h"
 #ifdef CompareString
 #undef CompareString
 #endif
@@ -183,17 +185,22 @@ nsFileProtocolHandler::NewURI(const nsAC
     return CallQueryInterface(url, result);
 }
 
 NS_IMETHODIMP
 nsFileProtocolHandler::NewChannel2(nsIURI* uri,
                                    nsILoadInfo* aLoadInfo,
                                    nsIChannel** result)
 {
-    nsFileChannel *chan = new nsFileChannel(uri);
+    nsFileChannel *chan;
+    if (IsNeckoChild()) {
+        chan = new mozilla::net::FileChannelChild(uri);
+    } else {
+        chan = new nsFileChannel(uri);
+    }
     if (!chan)
         return NS_ERROR_OUT_OF_MEMORY;
     NS_ADDREF(chan);
 
     nsresult rv = chan->Init();
     if (NS_FAILED(rv)) {
         NS_RELEASE(chan);
         return rv;