mirror of
https://github.com/gotenberg/gotenberg.git
synced 2026-08-18 13:12:17 +01:00
fix(api): handle correctly filename that takes more that 200 bytes
This commit is contained in:
@@ -43,12 +43,13 @@ var (
|
|||||||
|
|
||||||
// Context is the request context for a "multipart/form-data" request.
|
// Context is the request context for a "multipart/form-data" request.
|
||||||
type Context struct {
|
type Context struct {
|
||||||
dirPath string
|
dirPath string
|
||||||
values map[string][]string
|
values map[string][]string
|
||||||
files map[string]string
|
files map[string]string
|
||||||
filesByField map[string][]string
|
filesByField map[string][]string
|
||||||
outputPaths []string
|
diskToOriginal map[string]string
|
||||||
cancelled bool
|
outputPaths []string
|
||||||
|
cancelled bool
|
||||||
|
|
||||||
logger *slog.Logger
|
logger *slog.Logger
|
||||||
echoCtx echo.Context
|
echoCtx echo.Context
|
||||||
@@ -200,6 +201,7 @@ func newContext(echoCtx echo.Context, logger *slog.Logger, fs *gotenberg.FileSys
|
|||||||
ctx.values = form.Value
|
ctx.values = form.Value
|
||||||
ctx.files = make(map[string]string)
|
ctx.files = make(map[string]string)
|
||||||
ctx.filesByField = make(map[string][]string)
|
ctx.filesByField = make(map[string][]string)
|
||||||
|
ctx.diskToOriginal = make(map[string]string)
|
||||||
|
|
||||||
// First, try to download files listed in the "downloadFrom" form field, if
|
// First, try to download files listed in the "downloadFrom" form field, if
|
||||||
// any.
|
// any.
|
||||||
@@ -348,7 +350,12 @@ func newContext(echoCtx echo.Context, logger *slog.Logger, fs *gotenberg.FileSys
|
|||||||
// normalized.
|
// normalized.
|
||||||
// See: https://github.com/gotenberg/gotenberg/issues/662.
|
// See: https://github.com/gotenberg/gotenberg/issues/662.
|
||||||
filename = norm.NFC.String(filepath.Base(filename))
|
filename = norm.NFC.String(filepath.Base(filename))
|
||||||
path := fmt.Sprintf("%s/%s", ctx.dirPath, filename)
|
|
||||||
|
// Use a UUID-based name on disk to avoid filesystem
|
||||||
|
// NAME_MAX limits with long filenames.
|
||||||
|
// See: https://github.com/gotenberg/gotenberg/issues/1500.
|
||||||
|
safeName := uuid.New().String() + filepath.Ext(filename)
|
||||||
|
path := fmt.Sprintf("%s/%s", ctx.dirPath, safeName)
|
||||||
|
|
||||||
out, err := os.Create(path)
|
out, err := os.Create(path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -381,6 +388,7 @@ func newContext(echoCtx echo.Context, logger *slog.Logger, fs *gotenberg.FileSys
|
|||||||
dlSpan.End()
|
dlSpan.End()
|
||||||
|
|
||||||
ctx.files[filename] = path
|
ctx.files[filename] = path
|
||||||
|
ctx.diskToOriginal[path] = filename
|
||||||
|
|
||||||
// Route the downloaded file to the appropriate field bucket.
|
// Route the downloaded file to the appropriate field bucket.
|
||||||
switch {
|
switch {
|
||||||
@@ -422,7 +430,12 @@ func newContext(echoCtx echo.Context, logger *slog.Logger, fs *gotenberg.FileSys
|
|||||||
// normalized.
|
// normalized.
|
||||||
// See: https://github.com/gotenberg/gotenberg/issues/662.
|
// See: https://github.com/gotenberg/gotenberg/issues/662.
|
||||||
filename := norm.NFC.String(filepath.Base(fh.Filename))
|
filename := norm.NFC.String(filepath.Base(fh.Filename))
|
||||||
path := fmt.Sprintf("%s/%s", ctx.dirPath, filename)
|
|
||||||
|
// Use a UUID-based name on disk to avoid filesystem
|
||||||
|
// NAME_MAX limits with long filenames.
|
||||||
|
// See: https://github.com/gotenberg/gotenberg/issues/1500.
|
||||||
|
safeName := uuid.New().String() + filepath.Ext(filename)
|
||||||
|
path := fmt.Sprintf("%s/%s", ctx.dirPath, safeName)
|
||||||
|
|
||||||
out, err := os.Create(path)
|
out, err := os.Create(path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -441,6 +454,7 @@ func newContext(echoCtx echo.Context, logger *slog.Logger, fs *gotenberg.FileSys
|
|||||||
}
|
}
|
||||||
|
|
||||||
ctx.files[filename] = path
|
ctx.files[filename] = path
|
||||||
|
ctx.diskToOriginal[path] = filename
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -475,13 +489,29 @@ func (ctx *Context) Request() *http.Request {
|
|||||||
// FormData return a [FormData].
|
// FormData return a [FormData].
|
||||||
func (ctx *Context) FormData() *FormData {
|
func (ctx *Context) FormData() *FormData {
|
||||||
return &FormData{
|
return &FormData{
|
||||||
values: ctx.values,
|
values: ctx.values,
|
||||||
files: ctx.files,
|
files: ctx.files,
|
||||||
filesByField: ctx.filesByField,
|
filesByField: ctx.filesByField,
|
||||||
errors: nil,
|
diskToOriginal: ctx.diskToOriginal,
|
||||||
|
errors: nil,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// OriginalFilename returns the original filename associated with a disk path.
|
||||||
|
// If no mapping exists, it falls back to [filepath.Base].
|
||||||
|
func (ctx *Context) OriginalFilename(diskPath string) string {
|
||||||
|
if original, ok := ctx.diskToOriginal[diskPath]; ok {
|
||||||
|
return original
|
||||||
|
}
|
||||||
|
return filepath.Base(diskPath)
|
||||||
|
}
|
||||||
|
|
||||||
|
// RegisterDiskPath associates a disk path with an original filename so that
|
||||||
|
// [Context.OriginalFilename] can resolve it later.
|
||||||
|
func (ctx *Context) RegisterDiskPath(diskPath, originalFilename string) {
|
||||||
|
ctx.diskToOriginal[diskPath] = originalFilename
|
||||||
|
}
|
||||||
|
|
||||||
// DirPath returns the path to the request's working directory.
|
// DirPath returns the path to the request's working directory.
|
||||||
func (ctx *Context) DirPath() string {
|
func (ctx *Context) DirPath() string {
|
||||||
return ctx.dirPath
|
return ctx.dirPath
|
||||||
@@ -494,10 +524,14 @@ func (ctx *Context) GeneratePath(extension string) string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// GeneratePathFromFilename generates a path within the context's working
|
// GeneratePathFromFilename generates a path within the context's working
|
||||||
// directory, using the given filename (with extension). It does not create
|
// directory. It uses a UUID-based name on disk to avoid filesystem NAME_MAX
|
||||||
// a file.
|
// limits but registers the given filename so that [Context.OriginalFilename]
|
||||||
|
// can resolve it. It does not create a file.
|
||||||
func (ctx *Context) GeneratePathFromFilename(filename string) string {
|
func (ctx *Context) GeneratePathFromFilename(filename string) string {
|
||||||
return fmt.Sprintf("%s/%s", ctx.dirPath, filename)
|
safeName := uuid.New().String() + filepath.Ext(filename)
|
||||||
|
path := fmt.Sprintf("%s/%s", ctx.dirPath, safeName)
|
||||||
|
ctx.diskToOriginal[path] = filename
|
||||||
|
return path
|
||||||
}
|
}
|
||||||
|
|
||||||
// CreateSubDirectory creates a subdirectory within the context's working
|
// CreateSubDirectory creates a subdirectory within the context's working
|
||||||
@@ -564,7 +598,7 @@ func (ctx *Context) BuildOutputFile() (string, error) {
|
|||||||
filesInfo, err := archives.FilesFromDisk(ctx.Context, nil, func() map[string]string {
|
filesInfo, err := archives.FilesFromDisk(ctx.Context, nil, func() map[string]string {
|
||||||
f := make(map[string]string)
|
f := make(map[string]string)
|
||||||
for _, outputPath := range ctx.outputPaths {
|
for _, outputPath := range ctx.outputPaths {
|
||||||
f[outputPath] = ""
|
f[outputPath] = ctx.OriginalFilename(outputPath)
|
||||||
}
|
}
|
||||||
return f
|
return f
|
||||||
}())
|
}())
|
||||||
@@ -600,7 +634,7 @@ func (ctx *Context) OutputFilename(outputPath string) string {
|
|||||||
filename := ctx.echoCtx.Get("outputFilename").(string)
|
filename := ctx.echoCtx.Get("outputFilename").(string)
|
||||||
|
|
||||||
if filename == "" {
|
if filename == "" {
|
||||||
return filepath.Base(outputPath)
|
return ctx.OriginalFilename(outputPath)
|
||||||
}
|
}
|
||||||
|
|
||||||
return fmt.Sprintf("%s%s", filename, filepath.Ext(outputPath))
|
return fmt.Sprintf("%s%s", filename, filepath.Ext(outputPath))
|
||||||
|
|||||||
@@ -33,10 +33,11 @@ const (
|
|||||||
//
|
//
|
||||||
// form := ctx.FormData()
|
// form := ctx.FormData()
|
||||||
type FormData struct {
|
type FormData struct {
|
||||||
values map[string][]string
|
values map[string][]string
|
||||||
files map[string]string
|
files map[string]string
|
||||||
filesByField map[string][]string
|
filesByField map[string][]string
|
||||||
errors error
|
diskToOriginal map[string]string
|
||||||
|
errors error
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validate returns nil or an error related to the [FormData] values, with a
|
// Validate returns nil or an error related to the [FormData] values, with a
|
||||||
@@ -450,6 +451,15 @@ func (form *FormData) paths(extensions []string, target *[]string) *FormData {
|
|||||||
watermarks, wmOk := form.filesByField[WatermarkFormField]
|
watermarks, wmOk := form.filesByField[WatermarkFormField]
|
||||||
stamps, stOk := form.filesByField[StampFormField]
|
stamps, stOk := form.filesByField[StampFormField]
|
||||||
|
|
||||||
|
// Collect (originalFilename, diskPath) pairs so that we can sort by
|
||||||
|
// original filename rather than by UUID-based disk name.
|
||||||
|
// See https://github.com/gotenberg/gotenberg/issues/1500.
|
||||||
|
type entry struct {
|
||||||
|
original string
|
||||||
|
disk string
|
||||||
|
}
|
||||||
|
var entries []entry
|
||||||
|
|
||||||
for filename, path := range form.files {
|
for filename, path := range form.files {
|
||||||
if ok && slices.Contains(embeds, path) {
|
if ok && slices.Contains(embeds, path) {
|
||||||
continue
|
continue
|
||||||
@@ -466,13 +476,26 @@ func (form *FormData) paths(extensions []string, target *[]string) *FormData {
|
|||||||
for _, ext := range extensions {
|
for _, ext := range extensions {
|
||||||
// See https://github.com/gotenberg/gotenberg/issues/228.
|
// See https://github.com/gotenberg/gotenberg/issues/228.
|
||||||
if strings.ToLower(filepath.Ext(filename)) == ext {
|
if strings.ToLower(filepath.Ext(filename)) == ext {
|
||||||
*target = append(*target, path)
|
entries = append(entries, entry{original: filename, disk: path})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// See https://github.com/gotenberg/gotenberg/issues/139.
|
// See https://github.com/gotenberg/gotenberg/issues/139.
|
||||||
sort.Sort(gotenberg.AlphanumericSort(*target))
|
originals := make(gotenberg.AlphanumericSort, len(entries))
|
||||||
|
for i, e := range entries {
|
||||||
|
originals[i] = e.original
|
||||||
|
}
|
||||||
|
sort.Sort(originals)
|
||||||
|
|
||||||
|
// Build a lookup from original name to disk path.
|
||||||
|
lookup := make(map[string]string, len(entries))
|
||||||
|
for _, e := range entries {
|
||||||
|
lookup[e.original] = e.disk
|
||||||
|
}
|
||||||
|
for _, o := range originals {
|
||||||
|
*target = append(*target, lookup[o])
|
||||||
|
}
|
||||||
|
|
||||||
return form
|
return form
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -667,7 +667,7 @@ func markdownToHtml(ctx *api.Context, inputPath string, markdownPaths []string)
|
|||||||
var path string
|
var path string
|
||||||
|
|
||||||
for _, markdownPath := range markdownPaths {
|
for _, markdownPath := range markdownPaths {
|
||||||
markdownFilename := filepath.Base(markdownPath)
|
markdownFilename := ctx.OriginalFilename(markdownPath)
|
||||||
|
|
||||||
if filename == markdownFilename {
|
if filename == markdownFilename {
|
||||||
path = markdownPath
|
path = markdownPath
|
||||||
|
|||||||
@@ -420,7 +420,8 @@ func convertRoute(libreOffice libreofficeapi.Uno, engine gotenberg.PdfEngine) ap
|
|||||||
// document.docx -> document.docx.pdf, so that split naming
|
// document.docx -> document.docx.pdf, so that split naming
|
||||||
// document.docx_0.pdf, etc.
|
// document.docx_0.pdf, etc.
|
||||||
for i, inputPath := range inputPaths {
|
for i, inputPath := range inputPaths {
|
||||||
outputPath := fmt.Sprintf("%s.pdf", inputPath)
|
originalName := ctx.OriginalFilename(inputPath)
|
||||||
|
outputPath := ctx.GeneratePathFromFilename(originalName + ".pdf")
|
||||||
|
|
||||||
err = ctx.Rename(outputPaths[i], outputPath)
|
err = ctx.Rename(outputPaths[i], outputPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -502,7 +503,8 @@ func convertRoute(libreOffice libreofficeapi.Uno, engine gotenberg.PdfEngine) ap
|
|||||||
if len(outputPaths) > 1 && splitMode == zeroValuedSplitMode {
|
if len(outputPaths) > 1 && splitMode == zeroValuedSplitMode {
|
||||||
// If .zip archive, document.docx -> document.docx.pdf.
|
// If .zip archive, document.docx -> document.docx.pdf.
|
||||||
for i, inputPath := range inputPaths {
|
for i, inputPath := range inputPaths {
|
||||||
outputPath := fmt.Sprintf("%s.pdf", inputPath)
|
originalName := ctx.OriginalFilename(inputPath)
|
||||||
|
outputPath := ctx.GeneratePathFromFilename(originalName + ".pdf")
|
||||||
|
|
||||||
err = ctx.Rename(outputPaths[i], outputPath)
|
err = ctx.Rename(outputPaths[i], outputPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -5,10 +5,12 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/google/uuid"
|
||||||
"github.com/labstack/echo/v4"
|
"github.com/labstack/echo/v4"
|
||||||
|
|
||||||
"github.com/gotenberg/gotenberg/v8/pkg/gotenberg"
|
"github.com/gotenberg/gotenberg/v8/pkg/gotenberg"
|
||||||
@@ -282,9 +284,9 @@ func SplitPdfStub(ctx *api.Context, engine gotenberg.PdfEngine, mode gotenberg.S
|
|||||||
|
|
||||||
var outputPaths []string
|
var outputPaths []string
|
||||||
for _, inputPath := range inputPaths {
|
for _, inputPath := range inputPaths {
|
||||||
inputPathNoExt := inputPath[:len(inputPath)-len(filepath.Ext(inputPath))]
|
originalName := ctx.OriginalFilename(inputPath)
|
||||||
filenameNoExt := filepath.Base(inputPathNoExt)
|
originalNameNoExt := strings.TrimSuffix(originalName, filepath.Ext(originalName))
|
||||||
outputDirPath, err := ctx.CreateSubDirectory(strings.ReplaceAll(filepath.Base(filenameNoExt), ".", "_"))
|
outputDirPath, err := ctx.CreateSubDirectory(uuid.New().String())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("create subdirectory from input path: %w", err)
|
return nil, fmt.Errorf("create subdirectory from input path: %w", err)
|
||||||
}
|
}
|
||||||
@@ -297,15 +299,18 @@ func SplitPdfStub(ctx *api.Context, engine gotenberg.PdfEngine, mode gotenberg.S
|
|||||||
// Keep the original filename.
|
// Keep the original filename.
|
||||||
for i, path := range paths {
|
for i, path := range paths {
|
||||||
var newPath string
|
var newPath string
|
||||||
|
var newOriginal string
|
||||||
if mode.Unify && mode.Mode == gotenberg.SplitModePages {
|
if mode.Unify && mode.Mode == gotenberg.SplitModePages {
|
||||||
|
newOriginal = fmt.Sprintf("%s.pdf", originalNameNoExt)
|
||||||
newPath = fmt.Sprintf(
|
newPath = fmt.Sprintf(
|
||||||
"%s/%s.pdf",
|
"%s/%s",
|
||||||
outputDirPath, filenameNoExt,
|
outputDirPath, uuid.New().String()+".pdf",
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
|
newOriginal = fmt.Sprintf("%s_%d.pdf", originalNameNoExt, i)
|
||||||
newPath = fmt.Sprintf(
|
newPath = fmt.Sprintf(
|
||||||
"%s/%s_%d.pdf",
|
"%s/%s",
|
||||||
outputDirPath, filenameNoExt, i,
|
outputDirPath, uuid.New().String()+".pdf",
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -314,6 +319,7 @@ func SplitPdfStub(ctx *api.Context, engine gotenberg.PdfEngine, mode gotenberg.S
|
|||||||
return nil, fmt.Errorf("rename path: %w", err)
|
return nil, fmt.Errorf("rename path: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ctx.RegisterDiskPath(newPath, newOriginal)
|
||||||
outputPaths = append(outputPaths, newPath)
|
outputPaths = append(outputPaths, newPath)
|
||||||
|
|
||||||
if mode.Unify && mode.Mode == gotenberg.SplitModePages {
|
if mode.Unify && mode.Mode == gotenberg.SplitModePages {
|
||||||
@@ -413,7 +419,7 @@ func WriteBookmarksStub(ctx *api.Context, engine gotenberg.PdfEngine, bookmarks
|
|||||||
}
|
}
|
||||||
case map[string][]gotenberg.Bookmark:
|
case map[string][]gotenberg.Bookmark:
|
||||||
for _, inputPath := range inputPaths {
|
for _, inputPath := range inputPaths {
|
||||||
filename := filepath.Base(inputPath)
|
filename := ctx.OriginalFilename(inputPath)
|
||||||
if specificBookmarks, ok := b[filename]; ok {
|
if specificBookmarks, ok := b[filename]; ok {
|
||||||
err := engine.WriteBookmarks(ctx, ctx.Log(), inputPath, specificBookmarks)
|
err := engine.WriteBookmarks(ctx, ctx.Log(), inputPath, specificBookmarks)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -466,8 +472,28 @@ func EmbedFilesStub(ctx *api.Context, engine gotenberg.PdfEngine, embedPaths []s
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Engines like pdfcpu use filepath.Base(path) as the attachment name
|
||||||
|
// inside the PDF. Since disk filenames are now UUID-based, we create
|
||||||
|
// symlinks with the original names so that embeds are named correctly.
|
||||||
|
// See: https://github.com/gotenberg/gotenberg/issues/1500.
|
||||||
|
embedDir, err := ctx.CreateSubDirectory(uuid.New().String())
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("create embed subdirectory: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
resolvedPaths := make([]string, len(embedPaths))
|
||||||
|
for i, embedPath := range embedPaths {
|
||||||
|
originalName := ctx.OriginalFilename(embedPath)
|
||||||
|
resolvedPath := fmt.Sprintf("%s/%s", embedDir, originalName)
|
||||||
|
err := os.Symlink(embedPath, resolvedPath)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("symlink embed file '%s': %w", originalName, err)
|
||||||
|
}
|
||||||
|
resolvedPaths[i] = resolvedPath
|
||||||
|
}
|
||||||
|
|
||||||
for _, inputPath := range inputPaths {
|
for _, inputPath := range inputPaths {
|
||||||
err := engine.EmbedFiles(ctx, ctx.Log(), embedPaths, inputPath)
|
err := engine.EmbedFiles(ctx, ctx.Log(), resolvedPaths, inputPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("embed files into PDF '%s': %w", inputPath, err)
|
return fmt.Errorf("embed files into PDF '%s': %w", inputPath, err)
|
||||||
}
|
}
|
||||||
@@ -683,7 +709,7 @@ func mergeRoute(engine gotenberg.PdfEngine) api.Route {
|
|||||||
if bMap != nil || autoIndexBookmarks {
|
if bMap != nil || autoIndexBookmarks {
|
||||||
offset := 0
|
offset := 0
|
||||||
for _, inputPath := range inputPaths {
|
for _, inputPath := range inputPaths {
|
||||||
filename := filepath.Base(inputPath)
|
filename := ctx.OriginalFilename(inputPath)
|
||||||
|
|
||||||
var fileBookmarks []gotenberg.Bookmark
|
var fileBookmarks []gotenberg.Bookmark
|
||||||
if bMap != nil {
|
if bMap != nil {
|
||||||
@@ -973,7 +999,7 @@ func readMetadataRoute(engine gotenberg.PdfEngine) api.Route {
|
|||||||
return fmt.Errorf("read metadata: %w", err)
|
return fmt.Errorf("read metadata: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
res[filepath.Base(inputPath)] = metadata
|
res[ctx.OriginalFilename(inputPath)] = metadata
|
||||||
}
|
}
|
||||||
|
|
||||||
err = c.JSON(http.StatusOK, res)
|
err = c.JSON(http.StatusOK, res)
|
||||||
@@ -1051,7 +1077,7 @@ func readBookmarksRoute(engine gotenberg.PdfEngine) api.Route {
|
|||||||
return fmt.Errorf("read bookmarks: %w", err)
|
return fmt.Errorf("read bookmarks: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
res[filepath.Base(inputPath)] = bookmarks
|
res[ctx.OriginalFilename(inputPath)] = bookmarks
|
||||||
}
|
}
|
||||||
|
|
||||||
err = c.JSON(http.StatusOK, res)
|
err = c.JSON(http.StatusOK, res)
|
||||||
|
|||||||
@@ -1152,3 +1152,14 @@ Feature: /forms/chromium/convert/html
|
|||||||
| files | testdata/page-1-html/index.html | file |
|
| files | testdata/page-1-html/index.html | file |
|
||||||
Then the response status code should be 200
|
Then the response status code should be 200
|
||||||
Then the response header "Content-Type" should be "application/pdf"
|
Then the response header "Content-Type" should be "application/pdf"
|
||||||
|
|
||||||
|
# See: https://github.com/gotenberg/gotenberg/issues/1500.
|
||||||
|
Scenario: POST /forms/chromium/convert/html (Long Filename)
|
||||||
|
Given I have a default Gotenberg container
|
||||||
|
When I make a "POST" request to Gotenberg at the "/forms/chromium/convert/html" endpoint with the following form data and header(s):
|
||||||
|
| files | testdata/page-1-html/index.html | 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 1 PDF(s) in the response
|
||||||
|
Then the "foo.pdf" PDF should have 1 page(s)
|
||||||
|
|||||||
@@ -1128,3 +1128,15 @@ Feature: /forms/chromium/convert/markdown
|
|||||||
| files | testdata/page-1-markdown/page_1.md | file |
|
| files | testdata/page-1-markdown/page_1.md | file |
|
||||||
Then the response status code should be 200
|
Then the response status code should be 200
|
||||||
Then the response header "Content-Type" should be "application/pdf"
|
Then the response header "Content-Type" should be "application/pdf"
|
||||||
|
|
||||||
|
# See: https://github.com/gotenberg/gotenberg/issues/1500.
|
||||||
|
Scenario: POST /forms/chromium/convert/markdown (Long Filename)
|
||||||
|
Given I have a default Gotenberg container
|
||||||
|
When I make a "POST" request to Gotenberg at the "/forms/chromium/convert/markdown" endpoint with the following form data and header(s):
|
||||||
|
| files | testdata/page-1-markdown/index.html | file |
|
||||||
|
| files | testdata/page-1-markdown/page_1.md | 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 1 PDF(s) in the response
|
||||||
|
Then the "foo.pdf" PDF should have 1 page(s)
|
||||||
|
|||||||
@@ -781,3 +781,14 @@ Feature: /forms/libreoffice/convert
|
|||||||
| files | testdata/page_1.docx | file |
|
| files | testdata/page_1.docx | file |
|
||||||
Then the response status code should be 200
|
Then the response status code should be 200
|
||||||
Then the response header "Content-Type" should be "application/pdf"
|
Then the response header "Content-Type" should be "application/pdf"
|
||||||
|
|
||||||
|
# See: https://github.com/gotenberg/gotenberg/issues/1500.
|
||||||
|
Scenario: POST /forms/libreoffice/convert (Long Filename)
|
||||||
|
Given I have a default Gotenberg container
|
||||||
|
When I make a "POST" request to Gotenberg at the "/forms/libreoffice/convert" endpoint with the following form data and header(s):
|
||||||
|
| files | testdata/Longitudinell_jämförelse_mellan_laserkirurgi_och_strålbehandling_gällande_röstkvalitet_och_självskattad_kommunikation_upp_till_två_år_efter_tidig_stämbandscancer_i_ett_randomiserat_kontrollerat_försök.docx | 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 1 PDF(s) in the response
|
||||||
|
Then the "foo.pdf" PDF should have 1 page(s)
|
||||||
|
|||||||
@@ -180,3 +180,15 @@ Feature: /forms/pdfengines/encrypt
|
|||||||
| userPassword | foo | field |
|
| userPassword | foo | field |
|
||||||
Then the response status code should be 200
|
Then the response status code should be 200
|
||||||
Then the response header "Content-Type" should be "application/pdf"
|
Then the response header "Content-Type" should be "application/pdf"
|
||||||
|
|
||||||
|
# See: https://github.com/gotenberg/gotenberg/issues/1500.
|
||||||
|
Scenario: POST /forms/pdfengines/encrypt (Long Filename)
|
||||||
|
Given I have a default Gotenberg container
|
||||||
|
When I make a "POST" request to Gotenberg at the "/forms/pdfengines/encrypt" endpoint with the following form data and header(s):
|
||||||
|
| files | testdata/Longitudinell_jämförelse_mellan_laserkirurgi_och_strålbehandling_gällande_röstkvalitet_och_självskattad_kommunikation_upp_till_två_år_efter_tidig_stämbandscancer_i_ett_randomiserat_kontrollerat_försök.pdf | file |
|
||||||
|
| userPassword | foo | field |
|
||||||
|
| ownerPassword | bar | field |
|
||||||
|
| 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 1 PDF(s) in the response
|
||||||
|
|||||||
@@ -118,3 +118,14 @@ Feature: /forms/pdfengines/flatten
|
|||||||
| files | testdata/page_1.pdf | file |
|
| files | testdata/page_1.pdf | file |
|
||||||
Then the response status code should be 200
|
Then the response status code should be 200
|
||||||
Then the response header "Content-Type" should be "application/pdf"
|
Then the response header "Content-Type" should be "application/pdf"
|
||||||
|
|
||||||
|
# See: https://github.com/gotenberg/gotenberg/issues/1500.
|
||||||
|
Scenario: POST /forms/pdfengines/flatten (Long 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/Longitudinell_jämförelse_mellan_laserkirurgi_och_strålbehandling_gällande_röstkvalitet_och_självskattad_kommunikation_upp_till_två_år_efter_tidig_stämbandscancer_i_ett_randomiserat_kontrollerat_försök.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 1 PDF(s) in the response
|
||||||
|
Then the response PDF(s) should be flatten
|
||||||
|
|||||||
@@ -664,3 +664,14 @@ Feature: /forms/pdfengines/merge
|
|||||||
| pdfa | PDF/A-3b | field |
|
| pdfa | PDF/A-3b | field |
|
||||||
| embeds | testdata/embed_1.xml | file |
|
| embeds | testdata/embed_1.xml | file |
|
||||||
Then the response status code should be 200
|
Then the response status code should be 200
|
||||||
|
|
||||||
|
# See: https://github.com/gotenberg/gotenberg/issues/1500.
|
||||||
|
Scenario: POST /forms/pdfengines/merge (Long Filename)
|
||||||
|
Given I have a default Gotenberg container
|
||||||
|
When I make a "POST" request to Gotenberg at the "/forms/pdfengines/merge" endpoint with the following form data and header(s):
|
||||||
|
| files | testdata/Longitudinell_jämförelse_mellan_laserkirurgi_och_strålbehandling_gällande_röstkvalitet_och_självskattad_kommunikation_upp_till_två_år_efter_tidig_stämbandscancer_i_ett_randomiserat_kontrollerat_försök.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/pdf"
|
||||||
|
Then there should be 1 PDF(s) in the response
|
||||||
|
|||||||
@@ -293,3 +293,21 @@ Feature: /forms/pdfengines/metadata/{write|read}
|
|||||||
| files | teststore/foo.pdf | file |
|
| files | teststore/foo.pdf | file |
|
||||||
Then the response status code should be 200
|
Then the response status code should be 200
|
||||||
Then the response header "Content-Type" should be "application/json"
|
Then the response header "Content-Type" should be "application/json"
|
||||||
|
|
||||||
|
# See: https://github.com/gotenberg/gotenberg/issues/1500.
|
||||||
|
Scenario: POST /forms/pdfengines/metadata/read (Long Filename)
|
||||||
|
Given I have a default Gotenberg container
|
||||||
|
When I make a "POST" request to Gotenberg at the "/forms/pdfengines/metadata/read" endpoint with the following form data and header(s):
|
||||||
|
| files | testdata/Longitudinell_jämförelse_mellan_laserkirurgi_och_strålbehandling_gällande_röstkvalitet_och_självskattad_kommunikation_upp_till_två_år_efter_tidig_stämbandscancer_i_ett_randomiserat_kontrollerat_försök.pdf | file |
|
||||||
|
Then the response status code should be 200
|
||||||
|
|
||||||
|
# See: https://github.com/gotenberg/gotenberg/issues/1500.
|
||||||
|
Scenario: POST /forms/pdfengines/metadata/write (Long Filename)
|
||||||
|
Given I have a default Gotenberg container
|
||||||
|
When I make a "POST" request to Gotenberg at the "/forms/pdfengines/metadata/write" endpoint with the following form data and header(s):
|
||||||
|
| files | testdata/Longitudinell_jämförelse_mellan_laserkirurgi_och_strålbehandling_gällande_röstkvalitet_och_självskattad_kommunikation_upp_till_två_år_efter_tidig_stämbandscancer_i_ett_randomiserat_kontrollerat_försök.pdf | file |
|
||||||
|
| metadata | {"Author":"Test"} | field |
|
||||||
|
| 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 1 PDF(s) in the response
|
||||||
|
|||||||
@@ -162,3 +162,14 @@ Feature: /forms/pdfengines/rotate
|
|||||||
| rotateAngle | 90 | field |
|
| rotateAngle | 90 | field |
|
||||||
Then the response status code should be 200
|
Then the response status code should be 200
|
||||||
Then the response header "Content-Type" should be "application/pdf"
|
Then the response header "Content-Type" should be "application/pdf"
|
||||||
|
|
||||||
|
# See: https://github.com/gotenberg/gotenberg/issues/1500.
|
||||||
|
Scenario: POST /forms/pdfengines/rotate (Long Filename)
|
||||||
|
Given I have a default Gotenberg container
|
||||||
|
When I make a "POST" request to Gotenberg at the "/forms/pdfengines/rotate" endpoint with the following form data and header(s):
|
||||||
|
| files | testdata/Longitudinell_jämförelse_mellan_laserkirurgi_och_strålbehandling_gällande_röstkvalitet_och_självskattad_kommunikation_upp_till_två_år_efter_tidig_stämbandscancer_i_ett_randomiserat_kontrollerat_försök.pdf | file |
|
||||||
|
| rotateAngle | 90 | field |
|
||||||
|
| 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 1 PDF(s) in the response
|
||||||
|
|||||||
@@ -764,3 +764,16 @@ Feature: /forms/pdfengines/split
|
|||||||
| pdfa | PDF/A-3b | field |
|
| pdfa | PDF/A-3b | field |
|
||||||
| embeds | testdata/embed_1.xml | file |
|
| embeds | testdata/embed_1.xml | file |
|
||||||
Then the response status code should be 200
|
Then the response status code should be 200
|
||||||
|
|
||||||
|
# See: https://github.com/gotenberg/gotenberg/issues/1500.
|
||||||
|
Scenario: POST /forms/pdfengines/split (Long Filename)
|
||||||
|
Given I have a default Gotenberg container
|
||||||
|
When I make a "POST" request to Gotenberg at the "/forms/pdfengines/split" endpoint with the following form data and header(s):
|
||||||
|
| files | testdata/Longitudinell_jämförelse_mellan_laserkirurgi_och_strålbehandling_gällande_röstkvalitet_och_självskattad_kommunikation_upp_till_två_år_efter_tidig_stämbandscancer_i_ett_randomiserat_kontrollerat_försök.pdf | file |
|
||||||
|
| splitMode | pages | field |
|
||||||
|
| splitSpan | 1 | field |
|
||||||
|
| splitUnify | true | field |
|
||||||
|
| 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 1 PDF(s) in the response
|
||||||
|
|||||||
Binary file not shown.
Reference in New Issue
Block a user