store the correct image/png as attrs content type when generating a thumb fallback

This commit is contained in:
Gani Georgiev
2025-12-09 17:09:32 +02:00
parent abb6bcd6de
commit e89603497f
4 changed files with 68 additions and 23 deletions

View File

@@ -1,3 +1,8 @@
## v0.34.3 (WIP)
- Store the correct `image/png` as attrs content type when generating a thumb fallback _(e.g. for `webp`)_.
## v0.34.2
- Bumped JS SDK to v0.26.5 to fix Safari AbortError detection introduced with the previous release ([#7369](https://github.com/pocketbase/pocketbase/issues/7369)).

View File

@@ -52,8 +52,8 @@ func TestNewFileFromPath(t *testing.T) {
}
// existing file
originalName := "image_! noext"
normalizedNamePattern := regexp.QuoteMeta("image_noext_") + `\w{10}` + regexp.QuoteMeta(".png")
originalName := "image_!@ special"
normalizedNamePattern := regexp.QuoteMeta("image_special_") + `\w{10}` + regexp.QuoteMeta(".png")
f, err := filesystem.NewFileFromPath(filepath.Join(testDir, originalName))
if err != nil {
t.Fatalf("Expected nil error, got %v", err)
@@ -83,8 +83,8 @@ func TestNewFileFromBytes(t *testing.T) {
t.Fatal("Expected error, got nil")
}
originalName := "image_! noext"
normalizedNamePattern := regexp.QuoteMeta("image_noext_") + `\w{10}` + regexp.QuoteMeta(".txt")
originalName := "image_!@ special"
normalizedNamePattern := regexp.QuoteMeta("image_special_") + `\w{10}` + regexp.QuoteMeta(".txt")
f, err := filesystem.NewFileFromBytes([]byte("text\n"), originalName)
if err != nil {
t.Fatal(err)
@@ -175,8 +175,8 @@ func TestNewFileFromURLTimeout(t *testing.T) {
// valid response
{
originalName := "image_! noext"
normalizedNamePattern := regexp.QuoteMeta("image_noext_") + `\w{10}` + regexp.QuoteMeta(".txt")
originalName := "image_!@ special"
normalizedNamePattern := regexp.QuoteMeta("image_special_") + `\w{10}` + regexp.QuoteMeta(".txt")
f, err := filesystem.NewFileFromURL(context.Background(), srv.URL+"/"+originalName)
if err != nil {

View File

@@ -536,25 +536,38 @@ func (s *System) CreateThumb(originalKey string, thumbKey, thumbSize string) err
}
}
originalContentType := r.ContentType()
opts := &blob.WriterOptions{
ContentType: r.ContentType(),
ContentType: originalContentType,
}
// open a thumb storage writer (aka. prepare for upload)
w, writerErr := s.bucket.NewWriter(s.ctx, thumbKey, opts)
if writerErr != nil {
return writerErr
}
var format imaging.Format
// try to detect the thumb format based on the original file name
// (fallbacks to png on error)
format, err := imaging.FormatFromFilename(thumbKey)
if err != nil {
switch originalContentType {
case "image/jpeg":
format = imaging.JPEG
case "image/gif":
format = imaging.GIF
case "image/tiff":
format = imaging.TIFF
case "image/bmp":
format = imaging.BMP
default:
// fallback to PNG (this includes webp!)
opts.ContentType = "image/png"
format = imaging.PNG
}
// open a thumb storage writer (aka. prepare for upload)
w, err := s.bucket.NewWriter(s.ctx, thumbKey, opts)
if err != nil {
return err
}
// thumb encode (aka. upload)
if err := imaging.Encode(w, thumbImg, format); err != nil {
err = imaging.Encode(w, thumbImg, format)
if err != nil {
w.Close()
return err
}

View File

@@ -709,7 +709,8 @@ func TestFileSystemList(t *testing.T) {
"image.jpg",
"image.svg",
"image.webp",
"image_! noext",
"image_!@ special",
"image_noext",
"style.css",
"main.js",
"main.mjs",
@@ -861,6 +862,8 @@ func TestFileSystemCreateThumb(t *testing.T) {
{"image.jpg", "thumb.jpg", "100x100", "image/jpeg"},
// webp (should produce png)
{"image.webp", "thumb.webp", "100x100", "image/png"},
// without extension (should extract the mimetype from its stored ContentType)
{"image_noext", "image_noext.jpeg", "100x100", "image/jpeg"},
}
for _, s := range scenarios {
@@ -884,13 +887,20 @@ func TestFileSystemCreateThumb(t *testing.T) {
}
defer f.Close()
attrsMimeType := f.ContentType()
mt, err := mimetype.DetectReader(f)
if err != nil {
t.Fatalf("Failed to detect thumb %s mimetype (%v)", s.thumb, err)
}
fileMimeType := mt.String()
if mtStr := mt.String(); mtStr != s.expectedMimeType {
t.Fatalf("Expected thumb %s MimeType %q, got %q", s.thumb, s.expectedMimeType, mtStr)
if fileMimeType != s.expectedMimeType {
t.Fatalf("Expected thumb file %s MimeType %q, got %q", s.thumb, s.expectedMimeType, fileMimeType)
}
if attrsMimeType != s.expectedMimeType {
t.Fatalf("Expected thumb attrs %s MimeType %q, got %q", s.thumb, s.expectedMimeType, attrsMimeType)
}
})
}
@@ -975,16 +985,33 @@ func createTestDir(t *testing.T) string {
}
}
// no extension and invalid characters
// invalid/special characters
{
file, err := os.OpenFile(filepath.Join(dir, "image_! noext"), os.O_WRONLY|os.O_CREATE, 0644)
file, err := os.OpenFile(filepath.Join(dir, "image_!@ special"), os.O_WRONLY|os.O_CREATE, 0644)
if err != nil {
t.Fatal(err)
}
_ = png.Encode(file, image.Rect(0, 0, 1, 1)) // tiny 1x1 png
imgRect := image.Rect(0, 0, 1, 1) // tiny 1x1 png
_ = png.Encode(file, imgRect)
file.Close()
}
// no extension
{
fullPath := filepath.Join(dir, "image_noext")
file, err := os.OpenFile(fullPath, os.O_WRONLY|os.O_CREATE, 0644)
if err != nil {
t.Fatal(err)
}
imgRect := image.Rect(0, 0, 1, 1) // tiny 1x1 jpg
_ = jpeg.Encode(file, imgRect, nil)
file.Close()
err = os.WriteFile(fullPath+".attrs", []byte(`{"user.cache_control":"","user.content_disposition":"","user.content_encoding":"","user.content_language":"","user.content_type":"image/jpeg","user.metadata":null}`), 0644)
if err != nil {
t.Fatal(err)
}
}
// css
{
file, err := os.OpenFile(filepath.Join(dir, "style.css"), os.O_WRONLY|os.O_CREATE, 0644)