fix(webdav): stop refusing a type mapping on a guess about the generator

This commit is contained in:
Dominik Schmidt committed 2026-10-19 14:57:36 +02:00
1 parent 48f9990a41
commit ee4465f500
4 files changed
+3 -73

No files matched your search

+1 -1
View File
@@ -76,7 +76,7 @@ Three settings say what is made of what. They are merged onto the built-in defau
| `OC_THUMBNAIL_TYPE_MAPPING` | The type a thumbnail is returned in, per source type, as `mime:mime` entries, e.g. `image/vnd.microsoft.icon:image/png` |
| `OC_THUMBNAIL_GENERATOR_FORMATS` | The formats the generator writes, as `mime:format` entries, e.g. `image/webp:webp`. The format is the name its own `format(...)` filter uses |
Reading them as a chain: a source type is mapped to the type its thumbnail is returned in, and that type is asked for by the name the generator knows it under. An icon becomes `image/png`, which the generator is asked for as `format(png)`. A type nobody mapped becomes a JPEG, and a mapping onto a type the generator has no format name for is refused at startup, as long as previews are enabled.
Reading them as a chain: a source type is mapped to the type its thumbnail is returned in, and that type is asked for by the name the generator knows it under. An icon becomes `image/png`, which the generator is asked for as `format(png)`. A type nobody mapped becomes a JPEG, and so does a mapping onto a type this service has no format name for: what a generator behind the URL really writes is its own business, and a wrong guess here must not keep the service from starting.
The defaults return `image/png` for png and icon sources, keep `image/gif` for a gif and return `image/jpeg` for everything else, so a client must read the response's `Content-Type` instead of assuming the type it got before.
+2 -2
View File
@@ -43,8 +43,8 @@ type Config struct {
ThumbnailCacheS3SecretKey string `yaml:"thumbnail_cache_s3_secret_key" env:"WEBDAV_THUMBNAIL_CACHE_S3_SECRET_KEY" desc:"S3 secret key for thumbnail cache authentication." introductionVersion:"%%NEXT%%"`
ThumbnailSourceTypes []string `yaml:"thumbnail_source_types" env:"OC_THUMBNAIL_SOURCE_TYPES;WEBDAV_THUMBNAIL_SOURCE_TYPES" desc:"Additional mime types a preview is announced and attempted for, e.g. image/vnd.microsoft.icon for a generator that reads icons. The built-in list is included; this only adds to them. A type the running generator cannot read answers 404." introductionVersion:"%%NEXT%%"`
ThumbnailGeneratorFormats []string `yaml:"thumbnail_generator_formats" env:"OC_THUMBNAIL_GENERATOR_FORMATS;WEBDAV_THUMBNAIL_GENERATOR_FORMATS" desc:"The formats the thumbnail generator writes, as mime:format entries, e.g. image/webp:webp. The format is the name the generator's own format filter uses. A type that is not listed is one the generator cannot write, so a mapping onto it is refused at startup." introductionVersion:"%%NEXT%%"`
ThumbnailTypeMapping []string `yaml:"thumbnail_type_mapping" env:"OC_THUMBNAIL_TYPE_MAPPING;WEBDAV_THUMBNAIL_TYPE_MAPPING" desc:"The type a thumbnail is returned in, per type of the image it is made from, as mime:mime entries, e.g. image/vnd.microsoft.icon:image/png. The target is asked for by the name WEBDAV_THUMBNAIL_GENERATOR_FORMATS gives it. A type that is not listed becomes a JPEG; a target the generator cannot write is refused at startup." introductionVersion:"%%NEXT%%"`
ThumbnailGeneratorFormats []string `yaml:"thumbnail_generator_formats" env:"OC_THUMBNAIL_GENERATOR_FORMATS;WEBDAV_THUMBNAIL_GENERATOR_FORMATS" desc:"The formats the thumbnail generator writes, as mime:format entries, e.g. image/webp:webp. The format is the name the generator's own format filter uses. A type that is not listed is asked for as a JPEG instead, because what the generator behind the URL really writes is its own business." introductionVersion:"%%NEXT%%"`
ThumbnailTypeMapping []string `yaml:"thumbnail_type_mapping" env:"OC_THUMBNAIL_TYPE_MAPPING;WEBDAV_THUMBNAIL_TYPE_MAPPING" desc:"The type a thumbnail is returned in, per type of the image it is made from, as mime:mime entries, e.g. image/vnd.microsoft.icon:image/png. The target is asked for by the name WEBDAV_THUMBNAIL_GENERATOR_FORMATS gives it. A type that is not listed becomes a JPEG; a target this service has no format name for is asked for as a JPEG as well." introductionVersion:"%%NEXT%%"`
// the yaml key stays unprefixed, a config file written against it has to keep working
ThumbnailFontMapFile string `yaml:"font_map_file" env:"THUMBNAILS_TXT_FONTMAP_FILE;WEBDAV_THUMBNAIL_TXT_FONTMAP_FILE" desc:"The path to a font map file for txt thumbnails." introductionVersion:"%%NEXT%%"`
-22
View File
@@ -9,7 +9,6 @@ import (
"net/http"
"net/url"
"path"
"sort"
"strconv"
"strings"
"time"
@@ -183,9 +182,6 @@ func newThumbnailWorkflow(conf *config.Config, sourceTypes thumbnail.SourceTypes
typeMapping := thumbnail.NewTypeMapping(conf.ThumbnailTypeMapping)
formats := generator.NewFormats(conf.ThumbnailGeneratorFormats)
if err := checkTypeMapping(typeMapping, formats); err != nil {
return nil, err
}
s3cfg := cache.BuildS3CacheConfig(
conf.ThumbnailCacheS3Bucket,
@@ -228,24 +224,6 @@ func newThumbnailWorkflow(conf *config.Config, sourceTypes thumbnail.SourceTypes
)
}
// checkTypeMapping refuses a mapping that asks for a type the generator has no
// format name for: the thumbnail would silently become a JPEG instead.
func checkTypeMapping(mapping thumbnail.TypeMapping, formats generator.Formats) error {
var unknown []string
for source, target := range mapping.Targets() {
if target == "" || formats.For(target) != "" {
continue
}
unknown = append(unknown, fmt.Sprintf("%s (mapped from %s)", target, source))
}
if len(unknown) == 0 {
return nil
}
sort.Strings(unknown)
return fmt.Errorf("thumbnail type mapping: no generator format for %s", strings.Join(unknown, ", "))
}
// Webdav implements the business logic for Service.
type Webdav struct {
sourceTypes thumbnail.SourceTypes
@@ -1,48 +0,0 @@
package svc
import (
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
"github.com/opencloud-eu/opencloud/services/webdav/pkg/generator"
"github.com/opencloud-eu/opencloud/services/webdav/pkg/thumbnail"
)
var _ = Describe("checkTypeMapping", func() {
It("accepts the defaults", func() {
Expect(checkTypeMapping(thumbnail.NewTypeMapping(nil), generator.NewFormats(nil))).To(Succeed())
})
It("accepts a pair that was configured together", func() {
Expect(checkTypeMapping(
thumbnail.NewTypeMapping([]string{"image/png:image/webp"}),
generator.NewFormats([]string{"image/webp:webp"}),
)).To(Succeed())
})
It("refuses a target the generator has no format for", func() {
err := checkTypeMapping(
thumbnail.NewTypeMapping([]string{"image/png:image/webp"}),
generator.NewFormats(nil),
)
Expect(err).To(MatchError(ContainSubstring("no generator format for image/webp (mapped from image/png)")))
})
It("names every bad entry", func() {
err := checkTypeMapping(
thumbnail.NewTypeMapping([]string{"image/png:image/avif", "image/gif:image/webp"}),
generator.NewFormats(nil),
)
Expect(err).To(MatchError(ContainSubstring("image/avif (mapped from image/png)")))
Expect(err).To(MatchError(ContainSubstring("image/webp (mapped from image/gif)")))
})
It("takes an empty target as no override", func() {
Expect(checkTypeMapping(
thumbnail.NewTypeMapping([]string{"image/png:"}),
generator.NewFormats(nil),
)).To(Succeed())
})
})