Compare commits

..

6 Commits

Author SHA1 Message Date
Julien Neuhart
b76990ec16 feat(chromium): new flags chromium-allow-insecure-localhost and chromium-host-resolver-rules 2022-09-01 18:04:00 +02:00
Julien Neuhart
9bc93c5cf5 chore: remove ioutil package 2022-09-01 18:04:00 +02:00
Julien Neuhart
1d8ae79f84 feat(chromium): add ReturnAsStream support 2022-09-01 18:04:00 +02:00
Julien Neuhart
4269aa2422 chore: update Go dependencies 2022-09-01 18:04:00 +02:00
Julien Neuhart
c887dc1ec8 chore: upgrade golangci-lint to version from version 1.48 to 1.49 2022-09-01 18:04:00 +02:00
Julien Neuhart
8bbacd691d chore: update Golang versionin go.mod file 2022-08-19 15:24:09 +02:00
9 changed files with 208 additions and 41 deletions

View File

@@ -19,7 +19,7 @@ jobs:
- name: Run linters
uses: golangci/golangci-lint-action@v2
with:
version: v1.48
version: v1.49.0
tests:
needs:

View File

@@ -2,7 +2,6 @@ linters:
disable-all: true
enable:
- bodyclose
- deadcode
- errcheck
- gofmt
- goimports
@@ -13,11 +12,9 @@ linters:
- misspell
- prealloc
- staticcheck
- structcheck
- typecheck
- unconvert
- unused
- varcheck
run:
deadline: 5m

View File

@@ -12,7 +12,7 @@ GOTENBERG_USER_GID=1001
GOTENBERG_USER_UID=1001
NOTO_COLOR_EMOJI_VERSION=v2.034 # See https://github.com/googlefonts/noto-emoji/releases.
PDFTK_VERSION=v3.3.2 # See https://gitlab.com/pdftk-java/pdftk/-/releases - Binary package.
GOLANGCI_LINT_VERSION=v1.48.0 # See https://github.com/golangci/golangci-lint/releases.
GOLANGCI_LINT_VERSION=v1.49.0 # See https://github.com/golangci/golangci-lint/releases.
.PHONY: build
build: ## Build the Gotenberg's Docker image
@@ -34,9 +34,11 @@ API_ROOT_PATH=/
API_TRACE_HEADER=Gotenberg-Trace
API_DISABLE_HEALTH_CHECK_LOGGING=false
CHROMIUM_INCOGNITO=false
CHROMIUM_ALLOW_INSECURE_LOCALHOST=false
CHROMIUM_IGNORE_CERTIFICATE_ERRORS=false
CHROMIUM_DISABLE_WEB_SECURITY=false
CHROMIUM_ALLOW_FILE_ACCESS_FROM_FILES=false
CHROMIUM_HOST_RESOLVER_RULES=
CHROMIUM_PROXY_SERVER=
CHROMIUM_ALLOW_LIST=
CHROMIUM_DENY_LIST="^file:///[^tmp].*"
@@ -77,9 +79,11 @@ run: ## Start a Gotenberg container
--api-trace-header=$(API_TRACE_HEADER) \
--api-disable-health-check-logging=$(API_DISABLE_HEALTH_CHECK_LOGGING) \
--chromium-incognito=$(CHROMIUM_INCOGNITO) \
--chromium-allow-insecure-localhost=$(CHROMIUM_ALLOW_INSECURE_LOCALHOST) \
--chromium-ignore-certificate-errors=$(CHROMIUM_IGNORE_CERTIFICATE_ERRORS) \
--chromium-disable-web-security=$(CHROMIUM_DISABLE_WEB_SECURITY) \
--chromium-allow-file-access-from-files=$(CHROMIUM_ALLOW_FILE_ACCESS_FROM_FILES) \
--chromium-host-resolver-rules=$(CHROMIUM_HOST_RESOLVER_RULES) \
--chromium-proxy-server=$(CHROMIUM_PROXY_SERVER) \
--chromium-allow-list=$(CHROMIUM_ALLOW_LIST) \
--chromium-deny-list=$(CHROMIUM_DENY_LIST) \

14
go.mod
View File

@@ -1,12 +1,12 @@
module github.com/gotenberg/gotenberg/v7
go 1.18
go 1.19
require (
github.com/alexliesenfeld/health v0.6.0
github.com/andybalholm/brotli v1.0.4 // indirect
github.com/chromedp/cdproto v0.0.0-20220816211547-b8b15824df23
github.com/chromedp/chromedp v0.8.4
github.com/chromedp/cdproto v0.0.0-20220827030233-358ed4af73cf
github.com/chromedp/chromedp v0.8.5
github.com/golang/snappy v0.0.4 // indirect
github.com/google/uuid v1.3.0
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
@@ -27,12 +27,12 @@ require (
github.com/ulikunitz/xz v0.5.10 // indirect
go.uber.org/atomic v1.10.0 // indirect
go.uber.org/multierr v1.8.0
go.uber.org/zap v1.22.0
golang.org/x/crypto v0.0.0-20220817201139-bc19a97f63c8 // indirect
go.uber.org/zap v1.23.0
golang.org/x/crypto v0.0.0-20220829220503-c86fa9a7ed90 // indirect
golang.org/x/image v0.0.0-20220722155232-062f8c9fd539 // indirect
golang.org/x/net v0.0.0-20220812174116-3211cb980234
golang.org/x/net v0.0.0-20220826154423-83b083e8dc8b
golang.org/x/sync v0.0.0-20220819030929-7fc1605a5dde
golang.org/x/sys v0.0.0-20220818161305-2296e01440c6 // indirect
golang.org/x/sys v0.0.0-20220829200755-d48e67d00261 // indirect
golang.org/x/term v0.0.0-20220722155259-a9ba230a4035
golang.org/x/text v0.3.7
)

26
go.sum
View File

@@ -54,10 +54,10 @@ github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/cespare/xxhash/v2 v2.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE=
github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/chromedp/cdproto v0.0.0-20220816211547-b8b15824df23 h1:pXlKxzGxVoUO5B04CNAOC4ZHf5Rqhl/00pkoM97He1s=
github.com/chromedp/cdproto v0.0.0-20220816211547-b8b15824df23/go.mod h1:5Y4sD/eXpwrChIuxhSr/G20n9CdbCmoerOHnuAf0Zr0=
github.com/chromedp/chromedp v0.8.4 h1:50NSLCXC38kGsCmLCi8tXZ5V5FtQ3BOV/90u1O06Gq4=
github.com/chromedp/chromedp v0.8.4/go.mod h1:ikuiJrEMoOnTPFUBu6jV0XZFOGW6W/Nhgk/OZyvh00o=
github.com/chromedp/cdproto v0.0.0-20220827030233-358ed4af73cf h1:e0oJZmGJidTRZ0FvWXNhdj9OaOMN30Yf+T3K2Tf3L+s=
github.com/chromedp/cdproto v0.0.0-20220827030233-358ed4af73cf/go.mod h1:5Y4sD/eXpwrChIuxhSr/G20n9CdbCmoerOHnuAf0Zr0=
github.com/chromedp/chromedp v0.8.5 h1:HAVg54yQFcn7sg5reVjXtoI1eQaFxhjAjflHACicUFw=
github.com/chromedp/chromedp v0.8.5/go.mod h1:xal2XY5Di7m/bzlGwtoYpmgIOfDqCakOIVg5OfdkPZ4=
github.com/chromedp/sysutil v1.0.0 h1:+ZxhTpfpZlmchB58ih/LBHX52ky7w2VhQVKQMucy3Ic=
github.com/chromedp/sysutil v1.0.0/go.mod h1:kgWmDdq8fTzXYcKIBqIYvRRTnYb9aNS9moAV0xufSww=
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
@@ -276,8 +276,8 @@ github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk=
github.com/ulikunitz/xz v0.5.8/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14=
github.com/ulikunitz/xz v0.5.9/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14=
github.com/ulikunitz/xz v0.5.10 h1:t92gobL9l3HE202wg3rlk19F6X+JOxl9BBrCCMYEYd8=
@@ -302,16 +302,16 @@ go.uber.org/atomic v1.10.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0
go.uber.org/goleak v1.1.11 h1:wy28qYRKZgnJTxGxvye5/wgWr1EKjmUDGYox5mGlRlI=
go.uber.org/multierr v1.8.0 h1:dg6GjLku4EH+249NNmoIciG9N/jURbDG+pFlTkhzIC8=
go.uber.org/multierr v1.8.0/go.mod h1:7EAYxJLBy9rStEaz58O2t4Uvip6FSURkq8/ppBp95ak=
go.uber.org/zap v1.22.0 h1:Zcye5DUgBloQ9BaT4qc9BnjOFog5TvBSAGkJ3Nf70c0=
go.uber.org/zap v1.22.0/go.mod h1:H4siCOZOrAolnUPJEkfaSjDqyP+BDS0DdDWzwcgt3+U=
go.uber.org/zap v1.23.0 h1:OjGQ5KQDEUawVHxNwQgPpiypGHOxo2mNZsOqTak4fFY=
go.uber.org/zap v1.23.0/go.mod h1:D+nX8jyLsMHMYrln8A0rJjFt/T/9/bGgIhAqxv5URuY=
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20220817201139-bc19a97f63c8 h1:GIAS/yBem/gq2MUqgNIzUHW7cJMmx3TGZOrnyYaNQ6c=
golang.org/x/crypto v0.0.0-20220817201139-bc19a97f63c8/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.0.0-20220829220503-c86fa9a7ed90 h1:Y/gsMcFOcR+6S6f3YeMKl5g+dZMEWqcz5Czj/GWYbkM=
golang.org/x/crypto v0.0.0-20220829220503-c86fa9a7ed90/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
@@ -376,8 +376,8 @@ golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81R
golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
golang.org/x/net v0.0.0-20220812174116-3211cb980234 h1:RDqmgfe7SvlMWoqC3xwQ2blLO3fcWcxMa3eBLRdRW7E=
golang.org/x/net v0.0.0-20220812174116-3211cb980234/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=
golang.org/x/net v0.0.0-20220826154423-83b083e8dc8b h1:ZmngSVLe/wycRns9MKikG9OWIEjGcGAkacif7oYQaUY=
golang.org/x/net v0.0.0-20220826154423-83b083e8dc8b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
@@ -439,8 +439,8 @@ golang.org/x/sys v0.0.0-20211103235746-7861aae1554b/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220818161305-2296e01440c6 h1:Sx/u41w+OwrInGdEckYmEuU5gHoGSL4QbDz3S9s6j4U=
golang.org/x/sys v0.0.0-20220818161305-2296e01440c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220829200755-d48e67d00261 h1:v6hYoSR9T5oet+pMXwUWkbiVqx/63mlHjefrHmxwfeY=
golang.org/x/sys v0.0.0-20220829200755-d48e67d00261/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.0.0-20220722155259-a9ba230a4035 h1:Q5284mrmYTpACcm+eAKjKJH48BBwSyfJqmmGDTtT8Vc=

View File

@@ -1,6 +1,7 @@
package chromium
import (
"bufio"
"context"
"errors"
"fmt"
@@ -65,9 +66,11 @@ type Chromium struct {
engine gotenberg.PDFEngine
userAgent string
incognito bool
allowInsecureLocalhost bool
ignoreCertificateErrors bool
disableWebSecurity bool
allowFileAccessFromFiles bool
hostResolverRules string
proxyServer string
allowList *regexp.Regexp
denyList *regexp.Regexp
@@ -249,9 +252,11 @@ func (mod Chromium) Descriptor() gotenberg.ModuleDescriptor {
fs := flag.NewFlagSet("chromium", flag.ExitOnError)
fs.String("chromium-user-agent", "", "Override the default User-Agent header")
fs.Bool("chromium-incognito", false, "Start Chromium with incognito mode")
fs.Bool("chromium-allow-insecure-localhost", false, "Ignore TLS/SSL errors on localhost")
fs.Bool("chromium-ignore-certificate-errors", false, "Ignore the certificate errors")
fs.Bool("chromium-disable-web-security", false, "Don't enforce the same-origin policy")
fs.Bool("chromium-allow-file-access-from-files", false, "Allow file:// URIs to read other file:// URIs")
fs.String("chromium-host-resolver-rules", "", "Set custom mappings to the host resolver")
fs.String("chromium-proxy-server", "", "Set the outbound proxy server; this switch only affects HTTP and HTTPS requests")
fs.String("chromium-allow-list", "", "Set the allowed URLs for Chromium using a regular expression")
fs.String("chromium-deny-list", "^file:///[^tmp].*", "Set the denied URLs for Chromium using a regular expression")
@@ -273,9 +278,11 @@ func (mod Chromium) Descriptor() gotenberg.ModuleDescriptor {
func (mod *Chromium) Provision(ctx *gotenberg.Context) error {
flags := ctx.ParsedFlags()
mod.userAgent = flags.MustString("chromium-user-agent")
mod.allowInsecureLocalhost = flags.MustBool("chromium-allow-insecure-localhost")
mod.ignoreCertificateErrors = flags.MustBool("chromium-ignore-certificate-errors")
mod.disableWebSecurity = flags.MustBool("chromium-disable-web-security")
mod.allowFileAccessFromFiles = flags.MustBool("chromium-allow-file-access-from-files")
mod.hostResolverRules = flags.MustString("chromium-host-resolver-rules")
mod.proxyServer = flags.MustString("chromium-proxy-server")
mod.allowList = flags.MustRegexp("chromium-allow-list")
mod.denyList = flags.MustRegexp("chromium-deny-list")
@@ -381,6 +388,11 @@ func (mod Chromium) PDF(ctx context.Context, logger *zap.Logger, URL, outputPath
args = append(args, chromedp.Flag("incognito", mod.incognito))
}
if mod.allowInsecureLocalhost {
// See https://github.com/gotenberg/gotenberg/issues/488.
args = append(args, chromedp.Flag("allow-insecure-localhost", true))
}
if mod.ignoreCertificateErrors {
args = append(args, chromedp.IgnoreCertErrors)
}
@@ -394,6 +406,11 @@ func (mod Chromium) PDF(ctx context.Context, logger *zap.Logger, URL, outputPath
args = append(args, chromedp.Flag("allow-file-access-from-files", true))
}
if mod.hostResolverRules != "" {
// See https://github.com/gotenberg/gotenberg/issues/488.
args = append(args, chromedp.Flag("host-resolver-rules", mod.hostResolverRules))
}
if mod.proxyServer != "" {
// See https://github.com/gotenberg/gotenberg/issues/376.
args = append(args, chromedp.ProxyServer(mod.proxyServer))
@@ -425,7 +442,7 @@ func (mod Chromium) PDF(ctx context.Context, logger *zap.Logger, URL, outputPath
consoleExceptionsMu sync.RWMutex
)
printToPDF := func(URL string, options Options, result *[]byte) chromedp.Tasks {
printToPDF := func(URL string, options Options, outputPath string) chromedp.Tasks {
// We validate the underlying requests against our allow / deny lists.
// If a request does not pass the validation, we make it fail.
listenForEventRequestPaused(taskCtx, logger, mod.allowList, mod.denyList)
@@ -731,6 +748,7 @@ func (mod Chromium) PDF(ctx context.Context, logger *zap.Logger, URL, outputPath
}),
chromedp.ActionFunc(func(ctx context.Context) error {
printToPDF := page.PrintToPDF().
WithTransferMode(page.PrintToPDFTransferModeReturnAsStream).
WithLandscape(options.Landscape).
WithPrintBackground(options.PrintBackground).
WithScale(options.Scale).
@@ -748,12 +766,44 @@ func (mod Chromium) PDF(ctx context.Context, logger *zap.Logger, URL, outputPath
logger.Debug(fmt.Sprintf("print to PDF with: %+v", printToPDF))
data, _, err := printToPDF.Do(ctx)
_, stream, err := printToPDF.Do(ctx)
if err != nil {
return fmt.Errorf("print to PDF: %w", err)
}
*result = data
reader := &streamReader{
ctx: ctx,
handle: stream,
r: nil,
pos: 0,
eof: false,
}
defer func() {
err := reader.Close()
if err != nil {
logger.Error(fmt.Sprintf("close reader: %s", err))
}
}()
file, err := os.OpenFile(outputPath, os.O_CREATE|os.O_WRONLY, 0600)
if err != nil {
return fmt.Errorf("open output path: %w", err)
}
defer func() {
err := file.Close()
if err != nil {
logger.Error(fmt.Sprintf("close output path: %s", err))
}
}()
buffer := bufio.NewReader(reader)
_, err = buffer.WriteTo(file)
if err != nil {
return fmt.Errorf("write result to output path: %w", err)
}
return nil
}),
@@ -764,8 +814,7 @@ func (mod Chromium) PDF(ctx context.Context, logger *zap.Logger, URL, outputPath
activeInstancesCount += 1
activeInstancesCountMu.Unlock()
var buffer []byte
err := chromedp.Run(taskCtx, printToPDF(URL, options, &buffer))
err := chromedp.Run(taskCtx, printToPDF(URL, options, outputPath))
activeInstancesCountMu.Lock()
activeInstancesCount -= 1
@@ -807,11 +856,6 @@ func (mod Chromium) PDF(ctx context.Context, logger *zap.Logger, URL, outputPath
return fmt.Errorf("%v: %w", consoleExceptions, ErrConsoleExceptions)
}
err = os.WriteFile(outputPath, buffer, 0600)
if err != nil {
return fmt.Errorf("write result to output path: %w", err)
}
return nil
}

View File

@@ -3,7 +3,6 @@ package chromium
import (
"context"
"errors"
"io/ioutil"
"os"
"reflect"
"regexp"
@@ -232,9 +231,11 @@ func TestChromium_PDF(t *testing.T) {
options Options
userAgent string
incognito bool
allowInsecureLocalhost bool
ignoreCertificateErrors bool
disableWebSecurity bool
allowFileAccessFromFiles bool
hostResolverRules string
proxyServer string
allowList *regexp.Regexp
denyList *regexp.Regexp
@@ -380,8 +381,10 @@ func TestChromium_PDF(t *testing.T) {
userAgent: "foo",
incognito: true,
ignoreCertificateErrors: true,
allowInsecureLocalhost: true,
disableWebSecurity: true,
allowFileAccessFromFiles: true,
hostResolverRules: "foo",
proxyServer: "foo",
},
{
@@ -399,7 +402,7 @@ func TestChromium_PDF(t *testing.T) {
URL: "file:///tests/test/testdata/chromium/html/sample4/index.html",
options: Options{
HeaderTemplate: func() string {
b, err := ioutil.ReadFile("/tests/test/testdata/chromium/url/sample2/header.html")
b, err := os.ReadFile("/tests/test/testdata/chromium/url/sample2/header.html")
if err != nil {
t.Fatalf("expected no error but got: %v", err)
}
@@ -407,7 +410,7 @@ func TestChromium_PDF(t *testing.T) {
return string(b)
}(),
FooterTemplate: func() string {
b, err := ioutil.ReadFile("/tests/test/testdata/chromium/url/sample2/footer.html")
b, err := os.ReadFile("/tests/test/testdata/chromium/url/sample2/footer.html")
if err != nil {
t.Fatalf("expected no error but got: %v", err)
}
@@ -432,9 +435,11 @@ func TestChromium_PDF(t *testing.T) {
mod.binPath = os.Getenv("CHROMIUM_BIN_PATH")
mod.userAgent = tc.userAgent
mod.incognito = tc.incognito
mod.allowInsecureLocalhost = tc.allowInsecureLocalhost
mod.ignoreCertificateErrors = tc.ignoreCertificateErrors
mod.disableWebSecurity = tc.disableWebSecurity
mod.allowFileAccessFromFiles = tc.allowFileAccessFromFiles
mod.hostResolverRules = tc.hostResolverRules
mod.proxyServer = tc.proxyServer
if tc.allowList == nil {

View File

@@ -0,0 +1,117 @@
package chromium
import (
"bytes"
"context"
"encoding/base64"
"fmt"
"io"
"strings"
"github.com/chromedp/cdproto/cdp"
cdprotoio "github.com/chromedp/cdproto/io"
)
// Credits: https://raw.githubusercontent.com/mafredri/cdp/3c5eab7ffc5cbee667b0a813ce470ac423792811/protocol/io/stream_reader.go.
type streamReader struct {
ctx context.Context
handle cdprotoio.StreamHandle
r io.Reader
pos int
eof bool
}
// Read a chunk of the stream.
func (reader *streamReader) Read(p []byte) (n int, err error) {
if reader.r != nil {
// Continue reading from buffer.
return reader.read(p)
}
if reader.eof {
return 0, io.EOF
}
if len(p) == 0 {
return 0, nil
}
// Chromium might have an off-by-one when deciding the maximum size (at
// least for base64 encoded data), usually it will overflow. We subtract
// one to make sure it fits into p.
size := len(p) - 1
if size < 1 {
// Safety-check to avoid crashing Chrome (e.g. via SetSize(-1)).
size = 1
}
reply, err := reader.next(reader.pos, size)
if err != nil {
return 0, err
}
reader.eof = reply.EOF
switch {
case reply.Base64encoded:
b := []byte(reply.Data)
size := base64.StdEncoding.DecodedLen(len(b))
// Safety-check for fast-path to avoid panics.
if len(p) >= size {
n, err = base64.StdEncoding.Decode(p, b)
reader.pos += n
return n, err
}
reader.r = base64.NewDecoder(base64.StdEncoding, bytes.NewReader(b))
default:
reader.r = strings.NewReader(reply.Data)
}
return reader.read(p)
}
// Close closes the stream, discard any temporary backing storage.
func (reader *streamReader) Close() error {
err := cdprotoio.Close(reader.handle).Do(reader.ctx)
if err == nil {
return nil
}
return fmt.Errorf("close Chromium stream: %w", err)
}
func (reader *streamReader) next(pos, size int) (cdprotoio.ReadReturns, error) {
params := cdprotoio.
Read(reader.handle).
WithOffset(int64(pos)).
WithSize(int64(size))
var res cdprotoio.ReadReturns
err := cdp.Execute(reader.ctx, cdprotoio.CommandRead, params, &res)
if err == nil {
return res, nil
}
return res, fmt.Errorf("execute IO.read command: %w", err)
}
func (reader *streamReader) read(p []byte) (n int, err error) {
n, err = reader.r.Read(p)
reader.pos += n
if !reader.eof && err == io.EOF {
reader.r = nil
err = nil
}
return n, err
}
// Interface guards.
var (
_ io.Reader = (*streamReader)(nil)
)

View File

@@ -6,7 +6,7 @@ import (
"encoding/json"
"errors"
"fmt"
"io/ioutil"
"io"
"math/rand"
"mime/multipart"
"net/http"
@@ -450,7 +450,7 @@ func TestWebhookMiddlewareAsynchronousProcess(t *testing.T) {
}
if contentType == echo.MIMEApplicationJSONCharsetUTF8 {
body, err := ioutil.ReadAll(c.Request().Body)
body, err := io.ReadAll(c.Request().Body)
if err != nil {
errChan <- err
return nil
@@ -489,7 +489,7 @@ func TestWebhookMiddlewareAsynchronousProcess(t *testing.T) {
t.Errorf("test %d: expected '%s' '%s' to contain '%s'", i, echo.HeaderContentDisposition, contentDisposition, tc.expectWebhookFilename)
}
body, err := ioutil.ReadAll(c.Request().Body)
body, err := io.ReadAll(c.Request().Body)
if err != nil {
errChan <- err
return nil