Bug 1039846 - Patch 5.1: Set request upload stream and headers. r=baku,bkelly
authorNikhil Marathe <nsm.nikhil@gmail.com>
Tue, 09 Dec 2014 22:35:22 -0800
changeset 250711 27b9f23fc9e50604d4fdde9bf88259cdf6f94e44
parent 250710 b4c5a27a1ab474e05191b62814587831094b8d54
child 250712 8443140d7fcf57e0af143efd3fd19a0270dc6b8c
push id4610
push userjlund@mozilla.com
push dateMon, 30 Mar 2015 18:32:55 +0000
treeherdermozilla-beta@4df54044d9ef [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbaku, bkelly
bugs1039846
milestone38.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 1039846 - Patch 5.1: Set request upload stream and headers. r=baku,bkelly
dom/fetch/FetchDriver.cpp
dom/fetch/InternalHeaders.cpp
dom/fetch/InternalHeaders.h
--- a/dom/fetch/FetchDriver.cpp
+++ b/dom/fetch/FetchDriver.cpp
@@ -305,28 +305,29 @@ FetchDriver::ContinueHttpFetchAfterCORSP
   }
 
   return HttpNetworkFetch();
 }
 
 nsresult
 FetchDriver::HttpNetworkFetch()
 {
-  nsRefPtr<InternalRequest> httpRequest = new InternalRequest(*mRequest);
+  // We don't create a HTTPRequest copy since Necko sets the information on the
+  // nsIHttpChannel instead.
 
   nsresult rv;
 
   nsCOMPtr<nsIIOService> ios = do_GetIOService(&rv);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     FailWithNetworkError();
     return rv;
   }
 
   nsAutoCString url;
-  httpRequest->GetURL(url);
+  mRequest->GetURL(url);
   nsCOMPtr<nsIURI> uri;
   rv = NS_NewURI(getter_AddRefs(uri),
                           url,
                           nullptr,
                           nullptr,
                           ios);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     FailWithNetworkError();
@@ -351,18 +352,72 @@ FetchDriver::HttpNetworkFetch()
   if (httpChan) {
     nsAutoCString method;
     mRequest->GetMethod(method);
     rv = httpChan->SetRequestMethod(method);
     if (NS_WARN_IF(NS_FAILED(rv))) {
       FailWithNetworkError();
       return rv;
     }
+
+    nsAutoTArray<InternalHeaders::Entry, 5> headers;
+    mRequest->Headers()->GetEntries(headers);
+    for (uint32_t i = 0; i < headers.Length(); ++i) {
+      httpChan->SetRequestHeader(headers[i].mName, headers[i].mValue, false /* merge */);
+    }
+
+    MOZ_ASSERT(mRequest->ReferrerIsURL());
+    nsCString referrer = mRequest->ReferrerAsURL();
+    if (!referrer.IsEmpty()) {
+      nsCOMPtr<nsIURI> uri;
+      rv = NS_NewURI(getter_AddRefs(uri), referrer, nullptr, nullptr, ios);
+      if (NS_WARN_IF(NS_FAILED(rv))) {
+        return rv;
+      }
+      rv = httpChan->SetReferrer(uri);
+      if (NS_WARN_IF(NS_FAILED(rv))) {
+        return rv;
+      }
+    }
+
+    if (mRequest->ForceOriginHeader()) {
+      nsAutoString origin;
+      rv = nsContentUtils::GetUTFOrigin(mPrincipal, origin);
+      if (NS_WARN_IF(NS_FAILED(rv))) {
+        FailWithNetworkError();
+        return rv;
+      }
+      httpChan->SetRequestHeader(NS_LITERAL_CSTRING("origin"),
+                                 NS_ConvertUTF16toUTF8(origin),
+                                 false /* merge */);
+    }
   }
 
+  nsCOMPtr<nsIUploadChannel2> uploadChan = do_QueryInterface(chan);
+  if (uploadChan) {
+    nsAutoCString contentType;
+    ErrorResult result;
+    mRequest->Headers()->Get(NS_LITERAL_CSTRING("content-type"), contentType, result);
+    // This is an error because the Request constructor explicitly extracts and
+    // sets a content-type per spec.
+    if (result.Failed()) {
+      return result.ErrorCode();
+    }
+
+    nsCOMPtr<nsIInputStream> bodyStream;
+    mRequest->GetBody(getter_AddRefs(bodyStream));
+    if (bodyStream) {
+      nsAutoCString method;
+      mRequest->GetMethod(method);
+      rv = uploadChan->ExplicitSetUploadStream(bodyStream, contentType, -1, method, false /* aStreamHasHeaders */);
+      if (NS_WARN_IF(NS_FAILED(rv))) {
+        return rv;
+      }
+    }
+  }
   return chan->AsyncOpen(this, nullptr);
 }
 
 nsresult
 FetchDriver::ContinueHttpFetchAfterNetworkFetch()
 {
   workers::AssertIsOnMainThread();
   MOZ_ASSERT(mResponse);
@@ -464,23 +519,29 @@ FetchDriver::OnStartRequest(nsIRequest* 
     FailWithNetworkError();
     return rv;
   }
 
   nsCOMPtr<nsIHttpChannel> channel = do_QueryInterface(aRequest);
   // For now we only support HTTP.
   MOZ_ASSERT(channel);
 
-  uint32_t status;
-  channel->GetResponseStatus(&status);
+  aRequest->GetStatus(&rv);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    FailWithNetworkError();
+    return rv;
+  }
+
+  uint32_t responseStatus;
+  channel->GetResponseStatus(&responseStatus);
 
   nsAutoCString statusText;
   channel->GetResponseStatusText(statusText);
 
-  nsRefPtr<InternalResponse> response = new InternalResponse(status, statusText);
+  nsRefPtr<InternalResponse> response = new InternalResponse(responseStatus, statusText);
 
   nsRefPtr<FillResponseHeaders> visitor = new FillResponseHeaders(response);
   rv = channel->VisitResponseHeaders(visitor);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     NS_WARNING("Failed to visit all headers.");
   }
 
   mResponse = BeginAndGetFilteredResponse(response);
--- a/dom/fetch/InternalHeaders.cpp
+++ b/dom/fetch/InternalHeaders.cpp
@@ -319,10 +319,17 @@ InternalHeaders::CORSHeaders(InternalHea
         acExposedNames.Contains(entry.mName, comp)) {
       cors->Append(entry.mName, entry.mValue, result);
       MOZ_ASSERT(!result.Failed());
     }
   }
 
   return cors.forget();
 }
+
+void
+InternalHeaders::GetEntries(nsTArray<InternalHeaders::Entry>& aEntries) const
+{
+  MOZ_ASSERT(aEntries.IsEmpty());
+  aEntries.AppendElements(mList);
+}
 } // namespace dom
 } // namespace mozilla
--- a/dom/fetch/InternalHeaders.h
+++ b/dom/fetch/InternalHeaders.h
@@ -24,30 +24,31 @@ namespace dom {
 
 template<typename T> class MozMap;
 class HeadersOrByteStringSequenceSequenceOrByteStringMozMap;
 
 class InternalHeaders MOZ_FINAL
 {
   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(InternalHeaders)
 
-private:
+public:
   struct Entry
   {
     Entry(const nsACString& aName, const nsACString& aValue)
       : mName(aName)
       , mValue(aValue)
     { }
 
     Entry() { }
 
     nsCString mName;
     nsCString mValue;
   };
 
+private:
   HeadersGuardEnum mGuard;
   nsTArray<Entry> mList;
 
 public:
   explicit InternalHeaders(HeadersGuardEnum aGuard = HeadersGuardEnum::None)
     : mGuard(aGuard)
   {
   }
@@ -80,16 +81,19 @@ public:
 
   bool HasOnlySimpleHeaders() const;
 
   static already_AddRefed<InternalHeaders>
   BasicHeaders(InternalHeaders* aHeaders);
 
   static already_AddRefed<InternalHeaders>
   CORSHeaders(InternalHeaders* aHeaders);
+
+  void
+  GetEntries(nsTArray<InternalHeaders::Entry>& aEntries) const;
 private:
   virtual ~InternalHeaders();
 
   static bool IsSimpleHeader(const nsACString& aName,
                              const nsACString& aValue);
   static bool IsInvalidName(const nsACString& aName, ErrorResult& aRv);
   static bool IsInvalidValue(const nsACString& aValue, ErrorResult& aRv);
   bool IsImmutable(ErrorResult& aRv) const;