diff --git a/pkg/modules/chromium/browser.go b/pkg/modules/chromium/browser.go index 8b3a987a..adfb774c 100644 --- a/pkg/modules/chromium/browser.go +++ b/pkg/modules/chromium/browser.go @@ -259,7 +259,7 @@ func (b *chromiumBrowser) pdf(ctx context.Context, logger *zap.Logger, url, outp runtime.Enable(), disableJavaScriptActionFunc(logger, b.arguments.disableJavaScript), extraHttpHeadersActionFunc(logger, options.ExtraHttpHeaders), - navigateActionFunc(logger, url), + navigateActionFunc(logger, url, options.SkipNetworkIdleEvent), hideDefaultWhiteBackgroundActionFunc(logger, options.OmitBackground, options.PrintBackground), forceExactColorsActionFunc(), emulateMediaTypeActionFunc(logger, options.EmulatedMediaType), diff --git a/pkg/modules/chromium/browser_test.go b/pkg/modules/chromium/browser_test.go index 39d295fd..afe9e214 100644 --- a/pkg/modules/chromium/browser_test.go +++ b/pkg/modules/chromium/browser_test.go @@ -380,6 +380,41 @@ func TestChromiumBrowser_pdf(t *testing.T) { "'file:///etc/passwd' matches the expression from the denied list", }, }, + { + scenario: "skip networkIdle event", + browser: newChromiumBrowser( + browserArguments{ + binPath: os.Getenv("CHROMIUM_BIN_PATH"), + wsUrlReadTimeout: 5 * time.Second, + allowList: regexp.MustCompile(""), + denyList: regexp.MustCompile(""), + }, + ), + fs: func() *gotenberg.FileSystem { + fs := gotenberg.NewFileSystem() + + err := os.MkdirAll(fs.WorkingDirPath(), 0o755) + if err != nil { + t.Fatalf(fmt.Sprintf("expected no error but got: %v", err)) + } + + err = os.WriteFile(fmt.Sprintf("%s/index.html", fs.WorkingDirPath()), []byte("

Skip networkIdle event

"), 0o755) + if err != nil { + t.Fatalf("expected no error but got: %v", err) + } + + return fs + }(), + options: Options{ + SkipNetworkIdleEvent: true, + }, + noDeadline: false, + start: true, + expectError: false, + expectedLogEntries: []string{ + "skipping network idle event", + }, + }, { scenario: "ErrConsoleExceptions", browser: newChromiumBrowser( diff --git a/pkg/modules/chromium/chromium.go b/pkg/modules/chromium/chromium.go index fc9a9735..c23bff70 100644 --- a/pkg/modules/chromium/chromium.go +++ b/pkg/modules/chromium/chromium.go @@ -69,6 +69,13 @@ type Chromium struct { // Options are the available expectedOptions for converting HTML document to PDF. type Options struct { + // SkipNetworkIdleEvent set if the conversion should wait for the + // "networkIdle" event, drastically improving the conversion speed. It may + // not be suitable for all HTML documents, as some may not be fully + // rendered until this event is fired. + // Optional. + SkipNetworkIdleEvent bool + // FailOnConsoleExceptions sets if the conversion should fail if there are // exceptions in the Chromium console. // Optional. @@ -171,6 +178,7 @@ type Options struct { // DefaultOptions returns the default values for Options. func DefaultOptions() Options { return Options{ + SkipNetworkIdleEvent: false, FailOnConsoleExceptions: false, WaitDelay: 0, WaitWindowStatus: "", diff --git a/pkg/modules/chromium/routes.go b/pkg/modules/chromium/routes.go index 83e8e80b..1d5038ab 100644 --- a/pkg/modules/chromium/routes.go +++ b/pkg/modules/chromium/routes.go @@ -27,6 +27,7 @@ func FormDataChromiumPdfOptions(ctx *api.Context) (*api.FormData, Options) { defaultOptions := DefaultOptions() var ( + skipNetworkIdleEvent bool failOnConsoleExceptions bool waitDelay time.Duration waitWindowStatus string @@ -42,6 +43,7 @@ func FormDataChromiumPdfOptions(ctx *api.Context) (*api.FormData, Options) { ) form := ctx.FormData(). + Bool("skipNetworkIdleEvent", &skipNetworkIdleEvent, defaultOptions.SkipNetworkIdleEvent). Bool("failOnConsoleExceptions", &failOnConsoleExceptions, defaultOptions.FailOnConsoleExceptions). Duration("waitDelay", &waitDelay, defaultOptions.WaitDelay). String("waitWindowStatus", &waitWindowStatus, defaultOptions.WaitWindowStatus). @@ -91,6 +93,7 @@ func FormDataChromiumPdfOptions(ctx *api.Context) (*api.FormData, Options) { Bool("preferCssPageSize", &preferCssPageSize, defaultOptions.PreferCssPageSize) options := Options{ + SkipNetworkIdleEvent: skipNetworkIdleEvent, FailOnConsoleExceptions: failOnConsoleExceptions, WaitDelay: waitDelay, WaitWindowStatus: waitWindowStatus, diff --git a/pkg/modules/chromium/tasks.go b/pkg/modules/chromium/tasks.go index bf740c43..904553dd 100644 --- a/pkg/modules/chromium/tasks.go +++ b/pkg/modules/chromium/tasks.go @@ -136,7 +136,7 @@ func extraHttpHeadersActionFunc(logger *zap.Logger, extraHttpHeaders map[string] } } -func navigateActionFunc(logger *zap.Logger, url string) chromedp.ActionFunc { +func navigateActionFunc(logger *zap.Logger, url string, skipNetworkIdleEvent bool) chromedp.ActionFunc { return func(ctx context.Context) error { logger.Debug(fmt.Sprintf("navigate to '%s'", url)) @@ -145,12 +145,21 @@ func navigateActionFunc(logger *zap.Logger, url string) chromedp.ActionFunc { return fmt.Errorf("navigate to '%s': %w", url, err) } - err = runBatch( - ctx, + waitFunc := []func() error{ waitForEventDomContentEventFired(ctx, logger), waitForEventLoadEventFired(ctx, logger), - waitForEventNetworkIdle(ctx, logger), waitForEventLoadingFinished(ctx, logger), + } + + if !skipNetworkIdleEvent { + waitFunc = append(waitFunc, waitForEventNetworkIdle(ctx, logger)) + } else { + logger.Debug("skipping network idle event") + } + + err = runBatch( + ctx, + waitFunc..., ) if err == nil {