@@ -8,12 +8,10 @@ import (
88 "crypto/tls"
99 "fmt"
1010 "io"
11- "mime"
1211 "net/http"
1312 "net/url"
1413 "os"
1514 "path"
16- "path/filepath"
1715 "strings"
1816 "time"
1917
@@ -281,28 +279,41 @@ func (m *MinioStorage) Delete(path string) error {
281279}
282280
283281// URL gets the redirect URL to a file. The presigned link is valid for 5 minutes.
284- func (m * MinioStorage ) URL (path , name , method string , serveDirectReqParams url.Values ) (* url.URL , error ) {
282+ func (m * MinioStorage ) URL (storePath , name , method string , serveDirectReqParams url.Values ) (* url.URL , error ) {
285283 // copy serveDirectReqParams
286284 reqParams , err := url .ParseQuery (serveDirectReqParams .Encode ())
287285 if err != nil {
288286 return nil , err
289287 }
288+
289+ // Here we might not know the real filename, and it's quite inefficient to detect the mine type by pre-fetching the object head.
290+ // So we just do a quick detection by extension name, at least if works for the "View Raw File" for a LFS file on the Web UI.
290291 // Detect content type by extension name
291- contentDisposition := "attachment; filename=\" " + quoteEscaper .Replace (name ) + "\" "
292- ext := filepath .Ext (name )
293- mimetype := mime .TypeByExtension (ext )
294- reqParams .Set ("response-content-type" , mimetype )
295- if mimetype == "application/pdf" || strings .HasPrefix (mimetype , "image/" ) {
296- contentDisposition = "inline"
292+ ext := path .Ext (name )
293+ inlineExtMimeTypes := map [string ]string {
294+ ".png" : "image/png" ,
295+ ".jpg" : "image/jpeg" ,
296+ ".jpeg" : "image/jpeg" ,
297+ ".gif" : "image/gif" ,
298+ ".webp" : "iamge/webp" ,
299+ ".avif" : "image/avif" ,
300+ // don't support SVG because of security concerns: it can contain JS code, and maybe it needs proper Content-Security-Policy
301+ // HINT: PDF-RENDER-SANDBOX: PDF won't render in sandboxed context, it seems fine to render it inline
302+ ".pdf" : "application/pdf" ,
303+ }
304+ if mimeType , ok := inlineExtMimeTypes [ext ]; ok {
305+ reqParams .Set ("response-content-type" , mimeType )
306+ reqParams .Set ("response-content-disposition" , "inline" )
307+ } else {
308+ reqParams .Set ("response-content-disposition" , fmt .Sprintf (`attachment; filename="%s"` , quoteEscaper .Replace (name )))
297309 }
298310
299- reqParams .Set ("response-content-disposition" , contentDisposition )
300311 expires := 5 * time .Minute
301312 if method == http .MethodHead {
302- u , err := m .client .PresignedHeadObject (m .ctx , m .bucket , m .buildMinioPath (path ), expires , reqParams )
313+ u , err := m .client .PresignedHeadObject (m .ctx , m .bucket , m .buildMinioPath (storePath ), expires , reqParams )
303314 return u , convertMinioErr (err )
304315 }
305- u , err := m .client .PresignedGetObject (m .ctx , m .bucket , m .buildMinioPath (path ), expires , reqParams )
316+ u , err := m .client .PresignedGetObject (m .ctx , m .bucket , m .buildMinioPath (storePath ), expires , reqParams )
306317 return u , convertMinioErr (err )
307318}
308319
0 commit comments