Bug 1436517 - Limit access to the server-timing header to HTTPS contexts. r?mcmanus draft
authorNicholas Hurley <hurley@mozilla.com>
Wed, 07 Feb 2018 16:05:38 -0800
changeset 752361 e0d4f273e33e3a77558d954efe514b35399b099e
parent 752153 65133e49fbfd5306632301f74be7cd15890bdf9f
push id98239
push userbmo:hurley@mozilla.com
push dateThu, 08 Feb 2018 00:13:19 +0000
reviewersmcmanus
bugs1436517, 1436601
milestone60.0a1
Bug 1436517 - Limit access to the server-timing header to HTTPS contexts. r?mcmanus This also introduces a hidden pref to allow server-timing access from HTTP contexts for the purposes of our xpcshell tests. We'll remove that once we get h2 (and therefore tls test) support for server-timing trailers (https://bugzilla.mozilla.org/show_bug.cgi?id=1436601). This does not reject or otherwise error when receiving server-timing headers or trailers on non-HTTPS contexts, it just makes it unavailable outside the channel. MozReview-Commit-ID: qi4h0VQknE
netwerk/protocol/http/HttpBaseChannel.cpp
netwerk/protocol/http/nsHttpHandler.cpp
netwerk/protocol/http/nsHttpHandler.h
netwerk/test/unit/test_header_Server_Timing.js
--- a/netwerk/protocol/http/HttpBaseChannel.cpp
+++ b/netwerk/protocol/http/HttpBaseChannel.cpp
@@ -4492,22 +4492,27 @@ ParseServerTimingHeader(const nsAutoPtr<
   }
 }
 
 NS_IMETHODIMP
 HttpBaseChannel::GetServerTiming(nsIArray **aServerTiming)
 {
   NS_ENSURE_ARG_POINTER(aServerTiming);
 
-  nsTArray<nsCOMPtr<nsIServerTiming>> data;
-  nsresult rv = NS_OK;
-  nsCOMPtr<nsIMutableArray> array = do_CreateInstance(NS_ARRAY_CONTRACTID, &rv);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  ParseServerTimingHeader(mResponseHead, array);
-  ParseServerTimingHeader(mResponseTrailers, array);
-
-  array.forget(aServerTiming);
+  bool isHTTPS = false;
+  if (gHttpHandler->AllowPlaintextServerTiming() ||
+      (NS_SUCCEEDED(mURI->SchemeIs("https", &isHTTPS)) && isHTTPS)) {
+    nsTArray<nsCOMPtr<nsIServerTiming>> data;
+    nsresult rv = NS_OK;
+    nsCOMPtr<nsIMutableArray> array = do_CreateInstance(NS_ARRAY_CONTRACTID, &rv);
+    NS_ENSURE_SUCCESS(rv, rv);
+
+    ParseServerTimingHeader(mResponseHead, array);
+    ParseServerTimingHeader(mResponseTrailers, array);
+
+    array.forget(aServerTiming);
+  }
+
   return NS_OK;
 }
 
 } // namespace net
 } // namespace mozilla
--- a/netwerk/protocol/http/nsHttpHandler.cpp
+++ b/netwerk/protocol/http/nsHttpHandler.cpp
@@ -283,16 +283,17 @@ nsHttpHandler::nsHttpHandler()
     , mUseFastOpen(true)
     , mFastOpenConsecutiveFailureLimit(5)
     , mFastOpenConsecutiveFailureCounter(0)
     , mFastOpenStallsLimit(3)
     , mFastOpenStallsCounter(0)
     , mFastOpenStallsIdleTime(10)
     , mFastOpenStallsTimeout(20)
     , mActiveTabPriority(true)
+    , mAllowPlaintextServerTiming(false)
     , mProcessId(0)
     , mNextChannelId(1)
     , mLastActiveTabLoadOptimizationLock("nsHttpConnectionMgr::LastActiveTabLoadOptimization")
 {
     LOG(("Creating nsHttpHandler [this=%p].\n", this));
 
     mUserAgentOverride.SetIsVoid(true);
 
@@ -459,16 +460,17 @@ nsHttpHandler::Init()
         prefBranch->AddObserver(HTTP_PREF("tcp_keepalive.long_lived_connections"), this, true);
         prefBranch->AddObserver(SAFE_HINT_HEADER_VALUE, this, true);
         prefBranch->AddObserver(SECURITY_PREFIX, this, true);
         prefBranch->AddObserver(TCP_FAST_OPEN_ENABLE, this, true);
         prefBranch->AddObserver(TCP_FAST_OPEN_FAILURE_LIMIT, this, true);
         prefBranch->AddObserver(TCP_FAST_OPEN_STALLS_LIMIT, this, true);
         prefBranch->AddObserver(TCP_FAST_OPEN_STALLS_IDLE, this, true);
         prefBranch->AddObserver(TCP_FAST_OPEN_STALLS_TIMEOUT, this, true);
+        prefBranch->AddObserver(HTTP_PREF("allow-plaintext-server-timing"), this, false);
         PrefsChanged(prefBranch, nullptr);
     }
 
     nsHttpChannelAuthProvider::InitializePrefs();
 
     mMisc.AssignLiteral("rv:" MOZILLA_UAVERSION);
 
     mCompatFirefox.AssignLiteral("Firefox/" MOZILLA_UAVERSION);
@@ -1769,16 +1771,20 @@ nsHttpHandler::PrefsChanged(nsIPrefBranc
             if (ratio > 0 && ratio < 1) {
                 mFocusedWindowTransactionRatio = ratio;
             } else {
                 NS_WARNING("Wrong value for focused_window_transaction_ratio");
             }
         }
     }
 
+    if (PREF_CHANGED(HTTP_PREF("allow-plaintext-server-timing"))) {
+        Unused << prefs->GetBoolPref(HTTP_PREF("allow-plaintext-server-timing"), &mAllowPlaintextServerTiming);
+    }
+
     //
     // INTL options
     //
 
     if (PREF_CHANGED(INTL_ACCEPT_LANGUAGES)) {
         // We don't want to set the new accept languages here since
         // this pref is a complex type and it may be racy with flushing
         // string resources.
--- a/netwerk/protocol/http/nsHttpHandler.h
+++ b/netwerk/protocol/http/nsHttpHandler.h
@@ -143,16 +143,18 @@ public:
     uint32_t       TailBlockingDelayQuantum(bool aAfterDOMContentLoaded) {
       return aAfterDOMContentLoaded ? mTailDelayQuantumAfterDCL : mTailDelayQuantum;
     }
     uint32_t       TailBlockingDelayMax() { return mTailDelayMax; }
     uint32_t       TailBlockingTotalMax() { return mTailTotalMax; }
 
     uint32_t       ThrottlingReadLimit() { return mThrottleVersion == 1 ? 0 : mThrottleReadLimit; }
 
+    bool           AllowPlaintextServerTiming() { return mAllowPlaintextServerTiming; }
+
     // TCP Keepalive configuration values.
 
     // Returns true if TCP keepalive should be enabled for short-lived conns.
     bool TCPKeepaliveEnabledForShortLivedConns() {
       return mTCPKeepaliveShortLivedEnabled;
     }
     // Return time (secs) that a connection is consider short lived (for TCP
     // keepalive purposes). After this time, the connection is long-lived.
@@ -661,16 +663,18 @@ private:
     uint32_t mFastOpenStallsLimit;
     uint32_t mFastOpenStallsCounter;
     uint32_t mFastOpenStallsIdleTime;
     uint32_t mFastOpenStallsTimeout;
 
     // If true, the transactions from active tab will be dispatched first.
     bool mActiveTabPriority;
 
+    bool mAllowPlaintextServerTiming;
+
 private:
     // For Rate Pacing Certain Network Events. Only assign this pointer on
     // socket thread.
     void MakeNewRequestTokenBucket();
     RefPtr<EventTokenBucket> mRequestTokenBucket;
 
 public:
     // Socket thread only
--- a/netwerk/test/unit/test_header_Server_Timing.js
+++ b/netwerk/test/unit/test_header_Server_Timing.js
@@ -49,16 +49,21 @@ function contentHandler(metadata, respon
   response.write(body);
   response.write(createServerTimingHeader(trailerServerTiming));
   response.write("\r\n");
   response.finish();
 }
 
 function run_test()
 {
+  Services.prefs.setBoolPref("network.http.allow-plaintext-server-timing", true);
+  registerCleanupFunction(() => {
+    Services.prefs.clearUserPref("network.http.allow-plaintext-server-timing");
+  });
+
   httpServer = new HttpServer();
   httpServer.registerPathHandler("/content", contentHandler);
   httpServer.start(-1);
 
   do_test_pending();
   make_and_open_channel(URL, readServerContent);
 }