Fix #221: image pastes scale to fit, no code box, accurate size, raw serves image
CI / test (pull_request) Successful in 49s
CI / docker (pull_request) Skipped

- paste view: image attachments render in a scalable preview (max-height
  min(70vh, 720px), object-fit contain) and the code box is omitted;
  wrap/copy buttons hidden for image pastes
- SizeHuman/stats summary show the attachment size for file pastes
  (row.Content is empty for file pastes, was showing 0 B)
- /raw/{id} on a file paste streams the attachment bytes inline with its
  sniffed mime and filename instead of an empty text/plain body
This commit is contained in:
fen
2026-09-10 14:16:31 -05:00
parent 7c7e60375c
commit 6d9f9592b5
4 changed files with 77 additions and 5 deletions
+32
View File
@@ -9,6 +9,7 @@ import (
"errors"
"fmt"
"html/template"
"io"
"net/http"
"os"
"strconv"
@@ -443,6 +444,37 @@ func (a *apiServer) handleRaw(w http.ResponseWriter, r *http.Request) {
http.Error(w, "not found", 404)
return
}
// #221: file pastes store the bytes in the blob store, not row.Content.
// Raw on an image paste serves the attachment file itself (inline), the
// same as the paste-view preview link, instead of an empty body.
if row.Content == "" {
att, err := a.store.GetAttachmentForPaste(row.ID)
if err != nil {
http.Error(w, "db error", 500)
return
}
if att == nil {
http.Error(w, "not found", 404)
return
}
blobs := a.store.Blobs()
if blobs == nil {
http.Error(w, "blob storage unavailable", 500)
return
}
blob, err := blobs.Get(att.PasteID + "/" + att.SHA256)
if err != nil {
http.Error(w, "not found", 404)
return
}
defer blob.Close()
w.Header().Set("Content-Type", serveContentType(att.Mime))
w.Header().Set("X-Content-Type-Options", "nosniff")
w.Header().Set("Content-Disposition", fmt.Sprintf("inline; filename=%q", att.Filename))
a.store.IncrementViews(row.ID, "", 0)
io.Copy(w, blob)
return
}
// #49 decision: raw reads count against the read budget too, with the
// same per-viewer dedupe window as page views. #58: a reader that loses
// the burn claim must not receive the content.