Commit 75419134 authored by Paul Zuehlcke's avatar Paul Zuehlcke
Browse files

Bug 1704110 - Added PreflightCacheCleaner. r=necko-reviewers,johannh,dragana a=RyanVM

Differential Revision: https://phabricator.services.mozilla.com/D119290
parent 5dcec72a
......@@ -350,6 +350,14 @@ void nsCORSListenerProxy::Shutdown() {
sPreflightCache = nullptr;
}
/* static */
void nsCORSListenerProxy::ClearCache() {
if (!sPreflightCache) {
return;
}
sPreflightCache->Clear();
}
nsCORSListenerProxy::nsCORSListenerProxy(nsIStreamListener* aOuter,
nsIPrincipal* aRequestingPrincipal,
bool aWithCredentials)
......
......@@ -58,6 +58,7 @@ class nsCORSListenerProxy final : public nsIStreamListener,
NS_DECL_NSITHREADRETARGETABLESTREAMLISTENER
static void Shutdown();
static void ClearCache();
[[nodiscard]] nsresult Init(nsIChannel* aChannel,
DataURIHandling aAllowDataURI);
......
......@@ -10,6 +10,7 @@
#include "prsystem.h"
#include "AltServiceChild.h"
#include "nsCORSListenerProxy.h"
#include "nsError.h"
#include "nsHttp.h"
#include "nsHttpHandler.h"
......@@ -2534,6 +2535,12 @@ nsHttpHandler::EnsureHSTSDataReady(JSContext* aCx, Promise** aPromise) {
return EnsureHSTSDataReadyNative(wrapper);
}
NS_IMETHODIMP
nsHttpHandler::ClearCORSPreflightCache() {
nsCORSListenerProxy::ClearCache();
return NS_OK;
}
void nsHttpHandler::ShutdownConnectionManager() {
// ensure connection manager is shutdown
if (mConnMgr) {
......
......@@ -81,6 +81,11 @@ interface nsIHttpProtocolHandler : nsIProxiedProtocolHandler
*/
[noscript]
void EnsureHSTSDataReadyNative(in HSTSDataCallbackWrapperAlreadyAddRefed aCallback);
/*
* Clears the CORS preflight cache.
*/
void clearCORSPreflightCache();
};
%{C++
......
......@@ -1303,6 +1303,22 @@ const AboutHomeStartupCacheCleaner = {
},
};
const PreflightCacheCleaner = {
deleteByPrincipal(aPrincipal) {
return this.deleteAll();
},
deleteByBaseDomain(aBaseDomain) {
return this.deleteAll();
},
async deleteAll() {
Cc[`@mozilla.org/network/protocol;1?name=http`]
.getService(Ci.nsIHttpProtocolHandler)
.clearCORSPreflightCache();
},
};
// Here the map of Flags-Cleaners.
const FLAGS_MAP = [
{
......@@ -1402,6 +1418,11 @@ const FLAGS_MAP = [
flag: Ci.nsIClearDataService.CLEAR_CONTENT_BLOCKING_RECORDS,
cleaners: [ContentBlockingCleaner],
},
{
flag: Ci.nsIClearDataService.CLEAR_PREFLIGHT_CACHE,
cleaners: [PreflightCacheCleaner],
},
];
this.ClearDataService = function() {
......
......@@ -270,10 +270,15 @@ interface nsIClearDataService : nsISupports
*/
const uint32_t CLEAR_CSS_CACHE = 1 << 23;
/**
* Clear the CORS preflight cache.
*/
const uint32_t CLEAR_PREFLIGHT_CACHE = 1 << 24;
/**
* Use this value to delete all the data.
*/
const uint32_t CLEAR_ALL = 0xFFFFFF;
const uint32_t CLEAR_ALL = 0xFFFFFFFF;
/**************************************************************************
* The following flags are helpers: they combine some of the previous flags
......@@ -283,7 +288,8 @@ interface nsIClearDataService : nsISupports
/**
* Delete all the possible caches.
*/
const uint32_t CLEAR_ALL_CACHES = CLEAR_NETWORK_CACHE | CLEAR_IMAGE_CACHE | CLEAR_CSS_CACHE;
const uint32_t CLEAR_ALL_CACHES = CLEAR_NETWORK_CACHE | CLEAR_IMAGE_CACHE |
CLEAR_CSS_CACHE | CLEAR_PREFLIGHT_CACHE;
/**
* Delete all DOM storages
......
......@@ -6,6 +6,9 @@ support-files =
support-files =
file_image_cache.html
file_image_cache.jpg
[browser_preflight_cache.js]
support-files =
file_cors_preflight.sjs
[browser_serviceworkers.js]
[browser_sessionStorage.js]
[browser_quota.js]
......
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
const { SiteDataTestUtils } = ChromeUtils.import(
"resource://testing-common/SiteDataTestUtils.jsm"
);
const uuidGenerator = Cc["@mozilla.org/uuid-generator;1"].getService(
Ci.nsIUUIDGenerator
);
const ORIGIN_A = "http://example.net";
const ORIGIN_B = "http://example.org";
const PREFLIGHT_URL_PATH =
"/browser/toolkit/components/cleardata/tests/browser/file_cors_preflight.sjs";
const PREFLIGHT_URL_A = ORIGIN_A + PREFLIGHT_URL_PATH;
const PREFLIGHT_URL_B = ORIGIN_B + PREFLIGHT_URL_PATH;
function testPreflightCached(browser, url, token, isCached) {
return SpecialPowers.spawn(
browser,
[url, token, isCached],
async (url, token, isCached) => {
let response = await content.fetch(
new content.Request(`${url}?token=${token}`, {
mode: "cors",
method: "GET",
headers: [["x-test-header", "check"]],
})
);
let expected = isCached ? "0" : "1";
is(
await response.text(),
expected,
`Preflight cache for ${url} ${isCached ? "HIT" : "MISS"}.`
);
}
);
}
async function testDeleteAll(clearDataFlag) {
await BrowserTestUtils.withNewTab("http://example.com", async browser => {
let token = uuidGenerator.generateUUID().toString();
// Populate the preflight cache.
await testPreflightCached(browser, PREFLIGHT_URL_A, token, false);
await testPreflightCached(browser, PREFLIGHT_URL_B, token, false);
// Cache should be populated.
await testPreflightCached(browser, PREFLIGHT_URL_A, token, true);
await testPreflightCached(browser, PREFLIGHT_URL_B, token, true);
// Clear the preflight cache.
await new Promise(aResolve => {
Services.clearData.deleteData(clearDataFlag, value => {
Assert.equal(value, 0);
aResolve();
});
});
// Cache should be cleared.
await testPreflightCached(browser, PREFLIGHT_URL_A, token, false);
await testPreflightCached(browser, PREFLIGHT_URL_B, token, false);
});
SiteDataTestUtils.clear();
}
add_task(async function test_deleteAll() {
// The cleaner should be called when we target all cleaners, all cache
// cleaners, or just the preflight cache.
let {
CLEAR_ALL,
CLEAR_ALL_CACHES,
CLEAR_PREFLIGHT_CACHE,
} = Ci.nsIClearDataService;
for (let flag of [CLEAR_ALL, CLEAR_ALL_CACHES, CLEAR_PREFLIGHT_CACHE]) {
await testDeleteAll(flag);
}
});
/* 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/. */
'use strict';
Components.utils.importGlobalProperties(["URLSearchParams"]);
function handleRequest(request, response) {
let query = new URLSearchParams(request.queryString);
let token = query.get("token");
response.setHeader("Content-Type", "text/plain", false);
response.setHeader("Access-Control-Allow-Origin", "*", false);
response.setHeader("Access-Control-Allow-Headers", "x-test-header", false);
if (request.method == "OPTIONS") {
response.setHeader(
"Access-Control-Allow-Methods",
request.getHeader("Access-Control-Request-Method"),
false);
response.setHeader("Access-Control-Max-Age", "20", false);
setState(token, token);
} else {
let test_op = request.getHeader("x-test-header");
if (test_op == "check") {
let value = getState(token);
if (value) {
response.write("1");
setState(token, "");
} else {
response.write("0");
}
}
}
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment