Bug 1357678 - Make stream converters do omt. r=mayhemer
authorDragana Damjanovic <dd.mozilla@gmail.com>
Tue, 30 May 2017 14:11:34 +0200
changeset 409383 47e0df5e8bd1318caa8ae9984d117a7492493f5a
parent 409382 5f12fd37c3bd5e511968b5b9a1c389a41119f66c
child 409384 327ecc8de0295e4a7d64994dfd7add0128c50e2e
push id7391
push usermtabara@mozilla.com
push dateMon, 12 Jun 2017 13:08:53 +0000
treeherdermozilla-beta@2191d7f87e2e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmayhemer
bugs1357678
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 1357678 - Make stream converters do omt. r=mayhemer
netwerk/protocol/http/HttpBaseChannel.cpp
netwerk/streamconv/converters/nsHTTPCompressConv.cpp
netwerk/streamconv/converters/nsHTTPCompressConv.h
--- a/netwerk/protocol/http/HttpBaseChannel.cpp
+++ b/netwerk/protocol/http/HttpBaseChannel.cpp
@@ -1061,17 +1061,17 @@ class InterceptFailedOnStop : public nsI
   virtual ~InterceptFailedOnStop() {}
   nsCOMPtr<nsIStreamListener> mNext;
   HttpBaseChannel *mChannel;
 
 public:
   InterceptFailedOnStop(nsIStreamListener *arg, HttpBaseChannel *chan)
   : mNext(arg)
   , mChannel(chan) {}
-  NS_DECL_ISUPPORTS
+  NS_DECL_THREADSAFE_ISUPPORTS
 
   NS_IMETHOD OnStartRequest(nsIRequest *aRequest, nsISupports *aContext) override
   {
     return mNext->OnStartRequest(aRequest, aContext);
   }
 
   NS_IMETHOD OnStopRequest(nsIRequest *aRequest, nsISupports *aContext, nsresult aStatusCode) override
   {
--- a/netwerk/streamconv/converters/nsHTTPCompressConv.cpp
+++ b/netwerk/streamconv/converters/nsHTTPCompressConv.cpp
@@ -29,33 +29,35 @@ namespace net {
 extern LazyLogModule gHttpLog;
 #define LOG(args) MOZ_LOG(mozilla::net::gHttpLog, mozilla::LogLevel::Debug, args)
 
 // nsISupports implementation
 NS_IMPL_ISUPPORTS(nsHTTPCompressConv,
                   nsIStreamConverter,
                   nsIStreamListener,
                   nsIRequestObserver,
-                  nsICompressConvStats)
+                  nsICompressConvStats,
+                  nsIThreadRetargetableStreamListener)
 
 // nsFTPDirListingConv methods
 nsHTTPCompressConv::nsHTTPCompressConv()
   : mMode(HTTP_COMPRESS_IDENTITY)
   , mOutBuffer(nullptr)
   , mInpBuffer(nullptr)
   , mOutBufferLen(0)
   , mInpBufferLen(0)
   , mCheckHeaderDone(false)
   , mStreamEnded(false)
   , mStreamInitialized(false)
   , mLen(0)
   , hMode(0)
   , mSkipCount(0)
   , mFlags(0)
   , mDecodedDataLength(0)
+  , mMutex("nsHTTPCompressConv")
 {
   LOG(("nsHttpCompresssConv %p ctor\n", this));
   if (NS_IsMainThread()) {
     mFailUncleanStops =
       Preferences::GetBool("network.http.enforce-framing.http", false);
   } else {
     mFailUncleanStops = false;
   }
@@ -99,30 +101,35 @@ nsHTTPCompressConv::AsyncConvertData(con
              !PL_strncasecmp(aFromType, HTTP_X_GZIP_TYPE, sizeof(HTTP_X_GZIP_TYPE)-1)) {
     mMode = HTTP_COMPRESS_GZIP;
   } else if (!PL_strncasecmp(aFromType, HTTP_DEFLATE_TYPE, sizeof(HTTP_DEFLATE_TYPE)-1)) {
     mMode = HTTP_COMPRESS_DEFLATE;
   } else if (!PL_strncasecmp(aFromType, HTTP_BROTLI_TYPE, sizeof(HTTP_BROTLI_TYPE)-1)) {
     mMode = HTTP_COMPRESS_BROTLI;
   }
   LOG(("nsHttpCompresssConv %p AsyncConvertData %s %s mode %d\n",
-       this, aFromType, aToType, mMode));
+       this, aFromType, aToType, (CompressMode)mMode));
 
+  MutexAutoLock lock(mMutex);
   // hook ourself up with the receiving listener.
   mListener = aListener;
 
-  mAsyncConvContext = aCtxt;
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsHTTPCompressConv::OnStartRequest(nsIRequest* request, nsISupports *aContext)
 {
   LOG(("nsHttpCompresssConv %p onstart\n", this));
-  return mListener->OnStartRequest(request, aContext);
+  nsCOMPtr<nsIStreamListener> listener;
+  {
+    MutexAutoLock lock(mMutex);
+    listener = mListener;
+  }
+  return listener->OnStartRequest(request, aContext);
 }
 
 NS_IMETHODIMP
 nsHTTPCompressConv::OnStopRequest(nsIRequest* request, nsISupports *aContext,
                                   nsresult aStatus)
 {
   nsresult status = aStatus;
   LOG(("nsHttpCompresssConv %p onstop %" PRIx32 "\n", this, static_cast<uint32_t>(aStatus)));
@@ -140,26 +147,32 @@ nsHTTPCompressConv::OnStopRequest(nsIReq
     nsCOMPtr<nsIForcePendingChannel> fpChannel = do_QueryInterface(request);
     bool isPending = false;
     if (request) {
       request->IsPending(&isPending);
     }
     if (fpChannel && !isPending) {
       fpChannel->ForcePending(true);
     }
-    if (mBrotli && (mBrotli->mTotalOut == 0) && !BrotliStateIsStreamEnd(&mBrotli->mState)) {
+    if (mBrotli && (mBrotli->mTotalOut == 0) && !mBrotli->mBrotliStateIsStreamEnd) {
       status = NS_ERROR_INVALID_CONTENT_ENCODING;
     }
     LOG(("nsHttpCompresssConv %p onstop brotlihandler rv %" PRIx32 "\n",
          this, static_cast<uint32_t>(status)));
     if (fpChannel && !isPending) {
       fpChannel->ForcePending(false);
     }
   }
-  return mListener->OnStopRequest(request, aContext, status);
+
+  nsCOMPtr<nsIStreamListener> listener;
+  {
+    MutexAutoLock lock(mMutex);
+    listener = mListener;
+  }
+  return listener->OnStopRequest(request, aContext, status);
 }
 
 
 /* static */ nsresult
 nsHTTPCompressConv::BrotliHandler(nsIInputStream *stream, void *closure, const char *dataIn,
                                   uint32_t, uint32_t aAvail, uint32_t *countRead)
 {
   MOZ_ASSERT(stream);
@@ -184,20 +197,23 @@ nsHTTPCompressConv::BrotliHandler(nsIInp
   }
 
   do {
     outSize = kOutSize;
     outPtr = outBuffer.get();
 
     // brotli api is documented in brotli/dec/decode.h and brotli/dec/decode.c
     LOG(("nsHttpCompresssConv %p brotlihandler decompress %" PRIuSIZE "\n", self, avail));
+    size_t totalOut = self->mBrotli->mTotalOut;
     res = ::BrotliDecompressStream(
       &avail, reinterpret_cast<const unsigned char **>(&dataIn),
-      &outSize, &outPtr, &self->mBrotli->mTotalOut, &self->mBrotli->mState);
+      &outSize, &outPtr, &totalOut, &self->mBrotli->mState);
     outSize = kOutSize - outSize;
+    self->mBrotli->mTotalOut = totalOut;
+    self->mBrotli->mBrotliStateIsStreamEnd = BrotliStateIsStreamEnd(&self->mBrotli->mState);
     LOG(("nsHttpCompresssConv %p brotlihandler decompress rv=%" PRIx32 " out=%" PRIuSIZE "\n",
          self, static_cast<uint32_t>(res), outSize));
 
     if (res == BROTLI_RESULT_ERROR) {
       LOG(("nsHttpCompressConv %p marking invalid encoding", self));
       self->mBrotli->mStatus = NS_ERROR_INVALID_CONTENT_ENCODING;
       return self->mBrotli->mStatus;
     }
@@ -453,17 +469,22 @@ nsHTTPCompressConv::OnDataAvailable(nsIR
     }
     if (NS_FAILED(rv)) {
       return rv;
     }
   }
     break;
 
   default:
-    rv = mListener->OnDataAvailable(request, aContext, iStr, aSourceOffset, aCount);
+    nsCOMPtr<nsIStreamListener> listener;
+    {
+      MutexAutoLock lock(mMutex);
+      listener = mListener;
+    }
+    rv = listener->OnDataAvailable(request, aContext, iStr, aSourceOffset, aCount);
     if (NS_FAILED (rv)) {
       return rv;
     }
   } /* switch */
 
   return NS_OK;
 } /* OnDataAvailable */
 
@@ -486,18 +507,23 @@ nsHTTPCompressConv::do_OnDataAvailable(n
 {
   if (!mStream) {
     mStream = do_CreateInstance(NS_STRINGINPUTSTREAM_CONTRACTID);
     NS_ENSURE_STATE(mStream);
   }
 
   mStream->ShareData(buffer, count);
 
-  nsresult rv = mListener->OnDataAvailable(request, context, mStream,
-                                           offset, count);
+  nsCOMPtr<nsIStreamListener> listener;
+  {
+    MutexAutoLock lock(mMutex);
+    listener = mListener;
+  }
+  nsresult rv = listener->OnDataAvailable(request, context, mStream,
+                                          offset, count);
 
   // Make sure the stream no longer references |buffer| in case our listener
   // is crazy enough to try to read from |mStream| after ODA.
   mStream->ShareData("", 0);
   mDecodedDataLength += count;
 
   return rv;
 }
@@ -635,16 +661,32 @@ nsHTTPCompressConv::check_header(nsIInpu
         return streamLen;
       }
       break;
     }
   }
   return streamLen;
 }
 
+NS_IMETHODIMP
+nsHTTPCompressConv::CheckListenerChain()
+{
+  nsCOMPtr<nsIThreadRetargetableStreamListener> listener;
+  {
+    MutexAutoLock lock(mMutex);
+    listener = do_QueryInterface(mListener);
+  }
+
+  if (!listener) {
+    return NS_ERROR_NO_INTERFACE;
+  }
+
+  return listener->CheckListenerChain();
+}
+
 } // namespace net
 } // namespace mozilla
 
 nsresult
 NS_NewHTTPCompressConv(mozilla::net::nsHTTPCompressConv **aHTTPCompressConv)
 {
   NS_PRECONDITION(aHTTPCompressConv != nullptr, "null ptr");
   if (!aHTTPCompressConv) {
--- a/netwerk/streamconv/converters/nsHTTPCompressConv.h
+++ b/netwerk/streamconv/converters/nsHTTPCompressConv.h
@@ -4,18 +4,21 @@
  * 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/. */
 
 #if !defined (__nsHTTPCompressConv__h__)
 #define	__nsHTTPCompressConv__h__	1
 
 #include "nsIStreamConverter.h"
 #include "nsICompressConvStats.h"
+#include "nsIThreadRetargetableStreamListener.h"
 #include "nsCOMPtr.h"
 #include "nsAutoPtr.h"
+#include "mozilla/Atomics.h"
+#include "mozilla/Mutex.h"
 
 #include "zlib.h"
 
 // brotli includes
 #undef assert
 #include "assert.h"
 #include "state.h"
 
@@ -52,84 +55,89 @@ typedef enum    {
 } CompressMode;
 
 class BrotliWrapper
 {
 public:
   BrotliWrapper()
     : mTotalOut(0)
     , mStatus(NS_OK)
+    , mBrotliStateIsStreamEnd(false)
   {
     BrotliStateInit(&mState);
   }
   ~BrotliWrapper()
   {
     BrotliStateCleanup(&mState);
   }
 
-  BrotliState mState;
-  size_t       mTotalOut;
-  nsresult     mStatus;
+  BrotliState             mState;
+  Atomic<size_t, Relaxed> mTotalOut;
+  nsresult                mStatus;
+  Atomic<bool, Relaxed>   mBrotliStateIsStreamEnd;
 
   nsIRequest  *mRequest;
   nsISupports *mContext;
   uint64_t     mSourceOffset;
 };
 
 class nsHTTPCompressConv
   : public nsIStreamConverter
   , public nsICompressConvStats
+  , public nsIThreadRetargetableStreamListener
 {
   public:
   // nsISupports methods
     NS_DECL_THREADSAFE_ISUPPORTS
     NS_DECL_NSIREQUESTOBSERVER
     NS_DECL_NSISTREAMLISTENER
     NS_DECL_NSICOMPRESSCONVSTATS
+    NS_DECL_NSITHREADRETARGETABLESTREAMLISTENER
 
   // nsIStreamConverter methods
     NS_DECL_NSISTREAMCONVERTER
 
     nsHTTPCompressConv ();
 
 private:
     virtual ~nsHTTPCompressConv ();
 
     nsCOMPtr<nsIStreamListener> mListener; // this guy gets the converted data via his OnDataAvailable ()
-    CompressMode        mMode;
+    Atomic<CompressMode, Relaxed> mMode;
 
     unsigned char *mOutBuffer;
     unsigned char *mInpBuffer;
 
     uint32_t	mOutBufferLen;
     uint32_t	mInpBufferLen;
 
     nsAutoPtr<BrotliWrapper> mBrotli;
 
-    nsCOMPtr<nsISupports>   mAsyncConvContext;
     nsCOMPtr<nsIStringInputStream>  mStream;
 
     static nsresult
     BrotliHandler(nsIInputStream *stream, void *closure, const char *dataIn,
                   uint32_t, uint32_t avail, uint32_t *countRead);
 
     nsresult do_OnDataAvailable (nsIRequest *request, nsISupports *aContext,
                                  uint64_t aSourceOffset, const char *buffer,
                                  uint32_t aCount);
 
-    bool        mCheckHeaderDone;
-    bool        mStreamEnded;
-    bool        mStreamInitialized;
-    bool        mDummyStreamInitialised;
-    bool        mFailUncleanStops;
+    bool         mCheckHeaderDone;
+    Atomic<bool> mStreamEnded;
+    bool         mStreamInitialized;
+    bool         mDummyStreamInitialised;
+    bool         mFailUncleanStops;
 
     z_stream d_stream;
     unsigned mLen, hMode, mSkipCount, mFlags;
 
     uint32_t check_header (nsIInputStream *iStr, uint32_t streamLen, nsresult *rv);
 
-    uint32_t mDecodedDataLength;
+    Atomic<uint32_t, Relaxed> mDecodedDataLength;
+
+    mutable mozilla::Mutex mMutex;
 };
 
 } // namespace net
 } // namespace mozilla
 
 #endif