go 37 lines · 1 tab

Safe multipart uploads using temp files (bounded memory)

Leah Thompson Jan 2026
1 tab
package api

import (
  "io"
  "net/http"
  "os"
)

func Upload(w http.ResponseWriter, r *http.Request) {
  r.Body = http.MaxBytesReader(w, r.Body, 20<<20) // 20 MiB
  if err := r.ParseMultipartForm(20 << 20); err != nil {
    http.Error(w, "invalid upload", http.StatusBadRequest)
    return
  }

  f, _, err := r.FormFile("file")
  if err != nil {
    http.Error(w, "missing file", http.StatusBadRequest)
    return
  }
  defer f.Close()

  tmp, err := os.CreateTemp("", "upload-*")
  if err != nil {
    http.Error(w, "server error", http.StatusInternalServerError)
    return
  }
  defer os.Remove(tmp.Name())
  defer tmp.Close()

  if _, err := io.Copy(tmp, f); err != nil {
    http.Error(w, "failed to save", http.StatusInternalServerError)
    return
  }

  w.WriteHeader(http.StatusCreated)
}
1 file · go Explain with highlit

Multipart uploads are a common DOS vector if you let them allocate unbounded memory. I cap the request with http.MaxBytesReader, keep ParseMultipartForm bounded, and copy the file stream into a temp file using io.Copy. This avoids holding the whole file in RAM and gives you an artifact you can scan, validate, and then push to object storage. The other detail is cleanup: if any validation fails, the temp file should be removed, and file descriptors must be closed. In production I also validate MIME type by sniffing the first bytes rather than trusting the client header, and I track upload metrics (bytes, errors) so abuse is visible. This pattern is pragmatic and safe for most services.


Related snips

Share this code

Here's the card — post it anywhere.

Safe multipart uploads using temp files (bounded memory) — share card
Link copied