go’s http server does not buffer the entire request body by default—your handler runs immediately, and `r.body` is a streaming reader; however, uncontrolled slow clients (e.g., slowloris) can exhaust resources if you don’t enforce timeouts or limit read behavior.
In Go’s net/http package, the http.Request.Body is not pre-buffered into memory. Instead, it’s an io.ReadCloser backed by the underlying network connection—essentially a lazy, on-demand stream. When your ServeHTTP method is called, the HTTP server has already parsed the request headers and started reading the body, but it does not wait for the full body to arrive before invoking your handler. This means:
⚠️ Critical implication for security & resource usage:
If a malicious client sends a large Content-Length (e.g., 9 MB) but transmits bytes extremely slowly (one byte every 10 seconds), Go will keep the connection—and the associated goroutine and OS file descriptor—alive until the body is fully read or the connection closes. Since each active request consumes memory (stack, buffers, TLS state) and goroutines are cheap but not free, 10,000 such stalled connections can indeed exhaust memory, file descriptors, or CPU scheduler capacity, enabling Slowloris-style denial-of-service.
✅ The correct defense is timeout configuration — not buffering logic in your handler:
server := &http.Server{
Addr: ":8080",
Handler: &MyHandler{},
ReadTimeout: 5 * time.Second, // terminates slow header/body reads
WriteTimeout: 10 * time.Second, // protects response writes
IdleTimeout: 30 * time.Second, // enforces keep-alive idle limits
}
log.Fatal(server.ListenAndServe())? Additional hardening tips:
limitedBody := http.MaxBytesReader(w, r.Body, 10<<20) // max 10 MB
data, err := io.ReadAll(limitedBody)
if err == http.ErrBodyReadAfterClose {
// client closed early — handle gracefully
}
memory buffers for multipart data.In summary: Go gives you streaming control — not automatic buffering — making your handler responsible for safe, bounded consumption of request bodies. Combine ReadTimeout, MaxBytesReader, and defensive reading patterns to build resilient, production-ready HTTP handlers.