Commit 02ffe0cd authored by Christoph Kerschbaumer's avatar Christoph Kerschbaumer
Browse files

Bug 1729807: HTTPS-First should support fallback of view-source URIs from https to http r=valentin

parent acedd829
Loading
Loading
Loading
Loading
+31 −4
Original line number Diff line number Diff line
@@ -498,15 +498,42 @@ nsHTTPSOnlyUtils::PotentiallyDowngradeHttpsFirstRequest(nsIChannel* aChannel,
  nsresult rv = aChannel->GetURI(getter_AddRefs(uri));
  NS_ENSURE_SUCCESS(rv, nullptr);

  // Only downgrade if the current scheme is HTTPS
  if (!uri->SchemeIs("https")) {
  // Only downgrade if the current scheme is (a) https or (b) view-source:https
  nsAutoCString spec;
  if (uri->SchemeIs("https")) {
    rv = uri->GetSpec(spec);
    NS_ENSURE_SUCCESS(rv, nullptr);
  } else if (uri->SchemeIs("view-source")) {
    nsCOMPtr<nsINestedURI> nestedURI = do_QueryInterface(uri);
    if (!nestedURI) {
      return nullptr;
    }
    nsCOMPtr<nsIURI> innerURI;
    rv = nestedURI->GetInnerURI(getter_AddRefs(innerURI));
    NS_ENSURE_SUCCESS(rv, nullptr);
    if (!innerURI || !innerURI->SchemeIs("https")) {
      return nullptr;
    }
    nsAutoCString innerSpec;
    rv = innerURI->GetSpec(innerSpec);
    NS_ENSURE_SUCCESS(rv, nullptr);

    spec.Append("view-source:");
    spec.Append(innerSpec);
  } else {
    return nullptr;
  }

  // Change the scheme to http
  if (spec.Find("https://") < 0) {
    MOZ_ASSERT(false, "how can we end up here not dealing with an https: URI?");
    return nullptr;
  }
  spec.ReplaceSubstring("https://", "http://");

  nsCOMPtr<nsIURI> newURI;
  mozilla::Unused << NS_MutateURI(uri).SetScheme("http"_ns).Finalize(
      getter_AddRefs(newURI));
  rv = NS_NewURI(getter_AddRefs(newURI), spec);
  NS_ENSURE_SUCCESS(rv, nullptr);

  // Log downgrade to console
  NS_ConvertUTF8toUTF16 reportSpec(uri->GetSpecOrDefault());
+2 −0
Original line number Diff line number Diff line
@@ -6,3 +6,5 @@ support-files =
[browser_mixed_content_console.js]
support-files =
  file_mixed_content_console.html
[browser_downgrade_view_source.js]
support-files = file_downgrade_view_source.sjs
+53 −0
Original line number Diff line number Diff line
// This test ensures that view-source:https falls back to view-source:http
"use strict";

const TEST_PATH_HTTP = getRootDirectory(gTestPath).replace(
  "chrome://mochitests/content",
  "http://example.com"
);

const TEST_PATH_HTTPS = getRootDirectory(gTestPath).replace(
  "chrome://mochitests/content",
  "https://example.com"
);

async function runTest(desc, url, expectedURI, excpectedContent) {
  await BrowserTestUtils.withNewTab("about:blank", async function(browser) {
    let loaded = BrowserTestUtils.browserLoaded(browser, false, null, true);
    BrowserTestUtils.loadURI(browser, url);
    await loaded;

    await SpecialPowers.spawn(
      browser,
      [desc, expectedURI, excpectedContent],
      async function(desc, expectedURI, excpectedContent) {
        let loadedURI = content.document.documentURI;
        is(loadedURI, expectedURI, desc);
        let loadedContent = content.document.body.textContent;
        is(loadedContent, excpectedContent, desc);
      }
    );
  });
}

add_task(async function() {
  requestLongerTimeout(2);

  await SpecialPowers.pushPrefEnv({
    set: [["dom.security.https_first", true]],
  });

  await runTest(
    "URL with query 'downgrade' should be http:",
    `view-source:${TEST_PATH_HTTP}/file_downgrade_view_source.sjs?downgrade`,
    `view-source:${TEST_PATH_HTTP}/file_downgrade_view_source.sjs?downgrade`,
    "view-source:http://"
  );

  await runTest(
    "URL with query 'upgrade' should be https:",
    `view-source:${TEST_PATH_HTTP}/file_downgrade_view_source.sjs?upgrade`,
    `view-source:${TEST_PATH_HTTPS}/file_downgrade_view_source.sjs?upgrade`,
    "view-source:https://"
  );
});
+30 −0
Original line number Diff line number Diff line
"use strict";

function handleRequest(request, response) {
  // avoid confusing cache behaviour
  response.setHeader("Cache-Control", "no-cache", false);
  response.setHeader("Content-Type", "text/html", false);

  let query = request.queryString;
  let scheme = request.scheme;

  if (scheme === "https") {
    if (query === "downgrade") {
      response.setStatusLine("1.1", 400, "Bad Request");
      response.write("Bad Request\n");
      return;
    }
    if (query === "upgrade") {
      response.write("view-source:https://");
      return;
    }
  }

  if (scheme === "http" && query === "downgrade") {
    response.write("view-source:http://");
    return;
  }

  // We should arrive here when the redirection was downraded successful
  response.write("unexpected");
}