I am writing a web server wherein I need to register handlers at runtime. E.g. "/create" would create a new handler for all URLs like "/123/*" and so on. I need a corresponding "/destroy/123" which would unregister the handler for "/123/*".
Here's the code for handling "/create"
package main
import (
"fmt"
"net/http"
)
type MyHandler struct {
id int
}
func (hf *MyHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
fmt.Fprintln(w, r.URL.Path)
}
// Creates MyHandler instances and registers them as handlers at runtime
type HandlerFactory struct {
handler_id int
}
func (hf *HandlerFactory) ServeHTTP(w http.ResponseWriter, r *http.Request) {
hf.handler_id++
handler := MyHandler{hf.handler_id}
handle := fmt.Sprintf("/%d/", hf.handler_id)
http.Handle(handle, &handler)
}
func main() {
factory := HandlerFactory{0}
http.Handle("/create", &factory)
http.ListenAndServe("localhost:8080", nil)
}
I tried implementing my own multiplexer by embedding http.ServeMux
but it holds its pattern-to-Handler mapping in a private variable (ServeMux.m
)
What I would do is create a custom
ServerMux
. Copy the code fromGOROOT/src/pkg/net/http/server.go
. It starts on line 837 and ends at 939.The custom ServerMux would need a method for deregistration. This should be easy to implement. Just grab the lock and
del()
the map entry. For example (all code untested):In order to use this new mux, you would do something like this:
Modifying mux by calling
deregister()
from another goroutine is completely safe and will modify the wayListenAndServe()
routes messages.Maybe the unregistering can be "done" by registering a handler returning nothing (not writing anything to the ResponseWriter) or generating a 'not found' kind of response. Depends on your requirements and/or purpose/effect of the unregistering of a previously registered handler.
It appears you've already accepted an answer, but I wanted to propose an alternate solution.
I question the need for adding a custom muxer. In this example I'm using the gorilla muxer, however that's only because I'm familiar with its pattern matching. In theory you could match the pattern from the incoming URL without the need for replacing the default muxer.
My code maintains the handler functions in a map (string: the handler name => function literal)... This is suitable for using the default muxers HandleFunc method.
Sample input/output:
GET /register/123
GET /123
hello from123.
GET /destroy/123
GET /123
[nothing]