Enhance environment variable documentation and configuration
- 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:
@@ -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 {
|
||||
|
||||
Reference in New Issue
Block a user