Bug 1432429 DelayHttpChannelQueue 5/14 draft
authorAndrea Marchesini <amarchesini@mozilla.com>
Fri, 15 Jun 2018 19:09:48 -0700
changeset 826366 ca91839da98fc7f35b51ae5eb332e01269098c8b
parent 826365 a184f88143f7c23a42e6041e076d368d96881f1c
child 826367 6dba227d2f926b575f16258bfa82d76100414566
push id118310
push userbmo:tom@mozilla.com
push dateFri, 03 Aug 2018 18:22:17 +0000
bugs1432429
milestone62.0a1
Bug 1432429 DelayHttpChannelQueue 5/14 MozReview-Commit-ID: HbvegayNkkD
netwerk/protocol/http/DelayHttpChannelQueue.cpp
netwerk/protocol/http/DelayHttpChannelQueue.h
netwerk/protocol/http/moz.build
netwerk/protocol/http/nsHttpChannel.cpp
netwerk/protocol/http/nsHttpChannel.h
new file mode 100644
--- /dev/null
+++ b/netwerk/protocol/http/DelayHttpChannelQueue.cpp
@@ -0,0 +1,123 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* vim:set et cin ts=4 sw=4 sts=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 "DelayHttpChannelQueue.h"
+#include "mozilla/Services.h"
+#include "mozilla/StaticPtr.h"
+
+using namespace mozilla;
+using namespace mozilla::net;
+
+namespace {
+StaticRefPtr<DelayHttpChannelQueue> sDelayHttpChannelQueue;
+}
+
+bool
+DelayHttpChannelQueue::AttemptQueueChannel(nsHttpChannel* aChannel)
+{
+  MOZ_ASSERT(aChannel);
+  MOZ_ASSERT(NS_IsMainThread());
+
+  if (!sDelayHttpChannelQueue) {
+    RefPtr<DelayHttpChannelQueue> queue = new DelayHttpChannelQueue();
+    if (!queue->Initialize()) {
+      return false;
+    }
+
+    sDelayHttpChannelQueue = queue;
+  }
+
+  if (NS_WARN_IF(!sDelayHttpChannelQueue->mQueue.AppendElement(aChannel, fallible))) {
+    return false;
+  }
+
+  return true;
+}
+
+DelayHttpChannelQueue::DelayHttpChannelQueue()
+{
+  MOZ_ASSERT(NS_IsMainThread());
+}
+
+DelayHttpChannelQueue::~DelayHttpChannelQueue()
+{
+  MOZ_ASSERT(NS_IsMainThread());
+}
+
+bool
+DelayHttpChannelQueue::Initialize()
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
+  if (NS_WARN_IF(!obs)) {
+    return false;
+  }
+
+  nsresult rv = obs->AddObserver(this, "fuzzyfox-fire-outbound", false);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return false;
+  }
+
+  rv = obs->AddObserver(this, "xpcom-shutdown", false);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return false;
+  }
+
+  return true;
+}
+
+NS_IMETHODIMP
+DelayHttpChannelQueue::Observe(nsISupports* aSubject, const char* aTopic,
+                               const char16_t* aData)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  if (!strcmp(aTopic, "fuzzyfox-fire-outbound")) {
+    FireQueue();
+    return NS_OK;
+  }
+
+  MOZ_ASSERT(!strcmp(aTopic, "xpcom-shutdown"));
+
+  nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
+  if (NS_WARN_IF(!obs)) {
+    return NS_OK;
+  }
+
+  obs->RemoveObserver(this, "fuzzyfox-fire-outbound");
+  obs->RemoveObserver(this, "xpcom-shutdown");
+
+  return NS_OK;
+} 
+
+void
+DelayHttpChannelQueue::FireQueue()
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  if (mQueue.IsEmpty()) {
+    return;
+  }
+
+  //TODO: get this from the DOM clock?
+  TimeStamp ts = TimeStamp::Now();
+
+  FallibleTArray<RefPtr<nsHttpChannel>> queue;
+  queue.SwapElements(mQueue); 
+
+  for (RefPtr<nsHttpChannel>& channel : queue) {
+    channel->AsyncOpenFinal(ts);
+  }
+}
+
+NS_INTERFACE_MAP_BEGIN(DelayHttpChannelQueue)
+  NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIObserver)
+  NS_INTERFACE_MAP_ENTRY(nsIObserver)
+NS_INTERFACE_MAP_END
+
+NS_IMPL_ADDREF(DelayHttpChannelQueue)
+NS_IMPL_RELEASE(DelayHttpChannelQueue)
new file mode 100644
--- /dev/null
+++ b/netwerk/protocol/http/DelayHttpChannelQueue.h
@@ -0,0 +1,43 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* vim:set et cin ts=4 sw=4 sts=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 mozilla_net_DelayHttpChannelQueue_h
+#define mozilla_net_DelayHttpChannelQueue_h
+
+#include "nsIObserver.h"
+#include "nsTArray.h"
+
+namespace mozilla {
+namespace net {
+
+class nsHttpChannel;
+
+class DelayHttpChannelQueue final : public nsIObserver
+{
+public:
+  static bool
+  AttemptQueueChannel(nsHttpChannel* aChannel);
+
+  NS_DECL_ISUPPORTS
+  NS_DECL_NSIOBSERVER
+
+private:
+  DelayHttpChannelQueue();
+  ~DelayHttpChannelQueue();
+
+  bool
+  Initialize();
+
+  void
+  FireQueue();
+
+  FallibleTArray<RefPtr<nsHttpChannel>> mQueue;
+};
+
+} // net namespace
+} // mozilla namespace
+
+#endif // mozilla_net_DelayHttpChannelQueue_h
--- a/netwerk/protocol/http/moz.build
+++ b/netwerk/protocol/http/moz.build
@@ -95,16 +95,21 @@ UNIFIED_SOURCES += [
     'nsHttpResponseHead.cpp',
     'nsHttpTransaction.cpp',
     'nsServerTiming.cpp',
     'NullHttpChannel.cpp',
     'NullHttpTransaction.cpp',
     'TunnelUtils.cpp',
 ]
 
+if CONFIG['MOZ_FUZZYFOX']:
+    UNIFIED_SOURCES += [
+        'DelayHttpChannelQueue.cpp',
+    ]
+
 # These files cannot be built in unified mode because of OS X headers.
 SOURCES += [
     'nsHttpHandler.cpp',
 ]
 
 IPDL_SOURCES += [
     'PAltDataOutputStream.ipdl',
     'PHttpBackgroundChannel.ipdl',
--- a/netwerk/protocol/http/nsHttpChannel.cpp
+++ b/netwerk/protocol/http/nsHttpChannel.cpp
@@ -6011,24 +6011,41 @@ nsHttpChannel::AsyncOpen(nsIStreamListen
     }
 
     mIsPending = true;
     mWasOpened = true;
 
     mListener = listener;
     mListenerContext = context;
 
+#ifdef MOZ_FUZZYFOX
+    // PauseTask/DelayHttpChannel queuing
+    if (!DelayHttpChannelQueue::AttemptQueueChannel(this)) {
+        // If failed, the channel must continue.
+        AsyncOpenFinal(TimeStamp::Now());
+    }
+
+    return NS_OK;
+}
+
+nsresult
+nsHttpChannel::AsyncOpenFinal(TimeStamp aTimeStamp)
+{
+    // Added due to PauseTask/DelayHttpChannel
+    nsresult rv;
+#endif
+
     if (mLoadGroup)
         mLoadGroup->AddRequest(this, nullptr);
 
     // record asyncopen time unconditionally and clear it if we
     // don't want it after OnModifyRequest() weighs in. But waiting for
     // that to complete would mean we don't include proxy resolution in the
     // timing.
-    mAsyncOpenTime = TimeStamp::Now();
+    mAsyncOpenTime = aTimeStamp;
 
     // Remember we have Authorization header set here.  We need to check on it
     // just once and early, AsyncOpen is the best place.
     mCustomAuthHeader = mRequestHead.HasHeader(nsHttp::Authorization);
 
     // The common case for HTTP channels is to begin proxy resolution and return
     // at this point. The only time we know mProxyInfo already is if we're
     // proxying a non-http protocol like ftp. We don't need to discover proxy
--- a/netwerk/protocol/http/nsHttpChannel.h
+++ b/netwerk/protocol/http/nsHttpChannel.h
@@ -28,16 +28,20 @@
 #include "nsIStreamListener.h"
 #include "nsISupportsPrimitives.h"
 #include "nsICorsPreflightCallback.h"
 #include "AlternateServices.h"
 #include "nsIRaceCacheWithNetwork.h"
 #include "mozilla/extensions/PStreamFilterParent.h"
 #include "mozilla/Mutex.h"
 
+#ifdef MOZ_FUZZYFOX
+#include "DelayHttpChannelQueue.h"
+#endif
+
 class nsDNSPrefetch;
 class nsICancelable;
 class nsIHttpChannelAuthProvider;
 class nsInputStreamPump;
 class nsISSLStatus;
 
 namespace mozilla { namespace net {
 
@@ -196,16 +200,20 @@ public:
     HttpChannelSecurityWarningReporter* GetWarningReporter();
 public: /* internal necko use only */
 
     uint32_t GetRequestTime() const
     {
         return mRequestTime;
     }
 
+#ifdef MOZ_FUZZYFOX
+    nsresult AsyncOpenFinal(TimeStamp aTimeStamp);
+#endif
+
     MOZ_MUST_USE nsresult OpenCacheEntry(bool usingSSL);
     MOZ_MUST_USE nsresult OpenCacheEntryInternal(bool isHttps,
                                                  nsIApplicationCache *applicationCache,
                                                  bool noAppCache);
     MOZ_MUST_USE nsresult ContinueConnect();
 
     MOZ_MUST_USE nsresult StartRedirectChannelToURI(nsIURI *, uint32_t);