Skip to content

net/http: allow user-defined behaviour on malformed HTTP requests #25116

Closed as not planned
@mjwbyrne

Description

@mjwbyrne

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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    FeatureRequestIssues asking for a new feature that does not need a proposal.NeedsInvestigationSomeone must examine and confirm this is a valid issue and not a duplicate of an existing one.

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions