Skip to content

Commit 24ad057

Browse files
committed
fix(printing): update print preview handling for Dao scheme and enhance CSP for cross-scheme compatibility
1 parent 97f2e3e commit 24ad057

7 files changed

Lines changed: 180 additions & 2 deletions

File tree

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
diff --git a/chrome/browser/resources/pdf/pdf_internal_plugin_wrapper.ts b/chrome/browser/resources/pdf/pdf_internal_plugin_wrapper.ts
2+
index 0f221c0532..c0c8dd2941 100644
3+
--- a/chrome/browser/resources/pdf/pdf_internal_plugin_wrapper.ts
4+
+++ b/chrome/browser/resources/pdf/pdf_internal_plugin_wrapper.ts
5+
@@ -20,9 +20,15 @@ const plugin = document.querySelector<InProcessPdfPluginElement>('embed')!;
6+
7+
const srcUrl = new URL(plugin.src);
8+
let parentOrigin = srcUrl.origin;
9+
+const printPreviewParentOrigins = ['chrome://print', 'dao://print'];
10+
if (parentOrigin === 'chrome-untrusted://print') {
11+
// Within Print Preview, the source origin differs from the parent origin.
12+
- parentOrigin = 'chrome://print';
13+
+ const ancestorOrigin = window.location.ancestorOrigins.length > 0 ?
14+
+ window.location.ancestorOrigins[0]! :
15+
+ '';
16+
+ parentOrigin = printPreviewParentOrigins.includes(ancestorOrigin) ?
17+
+ ancestorOrigin :
18+
+ 'chrome://print';
19+
}
20+
21+
// Plugin-to-parent message handlers. All messages are passed through, but some
22+
@@ -93,7 +99,8 @@ channel.port1.onmessage = e => {
23+
// Snoop on "viewport" message to support real RTL scrolling in Print
24+
// Preview.
25+
// TODO(crbug.com/40737077): Support real RTL scrolling in the PDF viewer.
26+
- if (parentOrigin === 'chrome://print' && e.data.layoutOptions) {
27+
+ if (printPreviewParentOrigins.includes(parentOrigin) &&
28+
+ e.data.layoutOptions) {
29+
switch (e.data.layoutOptions.direction) {
30+
case 1:
31+
document.dir = 'rtl';
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
diff --git a/chrome/browser/resources/pdf/pdf_scripting_api.ts b/chrome/browser/resources/pdf/pdf_scripting_api.ts
2+
index 7e6a5a553d..d0f2e4f0a8 100644
3+
--- a/chrome/browser/resources/pdf/pdf_scripting_api.ts
4+
+++ b/chrome/browser/resources/pdf/pdf_scripting_api.ts
5+
@@ -97,7 +97,8 @@ export class PdfScriptingApi {
6+
window.addEventListener('message', event => {
7+
if (event.origin !==
8+
'chrome-extension://mhjfbmdgcfjbbpaeojofohoefgiehjai' &&
9+
- event.origin !== 'chrome://print') {
10+
+ event.origin !== 'chrome://print' &&
11+
+ event.origin !== 'dao://print') {
12+
console.error(
13+
'Received message that was not from the extension: ' + event);
14+
return;
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
diff --git a/chrome/browser/resources/print_preview/ui/plugin_proxy.ts b/chrome/browser/resources/print_preview/ui/plugin_proxy.ts
2+
index afbf6c857e..fcdbe21516 100644
3+
--- a/chrome/browser/resources/print_preview/ui/plugin_proxy.ts
4+
+++ b/chrome/browser/resources/print_preview/ui/plugin_proxy.ts
5+
@@ -85,7 +85,7 @@ export class PluginProxyImpl implements PluginProxy {
6+
assert(!this.plugin_);
7+
const srcUrl = this.getPreviewUrl_(previewUid, index);
8+
this.plugin_ = pdfCreateOutOfProcessPlugin(
9+
- srcUrl, 'chrome://print/pdf/index_print.html');
10+
+ srcUrl, 'dao://print/pdf/index_print.html');
11+
this.plugin_.classList.add('preview-area-plugin');
12+
// NOTE: The plugin's 'id' field must be set to 'pdf-viewer' since
13+
// chrome/renderer/printing/print_render_frame_helper.cc actually
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
diff --git a/chrome/renderer/chrome_content_renderer_client.cc b/chrome/renderer/chrome_content_renderer_client.cc
2+
index dcc6684123..a1b9be928a 100644
3+
--- a/chrome/renderer/chrome_content_renderer_client.cc
4+
+++ b/chrome/renderer/chrome_content_renderer_client.cc
5+
@@ -305,7 +305,9 @@ namespace {
6+
7+
#if BUILDFLAG(ENABLE_PDF)
8+
std::vector<url::Origin> GetAdditionalPdfInternalPluginAllowedOrigins() {
9+
- return {url::Origin::Create(GURL(chrome::kChromeUIPrintURL))};
10+
+ return {url::Origin::Create(GURL(chrome::kChromeUIPrintURL)),
11+
+ url::Origin::Create(
12+
+ GURL("dao://print/"))};
13+
}
14+
#endif // BUILDFLAG(ENABLE_PDF)
15+
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
diff --git a/components/printing/resources/print_header_footer_template_page.html b/components/printing/resources/print_header_footer_template_page.html
2+
index 5eaabb5798..8488d3dedd 100644
3+
--- a/components/printing/resources/print_header_footer_template_page.html
4+
+++ b/components/printing/resources/print_header_footer_template_page.html
5+
@@ -1,7 +1,6 @@
6+
<!doctype html>
7+
<html>
8+
<head>
9+
-<link rel="stylesheet" href="chrome://resources/css/text_defaults.css">
10+
<style>
11+
body {
12+
display: flex;

src/patches/content/browser/webui/web_ui_data_source_impl.cc.patch

Lines changed: 61 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,67 @@
11
diff --git a/content/browser/webui/web_ui_data_source_impl.cc b/content/browser/webui/web_ui_data_source_impl.cc
2-
index 8dd7796aab..d915b82723 100644
2+
index 07cdf7dde6..98b3f8e052 100644
33
--- a/content/browser/webui/web_ui_data_source_impl.cc
44
+++ b/content/browser/webui/web_ui_data_source_impl.cc
5-
@@ -340,6 +340,7 @@ void WebUIDataSourceImpl::AddFrameAncestor(const GURL& frame_ancestor) {
5+
@@ -133,6 +133,45 @@ void GetDataResourceBytesOnWorkerThreadFromDisk(
6+
}
7+
#endif // BUILDFLAG(LOAD_WEBUI_FROM_DISK)
8+
9+
+// Dao Browser: kChromeUIScheme is renamed from "chrome" to "dao". Many
10+
+// upstream Chromium WebUIs hard-code "chrome://..." source-list tokens in
11+
+// their CSP strings (e.g. `script-src chrome://resources chrome://webui-test
12+
+// 'self';`). Rather than patching every such WebUI, mirror every
13+
+// "chrome://X" token in a CSP value to also include the matching "dao://X"
14+
+// token (and vice versa), so loads from either scheme are allowed regardless
15+
+// of which one the caller spelled. This is paired with the URLDataSource
16+
+// patch that serves both schemes from the same data source.
17+
+std::string MirrorChromeAndDaoSchemesInCsp(const std::string& value) {
18+
+ static constexpr const char* kPrefixPairs[][2] = {
19+
+ {"chrome://", "dao://"},
20+
+ {"dao://", "chrome://"},
21+
+ };
22+
+ std::string result = value;
23+
+ for (const auto& pair : kPrefixPairs) {
24+
+ const std::string from_prefix = pair[0];
25+
+ const std::string to_prefix = pair[1];
26+
+ size_t scan_pos = 0;
27+
+ while ((scan_pos = result.find(from_prefix, scan_pos)) !=
28+
+ std::string::npos) {
29+
+ size_t end = result.find_first_of(" \t;", scan_pos);
30+
+ if (end == std::string::npos) {
31+
+ end = result.size();
32+
+ }
33+
+ const std::string from_token = result.substr(scan_pos, end - scan_pos);
34+
+ const std::string to_token =
35+
+ to_prefix + from_token.substr(from_prefix.size());
36+
+ if (result.find(to_token) == std::string::npos) {
37+
+ const std::string insertion = " " + to_token;
38+
+ result.insert(end, insertion);
39+
+ scan_pos = end + insertion.size();
40+
+ } else {
41+
+ scan_pos = end;
42+
+ }
43+
+ }
44+
+ }
45+
+ return result;
46+
+}
47+
+
48+
} // namespace
49+
50+
// Internal class to hide the fact that WebUIDataSourceImpl implements
51+
@@ -318,7 +357,11 @@ bool WebUIDataSourceImpl::IsWebUIDataSourceImpl() const {
52+
void WebUIDataSourceImpl::OverrideContentSecurityPolicy(
53+
network::mojom::CSPDirectiveName directive,
54+
const std::string& value) {
55+
- csp_overrides_.insert_or_assign(directive, value);
56+
+ // Dao Browser: rewrite the CSP value so any hard-coded "chrome://..." or
57+
+ // "dao://..." source-list token is mirrored to the other scheme. See
58+
+ // MirrorChromeAndDaoSchemesInCsp() above for rationale.
59+
+ csp_overrides_.insert_or_assign(directive,
60+
+ MirrorChromeAndDaoSchemesInCsp(value));
61+
}
62+
63+
void WebUIDataSourceImpl::OverrideCrossOriginOpenerPolicy(
64+
@@ -350,6 +393,7 @@ void WebUIDataSourceImpl::AddFrameAncestor(const GURL& frame_ancestor) {
665
// Do not allow a wildcard to be a frame ancestor or it will allow any website
766
// to embed the WebUI.
867
CHECK(frame_ancestor.SchemeIs(kChromeUIScheme) ||
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
diff --git a/pdf/pdf_view_web_plugin.cc b/pdf/pdf_view_web_plugin.cc
2+
index 1f1e8cb39d..205760c727 100644
3+
--- a/pdf/pdf_view_web_plugin.cc
4+
+++ b/pdf/pdf_view_web_plugin.cc
5+
@@ -152,6 +152,9 @@ constexpr std::string_view kChromeExtensionHost =
6+
// Print Preview base URL.
7+
constexpr std::string_view kChromePrintHost = "chrome://print/";
8+
9+
+// Dao Browser Print Preview base URL.
10+
+constexpr std::string_view kDaoPrintHost = "dao://print/";
11+
+
12+
// Untrusted Print Preview base URL.
13+
constexpr std::string_view kChromeUntrustedPrintHost =
14+
"chrome-untrusted://print/";
15+
@@ -244,6 +247,10 @@ bool IsPrintPreviewUrl(std::string_view url) {
16+
return base::StartsWith(url, kChromeUntrustedPrintHost);
17+
}
18+
19+
+bool IsPrintPreviewEmbedderOrigin(std::string_view origin) {
20+
+ return origin == kChromePrintHost || origin == kDaoPrintHost;
21+
+}
22+
+
23+
int ExtractPrintPreviewPageIndex(std::string_view src_url) {
24+
// Sample `src_url` format: chrome-untrusted://print/id/page_index/print.pdf
25+
// The page_index is zero-based, but can be negative with special meanings.
26+
@@ -573,7 +580,7 @@ bool PdfViewWebPlugin::InitializeCommon() {
27+
// This is enforced before creating the plugin (see
28+
// `pdf::CreateInternalPlugin()`), so we just `CHECK` for defense-in-depth.
29+
const std::string& embedder_origin = client_->GetEmbedderOriginString();
30+
- is_print_preview_ = (embedder_origin == kChromePrintHost);
31+
+ is_print_preview_ = IsPrintPreviewEmbedderOrigin(embedder_origin);
32+
CHECK(IsPrintPreview() || embedder_origin == kChromeExtensionHost);
33+
34+
full_frame_ = params->full_frame;

0 commit comments

Comments
 (0)