2

Is there a way to intercept a bad HEAD request in a Go HTTP server? A bad request here would be to send a JSON payload with a HEAD request. I call this a Bad Request, but when I attempt a HEAD request with a body via curl, I get this error. However, no logging occurs in Go.

package main

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

func handler(w http.ResponseWriter, r *http.Request) {
    log.Println(r.Method, r.URL)
    _, _ = fmt.Fprintf(w, "Hello")
}

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

If I send a curl request without a body, it works as expected and a log entry is generated 2019/11/28 10:58:59 HEAD / .

$ curl -v -X HEAD  http://localhost:8080
curl -i -X HEAD  http://localhost:8080
Warning: Setting custom HTTP method to HEAD with -X/--request may not work the
Warning: way you want. Consider using -I/--head instead.
HTTP/1.1 200 OK
Date: Thu, 28 Nov 2019 16:03:22 GMT
Content-Length: 5
Content-Type: text/plain; charset=utf-8

However, if I send a curl request with a body, then I get a Bad Request status but no log is updated.

$ curl -i -X HEAD  http://localhost:8080 -d '{}'
Warning: Setting custom HTTP method to HEAD with -X/--request may not work the
Warning: way you want. Consider using -I/--head instead.
HTTP/1.1 400 Bad Request
Content-Type: text/plain; charset=utf-8
Connection: close

400 Bad Request

I want to catch this error so I can send my own custom error message back. How can I intercept this?

Jonathan Hall
  • 75,165
  • 16
  • 143
  • 189
user3137124
  • 515
  • 1
  • 7
  • 13
  • 2
    Check the warning curl is giving you. '-X HEAD' "Specifies a custom request method"; whereas '-d' "Sends the specified data in a POST request". So this means you are requesting two different request types (POST and HEAD). I don't know what curl is actually sending to the application but the 400 indicates that it's invalid - https://stackoverflow.com/questions/286982/curl-post-data-and-headers-only might help. – Brits Nov 28 '19 at 19:05

1 Answers1

3

You can't. The HTTP server of the standard lib does not provide any interception point or callback for this case.

The invalid request is "killed" before your handler would be called. You can see this in server.go, conn.serve() method:

    w, err := c.readRequest(ctx)
    // ...
    if err != nil {
        switch {
        // ...
        default:
            publicErr := "400 Bad Request"
            if v, ok := err.(badRequestError); ok {
                publicErr = publicErr + ": " + string(v)
            }

            fmt.Fprintf(c.rwc, "HTTP/1.1 "+publicErr+errorHeaders+publicErr)
            return
        }
    }
    // ...
    serverHandler{c.server}.ServeHTTP(w, w.req)

Go's HTTP server provides you an implementation to handle incoming requests from clients that use / adhere to the HTTP protocol. All browsers and notable clients follow the HTTP protocol. It's not the implementation's goal to provide a fully customizable server.

icza
  • 389,944
  • 63
  • 907
  • 827