Skip to content

Commit a3647fe

Browse files
authored
fix(chromium): increase the scope of loading failed errors (gotenberg#962)
1 parent 300e73f commit a3647fe

6 files changed

Lines changed: 60 additions & 31 deletions

File tree

pkg/modules/chromium/browser.go

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -315,12 +315,14 @@ func (b *chromiumBrowser) do(ctx context.Context, logger *zap.Logger, url string
315315
}
316316

317317
var (
318-
connectionRefused error
319-
connectionRefusedMu sync.RWMutex
318+
loadingFailed error
319+
loadingFailedMu sync.RWMutex
320320
)
321321

322-
// See https://github.com/gotenberg/gotenberg/issues/913.
323-
listenForEventLoadingFailedOnConnectionRefused(taskCtx, logger, &connectionRefused, &connectionRefusedMu)
322+
// See:
323+
// https://github.com/gotenberg/gotenberg/issues/913.
324+
// https://github.com/gotenberg/gotenberg/issues/959.
325+
listenForEventLoadingFailed(taskCtx, logger, &loadingFailed, &loadingFailedMu)
324326

325327
err = chromedp.Run(taskCtx, tasks...)
326328
if err != nil {
@@ -357,12 +359,14 @@ func (b *chromiumBrowser) do(ctx context.Context, logger *zap.Logger, url string
357359
return fmt.Errorf("%v: %w", consoleExceptions, ErrConsoleExceptions)
358360
}
359361

360-
// See https://github.com/gotenberg/gotenberg/issues/913.
361-
connectionRefusedMu.RLock()
362-
defer connectionRefusedMu.RUnlock()
362+
// See:
363+
// https://github.com/gotenberg/gotenberg/issues/913.
364+
// https://github.com/gotenberg/gotenberg/issues/959.
365+
loadingFailedMu.RLock()
366+
defer loadingFailedMu.RUnlock()
363367

364-
if connectionRefused != nil {
365-
return fmt.Errorf("%v: %w", connectionRefused, ErrConnectionRefused)
368+
if loadingFailed != nil {
369+
return fmt.Errorf("%v: %w", loadingFailed, ErrLoadingFailed)
366370
}
367371

368372
return nil

pkg/modules/chromium/browser_test.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -480,7 +480,7 @@ func TestChromiumBrowser_pdf(t *testing.T) {
480480
expectedError: ErrConsoleExceptions,
481481
},
482482
{
483-
scenario: "ErrConnectionRefused",
483+
scenario: "ErrLoadingFailed",
484484
browser: newChromiumBrowser(
485485
browserArguments{
486486
binPath: os.Getenv("CHROMIUM_BIN_PATH"),
@@ -503,7 +503,7 @@ func TestChromiumBrowser_pdf(t *testing.T) {
503503
noDeadline: false,
504504
start: true,
505505
expectError: true,
506-
expectedError: ErrConnectionRefused,
506+
expectedError: ErrLoadingFailed,
507507
},
508508
{
509509
scenario: "clear cache",
@@ -1553,7 +1553,7 @@ func TestChromiumBrowser_screenshot(t *testing.T) {
15531553
expectedError: ErrConsoleExceptions,
15541554
},
15551555
{
1556-
scenario: "ErrConnectionRefused",
1556+
scenario: "ErrLoadingFailed",
15571557
browser: newChromiumBrowser(
15581558
browserArguments{
15591559
binPath: os.Getenv("CHROMIUM_BIN_PATH"),
@@ -1577,7 +1577,7 @@ func TestChromiumBrowser_screenshot(t *testing.T) {
15771577
noDeadline: false,
15781578
start: true,
15791579
expectError: true,
1580-
expectedError: ErrConnectionRefused,
1580+
expectedError: ErrLoadingFailed,
15811581
},
15821582
{
15831583
scenario: "clear cache",

pkg/modules/chromium/chromium.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,8 +42,8 @@ var (
4242
// is set to true.
4343
ErrConsoleExceptions = errors.New("console exceptions")
4444

45-
// ErrConnectionRefused happens when a URL cannot be reached.
46-
ErrConnectionRefused = errors.New("connection refused")
45+
// ErrLoadingFailed happens when a URL failed to load.
46+
ErrLoadingFailed = errors.New("loading failed")
4747

4848
// PDF specific.
4949

pkg/modules/chromium/events.go

Lines changed: 35 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,8 @@ import (
2121
)
2222

2323
// listenForEventRequestPaused listens for requests to check if they are
24-
// allowed or not.
24+
// allowed or not.network.SetBlockedURLS()
25+
// TODO: https://chromedevtools.github.io/devtools-protocol/tot/Network/#method-setBlockedURLs (experimental for now).
2526
func listenForEventRequestPaused(ctx context.Context, logger *zap.Logger, allowList *regexp2.Regexp, denyList *regexp2.Regexp) {
2627
chromedp.ListenTarget(ctx, func(ev interface{}) {
2728
switch e := ev.(type) {
@@ -95,24 +96,48 @@ func listenForEventResponseReceived(ctx context.Context, logger *zap.Logger, url
9596
})
9697
}
9798

98-
// listenForEventLoadingFailedOnConnectionRefused listens for an event
99-
// indicating that the main page failed to load.
100-
// See https://github.com/gotenberg/gotenberg/issues/913.
101-
func listenForEventLoadingFailedOnConnectionRefused(ctx context.Context, logger *zap.Logger, connectionRefused *error, connectionRefusedMu *sync.RWMutex) {
99+
// listenForEventLoadingFailed listens for an event indicating that the main
100+
// page failed to load.
101+
// See:
102+
// https://github.com/gotenberg/gotenberg/issues/913.
103+
// https://github.com/gotenberg/gotenberg/issues/959.
104+
func listenForEventLoadingFailed(ctx context.Context, logger *zap.Logger, loadingFailed *error, loadingFailedMu *sync.RWMutex) {
102105
chromedp.ListenTarget(ctx, func(ev interface{}) {
103106
switch ev := ev.(type) {
104107
case *network.EventLoadingFailed:
105108
logger.Debug(fmt.Sprintf("event EventLoadingFailed fired: %+v", ev.ErrorText))
106109

107-
if ev.ErrorText != "net::ERR_CONNECTION_REFUSED" || ev.Type != network.ResourceTypeDocument {
108-
logger.Debug("skip EventLoadingFailed: is not net::ERR_CONNECTION_REFUSED and/or resource type Document")
110+
if ev.Type != network.ResourceTypeDocument {
111+
logger.Debug("skip EventLoadingFailed: is not resource type Document")
109112
return
110113
}
111114

112-
connectionRefusedMu.Lock()
113-
defer connectionRefusedMu.Unlock()
115+
// Supposition: except iframe, an event loading failed with a
116+
// resource type Document is about the main page.
114117

115-
*connectionRefused = fmt.Errorf("%s", ev.ErrorText)
118+
// We are looking for common errors.
119+
// TODO: sufficient?
120+
errors := []string{
121+
"net::ERR_CONNECTION_CLOSED",
122+
"net::ERR_CONNECTION_RESET",
123+
"net::ERR_CONNECTION_REFUSED",
124+
"net::ERR_CONNECTION_ABORTED",
125+
"net::ERR_CONNECTION_FAILED",
126+
"net::ERR_NAME_NOT_RESOLVED",
127+
"net::ERR_INTERNET_DISCONNECTED",
128+
"net::ERR_ADDRESS_UNREACHABLE",
129+
"net::ERR_BLOCKED_BY_CLIENT",
130+
"net::ERR_BLOCKED_BY_RESPONSE",
131+
}
132+
if !slices.Contains(errors, ev.ErrorText) {
133+
logger.Debug(fmt.Sprintf("skip EventLoadingFailed: '%s' is not part of %+v", ev.ErrorText, errors))
134+
return
135+
}
136+
137+
loadingFailedMu.Lock()
138+
defer loadingFailedMu.Unlock()
139+
140+
*loadingFailed = fmt.Errorf("%s", ev.ErrorText)
116141
}
117142
})
118143
}

pkg/modules/chromium/routes.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -688,12 +688,12 @@ func handleChromiumError(err error, options Options) error {
688688
)
689689
}
690690

691-
if errors.Is(err, ErrConnectionRefused) {
691+
if errors.Is(err, ErrLoadingFailed) {
692692
return api.WrapError(
693693
err,
694694
api.NewSentinelHttpError(
695695
http.StatusBadRequest,
696-
"Chromium returned net::ERR_CONNECTION_REFUSED",
696+
fmt.Sprintf("Chromium returned %v", err),
697697
),
698698
)
699699
}

pkg/modules/chromium/routes_test.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1436,10 +1436,10 @@ func TestConvertUrl(t *testing.T) {
14361436
expectOutputPathsCount: 0,
14371437
},
14381438
{
1439-
scenario: "ErrConnectionRefused",
1439+
scenario: "ErrLoadingFailed",
14401440
ctx: &api.ContextMock{Context: new(api.Context)},
14411441
api: &ApiMock{PdfMock: func(ctx context.Context, logger *zap.Logger, url, outputPath string, options PdfOptions) error {
1442-
return ErrConnectionRefused
1442+
return ErrLoadingFailed
14431443
}},
14441444
options: DefaultPdfOptions(),
14451445
expectError: true,
@@ -1646,10 +1646,10 @@ func TestScreenshotUrl(t *testing.T) {
16461646
expectOutputPathsCount: 0,
16471647
},
16481648
{
1649-
scenario: "ErrConnectionRefused",
1649+
scenario: "ErrLoadingFailed",
16501650
ctx: &api.ContextMock{Context: new(api.Context)},
16511651
api: &ApiMock{ScreenshotMock: func(ctx context.Context, logger *zap.Logger, url, outputPath string, options ScreenshotOptions) error {
1652-
return ErrConnectionRefused
1652+
return ErrLoadingFailed
16531653
}},
16541654
options: DefaultScreenshotOptions(),
16551655
expectError: true,

0 commit comments

Comments
 (0)