backported fixes from v0.40.6

This commit is contained in:
Gani Georgiev committed 2026-10-23 13:35:25 +03:00
1 parent 92033215c9
commit 98308296c6
39 files changed
+158 -84

No files matched your search

+2 -2
View File
@@ -40,8 +40,8 @@ func TestNewFileFromPath(t *testing.T) {
if match, err := regexp.Match(normalizedNamePattern, []byte(f.Name)); !match {
t.Fatalf("Expected Name to match %v, got %q (%v)", normalizedNamePattern, f.Name, err)
}
if f.Size != 77 {
t.Fatalf("Expected Size %v, got %v", 77, f.Size)
if f.Size != 78 {
t.Fatalf("Expected Size %v, got %v", 78, f.Size)
}
if _, ok := f.Reader.(*filesystem.PathReader); !ok {
t.Fatalf("Expected Reader to be PathReader, got %v", f.Reader)
+24
View File
@@ -3,6 +3,7 @@ package filesystem
import (
"context"
"errors"
"fmt"
"image"
"io"
"mime/multipart"
@@ -23,6 +24,7 @@ import (
"github.com/pocketbase/pocketbase/tools/filesystem/internal/s3lite"
"github.com/pocketbase/pocketbase/tools/list"
"github.com/pocketbase/pocketbase/tools/routine"
"github.com/spf13/cast"
"gocloud.dev/blob"
"gocloud.dev/blob/fileblob"
)
@@ -478,6 +480,28 @@ func (s *System) createThumb(originalKey string, thumbKey, thumbSize string) err
}
defer r.Close()
// check image dimensions to minimize excessive memory usage
config, _, err := image.DecodeConfig(r)
if err != nil {
return fmt.Errorf("image headers decoding failed: %w", err)
}
maxPixels := cast.ToInt64(os.Getenv("PB_THUMBS_MAX_SOURCE_PIXELS"))
if maxPixels <= 0 {
maxPixels = 250 << 20
}
currentDimensions := int64(config.Width) * int64(config.Height)
if currentDimensions > maxPixels {
return fmt.Errorf("the original image is too large (%dx%d) and exceeds the total max allowed %d pixels", config.Width, config.Height, maxPixels)
}
// rewind
_, err = r.Seek(0, io.SeekStart)
if err != nil {
return fmt.Errorf("failed to rewind reader after config decode: %w", err)
}
// create imaging object from the original reader
// (note: only the first frame for animated image formats)
img, decodeErr := imaging.Decode(r, imaging.AutoOrientation(true))
+46 -7
View File
@@ -9,6 +9,7 @@ import (
"net/http/httptest"
"os"
"path/filepath"
"strconv"
"strings"
"testing"
@@ -368,7 +369,7 @@ func TestFileSystemServe(t *testing.T) {
map[string]string{
"Content-Disposition": "inline; filename=test_name.png",
"Content-Type": "image/png",
"Content-Length": "77",
"Content-Length": "78",
"Content-Security-Policy": csp,
"Cache-Control": cacheControl,
},
@@ -383,7 +384,7 @@ func TestFileSystemServe(t *testing.T) {
map[string]string{
"Content-Disposition": "attachment; filename=test_name_download.png",
"Content-Type": "image/png",
"Content-Length": "77",
"Content-Length": "78",
"Content-Security-Policy": csp,
"Cache-Control": cacheControl,
},
@@ -528,8 +529,8 @@ func TestFileSystemCopy(t *testing.T) {
if err != nil {
t.Fatalf("Missing copied file %q: %v", dst, err)
}
if f.Size() != 77 {
t.Fatalf("Expected file size %d, got %d", 77, f.Size())
if f.Size() != 78 {
t.Fatalf("Expected file size %d, got %d", 78, f.Size())
}
}
@@ -618,7 +619,7 @@ func TestFileSystemServeSingleRange(t *testing.T) {
t.Fatalf("Expected StatusCode %d, got %d", http.StatusPartialContent, result.StatusCode)
}
expectedRange := "bytes 0-20/77"
expectedRange := "bytes 0-20/78"
if cr := result.Header.Get("Content-Range"); cr != expectedRange {
t.Fatalf("Expected Content-Range %q, got %q", expectedRange, cr)
}
@@ -704,6 +705,44 @@ func TestFileSystemCreateThumb(t *testing.T) {
}
}
func TestFilesystemCreateThumbWithMaxPixelsLimit(t *testing.T) {
dir := createTestDir(t)
defer os.RemoveAll(dir)
fsys, err := filesystem.NewLocal(dir)
if err != nil {
t.Fatal(err)
}
defer fsys.Close()
scenarios := []struct {
name string
file string
thumb string
size string
maxPixels int
expectErr bool
}{
{"default limit", "image.png", "thumb_WxH", "100x100", 0, false},
{"below limit", "image.png", "thumb_WxH", "100x100", 24, true},
{"exact limit", "image.png", "thumb_WxH", "100x100", 25, false},
{"above limit", "image.png", "thumb_WxH", "100x100", 26, false},
}
for _, s := range scenarios {
t.Run(s.name, func(t *testing.T) {
os.Setenv("PB_THUMBS_MAX_SOURCE_PIXELS", strconv.Itoa(s.maxPixels))
err = fsys.CreateThumb(s.file, s.thumb, s.size)
hasErr := err != nil
if hasErr != s.expectErr {
t.Fatalf("Expected hasErr to be %v, got %v (%v)", s.expectErr, hasErr, err)
}
})
}
}
// ---
func createTestDir(t *testing.T) string {
@@ -732,7 +771,7 @@ func createTestDir(t *testing.T) string {
if err != nil {
t.Fatal(err)
}
imgRect := image.Rect(0, 0, 1, 1) // tiny 1x1 png
imgRect := image.Rect(0, 0, 5, 5) // tiny 5x5 png
png.Encode(file3, imgRect)
file3.Close()
err2 := os.WriteFile(filepath.Join(dir, "image.png.attrs"), []byte(`{"user.cache_control":"","user.content_disposition":"","user.content_encoding":"","user.content_language":"","user.content_type":"image/png","user.metadata":null}`), 0644)
@@ -756,7 +795,7 @@ func createTestDir(t *testing.T) string {
if err != nil {
t.Fatal(err)
}
png.Encode(file6, image.Rect(0, 0, 1, 1)) // tiny 1x1 png
png.Encode(file6, image.Rect(0, 0, 5, 5)) // tiny 5x5 png
file6.Close()
return dir