Bug 1351163: Part 2 - Add a nsSimpleChannel helper class for creating simple wrapper channels. r=bz r?mayhemer draft
authorKris Maglione <maglione.k@gmail.com>
Thu, 06 Apr 2017 11:53:05 -0700
changeset 557409 4149737a37ac6030ba147aac22e107f34b99a1a4
parent 554556 4c23bded68860e7859bf165edea438c4dee880b7
child 557410 5389cd8a42f8d10d9c505c40a15db362c065dfc1
push id52705
push usermaglione.k@gmail.com
push dateThu, 06 Apr 2017 18:59:23 +0000
reviewersbz, mayhemer
bugs1351163
milestone55.0a1
Bug 1351163: Part 2 - Add a nsSimpleChannel helper class for creating simple wrapper channels. r=bz r?mayhemer This helper class allows us to create simple channels that open an underlying input stream when the channel is first opened, using a closure function, without having to expose the nsBaseChannel class to non-necko code. MozReview-Commit-ID: 6jiImdMXUp0
netwerk/base/moz.build
netwerk/base/nsSimpleChannel.cpp
netwerk/base/nsSimpleChannel.h
netwerk/base/nsSyncStreamListener.cpp
--- a/netwerk/base/moz.build
+++ b/netwerk/base/moz.build
@@ -148,16 +148,17 @@ EXPORTS += [
     'nsASocketHandler.h',
     'nsAsyncRedirectVerifyHelper.h',
     'nsFileStreams.h',
     'nsInputStreamPump.h',
     'nsMIMEInputStream.h',
     'nsNetUtil.h',
     'nsReadLine.h',
     'nsSerializationHelper.h',
+    'nsSimpleChannel.h',
     'nsSimpleNestedURI.h',
     'nsSimpleURI.h',
     'nsStreamListenerWrapper.h',
     'nsTemporaryFileInputStream.h',
     'nsURIHashKey.h',
     'nsURLHelper.h',
     'nsURLParsers.h',
 ]
@@ -221,16 +222,17 @@ UNIFIED_SOURCES += [
     'nsPACMan.cpp',
     'nsPreloadedStream.cpp',
     'nsProtocolProxyService.cpp',
     'nsProxyInfo.cpp',
     'nsRequestObserverProxy.cpp',
     'nsSecCheckWrapChannel.cpp',
     'nsSerializationHelper.cpp',
     'nsServerSocket.cpp',
+    'nsSimpleChannel.cpp',
     'nsSimpleNestedURI.cpp',
     'nsSimpleStreamListener.cpp',
     'nsSimpleURI.cpp',
     'nsSocketTransport2.cpp',
     'nsSocketTransportService2.cpp',
     'nsStandardURL.cpp',
     'nsStreamListenerTee.cpp',
     'nsStreamListenerWrapper.cpp',
new file mode 100644
--- /dev/null
+++ b/netwerk/base/nsSimpleChannel.cpp
@@ -0,0 +1,86 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* 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 "nsBaseChannel.h"
+#include "nsIInputStream.h"
+#include "nsIRequest.h"
+#include "nsSimpleChannel.h"
+
+namespace mozilla {
+namespace net {
+
+// Like MOZ_TRY, but returns the unwrapped error value rather than a
+// GenericErrorResult on failure.
+#define TRY_VAR(target, expr) \
+  do { \
+    auto result = (expr); \
+    if (result.isErr()) { \
+      return result.unwrapErr(); \
+    } \
+    (target) = result.unwrap(); \
+  } while (0)
+
+class nsSimpleChannel final : public nsBaseChannel
+{
+public:
+    explicit nsSimpleChannel(UniquePtr<nsSimpleChannelCallbacks>&& aCallbacks);
+
+protected:
+    virtual ~nsSimpleChannel() {}
+
+    virtual nsresult OpenContentStream(bool async, nsIInputStream **streamOut,
+                                       nsIChannel** channel) override;
+
+    virtual nsresult BeginAsyncRead(nsIStreamListener* listener,
+                                    nsIRequest** request) override;
+
+private:
+    UniquePtr<nsSimpleChannelCallbacks> mCallbacks;;
+};
+
+nsSimpleChannel::nsSimpleChannel(UniquePtr<nsSimpleChannelCallbacks>&& aCallbacks)
+  : mCallbacks(Move(aCallbacks))
+{
+  EnableSynthesizedProgressEvents(true);
+}
+
+nsresult
+nsSimpleChannel::OpenContentStream(bool async, nsIInputStream **streamOut, nsIChannel** channel)
+{
+  nsCOMPtr<nsIInputStream> stream;
+  TRY_VAR(stream, mCallbacks->OpenContentStream(async, this));
+  MOZ_ASSERT(stream);
+
+  *channel = nullptr;
+  stream.forget(streamOut);
+  return NS_OK;
+}
+
+nsresult
+nsSimpleChannel::BeginAsyncRead(nsIStreamListener* listener, nsIRequest** request)
+{
+  nsCOMPtr<nsIRequest> req;
+  TRY_VAR(req, mCallbacks->StartAsyncRead(listener, this));
+
+  req.forget(request);
+  return NS_OK;
+}
+
+#undef TRY_VAR
+
+already_AddRefed<nsIChannel>
+NS_NewSimpleChannelInternal(nsIURI* aURI, nsILoadInfo* aLoadInfo, UniquePtr<nsSimpleChannelCallbacks>&& aCallbacks)
+{
+  RefPtr<nsSimpleChannel> chan = new nsSimpleChannel(Move(aCallbacks));
+
+  chan->SetURI(aURI);
+
+  MOZ_ALWAYS_SUCCEEDS(chan->SetLoadInfo(aLoadInfo));
+
+  return chan.forget();
+}
+
+} // namespace net
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/netwerk/base/nsSimpleChannel.h
@@ -0,0 +1,110 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* 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 nsSimpleChannel_h
+#define nsSimpleChannel_h
+
+#include "mozilla/Result.h"
+#include "mozilla/UniquePtr.h"
+#include "nsCOMPtr.h"
+
+class nsIChannel;
+class nsIInputStream;
+class nsILoadInfo;
+class nsIRequest;
+class nsIStreamListener;
+class nsIURI;
+
+//-----------------------------------------------------------------------------
+
+namespace mozilla {
+
+using InputStreamOrReason = Result<nsCOMPtr<nsIInputStream>, nsresult>;
+using RequestOrReason = Result<nsCOMPtr<nsIRequest>, nsresult>;
+
+namespace net {
+
+class nsSimpleChannelCallbacks
+{
+public:
+  virtual InputStreamOrReason OpenContentStream(bool async, nsIChannel* channel) = 0;
+
+  virtual RequestOrReason StartAsyncRead(nsIStreamListener* stream, nsIChannel* channel) = 0;
+
+  virtual ~nsSimpleChannelCallbacks() {}
+};
+
+template <typename F1, typename F2, typename T>
+class nsSimpleChannelCallbacksImpl final : public nsSimpleChannelCallbacks
+{
+public:
+  nsSimpleChannelCallbacksImpl(F1&& aStartAsyncRead, F2&& aOpenContentStream, T* context)
+    : mStartAsyncRead(aStartAsyncRead)
+    , mOpenContentStream(aOpenContentStream)
+    , mContext(context)
+  {}
+
+  virtual ~nsSimpleChannelCallbacksImpl() {}
+
+  virtual InputStreamOrReason OpenContentStream(bool async, nsIChannel* channel) override
+  {
+    return mOpenContentStream(async, channel, mContext);
+  }
+
+  virtual RequestOrReason StartAsyncRead(nsIStreamListener* listener, nsIChannel* channel) override
+  {
+    return mStartAsyncRead(listener, channel, mContext);
+  }
+
+private:
+  F1 mStartAsyncRead;
+  F2 mOpenContentStream;
+  RefPtr<T> mContext;
+};
+
+already_AddRefed<nsIChannel>
+NS_NewSimpleChannelInternal(nsIURI* aURI, nsILoadInfo* aLoadInfo, UniquePtr<nsSimpleChannelCallbacks>&& aCallbacks);
+
+} // namespace net
+} // namespace mozilla
+
+/**
+ * Creates a simple channel which wraps an input stream created by the given
+ * callbacks. The callbacks are not called until the underlying AsyncOpen2 or
+ * Open2 methods are called, and correspond to the nsBaseChannel::StartAsyncRead
+ * and nsBaseChannel::OpenContentStream methods of the same names.
+ *
+ * The last two arguments of each callback are the created channel instance,
+ * and the ref-counted context object passed to NS_NewSimpleChannel. A strong
+ * reference to that object is guaranteed to be kept alive until the channel
+ * is destroyed.
+ */
+template <typename T, typename F1, typename F2>
+inline already_AddRefed<nsIChannel>
+NS_NewSimpleChannel(nsIURI* aURI, nsILoadInfo* aLoadInfo, T* context, F1&& aStartAsyncRead, F2&& aOpenContentStream)
+{
+  using namespace mozilla;
+
+  auto callbacks = MakeUnique<net::nsSimpleChannelCallbacksImpl<F1, F2, T>>(
+      Move(aStartAsyncRead), Move(aOpenContentStream), context);
+
+  return net::NS_NewSimpleChannelInternal(aURI, aLoadInfo, Move(callbacks));
+}
+
+template <typename T, typename F1>
+inline already_AddRefed<nsIChannel>
+NS_NewSimpleChannel(nsIURI* aURI, nsILoadInfo* aLoadInfo, T* context, F1&& aStartAsyncRead)
+{
+  using namespace mozilla;
+
+  auto openContentStream = [] (bool async, nsIChannel* channel, T* context) {
+    return Err(NS_ERROR_NOT_IMPLEMENTED);
+  };
+
+  return NS_NewSimpleChannel(
+      aURI, aLoadInfo, context, Move(aStartAsyncRead), Move(openContentStream));
+}
+
+#endif // nsSimpleChannel_h
--- a/netwerk/base/nsSyncStreamListener.cpp
+++ b/netwerk/base/nsSyncStreamListener.cpp
@@ -3,16 +3,18 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsIOService.h"
 #include "nsSyncStreamListener.h"
 #include "nsIPipe.h"
 #include "nsThreadUtils.h"
 #include <algorithm>
 
+using namespace mozilla::net;
+
 nsresult
 nsSyncStreamListener::Init()
 {
     return NS_NewPipe(getter_AddRefs(mPipeIn),
                       getter_AddRefs(mPipeOut),
                       nsIOService::gDefaultSegmentSize,
                       UINT32_MAX, // no size limit
                       false,