No such built-in callback is supported by the standard library, but you may create one easily.
Denying based on incoming (request) headers
This is simple. Just start your handler with validating the incoming requests headers. This is sufficient, because your handler function is called once incoming HTTP headers are processed (read) but not the request body. And to tell if an incoming header is missing, you'd have to read all the HTTP headers anyway.
Denying based on remote IP
If you want to reject a request based on remote IP, you may create and use your own http.Server
instance, and it has a Server.ConnState
field where you can set a callback function. This callback will be called for state changes detailed at http.ConnState
. StateNew
is fired for new connections, StateActive
is fired before any handler would be called. Although you cannot signal in the callback that you want to reject the request, you can always close the connection which is passed to the callback.
If you don't want to do this, you may still check and reject serving the request in the handler (before the request body is read / processed), for details see How to limit client IP address when using golang http package.
Denying based on outgoing (response) headers
What you may do is mock the http.ResponseWriter
. Before any data is sent back to the client as the response, HTTP status code and HTTP headers have to be written. This is triggered by the ResponseWriter.WriteHeader()
method. So wrap the original http.ResponseWriter
, provide your own implementation of WriteHeader()
in which you may check the headers that are set and are about to be sent. During the check if you find some header is missing, you may decide to send back an error and stop serving the data that would be written by "downstream" handlers.
This is an example mocked ResponseWriter
:
type MyResponseWriter struct {
http.ResponseWriter
err error
}
func (mrw *MyResponseWriter) WriteHeader(statusCode int) {
// Inspect headers:
headers := mrw.Header()
if len(headers["myheader"]) == 0 {
mrw.ResponseWriter.WriteHeader(http.StatusInternalServerError)
mrw.err = fmt.Errorf("myheader was not set")
return
}
// Headers ok, let call "through":
mrw.ResponseWriter.WriteHeader(statusCode)
}
func (mrw *MyResponseWriter) Write(p []byte) (int, error) {
if mrw.err != nil {
return 0, mrw.err
}
return mrw.ResponseWriter.Write(p)
}
What it does is in MyResponseWriter.WriteHeader()
it looks for the HTTP header "myheader"
. If this is missing, reports HTTP 500 internal server error
to the client, and skips all Write()
(filters out response that would be sent by the handler).
Here's a simple example using it for a specific handler:
func fooHandler(w http.ResponseWriter, r *http.Request) {
}
func main() {
http.HandleFunc("/foo", func(w http.ResponseWriter, r *http.Request) {
w2 := &MyResponseWriter{ResponseWriter: w}
fooHandler(w2, r)
})
// ...
}
Note that to save resources, MyResponseWriter
should communicate that it will not "forward" data to the client, so subsequent handlers could omit writing data. This could be achieved by providing a method which handlers could check using a type assertion, or it may replace the request's context and cancel that (handlers must "monitor" the context for this to work of course).
Also see Golang read request body multiple times (which details mocking the request and response).