mirror of
https://github.com/opencloud-eu/opencloud.git
synced 2026-11-05 20:12:58 -05:00
Merge pull request #3884 from opencloud-eu/fix/webdav-generator-passthrough
fix(webdav): stream announced types without a converter to the generator
This commit is contained in:
3 files changed
+44
-22
No files matched your search
@@ -393,9 +393,8 @@ func ForType(mimeType string, opts Options) FileConverter {
|
||||
case "audio/ogg":
|
||||
return AudioDecoder{}
|
||||
default:
|
||||
// webdav decodes no image: an image/* source is streamed to the
|
||||
// generator untouched, so a type without a converter here is one
|
||||
// nobody can make a preview of.
|
||||
// webdav decodes no image: a type without a converter is streamed to
|
||||
// the generator untouched, which answers whether it can read it.
|
||||
return nil
|
||||
}
|
||||
}
|
||||
@@ -471,10 +471,9 @@ func (w *ThumbnailWorkflow) generate(ctx context.Context, ref *providerv1beta1.R
|
||||
// imagor's default resize does.
|
||||
genURL := generator.BuildURL(w.generatorURL, int32(box.Dx()), int32(box.Dy()), operation, outputFormat, noUpscale)
|
||||
|
||||
// Produce the source image to send to the generator, never decoding an image
|
||||
// in webdav: real images (incl. gif) are streamed straight through undecoded;
|
||||
// non-image sources are converted to image bytes here so the generator always
|
||||
// receives an image.
|
||||
// Produce the source to send to the generator, never decoding an image in
|
||||
// webdav: anything without a converter is streamed straight through undecoded,
|
||||
// the few types with one (text, audio, geogebra) are turned into image bytes here.
|
||||
imgStream, srcType, cleanup, err := w.sourceImage(ctx, ref, auth, mimeType, tr.Filename, logger)
|
||||
if err != nil {
|
||||
logger.Error().Err(err).Msg("could not obtain source image for thumbnail")
|
||||
@@ -505,17 +504,19 @@ func (w *ThumbnailWorkflow) generate(ctx context.Context, ref *providerv1beta1.R
|
||||
return Thumbnail{Data: thumbBytes, ContentType: outputType}, nil
|
||||
}
|
||||
|
||||
// sourceImage returns a reader over the source image to send to the generator,
|
||||
// plus a cleanup func to release any resources (download body, temp buffer). It
|
||||
// never decodes an image in webdav:
|
||||
// - real images (image/*, incl. gif) are streamed straight through from storage
|
||||
// undecoded; the generator handles decoding and multi-frame gifs itself.
|
||||
// sourceImage returns a reader over the source to send to the generator, plus a
|
||||
// cleanup func to release any resources (download body, temp buffer). It never
|
||||
// decodes an image in webdav:
|
||||
// - a type without a converter (image/*, incl. gif, and whatever else the source
|
||||
// types announce) is streamed straight through from storage undecoded; the
|
||||
// generator decides whether it can read it.
|
||||
// - text/plain is rendered to an image here (the only true conversion).
|
||||
// - audio and geogebra sources have their embedded image extracted to bytes.
|
||||
func (w *ThumbnailWorkflow) sourceImage(ctx context.Context, ref *providerv1beta1.Reference, auth, mimeType, filename string, logger log.Logger) (io.Reader, string, func(), error) {
|
||||
m, _, _ := mime.ParseMediaType(mimeType)
|
||||
|
||||
if strings.HasPrefix(m, "image/") {
|
||||
converter := preprocessor.ForType(m, preprocessor.Options{FontMapFile: w.fontMapFile, MaxImageSize: w.maxInputSize})
|
||||
if converter == nil {
|
||||
body, err := w.fileDownloader.DownloadStream(ctx, ref, auth)
|
||||
if err != nil {
|
||||
return nil, "", nil, fmt.Errorf("download: %w", err)
|
||||
@@ -534,12 +535,6 @@ func (w *ThumbnailWorkflow) sourceImage(ctx context.Context, ref *providerv1beta
|
||||
return nil, "", nil, fmt.Errorf("read source: %w", err)
|
||||
}
|
||||
|
||||
converter := preprocessor.ForType(mimeType, preprocessor.Options{FontMapFile: w.fontMapFile, MaxImageSize: w.maxInputSize})
|
||||
if converter == nil {
|
||||
logger.Debug().Str("mimetype", mimeType).Msg("no converter for this type")
|
||||
return nil, "", nil, fmt.Errorf("%w: no converter for %s", ErrNotFound, mimeType)
|
||||
}
|
||||
|
||||
img, err := converter.Convert(bytes.NewReader(fileBytes))
|
||||
if err != nil || img == nil {
|
||||
logger.Debug().Err(err).Msg("could not convert file to image")
|
||||
|
||||
@@ -217,6 +217,7 @@ func setupPreprocessTest(
|
||||
if err := r.ParseMultipartForm(10 << 20); err == nil {
|
||||
for _, fh := range r.MultipartForm.File["image"] {
|
||||
captured.filename = filepath.Base(fh.Filename)
|
||||
captured.contentType = fh.Header.Get("Content-Type")
|
||||
file, ferr := fh.Open()
|
||||
if ferr != nil {
|
||||
continue
|
||||
@@ -235,9 +236,10 @@ func setupPreprocessTest(
|
||||
}
|
||||
|
||||
type capturedUpload struct {
|
||||
path string
|
||||
filename string
|
||||
data []byte
|
||||
path string
|
||||
filename string
|
||||
contentType string
|
||||
data []byte
|
||||
}
|
||||
|
||||
var _ = Describe("ThumbnailWorkflow", func() {
|
||||
@@ -789,6 +791,25 @@ var _ = Describe("ThumbnailWorkflow", func() {
|
||||
Expect(captured.data).To(Equal(pngBytes))
|
||||
})
|
||||
|
||||
It("streams an announced type without a converter through untouched", func() {
|
||||
pdfBytes := []byte("%PDF-1.4 not really a pdf")
|
||||
|
||||
wf2, captured := setupPreprocessTest(GinkgoT(), gatewayClient, logger, testCache, "application/pdf", "doc.pdf", pdfBytes)
|
||||
wf2.sourceTypes = thumbnail.NewSourceTypes([]string{"application/pdf"})
|
||||
|
||||
tr := &requests.ThumbnailRequest{
|
||||
Ref: spaceRef("storageid$spaceid!opaqueid", "doc.pdf"),
|
||||
Filename: "doc.pdf",
|
||||
Width: 64,
|
||||
Height: 64,
|
||||
}
|
||||
|
||||
_, err := wf2.Execute(context.Background(), tr, testToken, logger)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(captured.data).To(Equal(pdfBytes))
|
||||
Expect(captured.contentType).To(Equal("application/pdf"), "the generator sees the file's own type, not a guess")
|
||||
})
|
||||
|
||||
It("converts audio to cover art before posting", func() {
|
||||
mp3Bytes, err := os.ReadFile(filepath.Join("..", "..", "preprocessor", "test_assets", "empty.mp3"))
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
@@ -997,6 +1018,13 @@ var _ = Describe("ThumbnailWorkflow", func() {
|
||||
Height: 64,
|
||||
}
|
||||
|
||||
untouched := httptest.NewServer(http.HandlerFunc(func(http.ResponseWriter, *http.Request) {
|
||||
defer GinkgoRecover()
|
||||
Fail("a type outside the source types must never reach the generator")
|
||||
}))
|
||||
defer untouched.Close()
|
||||
wf.generatorURL = untouched.URL
|
||||
|
||||
_, err := wf.Execute(context.Background(), tr, testToken, logger)
|
||||
Expect(err).To(HaveOccurred())
|
||||
Expect(errors.Is(err, ErrUnsupportedFileType)).To(BeTrue())
|
||||
|
||||
Reference in new issue
Block a user