Files
summercms/modules/lagoon/attach/inline.go
Jakub Zych 903859a131 feat(lagoon/attach): export UploadWriterOptions for blob writers that bypass Store (quick-261106-d20)
- attach.UploadWriterOptions (was the unexported uploadWriterOptions) gives
  code that writes an upload to the bucket itself the same Content-Type and
  Content-Disposition: attachment for non-inline types that attach.Store stores
- writeBlob calls it; Store behaviour unchanged
- TestUploadWriterOptions table test
- lagoon README, docs/database/attachments.md and docs/services/storage.md
  describe it for writers that bypass attach.Store
2026-11-06 09:31:51 +01:00

50 lines
1.9 KiB
Go

package attach
import (
"mime"
"strings"
"gocloud.dev/blob"
)
// inlineContentTypes are the raster image types a browser may show inline
// from an upload.
var inlineContentTypes = map[string]bool{
"image/avif": true,
"image/gif": true,
"image/jpeg": true,
"image/png": true,
"image/webp": true,
}
// attachmentDisposition is the Content-Disposition stored with a non-inline
// upload. It is the bare value with no filename parameter: the client's file
// name never reaches blob metadata or a response header.
const attachmentDisposition = "attachment"
// IsInlineContentType reports whether contentType, with parameters and case
// ignored, is a raster image a browser may show inline from an upload (JPEG,
// PNG, GIF, WebP, AVIF). An empty or unparsable value is not. Store stores
// every other type, SVG, PDF, HTML and plain text included, with
// Content-Disposition: attachment, and the surf uploads route serves it as a
// download.
func IsInlineContentType(contentType string) bool {
mediaType, _, err := mime.ParseMediaType(contentType)
return err == nil && inlineContentTypes[strings.ToLower(mediaType)]
}
// UploadWriterOptions returns the blob writer options of an upload: the
// content type, plus Content-Disposition: attachment (no filename parameter)
// for every type IsInlineContentType does not report as inline. Store writes
// with these options. Code that writes an upload to the bucket itself, with
// NewWriter or WriteAll, passes the sniffed type (the value stored in
// content_type) and names the file with DiskExtension, so its blob is served
// like one Store wrote. Each call returns a new value the caller may extend.
func UploadWriterOptions(contentType string) *blob.WriterOptions {
opts := &blob.WriterOptions{ContentType: contentType}
if !IsInlineContentType(contentType) {
opts.ContentDisposition = attachmentDisposition
}
return opts
}