Enhance environment variable documentation and configuration
Format / gofmt (push) Successful in 1m17s
CI / Build (push) Successful in 1m31s
CI / Go Tests (push) Successful in 1m36s

- Updated `.env.example` to include new environment variables for server access logging and security settings, ensuring comprehensive configuration options.
- Revised `docker-entrypoint.sh` to clarify the source of supported environment variables.
- Improved `README.md` to reflect the latest environment variable changes and maintain synchronization with the canonical list in `internal/config/config.go`.
- Added tests to ensure documentation consistency across `.env.example` and `README.md`, preventing future discrepancies.
This commit is contained in:
2026-07-15 16:24:55 -05:00
parent ad4355df17
commit 90eb56465b
11 changed files with 268 additions and 15 deletions
+30 -1
View File
@@ -172,6 +172,12 @@ func (s *Server) scratchPage(w http.ResponseWriter, r *http.Request) {
})
}
// multipartMaxMemory is how much of a multipart upload may live in RAM before
// the remainder spills to temporary files. It must NOT be tied to
// limits.max_upload_size: when that limit is multi-GiB, using it as maxMemory
// forces entire large files into process memory before storage compression.
const multipartMaxMemory = 32 << 20 // 32 MiB
func (s *Server) createScratch(w http.ResponseWriter, r *http.Request) {
r.Body = http.MaxBytesReader(w, r.Body, s.cfg.Limits.MaxUploadSizeBytes)
@@ -180,7 +186,7 @@ func (s *Server) createScratch(w http.ResponseWriter, r *http.Request) {
contentType := strings.TrimSpace(r.Header.Get("Content-Type"))
if strings.HasPrefix(contentType, "multipart/form-data") {
if err := r.ParseMultipartForm(s.cfg.Limits.MaxUploadSizeBytes); err != nil {
if err := r.ParseMultipartForm(multipartMaxMemory); err != nil {
s.writeCreateError(w, err)
return
}
@@ -315,6 +321,29 @@ func (s *Server) rawScratch(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Disposition", disposition)
}
w.Header().Set("Content-Type", meta.ContentType)
// Scratches larger than the raw cache cannot be retained in memory. Stream
// them from storage instead of io.ReadAll so multi-GiB downloads do not OOM.
// Range requests are only supported via the cache path (ServeContent needs a Seeker).
if meta.Size > s.cfg.Limits.RawCacheMaxBytes {
file, _, openErr := s.store.Open(meta.ID)
if openErr != nil {
if errors.Is(openErr, storage.ErrNotFound) {
s.rawCache.Delete(id)
w.WriteHeader(http.StatusGone)
return
}
http.Error(w, "failed to read scratch", http.StatusInternalServerError)
return
}
defer file.Close()
w.Header().Set("Accept-Ranges", "none")
w.Header().Set("Content-Length", fmt.Sprintf("%d", meta.Size))
w.WriteHeader(http.StatusOK)
_, _ = io.Copy(w, file)
return
}
content, err, _ := s.rawCache.GetOrLoad(meta.ID, func() ([]byte, error) {
file, _, openErr := s.store.Open(meta.ID)
if openErr != nil {