Description
The net/http HTTP server handles certain malformed HTTP requests completely autonomously, without ever passing control to non-library code. This means that the application is never made aware of them, so it cannot take any action, e.g. logging that a malformed request was received. It also prevents the application from customising the response.
For example, running a minimal Go HTTP server at localhost:8000 and doing this:
curl -v "http://localhost:8000/foo bar"
results in
* Trying 127.0.0.1...
* TCP_NODELAY set
* Connected to localhost (127.0.0.1) port 8000 (#0)
> GET /foo bar HTTP/1.1
> Host: localhost:8000
> User-Agent: curl/7.55.1
> Accept: */*
>
< HTTP/1.1 400 Bad Request
< Content-Type: text/plain; charset=utf-8
< Connection: close
<
* Closing connection 0
400 Bad Request
(The error is caused by the whitespace in the first line of the request - the parser naively splits it on space and expects [method, URI, protocol]).
This is a problem because:
- The application can't log the malformed request.
- I can't make a guarantee like "my API always returns JSON", because "400 Bad Request" is not valid JSON.
- The error message is very little help to the end user, and when the end user contacts me for support I have nothing to go on when diagnosing the problem because I couldn't log the request.
- Certain proxy_pass directives in Nginx do a silent (and probably unexpected) URL-decode on the request URI. So if you run a Go HTTP server behind an Nginx reverse proxy (surely a common scenario), the error above will be triggered by a correct-looking request with a %20 somewhere in it.
I propose adding an exported variable of type
func(error, http.ResponseWriter, []byte)
to http.Server. It can be set by the application before ListenAndServe or ListenAndServeTLS is called. If this is nil (the default), the current behaviour stays. If it is not nil, then it is called (with the error, responseWriter and, optionally, a byte slice containing the offending part of the request - or even all of it?) when the server encounters a malformed request which it cannot pass on to the handler.