feat(export): server-rendered artifacts behind one signed download URL #160
@@ -176,11 +176,15 @@ func subtleNeq(got, want string) bool {
|
||||
return !hmac.Equal([]byte(got), []byte(want))
|
||||
}
|
||||
|
||||
// serveAttachment writes bytes as a named file download.
|
||||
// serveAttachment writes bytes as a named file download. Content-Length is set
|
||||
// explicitly: a body over net/http's write buffer otherwise goes out chunked, and
|
||||
// Android's system DownloadManager (which VKWebAppDownloadFile delegates to) hangs
|
||||
// forever on a download of unknown length.
|
||||
func serveAttachment(c *gin.Context, filename, contentType string, data []byte) {
|
||||
c.Header("X-Content-Type-Options", "nosniff")
|
||||
c.Header("Content-Disposition", `attachment; filename="`+sanitizeFilename(filename)+`"`)
|
||||
c.Header("Cache-Control", "private, max-age=0")
|
||||
c.Header("Content-Length", strconv.Itoa(len(data)))
|
||||
c.Data(http.StatusOK, contentType, data)
|
||||
}
|
||||
|
||||
|
||||
@@ -14,6 +14,7 @@ import (
|
||||
"io"
|
||||
"net"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
@@ -465,6 +466,9 @@ func (s *Server) exportDownloadHandler() http.Handler {
|
||||
}
|
||||
w.Header().Set("X-Content-Type-Options", "nosniff")
|
||||
w.Header().Set("Cache-Control", "private, max-age=0")
|
||||
// Explicit length, or the body goes out chunked and Android's system
|
||||
// DownloadManager (the VKWebAppDownloadFile executor) hangs on it.
|
||||
w.Header().Set("Content-Length", strconv.Itoa(len(data)))
|
||||
_, _ = w.Write(data)
|
||||
})
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user