Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions modules/storage/azureblob.go
Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,7 @@ func (a *AzureBlobStorage) Delete(path string) error {
func (a *AzureBlobStorage) URL(path, name, _ string, reqParams url.Values) (*url.URL, error) {
blobClient := a.getBlobClient(path)

// TODO: OBJECT-STORAGE-CONTENT-TYPE: "browser inline rendering images/PDF" needs proper Content-Type header from storage
startTime := time.Now()
u, err := blobClient.GetSASURL(sas.BlobPermissions{
Read: true,
Expand Down
34 changes: 29 additions & 5 deletions modules/storage/minio.go
Original file line number Diff line number Diff line change
Expand Up @@ -279,20 +279,44 @@ func (m *MinioStorage) Delete(path string) error {
}

// URL gets the redirect URL to a file. The presigned link is valid for 5 minutes.
func (m *MinioStorage) URL(path, name, method string, serveDirectReqParams url.Values) (*url.URL, error) {
func (m *MinioStorage) URL(storePath, name, method string, serveDirectReqParams url.Values) (*url.URL, error) {
// copy serveDirectReqParams
reqParams, err := url.ParseQuery(serveDirectReqParams.Encode())
if err != nil {
return nil, err
}
// TODO it may be good to embed images with 'inline' like ServeData does, but we don't want to have to read the file, do we?
reqParams.Set("response-content-disposition", "attachment; filename=\""+quoteEscaper.Replace(name)+"\"")

// Here we might not know the real filename, and it's quite inefficient to detect the mine type by pre-fetching the object head.
// So we just do a quick detection by extension name, at least if works for the "View Raw File" for an LFS file on the Web UI.
// Detect content type by extension name, only support the well-known safe types for inline rendering.
// TODO: OBJECT-STORAGE-CONTENT-TYPE: need a complete solution and refactor for Azure in the future
ext := path.Ext(name)
inlineExtMimeTypes := map[string]string{
".png": "image/png",
".jpg": "image/jpeg",
".jpeg": "image/jpeg",
".gif": "image/gif",
".webp": "image/webp",
".avif": "image/avif",
// ATTENTION! Don't support unsafe types like HTML/SVG due to security concerns: they can contain JS code, and maybe they need proper Content-Security-Policy
// HINT: PDF-RENDER-SANDBOX: PDF won't render in sandboxed context, it seems fine to render it inline
".pdf": "application/pdf",

// TODO: refactor with "modules/public/mime_types.go", for example: "DetectWellKnownSafeInlineMimeType"
}
if mimeType, ok := inlineExtMimeTypes[ext]; ok {
reqParams.Set("response-content-type", mimeType)
reqParams.Set("response-content-disposition", "inline")
} else {
reqParams.Set("response-content-disposition", fmt.Sprintf(`attachment; filename="%s"`, quoteEscaper.Replace(name)))
}

expires := 5 * time.Minute
if method == http.MethodHead {
u, err := m.client.PresignedHeadObject(m.ctx, m.bucket, m.buildMinioPath(path), expires, reqParams)
u, err := m.client.PresignedHeadObject(m.ctx, m.bucket, m.buildMinioPath(storePath), expires, reqParams)
return u, convertMinioErr(err)
}
u, err := m.client.PresignedGetObject(m.ctx, m.bucket, m.buildMinioPath(path), expires, reqParams)
u, err := m.client.PresignedGetObject(m.ctx, m.bucket, m.buildMinioPath(storePath), expires, reqParams)
return u, convertMinioErr(err)
}

Expand Down
1 change: 1 addition & 0 deletions routers/web/repo/view.go
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ func getFileReader(ctx gocontext.Context, repoID int64, blob *git.Blob) (buf []b

meta, err := git_model.GetLFSMetaObjectByOid(ctx, repoID, pointer.Oid)
if err != nil { // fallback to a plain file
fi.lfsMeta = &pointer
log.Warn("Unable to access LFS pointer %s in repo %d: %v", pointer.Oid, repoID, err)
return buf, dataRc, fi, nil
}
Expand Down