fix(files): never cache file downloads in v1 or v2
Move the Cache-Control: no-cache header into the shared WriteFileDownload so every export and attachment download carries it, and add it to the standalone v1 export download writer too. Downloads must never be cached.
This commit is contained in:
parent
ee8dbf82ba
commit
4b92f23329
|
|
@ -132,6 +132,10 @@ func DownloadUserDataExport(c *echo.Context) error {
|
|||
return err
|
||||
}
|
||||
|
||||
// Downloads must never be cached; no-cache overrides the global no-store
|
||||
// directive while still allowing revalidation.
|
||||
c.Response().Header().Set("Cache-Control", "no-cache")
|
||||
|
||||
if config.FilesType.GetString() == "s3" {
|
||||
c.Response().Header().Set("Content-Disposition", "attachment; filename=\""+exportFile.Name+"\"")
|
||||
c.Response().Header().Set("Content-Type", exportFile.Mime)
|
||||
|
|
|
|||
|
|
@ -30,6 +30,10 @@ import (
|
|||
// (Range + If-Modified-Since for free), a manual 304 + io.Copy otherwise. It does
|
||||
// not close the reader; the caller owns it.
|
||||
func WriteFileDownload(w http.ResponseWriter, r *http.Request, f *files.File) {
|
||||
// Downloads must never be cached. no-cache overrides the global no-store
|
||||
// directive so revalidation (If-Modified-Since) still works.
|
||||
w.Header().Set("Cache-Control", "no-cache")
|
||||
|
||||
mimeToReturn := f.Mime
|
||||
if mimeToReturn == "" {
|
||||
mimeToReturn = "application/octet-stream"
|
||||
|
|
|
|||
|
|
@ -62,18 +62,18 @@ func toAttachmentUploadError(err error) AttachmentUploadError {
|
|||
|
||||
// WriteAttachmentDownload streams the attachment (or its inline image preview) to
|
||||
// the response and closes the file reader. The non-preview path delegates to
|
||||
// WriteFileDownload, adding the cache override that lets browsers cache attachments.
|
||||
// WriteFileDownload, which sets Cache-Control: no-cache; the preview branch returns
|
||||
// early, so it sets the same header itself.
|
||||
func WriteAttachmentDownload(w http.ResponseWriter, r *http.Request, ta *models.TaskAttachment, preview []byte) {
|
||||
defer func() { _ = ta.File.File.Close() }()
|
||||
|
||||
if preview != nil {
|
||||
w.Header().Set("Cache-Control", "no-cache")
|
||||
w.Header().Set("Content-Type", "image/png")
|
||||
w.Header().Set("Content-Length", strconv.Itoa(len(preview)))
|
||||
_, _ = w.Write(preview)
|
||||
return
|
||||
}
|
||||
|
||||
// Override the global no-store directive so browsers can cache attachments.
|
||||
w.Header().Set("Cache-Control", "no-cache")
|
||||
WriteFileDownload(w, r, ta.File)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -72,6 +72,7 @@ func TestHumaUserExport(t *testing.T) {
|
|||
require.Equal(t, http.StatusOK, rec.Code, "body: %s", rec.Body.String())
|
||||
assert.Equal(t, content, rec.Body.Bytes(), "the streamed export bytes must match")
|
||||
assert.Contains(t, rec.Header().Get("Content-Disposition"), "test")
|
||||
assert.Equal(t, "no-cache", rec.Header().Get("Cache-Control"), "downloads must never be cached")
|
||||
})
|
||||
|
||||
t.Run("Download with a wrong password is refused", func(t *testing.T) {
|
||||
|
|
|
|||
Loading…
Reference in New Issue