From f1944c7299a93fba712534296bf366a79e92440b Mon Sep 17 00:00:00 2001 From: Blake Kaplan Date: Fri, 27 Mar 2015 13:12:37 -0700 Subject: [PATCH] Bug 1058551 - Support redirects to data: URIs. r=honza --- netwerk/ipc/NeckoChild.cpp | 14 +++ netwerk/ipc/NeckoChild.h | 2 + netwerk/ipc/NeckoParent.cpp | 24 +++++ netwerk/ipc/NeckoParent.h | 8 ++ netwerk/ipc/PDataChannel.ipdl | 25 ++++++ netwerk/ipc/PNecko.ipdl | 9 ++ netwerk/ipc/moz.build | 1 + netwerk/protocol/data/DataChannelChild.cpp | 70 +++++++++++++++ netwerk/protocol/data/DataChannelChild.h | 43 +++++++++ netwerk/protocol/data/DataChannelParent.cpp | 87 +++++++++++++++++++ netwerk/protocol/data/DataChannelParent.h | 41 +++++++++ netwerk/protocol/data/moz.build | 8 ++ netwerk/protocol/data/nsDataChannel.h | 3 +- netwerk/protocol/data/nsDataHandler.cpp | 10 ++- .../unit/test_redirect_different-protocol.js | 8 +- 15 files changed, 342 insertions(+), 11 deletions(-) create mode 100644 netwerk/ipc/PDataChannel.ipdl create mode 100644 netwerk/protocol/data/DataChannelChild.cpp create mode 100644 netwerk/protocol/data/DataChannelChild.h create mode 100644 netwerk/protocol/data/DataChannelParent.cpp create mode 100644 netwerk/protocol/data/DataChannelParent.h diff --git a/netwerk/ipc/NeckoChild.cpp b/netwerk/ipc/NeckoChild.cpp index 09c0a1965c1c..85ef04f54826 100644 --- a/netwerk/ipc/NeckoChild.cpp +++ b/netwerk/ipc/NeckoChild.cpp @@ -167,6 +167,20 @@ NeckoChild::DeallocPWebSocketChild(PWebSocketChild* child) return true; } +PDataChannelChild* +NeckoChild::AllocPDataChannelChild(const uint32_t& channelId) +{ + MOZ_ASSERT_UNREACHABLE("Should never get here"); + return nullptr; +} + +bool +NeckoChild::DeallocPDataChannelChild(PDataChannelChild* child) +{ + // NB: See DataChannelChild::ActorDestroy. + return true; +} + PRtspControllerChild* NeckoChild::AllocPRtspControllerChild() { diff --git a/netwerk/ipc/NeckoChild.h b/netwerk/ipc/NeckoChild.h index 169879797a61..63e8b6cc4414 100644 --- a/netwerk/ipc/NeckoChild.h +++ b/netwerk/ipc/NeckoChild.h @@ -62,6 +62,8 @@ protected: const URIParams&, const OptionalURIParams&) override; virtual bool DeallocPRemoteOpenFileChild(PRemoteOpenFileChild*) override; + virtual PDataChannelChild* AllocPDataChannelChild(const uint32_t& channelId) override; + virtual bool DeallocPDataChannelChild(PDataChannelChild* child) override; virtual PRtspControllerChild* AllocPRtspControllerChild() override; virtual bool DeallocPRtspControllerChild(PRtspControllerChild*) override; virtual PRtspChannelChild* diff --git a/netwerk/ipc/NeckoParent.cpp b/netwerk/ipc/NeckoParent.cpp index 80c416d2e4ac..429415a96256 100644 --- a/netwerk/ipc/NeckoParent.cpp +++ b/netwerk/ipc/NeckoParent.cpp @@ -13,6 +13,7 @@ #include "mozilla/net/WyciwygChannelParent.h" #include "mozilla/net/FTPChannelParent.h" #include "mozilla/net/WebSocketChannelParent.h" +#include "mozilla/net/DataChannelParent.h" #ifdef NECKO_PROTOCOL_rtsp #include "mozilla/net/RtspControllerParent.h" #include "mozilla/net/RtspChannelParent.h" @@ -349,6 +350,29 @@ NeckoParent::DeallocPWebSocketParent(PWebSocketParent* actor) return true; } +PDataChannelParent* +NeckoParent::AllocPDataChannelParent(const uint32_t &channelId) +{ + nsRefPtr p = new DataChannelParent(); + return p.forget().take(); +} + +bool +NeckoParent::DeallocPDataChannelParent(PDataChannelParent* actor) +{ + nsRefPtr p = dont_AddRef(static_cast(actor)); + return true; +} + +bool +NeckoParent::RecvPDataChannelConstructor(PDataChannelParent* actor, + const uint32_t& channelId) +{ + DataChannelParent* p = static_cast(actor); + p->Init(channelId); + return true; +} + PRtspControllerParent* NeckoParent::AllocPRtspControllerParent() { diff --git a/netwerk/ipc/NeckoParent.h b/netwerk/ipc/NeckoParent.h index d9e6cf750209..bcd66cf45567 100644 --- a/netwerk/ipc/NeckoParent.h +++ b/netwerk/ipc/NeckoParent.h @@ -170,6 +170,14 @@ protected: virtual mozilla::ipc::IProtocol* CloneProtocol(Channel* aChannel, mozilla::ipc::ProtocolCloneContext* aCtx) override; + + virtual PDataChannelParent* + AllocPDataChannelParent(const uint32_t& channelId) override; + virtual bool DeallocPDataChannelParent(PDataChannelParent* parent) override; + + virtual bool RecvPDataChannelConstructor(PDataChannelParent* aActor, + const uint32_t& channelId) override; + virtual PRtspControllerParent* AllocPRtspControllerParent() override; virtual bool DeallocPRtspControllerParent(PRtspControllerParent*) override; diff --git a/netwerk/ipc/PDataChannel.ipdl b/netwerk/ipc/PDataChannel.ipdl new file mode 100644 index 000000000000..17a340cc0d46 --- /dev/null +++ b/netwerk/ipc/PDataChannel.ipdl @@ -0,0 +1,25 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set sw=2 ts=8 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 { + +async protocol PDataChannel +{ + manager PNecko; + +parent: + // Note: channels are opened during construction, so no open method here: + // see PNecko.ipdl + __delete__(); +}; + +} // namespace net +} // namespace mozilla diff --git a/netwerk/ipc/PNecko.ipdl b/netwerk/ipc/PNecko.ipdl index b35c7b816f5e..4e60f0a13d04 100644 --- a/netwerk/ipc/PNecko.ipdl +++ b/netwerk/ipc/PNecko.ipdl @@ -20,6 +20,7 @@ include protocol PDNSRequest; include protocol PChannelDiverter; include protocol PBlob; //FIXME: bug #792908 include protocol PFileDescriptorSet; +include protocol PDataChannel; include protocol PRtspController; include protocol PRtspChannel; @@ -48,6 +49,7 @@ prio(normal upto urgent) sync protocol PNecko manages PUDPSocket; manages PDNSRequest; manages PRemoteOpenFile; + manages PDataChannel; manages PRtspController; manages PRtspChannel; manages PChannelDiverter; @@ -76,6 +78,13 @@ parent: SpeculativeConnect(URIParams uri); HTMLDNSPrefetch(nsString hostname, uint16_t flags); CancelHTMLDNSPrefetch(nsString hostname, 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. + */ + PDataChannel(uint32_t channelId); + PRtspController(); PRtspChannel(RtspChannelConnectArgs args); PChannelDiverter(ChannelDiverterArgs channel); diff --git a/netwerk/ipc/moz.build b/netwerk/ipc/moz.build index 7f5d05df7b6b..d3c8f8ddd4cf 100644 --- a/netwerk/ipc/moz.build +++ b/netwerk/ipc/moz.build @@ -32,6 +32,7 @@ UNIFIED_SOURCES += [ IPDL_SOURCES = [ 'NeckoChannelParams.ipdlh', 'PChannelDiverter.ipdl', + 'PDataChannel.ipdl', 'PNecko.ipdl', 'PRemoteOpenFile.ipdl', 'PRtspChannel.ipdl', diff --git a/netwerk/protocol/data/DataChannelChild.cpp b/netwerk/protocol/data/DataChannelChild.cpp new file mode 100644 index 000000000000..8f6f846f9582 --- /dev/null +++ b/netwerk/protocol/data/DataChannelChild.cpp @@ -0,0 +1,70 @@ +/* -*- 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/. */ + +#include "DataChannelChild.h" + +#include "mozilla/unused.h" +#include "mozilla/net/NeckoChild.h" + +namespace mozilla { +namespace net { + +NS_IMPL_ISUPPORTS_INHERITED(DataChannelChild, nsDataChannel, nsIChildChannel) + +DataChannelChild::DataChannelChild(nsIURI* aURI) + : nsDataChannel(aURI) + , mIPCOpen(false) +{ +} + +DataChannelChild::~DataChannelChild() +{ +} + +NS_IMETHODIMP +DataChannelChild::ConnectParent(uint32_t aId) +{ + if (!gNeckoChild->SendPDataChannelConstructor(this, aId)) { + return NS_ERROR_FAILURE; + } + + // IPC now has a ref to us. + AddIPDLReference(); + return NS_OK; +} + +NS_IMETHODIMP +DataChannelChild::CompleteRedirectSetup(nsIStreamListener *aListener, + nsISupports *aContext) +{ + nsresult rv = AsyncOpen(aListener, aContext); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + + if (mIPCOpen) { + unused << Send__delete__(this); + } + return NS_OK; +} + +void +DataChannelChild::AddIPDLReference() +{ + AddRef(); + mIPCOpen = true; +} + +void +DataChannelChild::ActorDestroy(ActorDestroyReason why) +{ + MOZ_ASSERT(mIPCOpen); + mIPCOpen = false; + Release(); +} + +} // namespace mozilla +} // namespace net diff --git a/netwerk/protocol/data/DataChannelChild.h b/netwerk/protocol/data/DataChannelChild.h new file mode 100644 index 000000000000..112199d79704 --- /dev/null +++ b/netwerk/protocol/data/DataChannelChild.h @@ -0,0 +1,43 @@ +/* -*- 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 NS_DATACHANNELCHILD_H +#define NS_DATACHANNELCHILD_H + +#include "nsDataChannel.h" +#include "nsIChildChannel.h" +#include "nsISupportsImpl.h" + +#include "mozilla/net/PDataChannelChild.h" + +namespace mozilla { +namespace net { + +class DataChannelChild : public nsDataChannel + , public nsIChildChannel + , public PDataChannelChild +{ +public: + explicit DataChannelChild(nsIURI *uri); + + NS_DECL_ISUPPORTS + NS_DECL_NSICHILDCHANNEL + +protected: + virtual void ActorDestroy(ActorDestroyReason why) override; + +private: + ~DataChannelChild(); + + void AddIPDLReference(); + + bool mIPCOpen; +}; + +} // namespace mozilla +} // namespace net + +#endif /* NS_DATACHANNELCHILD_H */ diff --git a/netwerk/protocol/data/DataChannelParent.cpp b/netwerk/protocol/data/DataChannelParent.cpp new file mode 100644 index 000000000000..ece9a0aae82b --- /dev/null +++ b/netwerk/protocol/data/DataChannelParent.cpp @@ -0,0 +1,87 @@ +/* -*- 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/. */ + +#include "DataChannelParent.h" +#include "mozilla/Assertions.h" + +namespace mozilla { +namespace net { + +NS_IMPL_ISUPPORTS(DataChannelParent, nsIParentChannel, nsIStreamListener) + +DataChannelParent::~DataChannelParent() +{ +} + +bool +DataChannelParent::Init(const uint32_t &channelId) +{ + nsCOMPtr channel; + MOZ_ALWAYS_TRUE(NS_SUCCEEDED( + NS_LinkRedirectChannels(channelId, this, getter_AddRefs(channel)))); + + return true; +} + +NS_IMETHODIMP +DataChannelParent::SetParentListener(HttpChannelParentListener* aListener) +{ + // Nothing to do. + return NS_OK; +} + +NS_IMETHODIMP +DataChannelParent::NotifyTrackingProtectionDisabled() +{ + // Nothing to do. + return NS_OK; +} + +NS_IMETHODIMP +DataChannelParent::Delete() +{ + // Nothing to do. + return NS_OK; +} + +void +DataChannelParent::ActorDestroy(ActorDestroyReason why) +{ +} + +NS_IMETHODIMP +DataChannelParent::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 +DataChannelParent::OnStopRequest(nsIRequest *aRequest, + nsISupports *aContext, + nsresult aStatusCode) +{ + // See above. + MOZ_ASSERT(NS_FAILED(aStatusCode)); + return NS_OK; +} + +NS_IMETHODIMP +DataChannelParent::OnDataAvailable(nsIRequest *aRequest, + nsISupports *aContext, + nsIInputStream *aInputStream, + uint64_t aOffset, + uint32_t aCount) +{ + // See above. + MOZ_CRASH("Should never be called"); +} + +} // namespace mozilla +} // namespace net diff --git a/netwerk/protocol/data/DataChannelParent.h b/netwerk/protocol/data/DataChannelParent.h new file mode 100644 index 000000000000..692727184914 --- /dev/null +++ b/netwerk/protocol/data/DataChannelParent.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 NS_DATACHANNELPARENT_H +#define NS_DATACHANNELPARENT_H + +#include "nsIParentChannel.h" +#include "nsISupportsImpl.h" + +#include "mozilla/net/PDataChannelParent.h" + +namespace mozilla { +namespace net { + +// In order to support HTTP redirects to data:, we need to implement the HTTP +// redirection API, which requires a class that implements nsIParentChannel +// and which calls NS_LinkRedirectChannels. +class DataChannelParent : public nsIParentChannel + , public PDataChannelParent +{ +public: + NS_DECL_ISUPPORTS + NS_DECL_NSIPARENTCHANNEL + NS_DECL_NSIREQUESTOBSERVER + NS_DECL_NSISTREAMLISTENER + + bool Init(const uint32_t& aArgs); + +private: + ~DataChannelParent(); + + virtual void ActorDestroy(ActorDestroyReason why) override; +}; + +} // namespace mozilla +} // namespace net + +#endif /* NS_DATACHANNELPARENT_H */ diff --git a/netwerk/protocol/data/moz.build b/netwerk/protocol/data/moz.build index 9486e8f246ef..75a137ffb275 100644 --- a/netwerk/protocol/data/moz.build +++ b/netwerk/protocol/data/moz.build @@ -4,11 +4,19 @@ # 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/. +EXPORTS.mozilla.net += [ + 'DataChannelParent.h', +] + UNIFIED_SOURCES += [ + 'DataChannelChild.cpp', + 'DataChannelParent.cpp', 'nsDataChannel.cpp', 'nsDataHandler.cpp', ] +include('/ipc/chromium/chromium-config.mozbuild') + FAIL_ON_WARNINGS = True FINAL_LIBRARY = 'xul' diff --git a/netwerk/protocol/data/nsDataChannel.h b/netwerk/protocol/data/nsDataChannel.h index 7fdab0e2e8e7..20bf861fed5e 100644 --- a/netwerk/protocol/data/nsDataChannel.h +++ b/netwerk/protocol/data/nsDataChannel.h @@ -12,7 +12,8 @@ class nsIInputStream; -class nsDataChannel : public nsBaseChannel { +class nsDataChannel : public nsBaseChannel +{ public: explicit nsDataChannel(nsIURI *uri) { SetURI(uri); diff --git a/netwerk/protocol/data/nsDataHandler.cpp b/netwerk/protocol/data/nsDataHandler.cpp index b242593d29bc..f82e09f1d054 100644 --- a/netwerk/protocol/data/nsDataHandler.cpp +++ b/netwerk/protocol/data/nsDataHandler.cpp @@ -7,6 +7,7 @@ #include "nsDataHandler.h" #include "nsNetCID.h" #include "nsError.h" +#include "DataChannelChild.h" static NS_DEFINE_CID(kSimpleURICID, NS_SIMPLEURI_CID); @@ -108,9 +109,12 @@ nsDataHandler::NewChannel2(nsIURI* uri, nsIChannel** result) { NS_ENSURE_ARG_POINTER(uri); - nsDataChannel* channel = new nsDataChannel(uri); - if (!channel) - return NS_ERROR_OUT_OF_MEMORY; + nsDataChannel* channel; + if (XRE_GetProcessType() == GeckoProcessType_Default) { + channel = new nsDataChannel(uri); + } else { + channel = new mozilla::net::DataChannelChild(uri); + } NS_ADDREF(channel); nsresult rv = channel->Init(); diff --git a/netwerk/test/unit/test_redirect_different-protocol.js b/netwerk/test/unit/test_redirect_different-protocol.js index 401fc47b6c09..89114d686c07 100644 --- a/netwerk/test/unit/test_redirect_different-protocol.js +++ b/netwerk/test/unit/test_redirect_different-protocol.js @@ -44,13 +44,7 @@ function redirectHandler(metadata, response) function finish_test(request, buffer) { - if (inChildProcess()) { - // redirects to protocols other than http/ftp will fail until bug 590682 is fixed. - do_check_eq(buffer, response301Body); - } else { - do_check_eq(buffer, redirectTargetBody); - } - + do_check_eq(buffer, redirectTargetBody); httpServer.stop(do_test_finished); }