feat_allow_code_cache_in_custom_schemes.patch 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468
  1. From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
  2. From: Cheng Zhao <[email protected]>
  3. Date: Thu, 14 Dec 2023 21:16:53 +0900
  4. Subject: Enable V8 code cache for custom schemes
  5. Add a new category in ContentClient::AddAdditionalSchemes which allows
  6. embedders to make custom schemes allow V8 code cache.
  7. Chromium CL: https://chromium-review.googlesource.com/c/chromium/src/+/5019665
  8. diff --git a/content/browser/code_cache/generated_code_cache.cc b/content/browser/code_cache/generated_code_cache.cc
  9. index f9e76bffba1f153f4b735a1b6e3fa0b6110c437c..ca6c37281dc31623f065da56171c42617e4aa946 100644
  10. --- a/content/browser/code_cache/generated_code_cache.cc
  11. +++ b/content/browser/code_cache/generated_code_cache.cc
  12. @@ -6,6 +6,7 @@
  13. #include <iostream>
  14. +#include "base/containers/contains.h"
  15. #include "base/feature_list.h"
  16. #include "base/functional/bind.h"
  17. #include "base/functional/callback_helpers.h"
  18. @@ -25,6 +26,7 @@
  19. #include "net/http/http_cache.h"
  20. #include "third_party/blink/public/common/scheme_registry.h"
  21. #include "url/gurl.h"
  22. +#include "url/url_util.h"
  23. using storage::BigIOBuffer;
  24. @@ -37,7 +39,7 @@ constexpr char kSeparator[] = " \n";
  25. // We always expect to receive valid URLs that can be used as keys to the code
  26. // cache. The relevant checks (for ex: resource_url is valid, origin_lock is
  27. -// not opque etc.,) must be done prior to requesting the code cache.
  28. +// not opaque etc.,) must be done prior to requesting the code cache.
  29. //
  30. // This function doesn't enforce anything in the production code. It is here
  31. // to make the assumptions explicit and to catch any errors when DCHECKs are
  32. @@ -47,33 +49,55 @@ void CheckValidKeys(const GURL& resource_url,
  33. GeneratedCodeCache::CodeCacheType cache_type) {
  34. // If the resource url is invalid don't cache the code.
  35. DCHECK(resource_url.is_valid());
  36. - bool resource_url_is_chrome_or_chrome_untrusted =
  37. +
  38. + // There are 3 kind of URL scheme compatible for the `resource_url`.
  39. + // 1. http: and https: URLs.
  40. + // 2. chrome: and chrome-untrusted: URLs.
  41. + // 3. URLs whose scheme are allowed by the content/ embedder.
  42. + const bool resource_url_http = resource_url.SchemeIsHTTPOrHTTPS();
  43. + const bool resource_url_webui =
  44. resource_url.SchemeIs(content::kChromeUIScheme) ||
  45. resource_url.SchemeIs(content::kChromeUIUntrustedScheme);
  46. - DCHECK(resource_url.SchemeIsHTTPOrHTTPS() ||
  47. - resource_url_is_chrome_or_chrome_untrusted ||
  48. - blink::CommonSchemeRegistry::IsExtensionScheme(resource_url.scheme()));
  49. -
  50. - // |origin_lock| should be either empty or should have
  51. - // Http/Https/chrome/chrome-untrusted schemes and it should not be a URL with
  52. - // opaque origin. Empty origin_locks are allowed when the renderer is not
  53. - // locked to an origin.
  54. - bool origin_lock_is_chrome_or_chrome_untrusted =
  55. +
  56. + const bool resource_url_embedder =
  57. + base::Contains(url::GetCodeCacheSchemes(), resource_url.scheme());
  58. + DCHECK(resource_url_http || resource_url_webui || resource_url_embedder);
  59. +
  60. + // |origin_lock| should be either empty or should have code cache allowed
  61. + // schemes (http/https/chrome/chrome-untrusted or other custom schemes added
  62. + // by url::AddCodeCacheScheme), and it should not be a URL with opaque
  63. + // origin. Empty origin_locks are allowed when the renderer is not locked to
  64. + // an origin.
  65. + const bool origin_lock_empty = origin_lock.is_empty();
  66. + const bool origin_lock_for_http = origin_lock.SchemeIsHTTPOrHTTPS();
  67. + const bool origin_lock_for_webui =
  68. origin_lock.SchemeIs(content::kChromeUIScheme) ||
  69. origin_lock.SchemeIs(content::kChromeUIUntrustedScheme);
  70. - DCHECK(
  71. - origin_lock.is_empty() ||
  72. - ((origin_lock.SchemeIsHTTPOrHTTPS() ||
  73. - origin_lock_is_chrome_or_chrome_untrusted ||
  74. - blink::CommonSchemeRegistry::IsExtensionScheme(origin_lock.scheme())) &&
  75. - !url::Origin::Create(origin_lock).opaque()));
  76. -
  77. - // The chrome and chrome-untrusted schemes are only used with the WebUI
  78. - // code cache type.
  79. - DCHECK_EQ(origin_lock_is_chrome_or_chrome_untrusted,
  80. - cache_type == GeneratedCodeCache::kWebUIJavaScript);
  81. - DCHECK_EQ(resource_url_is_chrome_or_chrome_untrusted,
  82. - cache_type == GeneratedCodeCache::kWebUIJavaScript);
  83. + const bool origin_lock_for_embedder =
  84. + base::Contains(url::GetCodeCacheSchemes(), origin_lock.scheme());
  85. +
  86. + DCHECK(origin_lock_empty || ((origin_lock_for_http || origin_lock_for_webui ||
  87. + origin_lock_for_embedder) &&
  88. + !url::Origin::Create(origin_lock).opaque()));
  89. +
  90. + // The webui schemes are only used with their dedicated code cache type.
  91. + switch (cache_type) {
  92. + case GeneratedCodeCache::kJavaScript:
  93. + case GeneratedCodeCache::kWebAssembly:
  94. + DCHECK(!origin_lock_for_webui);
  95. + DCHECK(!resource_url_webui);
  96. + break;
  97. + case GeneratedCodeCache::kWebUIJavaScript:
  98. + DCHECK(origin_lock_for_webui);
  99. + DCHECK(resource_url_webui);
  100. + break;
  101. + }
  102. +
  103. + // The custom schemes share the cache type with http(s).
  104. + if (origin_lock_for_embedder || resource_url_embedder) {
  105. + DCHECK(cache_type == GeneratedCodeCache::kJavaScript ||
  106. + cache_type == GeneratedCodeCache::kWebAssembly);
  107. + }
  108. }
  109. // Generates the cache key for the given |resource_url|, |origin_lock| and
  110. diff --git a/content/browser/code_cache/generated_code_cache.h b/content/browser/code_cache/generated_code_cache.h
  111. index f5c5ff2c89489257003dfe3284ee9de9f517c99b..fdd2e2483171c4d43963590200817dac27d22cf9 100644
  112. --- a/content/browser/code_cache/generated_code_cache.h
  113. +++ b/content/browser/code_cache/generated_code_cache.h
  114. @@ -52,12 +52,14 @@ class CONTENT_EXPORT GeneratedCodeCache {
  115. // Cache type. Used for collecting statistics for JS and Wasm in separate
  116. // buckets.
  117. enum CodeCacheType {
  118. - // JavaScript from http(s) pages.
  119. + // JavaScript from pages of http(s) schemes or custom schemes registered by
  120. + // url::AddCodeCacheScheme.
  121. kJavaScript,
  122. - // WebAssembly from http(s) pages. This cache allows more total size and
  123. - // more size per item than the JavaScript cache, since some
  124. - // WebAssembly programs are very large.
  125. + // WebAssembly from pages of http(s) schemes or custom schemes registered by
  126. + // url::AddCodeCacheScheme. This cache allows more total size and more size
  127. + // per item than the JavaScript cache, since some WebAssembly programs are
  128. + // very large.
  129. kWebAssembly,
  130. // JavaScript from chrome and chrome-untrusted pages. The resource URLs are
  131. diff --git a/content/browser/code_cache/generated_code_cache_browsertest.cc b/content/browser/code_cache/generated_code_cache_browsertest.cc
  132. index f78d1ce2541de573aa53d253bf707f0234a25f55..02c4e48bf7ddc6325a3f09b39ed1f5ecb16465de 100644
  133. --- a/content/browser/code_cache/generated_code_cache_browsertest.cc
  134. +++ b/content/browser/code_cache/generated_code_cache_browsertest.cc
  135. @@ -8,13 +8,18 @@
  136. #include "content/browser/code_cache/generated_code_cache.h"
  137. #include "content/browser/code_cache/generated_code_cache_context.h"
  138. #include "content/browser/renderer_host/code_cache_host_impl.h"
  139. +#include "content/browser/storage_partition_impl.h"
  140. +#include "content/common/url_schemes.h"
  141. #include "content/public/browser/browser_context.h"
  142. +#include "content/public/browser/browser_thread.h"
  143. #include "content/public/browser/storage_partition.h"
  144. #include "content/public/test/browser_test.h"
  145. #include "content/public/test/browser_test_utils.h"
  146. #include "content/public/test/content_browser_test.h"
  147. #include "content/public/test/content_browser_test_utils.h"
  148. +#include "content/public/test/test_browser_context.h"
  149. #include "content/shell/browser/shell.h"
  150. +#include "content/test/test_content_client.h"
  151. #include "net/dns/mock_host_resolver.h"
  152. #include "third_party/blink/public/common/features.h"
  153. #include "third_party/blink/public/common/page/v8_compile_hints_histograms.h"
  154. @@ -23,6 +28,8 @@ namespace content {
  155. namespace {
  156. +const std::string kCodeCacheScheme = "test-code-cache";
  157. +
  158. bool SupportsSharedWorker() {
  159. #if BUILDFLAG(IS_ANDROID)
  160. // SharedWorkers are not enabled on Android. https://crbug.com/154571
  161. @@ -116,8 +123,7 @@ class CodeCacheBrowserTest
  162. // Worker scripts will fetch this once the cacheable resource has been
  163. // loaded and the test logic (checking histograms) can continue.
  164. if (absolute_url.path() == "/done.js") {
  165. - content::GetUIThreadTaskRunner({})->PostTask(FROM_HERE,
  166. - std::move(done_callback_));
  167. + GetUIThreadTaskRunner({})->PostTask(FROM_HERE, std::move(done_callback_));
  168. auto http_response =
  169. std::make_unique<net::test_server::BasicHttpResponse>();
  170. @@ -630,4 +636,82 @@ IN_PROC_BROWSER_TEST_F(LocalCompileHintsBrowserTest, LocalCompileHints) {
  171. }
  172. }
  173. +class CodeCacheInCustomSchemeBrowserTest : public ContentBrowserTest,
  174. + public TestContentClient {
  175. + public:
  176. + CodeCacheInCustomSchemeBrowserTest() {
  177. + SetContentClient(this);
  178. + ReRegisterContentSchemesForTests();
  179. + }
  180. +
  181. + ~CodeCacheInCustomSchemeBrowserTest() override { SetContentClient(nullptr); }
  182. +
  183. + private:
  184. + void AddAdditionalSchemes(Schemes* schemes) override {
  185. + schemes->standard_schemes.push_back(kCodeCacheScheme);
  186. + schemes->code_cache_schemes.push_back(kCodeCacheScheme);
  187. + }
  188. +
  189. + url::ScopedSchemeRegistryForTests scheme_registry_;
  190. +};
  191. +
  192. +IN_PROC_BROWSER_TEST_F(CodeCacheInCustomSchemeBrowserTest,
  193. + AllowedCustomSchemeCanGenerateCodeCache) {
  194. + StoragePartitionImpl* partition =
  195. + static_cast<StoragePartitionImpl*>(shell()
  196. + ->web_contents()
  197. + ->GetBrowserContext()
  198. + ->GetDefaultStoragePartition());
  199. + scoped_refptr<GeneratedCodeCacheContext> context =
  200. + partition->GetGeneratedCodeCacheContext();
  201. + EXPECT_NE(context, nullptr);
  202. +
  203. + GURL url(kCodeCacheScheme + "://host4/script.js");
  204. + GURL origin(kCodeCacheScheme + "://host1:1/");
  205. + ASSERT_TRUE(url.is_valid());
  206. + ASSERT_TRUE(origin.is_valid());
  207. + std::string data("SomeData");
  208. +
  209. + // Add a code cache entry for the custom scheme.
  210. + base::test::TestFuture<void> add_entry_future;
  211. + GeneratedCodeCacheContext::RunOrPostTask(
  212. + context.get(), FROM_HERE,
  213. + base::BindOnce(
  214. + [](scoped_refptr<GeneratedCodeCacheContext> context, const GURL& url,
  215. + const GURL& origin, const std::string& data,
  216. + base::OnceClosure callback) {
  217. + context->generated_js_code_cache()->WriteEntry(
  218. + url, origin, net::NetworkIsolationKey(), base::Time::Now(),
  219. + std::vector<uint8_t>(data.begin(), data.end()));
  220. + GetUIThreadTaskRunner({})->PostTask(FROM_HERE, std::move(callback));
  221. + },
  222. + context, url, origin, data, add_entry_future.GetCallback()));
  223. + ASSERT_TRUE(add_entry_future.Wait());
  224. +
  225. + // Get the code cache entry.
  226. + base::test::TestFuture<std::string> get_entry_future;
  227. + GeneratedCodeCacheContext::RunOrPostTask(
  228. + context.get(), FROM_HERE,
  229. + base::BindOnce(
  230. + [](scoped_refptr<GeneratedCodeCacheContext> context, const GURL& url,
  231. + const GURL& origin,
  232. + base::OnceCallback<void(std::string)> callback) {
  233. + context->generated_js_code_cache()->FetchEntry(
  234. + url, origin, net::NetworkIsolationKey(),
  235. + base::BindOnce(
  236. + [](base::OnceCallback<void(std::string)> callback,
  237. + const base::Time& response_time,
  238. + mojo_base::BigBuffer buffer) {
  239. + std::string data(buffer.data(),
  240. + buffer.data() + buffer.size());
  241. + GetUIThreadTaskRunner({})->PostTask(
  242. + FROM_HERE, base::BindOnce(std::move(callback), data));
  243. + },
  244. + std::move(callback)));
  245. + },
  246. + context, url, origin, get_entry_future.GetCallback()));
  247. + ASSERT_TRUE(get_entry_future.Wait());
  248. + ASSERT_EQ(data, get_entry_future.Get<0>());
  249. +}
  250. +
  251. } // namespace content
  252. diff --git a/content/browser/renderer_host/code_cache_host_impl.cc b/content/browser/renderer_host/code_cache_host_impl.cc
  253. index b083cd89c46e676f26a7c28eda091cedbf9a5a97..84736ba6b3ae6111f1cebad862989daadb838234 100644
  254. --- a/content/browser/renderer_host/code_cache_host_impl.cc
  255. +++ b/content/browser/renderer_host/code_cache_host_impl.cc
  256. @@ -6,6 +6,7 @@
  257. #include <utility>
  258. +#include "base/containers/contains.h"
  259. #include "base/functional/bind.h"
  260. #include "base/functional/callback_helpers.h"
  261. #include "base/metrics/histogram_functions.h"
  262. @@ -29,6 +30,7 @@
  263. #include "third_party/blink/public/common/scheme_registry.h"
  264. #include "url/gurl.h"
  265. #include "url/origin.h"
  266. +#include "url/url_util.h"
  267. using blink::mojom::CacheStorageError;
  268. @@ -36,6 +38,11 @@ namespace content {
  269. namespace {
  270. +bool ProcessLockURLIsCodeCacheScheme(const ProcessLock& process_lock) {
  271. + return base::Contains(url::GetCodeCacheSchemes(),
  272. + process_lock.lock_url().scheme());
  273. +}
  274. +
  275. bool CheckSecurityForAccessingCodeCacheData(
  276. const GURL& resource_url,
  277. int render_process_id,
  278. @@ -46,39 +53,57 @@ bool CheckSecurityForAccessingCodeCacheData(
  279. // Code caching is only allowed for http(s) and chrome/chrome-untrusted
  280. // scripts. Furthermore, there is no way for http(s) pages to load chrome or
  281. + // Code caching is only allowed for scripts from:
  282. + // 1. http: and https: schemes.
  283. + // 2. chrome: and chrome-untrusted: schemes.
  284. + // 3. Schemes registered by content/ embedder via url::AddCodeCacheScheme.
  285. + //
  286. + // Furthermore, we know there are no way for http(s) pages to load chrome or
  287. // chrome-untrusted scripts, so any http(s) page attempting to store data
  288. // about a chrome or chrome-untrusted script would be an indication of
  289. // suspicious activity.
  290. - if (resource_url.SchemeIs(content::kChromeUIScheme) ||
  291. - resource_url.SchemeIs(content::kChromeUIUntrustedScheme)) {
  292. - if (!process_lock.is_locked_to_site()) {
  293. - // We can't tell for certain whether this renderer is doing something
  294. - // malicious, but we don't trust it enough to store data.
  295. - return false;
  296. - }
  297. + if (resource_url.SchemeIsHTTPOrHTTPS()) {
  298. if (process_lock.matches_scheme(url::kHttpScheme) ||
  299. process_lock.matches_scheme(url::kHttpsScheme)) {
  300. - if (operation == CodeCacheHostImpl::Operation::kWrite) {
  301. + return true;
  302. + }
  303. + // Pages in custom schemes like isolated-app: are allowed to load http(s)
  304. + // resources.
  305. + if (ProcessLockURLIsCodeCacheScheme(process_lock)) {
  306. + return true;
  307. + }
  308. + // It is possible for WebUI pages to include open-web content, but such
  309. + // usage is rare and we've decided that reasoning about security is easier
  310. + // if the WebUI code cache includes only WebUI scripts.
  311. + return false;
  312. + }
  313. +
  314. + if (resource_url.SchemeIs(kChromeUIScheme) ||
  315. + resource_url.SchemeIs(kChromeUIUntrustedScheme)) {
  316. + if (process_lock.matches_scheme(kChromeUIScheme) ||
  317. + process_lock.matches_scheme(kChromeUIUntrustedScheme)) {
  318. + return true;
  319. + }
  320. + if (operation == CodeCacheHostImpl::Operation::kWrite) {
  321. + if (process_lock.matches_scheme(url::kHttpScheme) ||
  322. + process_lock.matches_scheme(url::kHttpsScheme)) {
  323. mojo::ReportBadMessage("HTTP(S) pages cannot cache WebUI code");
  324. }
  325. + if (ProcessLockURLIsCodeCacheScheme(process_lock)) {
  326. + mojo::ReportBadMessage(
  327. + "Page whose scheme are allowed by content/ embedders cannot cache "
  328. + "WebUI code. Did the embedder misconfigured content/?");
  329. + }
  330. return false;
  331. }
  332. // Other schemes which might successfully load chrome or chrome-untrusted
  333. // scripts, such as the PDF viewer, are unsupported but not considered
  334. - // dangerous.
  335. - return process_lock.matches_scheme(content::kChromeUIScheme) ||
  336. - process_lock.matches_scheme(content::kChromeUIUntrustedScheme);
  337. + // dangerous. Similarly, the process might not be locked to a site.
  338. + return false;
  339. }
  340. - if (resource_url.SchemeIsHTTPOrHTTPS() ||
  341. - blink::CommonSchemeRegistry::IsExtensionScheme(resource_url.scheme())) {
  342. - if (process_lock.matches_scheme(content::kChromeUIScheme) ||
  343. - process_lock.matches_scheme(content::kChromeUIUntrustedScheme)) {
  344. - // It is possible for WebUI pages to include open-web content, but such
  345. - // usage is rare and we've decided that reasoning about security is easier
  346. - // if the WebUI code cache includes only WebUI scripts.
  347. - return false;
  348. - }
  349. - return true;
  350. +
  351. + if (base::Contains(url::GetCodeCacheSchemes(), resource_url.scheme())) {
  352. + return ProcessLockURLIsCodeCacheScheme(process_lock);
  353. }
  354. if (operation == CodeCacheHostImpl::Operation::kWrite) {
  355. @@ -425,6 +450,7 @@ std::optional<GURL> CodeCacheHostImpl::GetSecondaryKeyForCodeCache(
  356. process_lock.matches_scheme(url::kHttpsScheme) ||
  357. process_lock.matches_scheme(content::kChromeUIScheme) ||
  358. process_lock.matches_scheme(content::kChromeUIUntrustedScheme) ||
  359. + ProcessLockURLIsCodeCacheScheme(process_lock) ||
  360. blink::CommonSchemeRegistry::IsExtensionScheme(
  361. process_lock.lock_url().scheme())) {
  362. return process_lock.lock_url();
  363. diff --git a/content/common/url_schemes.cc b/content/common/url_schemes.cc
  364. index ce9644d33fe83379127b01bf9a2b1c4badc3bc7c..fd486d4637ae4766ed78571dee7f9cebbd809f38 100644
  365. --- a/content/common/url_schemes.cc
  366. +++ b/content/common/url_schemes.cc
  367. @@ -98,6 +98,14 @@ void RegisterContentSchemes(bool should_lock_registry) {
  368. for (auto& scheme : schemes.empty_document_schemes)
  369. url::AddEmptyDocumentScheme(scheme.c_str());
  370. + for (auto& scheme : schemes.code_cache_schemes) {
  371. + CHECK_NE(scheme, kChromeUIScheme);
  372. + CHECK_NE(scheme, kChromeUIUntrustedScheme);
  373. + CHECK_NE(scheme, url::kHttpScheme);
  374. + CHECK_NE(scheme, url::kHttpsScheme);
  375. + url::AddCodeCacheScheme(scheme.c_str());
  376. + }
  377. +
  378. #if BUILDFLAG(IS_ANDROID)
  379. if (schemes.allow_non_standard_schemes_in_origins)
  380. url::EnableNonStandardSchemesForAndroidWebView();
  381. diff --git a/content/public/common/content_client.h b/content/public/common/content_client.h
  382. index 5d1484651fb8c3e03337665d3d5342ba51df3154..d4432a660d6c5a5e937dedabb7e4b71b87c9504b 100644
  383. --- a/content/public/common/content_client.h
  384. +++ b/content/public/common/content_client.h
  385. @@ -139,6 +139,9 @@ class CONTENT_EXPORT ContentClient {
  386. // Registers a URL scheme as strictly empty documents, allowing them to
  387. // commit synchronously.
  388. std::vector<std::string> empty_document_schemes;
  389. + // Registers a URL scheme whose js and wasm scripts have V8 code cache
  390. + // enabled.
  391. + std::vector<std::string> code_cache_schemes;
  392. // Registers a URL scheme as extension scheme.
  393. std::vector<std::string> extension_schemes;
  394. // Registers a URL scheme with a predefined default custom handler.
  395. diff --git a/url/url_util.cc b/url/url_util.cc
  396. index 16875957448d2c10c889bb406a5e749cfae41ddc..038037d558ad4deedcbfc5c7c8264a8eab93c0d7 100644
  397. --- a/url/url_util.cc
  398. +++ b/url/url_util.cc
  399. @@ -115,6 +115,9 @@ struct SchemeRegistry {
  400. kAboutScheme,
  401. };
  402. + // Embedder schemes that have V8 code cache enabled in js and wasm scripts.
  403. + std::vector<std::string> code_cache_schemes = {};
  404. +
  405. // Schemes with a predefined default custom handler.
  406. std::vector<SchemeWithHandler> predefined_handler_schemes;
  407. @@ -681,6 +684,15 @@ const std::vector<std::string>& GetEmptyDocumentSchemes() {
  408. return GetSchemeRegistry().empty_document_schemes;
  409. }
  410. +void AddCodeCacheScheme(const char* new_scheme) {
  411. + DoAddScheme(new_scheme,
  412. + &GetSchemeRegistryWithoutLocking()->code_cache_schemes);
  413. +}
  414. +
  415. +const std::vector<std::string>& GetCodeCacheSchemes() {
  416. + return GetSchemeRegistry().code_cache_schemes;
  417. +}
  418. +
  419. void AddPredefinedHandlerScheme(const char* new_scheme, const char* handler) {
  420. DoAddSchemeWithHandler(
  421. new_scheme, handler,
  422. diff --git a/url/url_util.h b/url/url_util.h
  423. index 8c94c7a4f6d5f653d326199e5b43452f969911d4..518ea53a033233ca88b411200e008beb7bbd75ef 100644
  424. --- a/url/url_util.h
  425. +++ b/url/url_util.h
  426. @@ -115,6 +115,15 @@ COMPONENT_EXPORT(URL) const std::vector<std::string>& GetCSPBypassingSchemes();
  427. COMPONENT_EXPORT(URL) void AddEmptyDocumentScheme(const char* new_scheme);
  428. COMPONENT_EXPORT(URL) const std::vector<std::string>& GetEmptyDocumentSchemes();
  429. +// Adds an application-defined scheme to the list of schemes that have V8 code
  430. +// cache enabled for the js and wasm scripts.
  431. +// The WebUI schemes (chrome/chrome-untrusted) do not belong to this list, as
  432. +// they are treated as a separate cache type for security purpose.
  433. +// The http(s) schemes do not belong to this list neither, they always have V8
  434. +// code cache enabled.
  435. +COMPONENT_EXPORT(URL) void AddCodeCacheScheme(const char* new_scheme);
  436. +COMPONENT_EXPORT(URL) const std::vector<std::string>& GetCodeCacheSchemes();
  437. +
  438. // Adds a scheme with a predefined default handler.
  439. //
  440. // This pair of strings must be normalized protocol handler parameters as