diff --git a/pkg/modules/api/api.go b/pkg/modules/api/api.go index 72a831ce..3863bcac 100644 --- a/pkg/modules/api/api.go +++ b/pkg/modules/api/api.go @@ -462,6 +462,7 @@ func (a *Api) Start() error { latencyMiddleware(), rootPathMiddleware(a.rootPath), traceMiddleware(a.traceHeader), + outputFilenameMiddleware(), loggerMiddleware(a.logger, disableLoggingForPaths), ) diff --git a/pkg/modules/api/context.go b/pkg/modules/api/context.go index 576c3176..61c6dcb4 100644 --- a/pkg/modules/api/context.go +++ b/pkg/modules/api/context.go @@ -513,7 +513,7 @@ func (ctx *Context) BuildOutputFile() (string, error) { // OutputFilename returns the filename based on the given output path or the // "Gotenberg-Output-Filename" header's value. func (ctx *Context) OutputFilename(outputPath string) string { - filename := ctx.echoCtx.Request().Header.Get("Gotenberg-Output-Filename") + filename := ctx.echoCtx.Get("outputFilename").(string) if filename == "" { return filepath.Base(outputPath) diff --git a/pkg/modules/api/middlewares.go b/pkg/modules/api/middlewares.go index d1cb3c54..176d6f4d 100644 --- a/pkg/modules/api/middlewares.go +++ b/pkg/modules/api/middlewares.go @@ -6,6 +6,7 @@ import ( "errors" "fmt" "net/http" + "path/filepath" "strings" "time" @@ -150,6 +151,25 @@ func traceMiddleware(header string) echo.MiddlewareFunc { } } +// outputFilenameMiddleware sets the output filename in the [echo.Context] +// under "outputFilename". +// +// outputFilename := c.Get("outputFilename").(string) +func outputFilenameMiddleware() echo.MiddlewareFunc { + return func(next echo.HandlerFunc) echo.HandlerFunc { + return func(c echo.Context) error { + filename := c.Request().Header.Get("Gotenberg-Output-Filename") + // See https://github.com/gotenberg/gotenberg/issues/1227. + if filename != "" { + filename = filepath.Base(filename) + } + c.Set("outputFilename", filename) + // Call the next middleware in the chain. + return next(c) + } + } +} + // loggerMiddleware sets the logger in the [echo.Context] under "logger" and // logs a synchronous request result. // diff --git a/test/integration/features/output_filename.feature b/test/integration/features/output_filename.feature new file mode 100644 index 00000000..f4f8b44c --- /dev/null +++ b/test/integration/features/output_filename.feature @@ -0,0 +1,33 @@ +Feature: Output Filename + + Scenario: Default (Single Output File) + Given I have a default Gotenberg container + When I make a "POST" request to Gotenberg at the "/forms/pdfengines/flatten" endpoint with the following form data and header(s): + | files | testdata/page_1.pdf | file | + | Gotenberg-Output-Filename | foo | header | + Then the response status code should be 200 + Then the response header "Content-Type" should be "application/pdf" + Then there should be the following file(s) in the response: + | foo.pdf | + + Scenario: Default (Many Output Files) + Given I have a default Gotenberg container + When I make a "POST" request to Gotenberg at the "/forms/pdfengines/flatten" endpoint with the following form data and header(s): + | files | testdata/page_1.pdf | file | + | files | testdata/page_2.pdf | file | + | Gotenberg-Output-Filename | foo | header | + Then the response status code should be 200 + Then the response header "Content-Type" should be "application/zip" + Then there should be the following file(s) in the response: + | foo.zip | + + # See https://github.com/gotenberg/gotenberg/issues/1227. + Scenario: Path As Filename + Given I have a default Gotenberg container + When I make a "POST" request to Gotenberg at the "/forms/pdfengines/flatten" endpoint with the following form data and header(s): + | files | testdata/page_1.pdf | file | + | Gotenberg-Output-Filename | /tmp/foo | header | + Then the response status code should be 200 + Then the response header "Content-Type" should be "application/pdf" + Then there should be the following file(s) in the response: + | foo.pdf |