feat(chromium): add emulated media type

This commit is contained in:
Julien Neuhart
2021-11-22 16:55:24 +01:00
parent ed47493459
commit dd1e11f102
5 changed files with 106 additions and 0 deletions

View File

@@ -11,6 +11,7 @@ import (
"sync"
"time"
"github.com/chromedp/cdproto/emulation"
"github.com/chromedp/cdproto/fetch"
"github.com/chromedp/cdproto/network"
"github.com/chromedp/cdproto/page"
@@ -30,6 +31,10 @@ var (
// allowed/denied lists.
ErrURLNotAuthorized = errors.New("URL not authorized")
// ErrInvalidEmulatedMediaType happens if the emulated media type is not
// "screen" nor "print". Empty value are allowed though.
ErrInvalidEmulatedMediaType = errors.New("invalid emulated media type")
// ErrInvalidEvaluationExpression happens if an evaluation expression
// returns an exception or undefined.
ErrInvalidEvaluationExpression = errors.New("invalid evaluation expression")
@@ -89,6 +94,11 @@ type Options struct {
// Optional.
ExtraHTTPHeaders map[string]string
// EmulatedMediaType is the media type to emulate, either "screen" or
// "print".
// Optional.
EmulatedMediaType string
// Landscape sets the paper orientation.
// Optional.
Landscape bool
@@ -161,6 +171,7 @@ func DefaultOptions() Options {
WaitForExpression: "",
UserAgent: "",
ExtraHTTPHeaders: nil,
EmulatedMediaType: "",
Landscape: false,
PrintBackground: false,
Scale: 1.0,
@@ -446,6 +457,28 @@ func (mod Chromium) PDF(ctx context.Context, logger *zap.Logger, URL, outputPath
return fmt.Errorf("add CSS for exact colors: %w", err)
}),
chromedp.ActionFunc(func(ctx context.Context) error {
if options.EmulatedMediaType == "" {
logger.Debug("no emulated media type")
return nil
}
if options.EmulatedMediaType != "screen" && options.EmulatedMediaType != "print" {
return fmt.Errorf("validate emulated media type '%s': %w", options.EmulatedMediaType, ErrInvalidEmulatedMediaType)
}
logger.Debug(fmt.Sprintf("emulate media type '%s'", options.EmulatedMediaType))
emulatedMedia := emulation.SetEmulatedMedia()
err := emulatedMedia.WithMedia(options.EmulatedMediaType).Do(ctx)
if err == nil {
return nil
}
return fmt.Errorf("emulate media type '%s': %w", options.EmulatedMediaType, err)
}),
chromedp.ActionFunc(func(ctx context.Context) error {
if options.WaitDelay > 0 {
// We wait for a given amount of time so that JavaScript

View File

@@ -264,6 +264,25 @@ func TestChromium_PDF(t *testing.T) {
},
},
},
{
URL: "file:///tests/test/testdata/chromium/html/sample8/index.html",
options: Options{
EmulatedMediaType: "foo",
},
expectErr: true,
},
{
URL: "file:///tests/test/testdata/chromium/html/sample8/index.html",
options: Options{
EmulatedMediaType: "screen",
},
},
{
URL: "file:///tests/test/testdata/chromium/html/sample8/index.html",
options: Options{
EmulatedMediaType: "print",
},
},
{
URL: "file:///tests/test/testdata/chromium/html/sample4/index.html",
options: Options{
@@ -300,6 +319,13 @@ func TestChromium_PDF(t *testing.T) {
WaitForExpression: "window.status === 'ready'",
},
},
{
URL: "file:///tests/test/testdata/chromium/html/sample4/index.html",
options: Options{
WaitForExpression: "return undefined",
},
expectErr: true,
},
{
URL: "file:///tests/test/testdata/chromium/html/sample4/index.html",
options: Options{

View File

@@ -31,6 +31,7 @@ func FormDataChromiumPDFOptions(ctx *api.Context) (*api.FormData, Options) {
waitForExpression string
userAgent string
extraHTTPHeaders map[string]string
emulatedMediaType string
landscape, printBackground bool
scale, paperWidth, paperHeight float64
marginTop, marginBottom, marginLeft, marginRight float64
@@ -58,6 +59,7 @@ func FormDataChromiumPDFOptions(ctx *api.Context) (*api.FormData, Options) {
return nil
}).
String("emulatedMediaType", &emulatedMediaType, defaultOptions.EmulatedMediaType).
Bool("landscape", &landscape, defaultOptions.Landscape).
Bool("printBackground", &printBackground, defaultOptions.PrintBackground).
Float64("scale", &scale, defaultOptions.Scale).
@@ -78,6 +80,7 @@ func FormDataChromiumPDFOptions(ctx *api.Context) (*api.FormData, Options) {
WaitForExpression: waitForExpression,
UserAgent: userAgent,
ExtraHTTPHeaders: extraHTTPHeaders,
EmulatedMediaType: emulatedMediaType,
Landscape: landscape,
PrintBackground: printBackground,
Scale: scale,
@@ -294,6 +297,16 @@ func convertURL(ctx *api.Context, chromium API, engine gotenberg.PDFEngine, URL,
)
}
if errors.Is(err, ErrInvalidEmulatedMediaType) {
return api.WrapError(
fmt.Errorf("convert to PDF: %w", err),
api.NewSentinelHTTPError(
http.StatusBadRequest,
fmt.Sprintf("The media type '%s' (emulatedMediaType) is invalid: allowed values are 'screen' or 'print'", options.EmulatedMediaType),
),
)
}
if errors.Is(err, ErrInvalidEvaluationExpression) {
if options.WaitForExpression == "" {
// We do not expect the 'waitWindowStatus' form field to return

View File

@@ -544,6 +544,21 @@ func TestConvertURL(t *testing.T) {
expectHTTPErr: true,
expectHTTPStatus: http.StatusForbidden,
},
{
ctx: &api.MockContext{Context: &api.Context{}},
api: func() API {
chromiumAPI := struct{ ProtoAPI }{}
chromiumAPI.pdf = func(_ context.Context, _ *zap.Logger, _, _ string, _ Options) error {
return ErrInvalidEmulatedMediaType
}
return chromiumAPI
}(),
options: DefaultOptions(),
expectErr: true,
expectHTTPErr: true,
expectHTTPStatus: http.StatusBadRequest,
},
{
ctx: &api.MockContext{Context: &api.Context{}},
api: func() API {