Bug 1240929 - Copy some HTTP request headers automatically on redirect, r=mcmanus
authorHonza Bambas <honzab.moz@firemni.cz>
Wed, 06 Apr 2016 09:28:00 +0200
changeset 317036 f81406821d565c0d9d5d5d9120f0b4b4347a3c5b
parent 317035 0eb8cf4e5b9283b3be5a5a6b3c5aab1ec927718a
child 317037 ca9577b9e37a277d970e65ccbee3189d559e7484
push id9480
push userjlund@mozilla.com
push dateMon, 25 Apr 2016 17:12:58 +0000
treeherdermozilla-aurora@0d6a91c76a9e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmcmanus
bugs1240929
milestone48.0a1
Bug 1240929 - Copy some HTTP request headers automatically on redirect, r=mcmanus
netwerk/protocol/http/HttpBaseChannel.cpp
--- a/netwerk/protocol/http/HttpBaseChannel.cpp
+++ b/netwerk/protocol/http/HttpBaseChannel.cpp
@@ -46,16 +46,17 @@
 #include "nsIChannelEventSink.h"
 #include "nsILoadGroupChild.h"
 #include "mozilla/ConsoleReportCollector.h"
 #include "LoadInfo.h"
 #include "nsISSLSocketControl.h"
 #include "mozilla/Telemetry.h"
 #include "nsIURL.h"
 #include "nsIConsoleService.h"
+#include "mozilla/BinarySearch.h"
 
 #include <algorithm>
 
 namespace mozilla {
 namespace net {
 
 HttpBaseChannel::HttpBaseChannel()
   : mStartPos(UINT64_MAX)
@@ -2689,16 +2690,66 @@ HttpBaseChannel::ShouldRewriteRedirectTo
   // rewrite for 303 unless it was HEAD
   if (httpStatus == 303)
     return method != nsHttpRequestHead::kMethod_Head;
 
   // otherwise, such as for 307, do not rewrite
   return false;
 }
 
+static
+bool IsHeaderBlacklistedForRedirectCopy(nsHttpAtom const& aHeader)
+{
+  // IMPORTANT: keep this list ASCII-code sorted
+  static nsHttpAtom const* blackList[] = {
+    &nsHttp::Accept,
+    &nsHttp::Accept_Encoding,
+    &nsHttp::Accept_Language,
+    &nsHttp::Authentication,
+    &nsHttp::Authorization,
+    &nsHttp::Connection,
+    &nsHttp::Content_Length,
+    &nsHttp::Cookie,
+    &nsHttp::Host,
+    &nsHttp::If,
+    &nsHttp::If_Match,
+    &nsHttp::If_Modified_Since,
+    &nsHttp::If_None_Match,
+    &nsHttp::If_None_Match_Any,
+    &nsHttp::If_Range,
+    &nsHttp::If_Unmodified_Since,
+    &nsHttp::Proxy_Authenticate,
+    &nsHttp::Proxy_Authorization,
+    &nsHttp::Range,
+    &nsHttp::TE,
+    &nsHttp::Transfer_Encoding,
+    &nsHttp::Upgrade,
+    &nsHttp::User_Agent,
+    &nsHttp::WWW_Authenticate
+  };
+
+  class HttpAtomComparator
+  {
+    nsHttpAtom const& mTarget;
+  public:
+    explicit HttpAtomComparator(nsHttpAtom const& aTarget)
+      : mTarget(aTarget) {}
+    int operator()(nsHttpAtom const* aVal) const {
+      if (mTarget == *aVal) {
+        return 0;
+      }
+      return strcmp(mTarget._val, aVal->_val);
+    }
+  };
+
+  size_t unused;
+  return BinarySearchIf(blackList, 0, ArrayLength(blackList),
+                        HttpAtomComparator(aHeader), &unused);
+}
+
 nsresult
 HttpBaseChannel::SetupReplacementChannel(nsIURI       *newURI,
                                          nsIChannel   *newChannel,
                                          bool          preserveMethod,
                                          uint32_t      redirectFlags)
 {
   LOG(("HttpBaseChannel::SetupReplacementChannel "
      "[this=%p newChannel=%p preserveMethod=%d]",
@@ -2928,16 +2979,33 @@ HttpBaseChannel::SetupReplacementChannel
     if (loadInfo && loadInfo->GetExternalContentPolicyType() != nsIContentPolicy::TYPE_DOCUMENT) {
       nsCOMPtr<nsIPrincipal> principal = loadInfo->LoadingPrincipal();
       newTimedChannel->SetAllRedirectsPassTimingAllowCheck(
         mAllRedirectsPassTimingAllowCheck &&
         oldTimedChannel->TimingAllowCheck(principal));
     }
   }
 
+  if (redirectFlags & (nsIChannelEventSink::REDIRECT_INTERNAL |
+                       nsIChannelEventSink::REDIRECT_STS_UPGRADE)) {
+    // Copy non-origin related headers to the new channel.
+    nsHttpHeaderArray& requestHeaders = mRequestHead.Headers();
+    uint32_t requestHeaderCount = requestHeaders.Count();
+    for (uint32_t i = 0; i < requestHeaderCount; ++i) {
+      nsHttpAtom header;
+      const char *val = requestHeaders.PeekHeaderAt(i, header);
+      if (!val || IsHeaderBlacklistedForRedirectCopy(header)) {
+          continue;
+      }
+
+      httpChannel->SetRequestHeader(nsDependentCString(header.get()),
+                                    nsDependentCString(val), false);
+    }
+  }
+
   // This channel has been redirected. Don't report timing info.
   mTimingEnabled = false;
   return NS_OK;
 }
 
 // Redirect Tracking
 bool
 HttpBaseChannel::SameOriginWithOriginalUri(nsIURI *aURI)