diff --git a/go.mod b/go.mod index 11612374..2e288727 100644 --- a/go.mod +++ b/go.mod @@ -5,17 +5,17 @@ go 1.17 require ( github.com/alexliesenfeld/health v0.6.0 github.com/andybalholm/brotli v1.0.3 // indirect - github.com/chromedp/cdproto v0.0.0-20210823203301-2c0adcc9edc4 + github.com/chromedp/cdproto v0.0.0-20210910012206-68626162910d github.com/chromedp/chromedp v0.7.4 github.com/golang/snappy v0.0.4 // indirect github.com/google/uuid v1.3.0 github.com/hashicorp/go-cleanhttp v0.5.2 // indirect github.com/hashicorp/go-retryablehttp v0.7.0 - github.com/klauspost/compress v1.13.4 // indirect + github.com/klauspost/compress v1.13.6 // indirect github.com/klauspost/pgzip v1.2.5 // indirect github.com/labstack/echo/v4 v4.5.0 github.com/labstack/gommon v0.3.0 - github.com/mattn/go-isatty v0.0.13 // indirect + github.com/mattn/go-isatty v0.0.14 // indirect github.com/mholt/archiver/v3 v3.5.0 github.com/microcosm-cc/bluemonday v1.0.15 github.com/nwaples/rardecode v1.1.2 // indirect @@ -26,7 +26,7 @@ require ( github.com/ulikunitz/xz v0.5.10 // indirect go.uber.org/atomic v1.9.0 // indirect go.uber.org/multierr v1.7.0 - go.uber.org/zap v1.19.0 + go.uber.org/zap v1.19.1 golang.org/x/crypto v0.0.0-20210817164053-32db794688a5 // indirect golang.org/x/image v0.0.0-20210628002857-a66eb6448b8d // indirect golang.org/x/net v0.0.0-20210813160813-60bc85c4be6d // indirect diff --git a/go.sum b/go.sum index 56a10994..adaa9e27 100644 --- a/go.sum +++ b/go.sum @@ -11,6 +11,8 @@ github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZx github.com/chromedp/cdproto v0.0.0-20210713064928-7d28b402946a/go.mod h1:At5TxYYdxkbQL0TSefRjhLE3Q0lgvqKKMSFUglJ7i1U= github.com/chromedp/cdproto v0.0.0-20210823203301-2c0adcc9edc4 h1:cD7F5LfNjC4dtb+BQe1KxxE8RsceYtS+Kyo+yEs4iUc= github.com/chromedp/cdproto v0.0.0-20210823203301-2c0adcc9edc4/go.mod h1:At5TxYYdxkbQL0TSefRjhLE3Q0lgvqKKMSFUglJ7i1U= +github.com/chromedp/cdproto v0.0.0-20210910012206-68626162910d h1:77O+89zb1W9dPNUGjXOGt/J4LP70jPIPz9Rxs3aSX1w= +github.com/chromedp/cdproto v0.0.0-20210910012206-68626162910d/go.mod h1:At5TxYYdxkbQL0TSefRjhLE3Q0lgvqKKMSFUglJ7i1U= github.com/chromedp/chromedp v0.7.4 h1:U+0d3WbB/Oj4mDuBOI0P7S3PJEued5UZIl5AJ3QulwU= github.com/chromedp/chromedp v0.7.4/go.mod h1:dBj+SXuQHznp6ZPwZeDDEBZKwclUwDLbZ0hjMialMYs= github.com/chromedp/sysutil v1.0.0 h1:+ZxhTpfpZlmchB58ih/LBHX52ky7w2VhQVKQMucy3Ic= @@ -54,6 +56,8 @@ github.com/klauspost/compress v1.4.1/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0 github.com/klauspost/compress v1.10.10/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= github.com/klauspost/compress v1.13.4 h1:0zhec2I8zGnjWcKyLl6i3gPqKANCCn5e9xmviEEeX6s= github.com/klauspost/compress v1.13.4/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8eO+e+Dq5Gzg= +github.com/klauspost/compress v1.13.6 h1:P76CopJELS0TiO2mebmnzgWaajssP/EszplttgQxcgc= +github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= github.com/klauspost/cpuid v1.2.0/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= github.com/klauspost/pgzip v1.2.4/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs= github.com/klauspost/pgzip v1.2.5 h1:qnWYvvKqedOF2ulHpMG72XQol4ILEJ8k2wwRl/Km8oE= @@ -77,6 +81,8 @@ github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2y github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= github.com/mattn/go-isatty v0.0.13 h1:qdl+GuBjcsKKDco5BsxPJlId98mSWNKqYA+Co0SC1yA= github.com/mattn/go-isatty v0.0.13/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y= +github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= github.com/mholt/archiver/v3 v3.5.0 h1:nE8gZIrw66cu4osS/U7UW7YDuGMHssxKutU8IfWxwWE= github.com/mholt/archiver/v3 v3.5.0/go.mod h1:qqTTPUK/HZPFgFQ/TJ3BzvTpF/dPtFVJXdQbCmeMxwc= github.com/microcosm-cc/bluemonday v1.0.15 h1:J4uN+qPng9rvkBZBoBb8YGR+ijuklIMpSOZZLjYpbeY= @@ -124,11 +130,14 @@ go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE= go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/goleak v1.1.10 h1:z+mqJhf6ss6BSfSM671tgKyZBFPTTJM+HLxnhPC3wu0= go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A= +go.uber.org/goleak v1.1.11-0.20210813005559-691160354723/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= go.uber.org/multierr v1.7.0 h1:zaiO/rmgFjbmCXdSYJWQcdvOCsthmdaHfr3Gm2Kx4Ec= go.uber.org/multierr v1.7.0/go.mod h1:7EAYxJLBy9rStEaz58O2t4Uvip6FSURkq8/ppBp95ak= go.uber.org/zap v1.19.0 h1:mZQZefskPPCMIBCSEH0v2/iUqqLrYtaeqwD6FUGUnFE= go.uber.org/zap v1.19.0/go.mod h1:xg/QME4nWcxGxrpdeYfq7UvYrLh66cuVKdrbD1XF/NI= +go.uber.org/zap v1.19.1 h1:ue41HOKd1vGURxrmeKIgELGb3jPW9DMUDGtsinblHwI= +go.uber.org/zap v1.19.1/go.mod h1:j3DNczoxDZroyBnOT1L/Q79cfUMGZxlv/9dzN7SM1rI= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= @@ -166,6 +175,7 @@ golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210525143221-35b2ab0089ea/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210820121016-41cdb8703e55 h1:rw6UNGRMfarCepjI8qOepea/SXwIBVfTKjztZ5gBbq4= golang.org/x/sys v0.0.0-20210820121016-41cdb8703e55/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= diff --git a/pkg/modules/api/context.go b/pkg/modules/api/context.go index 88fb79c3..41e53ce0 100644 --- a/pkg/modules/api/context.go +++ b/pkg/modules/api/context.go @@ -125,10 +125,9 @@ func newContext(echoCtx echo.Context, logger *zap.Logger, timeout time.Duration) copyToDisk := func(fh *multipart.FileHeader) error { // Avoid directory traversal and normalize filename. // See https://github.com/gotenberg/gotenberg/issues/104. - // See https://github.com/gotenberg/gotenberg/issues/228. t := transform.Chain(norm.NFD, runes.Remove(runes.In(unicode.Mn)), norm.NFC) - filename, _, err := transform.String(t, strings.ToLower(filepath.Base(fh.Filename))) + filename, _, err := transform.String(t, filepath.Base(fh.Filename)) if err != nil { return fmt.Errorf("transform filename: %w", err) } diff --git a/pkg/modules/api/formdata.go b/pkg/modules/api/formdata.go index c4260a36..376e8df5 100644 --- a/pkg/modules/api/formdata.go +++ b/pkg/modules/api/formdata.go @@ -396,7 +396,9 @@ func (form *FormData) mustAssign(key, value string, target interface{}) *FormDat // path binds the absolute path of a form data file to a string variable. func (form *FormData) path(filename string, target *string) *FormData { for name, path := range form.files { - if name == filename { + // See https://github.com/gotenberg/gotenberg/issues/228. + nameLowerExt := strings.TrimSuffix(name, filepath.Ext(name)) + strings.ToLower(filepath.Ext(name)) + if name == filename || nameLowerExt == filename { *target = path return form } diff --git a/pkg/modules/api/formdata_test.go b/pkg/modules/api/formdata_test.go index f16a4e5d..8773c9d0 100644 --- a/pkg/modules/api/formdata_test.go +++ b/pkg/modules/api/formdata_test.go @@ -850,6 +850,7 @@ func TestFormData_MandatoryPath(t *testing.T) { func TestFormData_Content(t *testing.T) { for i, tc := range []struct { form *FormData + filename string defaultValue string expect string expectErr bool @@ -863,6 +864,7 @@ func TestFormData_Content(t *testing.T) { "bar": "/bar", }, }, + filename: "foo", }, { form: &FormData{ @@ -870,6 +872,7 @@ func TestFormData_Content(t *testing.T) { "bar": "/bar", }, }, + filename: "foo", defaultValue: "foo", expect: "foo", }, @@ -879,6 +882,7 @@ func TestFormData_Content(t *testing.T) { "foo": "/foo", }, }, + filename: "foo", expectErr: true, }, { @@ -887,12 +891,31 @@ func TestFormData_Content(t *testing.T) { "foo": "/tests/test/testdata/api/sample1.txt", }, }, - expect: "foo", + filename: "foo", + expect: "foo", + }, + { + form: &FormData{ + files: map[string]string{ + "foo.TXT": "/tests/test/testdata/api/sample1.txt", + }, + }, + filename: "foo.txt", + expect: "foo", + }, + { + form: &FormData{ + files: map[string]string{ + "foo.txt": "/tests/test/testdata/api/sample1.txt", + }, + }, + filename: "foo.txt", + expect: "foo", }, } { var actual string - tc.form.Content("foo", &actual, tc.defaultValue) + tc.form.Content(tc.filename, &actual, tc.defaultValue) if actual != tc.expect { t.Errorf("test %d: expected '%s' but got '%s'", i, tc.expect, actual) @@ -911,11 +934,13 @@ func TestFormData_Content(t *testing.T) { func TestFormData_MandatoryContent(t *testing.T) { for i, tc := range []struct { form *FormData + filename string expect string expectErr bool }{ { form: &FormData{}, + filename: "foo", expectErr: true, }, { @@ -924,6 +949,7 @@ func TestFormData_MandatoryContent(t *testing.T) { "bar": "/bar", }, }, + filename: "foo", expectErr: true, }, { @@ -932,6 +958,7 @@ func TestFormData_MandatoryContent(t *testing.T) { "foo": "/foo", }, }, + filename: "foo", expectErr: true, }, { @@ -940,12 +967,31 @@ func TestFormData_MandatoryContent(t *testing.T) { "foo": "/tests/test/testdata/api/sample1.txt", }, }, - expect: "foo", + filename: "foo", + expect: "foo", + }, + { + form: &FormData{ + files: map[string]string{ + "foo.TXT": "/tests/test/testdata/api/sample1.txt", + }, + }, + filename: "foo.txt", + expect: "foo", + }, + { + form: &FormData{ + files: map[string]string{ + "foo.txt": "/tests/test/testdata/api/sample1.txt", + }, + }, + filename: "foo.txt", + expect: "foo", }, } { var actual string - tc.form.MandatoryContent("foo", &actual) + tc.form.MandatoryContent(tc.filename, &actual) if actual != tc.expect { t.Errorf("test %d: expected '%s' but got '%s'", i, tc.expect, actual) @@ -995,6 +1041,21 @@ func TestFormData_Paths(t *testing.T) { }, expectCount: 2, }, + { + form: &FormData{ + files: map[string]string{ + "foo.zip": "/foo.zip", + "b.PDF": "/b.PDF", + "a.pdf": "/a.pdf", + }, + }, + extensions: []string{".pdf"}, + expect: []string{ + "/a.pdf", + "/b.PDF", + }, + expectCount: 2, + }, } { var actual []string @@ -1051,6 +1112,21 @@ func TestFormData_MandatoryPaths(t *testing.T) { }, expectCount: 2, }, + { + form: &FormData{ + files: map[string]string{ + "foo.zip": "/foo.zip", + "b.PDF": "/b.PDF", + "a.pdf": "/a.pdf", + }, + }, + extensions: []string{".pdf"}, + expect: []string{ + "/a.pdf", + "/b.PDF", + }, + expectCount: 2, + }, } { var actual []string diff --git a/pkg/modules/api/middlewares_test.go b/pkg/modules/api/middlewares_test.go index 6c4a68c4..d3391eca 100644 --- a/pkg/modules/api/middlewares_test.go +++ b/pkg/modules/api/middlewares_test.go @@ -111,7 +111,7 @@ func TestHttpErrorHandler(t *testing.T) { func() { rand.Seed(time.Now().UnixNano()) - webhookPort := rand.Intn(65535 - 1025 + 1) + 1025 + webhookPort := rand.Intn(65535-1025+1) + 1025 tc.webhookClient.errorURL = fmt.Sprintf(tc.webhookClient.errorURL, webhookPort) @@ -825,7 +825,7 @@ func TestContextMiddlewareWithWebhook(t *testing.T) { webhook.HidePort = true rand.Seed(time.Now().UnixNano()) - webhookPort := rand.Intn(65535 - 1025 + 1) + 1025 + webhookPort := rand.Intn(65535-1025+1) + 1025 if tc.autoWebhookURLs { c.Request().Header.Set("Gotenberg-Webhook-Url", fmt.Sprintf("http://localhost:%d/", webhookPort)) diff --git a/pkg/modules/chromium/chromium_test.go b/pkg/modules/chromium/chromium_test.go index 8c1e374d..7e3d7718 100644 --- a/pkg/modules/chromium/chromium_test.go +++ b/pkg/modules/chromium/chromium_test.go @@ -312,6 +312,9 @@ func TestChromium_PDF(t *testing.T) { }(), }, }, + { + URL: "file:///tests/test/testdata/chromium/html/sample5/index.html", + }, } { func() { mod := new(Chromium) diff --git a/test/testdata/chromium/html/sample5/MyImg.gif b/test/testdata/chromium/html/sample5/MyImg.gif new file mode 100644 index 00000000..6b066b53 Binary files /dev/null and b/test/testdata/chromium/html/sample5/MyImg.gif differ diff --git a/test/testdata/chromium/html/sample5/index.html b/test/testdata/chromium/html/sample5/index.html new file mode 100644 index 00000000..087135fc --- /dev/null +++ b/test/testdata/chromium/html/sample5/index.html @@ -0,0 +1,15 @@ + + +
+ +
+