Bug 1641208 - `Accept` header does not include `image/avif` even when `image.avif.enable` is set. r=mattwoodrow,aosmond,necko-reviewers,valentin
authorJon Bauman <jbauman@mozilla.com>
Mon, 01 Jun 2020 22:21:05 +0000
changeset 597495 403e442028a7cb2e5ffd90d2043cd3a0775c338c
parent 597494 7cdace6683db3a0a655bd04c4ba096df5637579a
child 597496 e9507c0042be96c52728621968e255d1114e593e
push id13310
push userffxbld-merge
push dateMon, 29 Jun 2020 14:50:06 +0000
treeherdermozilla-beta@15a59a0afa5c [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmattwoodrow, aosmond, necko-reviewers, valentin
bugs1641208
milestone79.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 1641208 - `Accept` header does not include `image/avif` even when `image.avif.enable` is set. r=mattwoodrow,aosmond,necko-reviewers,valentin Differential Revision: https://phabricator.services.mozilla.com/D77371
dom/tests/browser/browser_persist_image_accept.js
modules/libpref/init/all.js
netwerk/protocol/http/nsHttpHandler.cpp
--- a/dom/tests/browser/browser_persist_image_accept.js
+++ b/dom/tests/browser/browser_persist_image_accept.js
@@ -38,16 +38,28 @@ function createTemporarySaveDirectory() 
   if (!saveDir.exists()) {
     info("create testsavedir!");
     saveDir.create(Ci.nsIFile.DIRECTORY_TYPE, 0o755);
   }
   info("return from createTempSaveDir: " + saveDir.path);
   return saveDir;
 }
 
+function expectedImageAcceptHeader() {
+  if (Services.prefs.prefHasUserValue("image.http.accept")) {
+    return Services.prefs.getCharPref("image.http.accept");
+  }
+
+  return (
+    (Services.prefs.getBoolPref("image.avif.enabled") ? "image/avif," : "") +
+    (Services.prefs.getBoolPref("image.webp.enabled") ? "image/webp," : "") +
+    "*/*"
+  );
+}
+
 add_task(async function test_image_download() {
   await BrowserTestUtils.withNewTab(TEST_PATH + "dummy.html", async browser => {
     // Add the image, and wait for it to load.
     await SpecialPowers.spawn(browser, [], async function() {
       let loc = content.document.location.href;
       let imgloc = new content.URL("dummy.png", loc);
       let img = content.document.createElement("img");
       img.src = imgloc;
@@ -94,17 +106,17 @@ add_task(async function test_image_downl
         if (!uri.endsWith("dummy.png")) {
           info("Ignoring request for " + uri);
           return false;
         }
         ok(channel instanceof Ci.nsIHttpChannel, "Should be HTTP channel");
         channel.QueryInterface(Ci.nsIHttpChannel);
         is(
           channel.getRequestHeader("Accept"),
-          Services.prefs.getCharPref("image.http.accept"),
+          expectedImageAcceptHeader(),
           "Header should be image header"
         );
         return true;
       }
     );
     // open the context menu.
     let popup = document.getElementById("contentAreaContextMenu");
     let popupShown = BrowserTestUtils.waitForEvent(popup, "popupshown");
--- a/modules/libpref/init/all.js
+++ b/modules/libpref/init/all.js
@@ -3876,18 +3876,19 @@ pref("browser.formfill.prefixWeight",   
 // Zoom prefs
 pref("browser.zoom.full", false);
 pref("toolkit.zoomManager.zoomValues", ".3,.5,.67,.8,.9,1,1.1,1.2,1.33,1.5,1.7,2,2.4,3");
 
 //
 // Image-related prefs
 //
 
-// The default Accept header sent for images loaded over HTTP(S)
-pref("image.http.accept", "image/webp,*/*");
+// By default the Accept header sent for images loaded over HTTP(S) is derived
+// by ImageAcceptHeader() in nsHttpHandler.cpp. If set, this pref overrides it.
+pref("image.http.accept", "");
 
 //
 // Image memory management prefs
 //
 
 // Allows image locking of decoded image data in content processes.
 pref("image.mem.allow_locking_in_content_processes", true);
 
--- a/netwerk/protocol/http/nsHttpHandler.cpp
+++ b/netwerk/protocol/http/nsHttpHandler.cpp
@@ -1,9 +1,9 @@
-/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim:set ts=4 sw=2 sts=2 et cin: */
 /* 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/. */
 
 // HttpLog.h should generally be included first
 #include "HttpLog.h"
 
@@ -62,16 +62,17 @@
 #include "mozilla/net/SocketProcessParent.h"
 #include "mozilla/ipc/URIUtils.h"
 #include "mozilla/Telemetry.h"
 #include "mozilla/Unused.h"
 #include "mozilla/AntiTrackingRedirectHeuristic.h"
 #include "mozilla/DynamicFpiRedirectHeuristic.h"
 #include "mozilla/BasePrincipal.h"
 #include "mozilla/LazyIdleThread.h"
+#include "mozilla/StaticPrefs_image.h"
 #include "mozilla/SyncRunnable.h"
 
 #include "mozilla/dom/ContentParent.h"
 #include "mozilla/dom/Navigator.h"
 #include "mozilla/dom/Promise.h"
 #include "mozilla/dom/network/Connection.h"
 
 #include "nsNSSComponent.h"
@@ -116,17 +117,16 @@
 #define TCP_FAST_OPEN_STALLS_LIMIT "network.tcp.tcp_fastopen_http_stalls_limit"
 #define TCP_FAST_OPEN_STALLS_IDLE \
   "network.tcp.tcp_fastopen_http_check_for_stalls_only_if_idle_for"
 #define TCP_FAST_OPEN_STALLS_TIMEOUT \
   "network.tcp.tcp_fastopen_http_stalls_timeout"
 
 #define ACCEPT_HEADER_NAVIGATION \
   "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8"
-#define ACCEPT_HEADER_IMAGE "image/webp,*/*"
 #define ACCEPT_HEADER_STYLE "text/css,*/*;q=0.1"
 #define ACCEPT_HEADER_ALL "*/*"
 
 #define UA_PREF(_pref) UA_PREF_PREFIX _pref
 #define HTTP_PREF(_pref) HTTP_PREF_PREFIX _pref
 #define BROWSER_PREF(_pref) BROWSER_PREF_PREFIX _pref
 
 #define NS_HTTP_PROTOCOL_FLAGS \
@@ -182,16 +182,35 @@ already_AddRefed<nsHttpHandler> nsHttpHa
     // shutdown and still referencing gHttpHandler.
     ClearOnShutdown(&gHttpHandler,
                     ShutdownPhase::ShutdownPostLastCycleCollection);
   }
   RefPtr<nsHttpHandler> httpHandler = gHttpHandler;
   return httpHandler.forget();
 }
 
+/// Derive the HTTP Accept header for image requests based on the enabled prefs
+/// for non-universal image types. This may be overridden in its entirety by
+/// the image.http.accept pref.
+static nsCString ImageAcceptHeader() {
+  nsCString mimeTypes;
+
+  if (mozilla::StaticPrefs::image_avif_enabled()) {
+    mimeTypes.Append("image/avif,");
+  }
+
+  if (mozilla::StaticPrefs::image_webp_enabled()) {
+    mimeTypes.Append("image/webp,");
+  }
+
+  mimeTypes.Append("*/*");
+
+  return mimeTypes;
+}
+
 nsHttpHandler::nsHttpHandler()
     : mHttpVersion(HttpVersion::v1_1),
       mProxyHttpVersion(HttpVersion::v1_1),
       mCapabilities(NS_HTTP_ALLOW_KEEPALIVE),
       mFastFallbackToIPv4(false),
       mIdleTimeout(PR_SecondsToInterval(10)),
       mSpdyTimeout(PR_SecondsToInterval(180)),
       mResponseTimeout(PR_SecondsToInterval(300)),
@@ -221,17 +240,17 @@ nsHttpHandler::nsHttpHandler()
       mTailDelayQuantumAfterDCL(100),
       mTailDelayMax(6000),
       mTailTotalMax(0),
       mRedirectionLimit(10),
       mBeConservativeForProxy(true),
       mPhishyUserPassLength(1),
       mQoSBits(0x00),
       mEnforceAssocReq(false),
-      mImageAcceptHeader(ACCEPT_HEADER_IMAGE),
+      mImageAcceptHeader(ImageAcceptHeader()),
       mLastUniqueID(NowInSeconds()),
       mSessionStartTime(0),
       mLegacyAppName("Mozilla"),
       mLegacyAppVersion("5.0"),
       mProduct("Gecko"),
       mCompatFirefoxEnabled(false),
       mUserAgentIsDirty(true),
       mAcceptLanguagesIsDirty(true),
@@ -420,16 +439,18 @@ static const char* gCallbackPrefs[] = {
     SECURITY_PREFIX,
     DOM_SECURITY_PREFIX,
     TCP_FAST_OPEN_ENABLE,
     TCP_FAST_OPEN_FAILURE_LIMIT,
     TCP_FAST_OPEN_STALLS_LIMIT,
     TCP_FAST_OPEN_STALLS_IDLE,
     TCP_FAST_OPEN_STALLS_TIMEOUT,
     "image.http.accept",
+    "image.avif.enabled",
+    "image.webp.enabled",
     nullptr,
 };
 
 nsresult nsHttpHandler::Init() {
   nsresult rv;
 
   LOG(("nsHttpHandler::Init\n"));
   MOZ_ASSERT(NS_IsMainThread());
@@ -1926,20 +1947,32 @@ void nsHttpHandler::PrefsChanged(const c
   if (PREF_CHANGED(HTTP_PREF("http3.default-max-stream-blocked"))) {
     rv = Preferences::GetInt(HTTP_PREF("http3.default-max-stream-blocked"),
                              &val);
     if (NS_SUCCEEDED(rv)) {
       mHttp3MaxBlockedStreams = clamped(val, 0, 0xffff);
     }
   }
 
-  if (PREF_CHANGED("image.http.accept")) {
-    rv = Preferences::GetCString("image.http.accept", mImageAcceptHeader);
-    if (NS_FAILED(rv)) {
-      mImageAcceptHeader.Assign(ACCEPT_HEADER_IMAGE);
+  if (PREF_CHANGED("image.http.accept") || PREF_CHANGED("image.avif.enabled") ||
+      PREF_CHANGED("image.webp.enabled")) {
+    nsAutoCString userSetImageAcceptHeader;
+
+    if (Preferences::HasUserValue("image.http.accept")) {
+      rv = Preferences::GetCString("image.http.accept",
+                                   userSetImageAcceptHeader);
+      if (NS_FAILED(rv)) {
+        userSetImageAcceptHeader.Truncate();
+      }
+    }
+
+    if (userSetImageAcceptHeader.IsEmpty()) {
+      mImageAcceptHeader.Assign(ImageAcceptHeader());
+    } else {
+      mImageAcceptHeader.Assign(userSetImageAcceptHeader);
     }
   }
 
   // Enable HTTP response timeout if TCP Keepalives are disabled.
   mResponseTimeoutEnabled =
       !mTCPKeepaliveShortLivedEnabled && !mTCPKeepaliveLongLivedEnabled;
 
 #undef PREF_CHANGED