From fb7536a526cf86d8904242fd2d098587889cc520 Mon Sep 17 00:00:00 2001 From: Julien Neuhart Date: Wed, 9 Sep 2026 19:38:40 +0200 Subject: [PATCH] fix(chromium): disable the WebUI omnibox popup preloaded at browser start --- pkg/modules/chromium/browser.go | 21 +++++++++++++++++++++ pkg/modules/chromium/browser_test.go | 22 ++++++++++++++++++++++ 2 files changed, 43 insertions(+) diff --git a/pkg/modules/chromium/browser.go b/pkg/modules/chromium/browser.go index 67eaa4f1..ca54fb76 100644 --- a/pkg/modules/chromium/browser.go +++ b/pkg/modules/chromium/browser.go @@ -23,6 +23,25 @@ import ( "github.com/gotenberg/gotenberg/v8/pkg/gotenberg" ) +// chromiumDisableFeatures is the value of Chromium's --disable-features +// switch. +// +// It restates the "site-per-process,Translate,BlinkGenPropertyTrees" default +// from chromedp.DefaultExecAllocatorOptions (chromedp v0.14.2) on purpose: +// chromedp.Flag keys its flags by switch name, so a second --disable-features +// replaces chromedp's value instead of merging with it. Revisit this list when +// bumping chromedp. +// +// WebUIOmniboxPopup and WebUIOmniboxAimPopup became enabled by default in +// Chromium 151.0.7922.132. Their presenters build the address-bar popup WebUI +// at browser start, headless included, which leaves a renderer process holding +// ~85 MB of anonymous memory for a UI a PDF service can never show. Chromium +// silently ignores feature names it does not know, so both stay harmless on +// older builds (they exist but default to disabled on the Chromium pinned for +// ppc64el) and once upstream eventually removes them. +// See https://github.com/gotenberg/gotenberg/issues/1656. +const chromiumDisableFeatures = "site-per-process,Translate,BlinkGenPropertyTrees,WebUIOmniboxPopup,WebUIOmniboxAimPopup" + type browser interface { gotenberg.Process pdf(ctx context.Context, logger *slog.Logger, url, outputPath string, options PdfOptions, aggregate *networkAggregate) error @@ -133,6 +152,8 @@ func (b *chromiumBrowser) Start(logger *slog.Logger) error { chromedp.Flag("disable-dev-shm-usage", true), // See https://github.com/gotenberg/gotenberg/issues/1293. chromedp.Flag("disable-component-update", false), + // See https://github.com/gotenberg/gotenberg/issues/1656. + chromedp.Flag("disable-features", chromiumDisableFeatures), ) if b.arguments.allowInsecureLocalhost { diff --git a/pkg/modules/chromium/browser_test.go b/pkg/modules/chromium/browser_test.go index 1067b888..0c25f5e0 100644 --- a/pkg/modules/chromium/browser_test.go +++ b/pkg/modules/chromium/browser_test.go @@ -3,6 +3,7 @@ package chromium import ( "context" "log/slog" + "slices" "strings" "testing" ) @@ -37,3 +38,24 @@ func TestChromiumBrowser_Start_rejectsOverlappingStart(t *testing.T) { t.Fatal("expected the browser to stay not started") } } + +// TestChromiumDisableFeatures guards the override described in +// https://github.com/gotenberg/gotenberg/issues/1656. Gotenberg replaces +// chromedp's --disable-features value rather than extending it, as +// chromedp.Flag keys its flags by switch name. Dropping one of chromedp's own +// entries while editing this list would silently re-enable it. +func TestChromiumDisableFeatures(t *testing.T) { + for _, feature := range []string{ + // chromedp.DefaultExecAllocatorOptions. + "site-per-process", + "Translate", + "BlinkGenPropertyTrees", + // The address-bar popup WebUI, built even in headless. + "WebUIOmniboxPopup", + "WebUIOmniboxAimPopup", + } { + if !slices.Contains(strings.Split(chromiumDisableFeatures, ","), feature) { + t.Errorf("expected %q to be disabled, got %q", feature, chromiumDisableFeatures) + } + } +}