Bug 1348062 - Mark channels used for downloads as throttable, r=nick+paolo draft
authorHonza Bambas <honzab.moz@firemni.cz>
Sun, 16 Apr 2017 14:53:30 +0100
changeset 563365 744c15cf2fcb20a98eff7e9532cc595413189cc9
parent 563120 9379831bb9c3d9abfea7dbf8dd06dbdab1d81dc4
child 563366 24e89ea8bcbfd171797ff0a5c008bb593a869970
push id54266
push userpaolo.mozmail@amadzone.org
push dateSun, 16 Apr 2017 15:00:06 +0000
reviewersnick
bugs1348062
milestone55.0a1
Bug 1348062 - Mark channels used for downloads as throttable, r=nick+paolo MozReview-Commit-ID: 9cg4PwrXtNa
netwerk/protocol/http/nsHttpChannel.cpp
netwerk/protocol/http/nsHttpChannel.h
toolkit/components/jsdownloads/src/DownloadCore.jsm
toolkit/components/jsdownloads/test/unit/common_test_Download.js
uriloader/exthandler/nsExternalHelperAppService.cpp
--- a/netwerk/protocol/http/nsHttpChannel.cpp
+++ b/netwerk/protocol/http/nsHttpChannel.cpp
@@ -6392,16 +6392,28 @@ nsHttpChannel::ForceIntercepted(uint64_t
     }
 
     MarkIntercepted();
     mResponseCouldBeSynthesized = true;
     mInterceptionID = aInterceptionID;
     return NS_OK;
 }
 
+NS_IMETHODIMP
+nsHttpChannel::SetChannelIsForDownload(bool aChannelIsForDownload)
+{
+  if (aChannelIsForDownload) {
+    AddClassFlags(nsIClassOfService::Throttleable);
+  } else {
+    ClearClassFlags(nsIClassOfService::Throttleable);
+  }
+
+  return HttpBaseChannel::SetChannelIsForDownload(aChannelIsForDownload);
+}
+
 //-----------------------------------------------------------------------------
 // nsHttpChannel::nsISupportsPriority
 //-----------------------------------------------------------------------------
 
 NS_IMETHODIMP
 nsHttpChannel::SetPriority(int32_t value)
 {
     int16_t newValue = clamped<int32_t>(value, INT16_MIN, INT16_MAX);
--- a/netwerk/protocol/http/nsHttpChannel.h
+++ b/netwerk/protocol/http/nsHttpChannel.h
@@ -152,16 +152,17 @@ public:
     NS_IMETHOD GetSecurityInfo(nsISupports **aSecurityInfo) override;
     NS_IMETHOD AsyncOpen(nsIStreamListener *listener, nsISupports *aContext) override;
     NS_IMETHOD AsyncOpen2(nsIStreamListener *aListener) override;
     // nsIHttpChannel
     NS_IMETHOD GetEncodedBodySize(uint64_t *aEncodedBodySize) override;
     // nsIHttpChannelInternal
     NS_IMETHOD SetupFallbackChannel(const char *aFallbackKey) override;
     NS_IMETHOD ForceIntercepted(uint64_t aInterceptionID) override;
+    NS_IMETHOD SetChannelIsForDownload(bool aChannelIsForDownload) override;
     // nsISupportsPriority
     NS_IMETHOD SetPriority(int32_t value) override;
     // nsIClassOfService
     NS_IMETHOD SetClassFlags(uint32_t inFlags) override;
     NS_IMETHOD AddClassFlags(uint32_t inFlags) override;
     NS_IMETHOD ClearClassFlags(uint32_t inFlags) override;
 
     // nsIResumableChannel
--- a/toolkit/components/jsdownloads/src/DownloadCore.jsm
+++ b/toolkit/components/jsdownloads/src/DownloadCore.jsm
@@ -1971,16 +1971,22 @@ this.DownloadCopySaver.prototype = {
           if (channel instanceof Ci.nsIPrivateBrowsingChannel) {
             channel.setPrivate(download.source.isPrivate);
           }
           if (channel instanceof Ci.nsIHttpChannel &&
               download.source.referrer) {
             channel.referrer = NetUtil.newURI(download.source.referrer);
           }
 
+          // This makes the channel be corretly throttled during page loads
+          // and also prevents its caching.
+          if (channel instanceof Ci.nsIHttpChannelInternal) {
+            channel.channelIsForDownload = true;
+          }
+
           // If we have data that we can use to resume the download from where
           // it stopped, try to use it.
           let resumeAttempted = false;
           let resumeFromBytes = 0;
           if (channel instanceof Ci.nsIResumableChannel && this.entityID &&
               partFilePath && keepPartialData) {
             try {
               let stat = yield OS.File.stat(partFilePath);
--- a/toolkit/components/jsdownloads/test/unit/common_test_Download.js
+++ b/toolkit/components/jsdownloads/test/unit/common_test_Download.js
@@ -359,16 +359,17 @@ add_task(function* test_adjustChannel() 
     do_check_eq(aRequest.getHeader(customHeader.name), customHeader.value);
 
     const stream = aRequest.bodyInputStream;
     const body = NetUtil.readInputStreamToString(stream, stream.available());
     do_check_eq(body, postData);
   });
 
   function adjustChannel(channel) {
+    do_check_true(channel.channelIsForDownload);
     channel.QueryInterface(Ci.nsIHttpChannel);
     channel.setRequestHeader(customHeader.name, customHeader.value, false);
 
     const stream = Cc["@mozilla.org/io/string-input-stream;1"]
                    .createInstance(Ci.nsIStringInputStream);
     stream.setData(postData, postData.length);
 
     channel.QueryInterface(Ci.nsIUploadChannel2);
--- a/uriloader/exthandler/nsExternalHelperAppService.cpp
+++ b/uriloader/exthandler/nsExternalHelperAppService.cpp
@@ -1672,17 +1672,18 @@ NS_IMETHODIMP nsExternalAppHandler::OnSt
     if (mTempFile)
       mTempFile->GetPath(path);
 
     SendStatusChange(kWriteError, transferError, request, path);
 
     return NS_OK;
   }
 
-  // Inform channel it is open on behalf of a download to prevent caching.
+  // Inform channel it is open on behalf of a download to throttle it during
+  // page loads and prevent its caching.
   nsCOMPtr<nsIHttpChannelInternal> httpInternal = do_QueryInterface(aChannel);
   if (httpInternal) {
     rv = httpInternal->SetChannelIsForDownload(true);
     MOZ_ASSERT(NS_SUCCEEDED(rv));
   }
 
   // now that the temp file is set up, find out if we need to invoke a dialog
   // asking the user what they want us to do with this content...