mirror of
https://github.com/gotenberg/gotenberg.git
synced 2026-08-17 04:32:15 +01:00
fix(chromium): increase the scope of loading failed errors (#962)
This commit is contained in:
@@ -315,12 +315,14 @@ func (b *chromiumBrowser) do(ctx context.Context, logger *zap.Logger, url string
|
|||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
connectionRefused error
|
loadingFailed error
|
||||||
connectionRefusedMu sync.RWMutex
|
loadingFailedMu sync.RWMutex
|
||||||
)
|
)
|
||||||
|
|
||||||
// See https://github.com/gotenberg/gotenberg/issues/913.
|
// See:
|
||||||
listenForEventLoadingFailedOnConnectionRefused(taskCtx, logger, &connectionRefused, &connectionRefusedMu)
|
// https://github.com/gotenberg/gotenberg/issues/913.
|
||||||
|
// https://github.com/gotenberg/gotenberg/issues/959.
|
||||||
|
listenForEventLoadingFailed(taskCtx, logger, &loadingFailed, &loadingFailedMu)
|
||||||
|
|
||||||
err = chromedp.Run(taskCtx, tasks...)
|
err = chromedp.Run(taskCtx, tasks...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -357,12 +359,14 @@ func (b *chromiumBrowser) do(ctx context.Context, logger *zap.Logger, url string
|
|||||||
return fmt.Errorf("%v: %w", consoleExceptions, ErrConsoleExceptions)
|
return fmt.Errorf("%v: %w", consoleExceptions, ErrConsoleExceptions)
|
||||||
}
|
}
|
||||||
|
|
||||||
// See https://github.com/gotenberg/gotenberg/issues/913.
|
// See:
|
||||||
connectionRefusedMu.RLock()
|
// https://github.com/gotenberg/gotenberg/issues/913.
|
||||||
defer connectionRefusedMu.RUnlock()
|
// https://github.com/gotenberg/gotenberg/issues/959.
|
||||||
|
loadingFailedMu.RLock()
|
||||||
|
defer loadingFailedMu.RUnlock()
|
||||||
|
|
||||||
if connectionRefused != nil {
|
if loadingFailed != nil {
|
||||||
return fmt.Errorf("%v: %w", connectionRefused, ErrConnectionRefused)
|
return fmt.Errorf("%v: %w", loadingFailed, ErrLoadingFailed)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
|||||||
@@ -480,7 +480,7 @@ func TestChromiumBrowser_pdf(t *testing.T) {
|
|||||||
expectedError: ErrConsoleExceptions,
|
expectedError: ErrConsoleExceptions,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
scenario: "ErrConnectionRefused",
|
scenario: "ErrLoadingFailed",
|
||||||
browser: newChromiumBrowser(
|
browser: newChromiumBrowser(
|
||||||
browserArguments{
|
browserArguments{
|
||||||
binPath: os.Getenv("CHROMIUM_BIN_PATH"),
|
binPath: os.Getenv("CHROMIUM_BIN_PATH"),
|
||||||
@@ -503,7 +503,7 @@ func TestChromiumBrowser_pdf(t *testing.T) {
|
|||||||
noDeadline: false,
|
noDeadline: false,
|
||||||
start: true,
|
start: true,
|
||||||
expectError: true,
|
expectError: true,
|
||||||
expectedError: ErrConnectionRefused,
|
expectedError: ErrLoadingFailed,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
scenario: "clear cache",
|
scenario: "clear cache",
|
||||||
@@ -1553,7 +1553,7 @@ func TestChromiumBrowser_screenshot(t *testing.T) {
|
|||||||
expectedError: ErrConsoleExceptions,
|
expectedError: ErrConsoleExceptions,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
scenario: "ErrConnectionRefused",
|
scenario: "ErrLoadingFailed",
|
||||||
browser: newChromiumBrowser(
|
browser: newChromiumBrowser(
|
||||||
browserArguments{
|
browserArguments{
|
||||||
binPath: os.Getenv("CHROMIUM_BIN_PATH"),
|
binPath: os.Getenv("CHROMIUM_BIN_PATH"),
|
||||||
@@ -1577,7 +1577,7 @@ func TestChromiumBrowser_screenshot(t *testing.T) {
|
|||||||
noDeadline: false,
|
noDeadline: false,
|
||||||
start: true,
|
start: true,
|
||||||
expectError: true,
|
expectError: true,
|
||||||
expectedError: ErrConnectionRefused,
|
expectedError: ErrLoadingFailed,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
scenario: "clear cache",
|
scenario: "clear cache",
|
||||||
|
|||||||
@@ -42,8 +42,8 @@ var (
|
|||||||
// is set to true.
|
// is set to true.
|
||||||
ErrConsoleExceptions = errors.New("console exceptions")
|
ErrConsoleExceptions = errors.New("console exceptions")
|
||||||
|
|
||||||
// ErrConnectionRefused happens when a URL cannot be reached.
|
// ErrLoadingFailed happens when a URL failed to load.
|
||||||
ErrConnectionRefused = errors.New("connection refused")
|
ErrLoadingFailed = errors.New("loading failed")
|
||||||
|
|
||||||
// PDF specific.
|
// PDF specific.
|
||||||
|
|
||||||
|
|||||||
@@ -21,7 +21,8 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// listenForEventRequestPaused listens for requests to check if they are
|
// listenForEventRequestPaused listens for requests to check if they are
|
||||||
// allowed or not.
|
// allowed or not.network.SetBlockedURLS()
|
||||||
|
// TODO: https://chromedevtools.github.io/devtools-protocol/tot/Network/#method-setBlockedURLs (experimental for now).
|
||||||
func listenForEventRequestPaused(ctx context.Context, logger *zap.Logger, allowList *regexp2.Regexp, denyList *regexp2.Regexp) {
|
func listenForEventRequestPaused(ctx context.Context, logger *zap.Logger, allowList *regexp2.Regexp, denyList *regexp2.Regexp) {
|
||||||
chromedp.ListenTarget(ctx, func(ev interface{}) {
|
chromedp.ListenTarget(ctx, func(ev interface{}) {
|
||||||
switch e := ev.(type) {
|
switch e := ev.(type) {
|
||||||
@@ -95,24 +96,48 @@ func listenForEventResponseReceived(ctx context.Context, logger *zap.Logger, url
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// listenForEventLoadingFailedOnConnectionRefused listens for an event
|
// listenForEventLoadingFailed listens for an event indicating that the main
|
||||||
// indicating that the main page failed to load.
|
// page failed to load.
|
||||||
// See https://github.com/gotenberg/gotenberg/issues/913.
|
// See:
|
||||||
func listenForEventLoadingFailedOnConnectionRefused(ctx context.Context, logger *zap.Logger, connectionRefused *error, connectionRefusedMu *sync.RWMutex) {
|
// https://github.com/gotenberg/gotenberg/issues/913.
|
||||||
|
// https://github.com/gotenberg/gotenberg/issues/959.
|
||||||
|
func listenForEventLoadingFailed(ctx context.Context, logger *zap.Logger, loadingFailed *error, loadingFailedMu *sync.RWMutex) {
|
||||||
chromedp.ListenTarget(ctx, func(ev interface{}) {
|
chromedp.ListenTarget(ctx, func(ev interface{}) {
|
||||||
switch ev := ev.(type) {
|
switch ev := ev.(type) {
|
||||||
case *network.EventLoadingFailed:
|
case *network.EventLoadingFailed:
|
||||||
logger.Debug(fmt.Sprintf("event EventLoadingFailed fired: %+v", ev.ErrorText))
|
logger.Debug(fmt.Sprintf("event EventLoadingFailed fired: %+v", ev.ErrorText))
|
||||||
|
|
||||||
if ev.ErrorText != "net::ERR_CONNECTION_REFUSED" || ev.Type != network.ResourceTypeDocument {
|
if ev.Type != network.ResourceTypeDocument {
|
||||||
logger.Debug("skip EventLoadingFailed: is not net::ERR_CONNECTION_REFUSED and/or resource type Document")
|
logger.Debug("skip EventLoadingFailed: is not resource type Document")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
connectionRefusedMu.Lock()
|
// Supposition: except iframe, an event loading failed with a
|
||||||
defer connectionRefusedMu.Unlock()
|
// resource type Document is about the main page.
|
||||||
|
|
||||||
*connectionRefused = fmt.Errorf("%s", ev.ErrorText)
|
// We are looking for common errors.
|
||||||
|
// TODO: sufficient?
|
||||||
|
errors := []string{
|
||||||
|
"net::ERR_CONNECTION_CLOSED",
|
||||||
|
"net::ERR_CONNECTION_RESET",
|
||||||
|
"net::ERR_CONNECTION_REFUSED",
|
||||||
|
"net::ERR_CONNECTION_ABORTED",
|
||||||
|
"net::ERR_CONNECTION_FAILED",
|
||||||
|
"net::ERR_NAME_NOT_RESOLVED",
|
||||||
|
"net::ERR_INTERNET_DISCONNECTED",
|
||||||
|
"net::ERR_ADDRESS_UNREACHABLE",
|
||||||
|
"net::ERR_BLOCKED_BY_CLIENT",
|
||||||
|
"net::ERR_BLOCKED_BY_RESPONSE",
|
||||||
|
}
|
||||||
|
if !slices.Contains(errors, ev.ErrorText) {
|
||||||
|
logger.Debug(fmt.Sprintf("skip EventLoadingFailed: '%s' is not part of %+v", ev.ErrorText, errors))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
loadingFailedMu.Lock()
|
||||||
|
defer loadingFailedMu.Unlock()
|
||||||
|
|
||||||
|
*loadingFailed = fmt.Errorf("%s", ev.ErrorText)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -688,12 +688,12 @@ func handleChromiumError(err error, options Options) error {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
if errors.Is(err, ErrConnectionRefused) {
|
if errors.Is(err, ErrLoadingFailed) {
|
||||||
return api.WrapError(
|
return api.WrapError(
|
||||||
err,
|
err,
|
||||||
api.NewSentinelHttpError(
|
api.NewSentinelHttpError(
|
||||||
http.StatusBadRequest,
|
http.StatusBadRequest,
|
||||||
"Chromium returned net::ERR_CONNECTION_REFUSED",
|
fmt.Sprintf("Chromium returned %v", err),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1436,10 +1436,10 @@ func TestConvertUrl(t *testing.T) {
|
|||||||
expectOutputPathsCount: 0,
|
expectOutputPathsCount: 0,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
scenario: "ErrConnectionRefused",
|
scenario: "ErrLoadingFailed",
|
||||||
ctx: &api.ContextMock{Context: new(api.Context)},
|
ctx: &api.ContextMock{Context: new(api.Context)},
|
||||||
api: &ApiMock{PdfMock: func(ctx context.Context, logger *zap.Logger, url, outputPath string, options PdfOptions) error {
|
api: &ApiMock{PdfMock: func(ctx context.Context, logger *zap.Logger, url, outputPath string, options PdfOptions) error {
|
||||||
return ErrConnectionRefused
|
return ErrLoadingFailed
|
||||||
}},
|
}},
|
||||||
options: DefaultPdfOptions(),
|
options: DefaultPdfOptions(),
|
||||||
expectError: true,
|
expectError: true,
|
||||||
@@ -1646,10 +1646,10 @@ func TestScreenshotUrl(t *testing.T) {
|
|||||||
expectOutputPathsCount: 0,
|
expectOutputPathsCount: 0,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
scenario: "ErrConnectionRefused",
|
scenario: "ErrLoadingFailed",
|
||||||
ctx: &api.ContextMock{Context: new(api.Context)},
|
ctx: &api.ContextMock{Context: new(api.Context)},
|
||||||
api: &ApiMock{ScreenshotMock: func(ctx context.Context, logger *zap.Logger, url, outputPath string, options ScreenshotOptions) error {
|
api: &ApiMock{ScreenshotMock: func(ctx context.Context, logger *zap.Logger, url, outputPath string, options ScreenshotOptions) error {
|
||||||
return ErrConnectionRefused
|
return ErrLoadingFailed
|
||||||
}},
|
}},
|
||||||
options: DefaultScreenshotOptions(),
|
options: DefaultScreenshotOptions(),
|
||||||
expectError: true,
|
expectError: true,
|
||||||
|
|||||||
Reference in New Issue
Block a user