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
This commit is contained in:
@@ -33,9 +33,14 @@ func IsInlineContentType(contentType string) bool {
|
||||
return err == nil && inlineContentTypes[strings.ToLower(mediaType)]
|
||||
}
|
||||
|
||||
// uploadWriterOptions are the blob writer options of an upload: the content
|
||||
// type, plus the attachment disposition when the type is not inline.
|
||||
func uploadWriterOptions(contentType string) *blob.WriterOptions {
|
||||
// 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
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package attach
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
@@ -40,6 +41,44 @@ func TestIsInlineContentType(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestUploadWriterOptions(t *testing.T) {
|
||||
cases := []struct {
|
||||
in string
|
||||
disposition string
|
||||
}{
|
||||
{"image/png", ""},
|
||||
{"image/jpeg", ""},
|
||||
{"image/gif", ""},
|
||||
{"image/avif", ""},
|
||||
{"IMAGE/WEBP; charset=binary", ""},
|
||||
{"text/html", "attachment"},
|
||||
{"text/xml", "attachment"},
|
||||
{"image/svg+xml", "attachment"},
|
||||
{"application/pdf", "attachment"},
|
||||
{"text/plain", "attachment"},
|
||||
{"application/octet-stream", "attachment"},
|
||||
{"", "attachment"},
|
||||
}
|
||||
for _, tc := range cases {
|
||||
got := UploadWriterOptions(tc.in)
|
||||
want := &blob.WriterOptions{ContentType: tc.in, ContentDisposition: tc.disposition}
|
||||
if !reflect.DeepEqual(got, want) {
|
||||
t.Errorf("UploadWriterOptions(%q) = %+v, want %+v", tc.in, got, want)
|
||||
}
|
||||
}
|
||||
|
||||
first := UploadWriterOptions("text/html")
|
||||
second := UploadWriterOptions("text/html")
|
||||
if first == second {
|
||||
t.Fatal("UploadWriterOptions returned the same pointer twice")
|
||||
}
|
||||
first.ContentDisposition = "inline"
|
||||
first.CacheControl = "no-store"
|
||||
if third := UploadWriterOptions("text/html"); third.ContentDisposition != "attachment" || third.CacheControl != "" {
|
||||
t.Errorf("mutating one result changed the next: %+v", third)
|
||||
}
|
||||
}
|
||||
|
||||
// TestWriteBlobDisposition is the driver half of the public-bucket fix: a
|
||||
// public bucket serves the headers Store stores with the object, so the
|
||||
// attachment disposition must survive the write on the real drivers. The
|
||||
|
||||
@@ -205,7 +205,7 @@ func Store(ctx context.Context, db *gorm.DB, bucket *blob.Bucket, in Upload, lim
|
||||
func writeBlob(ctx context.Context, bucket *blob.Bucket, key string, r io.Reader, contentType string, limit int64) (int64, error) {
|
||||
writeCtx, cancel := context.WithCancel(ctx)
|
||||
defer cancel()
|
||||
w, err := bucket.NewWriter(writeCtx, key, uploadWriterOptions(contentType))
|
||||
w, err := bucket.NewWriter(writeCtx, key, UploadWriterOptions(contentType))
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("attach: blob writer: %w", err)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user