Skip to content

net/http: unwrap ResponseWriter in MaxBytesReader for finding requestTooLarger #73754

Open
@EricGusmao

Description

@EricGusmao

Summary

http.MaxBytesReader in the standard library uses an internal interface (requestTooLarger) on the provided http.ResponseWriter to notify the server when a request body exceeds the specified limit. However, when a custom ResponseWriter wrapper is used, this internal callback is not invoked because the library does not unwrap the writer chain to find an implementation.

This causes the server to miss the "request too large" event, not closing the connection.

Proposal

Modify http.MaxBytesReader to recursively unwrap the given ResponseWriter if it implements an Unwrap() http.ResponseWriter method (similar to how http.ResponseController is handled), and call the internal requestTooLarge() callback on the innermost ResponseWriter that implements it.

This change would maintain backward compatibility, and improve behavior in common scenarios where middleware wraps the writer.

Motivation

When developers wrap http.ResponseWriter to implement middleware features like logging, metrics, or response modification, they typically embed the original ResponseWriter.

The current design of MaxBytesReader checks only the top-level writer for the internal requestTooLarger interface. As a result, an oversized request does not close the connection.

Example and Reproduction Steps

Here is a minimal example that illustrates the problem when wrapping ResponseWriter:

package main

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

type myWrapper struct {
	http.ResponseWriter
}

func handler(w http.ResponseWriter, r *http.Request) {
	wrapped := myWrapper{w}

	r.Body = http.MaxBytesReader(wrapped, r.Body, 10)

	body, err := io.ReadAll(r.Body)
	if err != nil {
		log.Println("Read error:", err)
	} else {
		log.Println("Read body:", string(body))
	}

	w.WriteHeader(http.StatusOK)
	w.Write([]byte("done"))
}

func main() {
	http.HandleFunc("/", handler)
	log.Fatal(http.ListenAndServe(":8080", nil))
}

Curl with a request body exceeding the limit doesn't close the connection.

I have a patch ready implementing this fix and can submit a PR upon approval.

Metadata

Metadata

Assignees

No one assigned

    Labels

    NeedsFixThe path to resolution is known, but the work has not been done.help wanted

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions