/
methodmux.go
81 lines (70 loc) · 2.37 KB
/
methodmux.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
package muxchainutil
import (
"fmt"
"net/http"
"strings"
)
// MethodMux allows the caller to specify handlers that are specific to a particular HTTP method
type MethodMux struct {
methods map[string]*http.ServeMux
NotFoundHandler http.Handler
}
// NewMethodMux returns a new MethodMux
func NewMethodMux() *MethodMux {
methods := make(map[string]*http.ServeMux)
methods["*"] = http.NewServeMux()
return &MethodMux{methods, http.HandlerFunc(NoopHandler)}
}
func NoopHandler(w http.ResponseWriter, req *http.Request) {
}
// Handle registers a pattern to a particular handler. The pattern may optionally begin with an HTTP
// method, followed by a space, e.g.: "GET /homepage". The method may be *, which matches all methods.
// The method may also be omitted, which is the same as *.
func (m *MethodMux) Handle(pattern string, h http.Handler) {
s := strings.SplitN(pattern, " ", 2)
if len(s) < 2 {
m.handle("*", s[0], h)
} else {
m.handle(s[0], s[1], h)
}
}
func (m *MethodMux) ServeHTTP(w http.ResponseWriter, req *http.Request) {
h, _ := m.Handler(req)
h.ServeHTTP(w, req)
}
func (m *MethodMux) HandleFunc(pattern string, handler func(http.ResponseWriter, *http.Request)) {
m.Handle(pattern, http.HandlerFunc(handler))
}
// HandleMethods registers a pattern to a handler for the given methods.
func (m *MethodMux) HandleMethods(pattern string, h http.Handler, methods ...string) {
for _, method := range methods {
m.Handle(fmt.Sprintf("%s %s", method, pattern), h)
}
}
func (m *MethodMux) handle(method string, pattern string, h http.Handler) {
muxer, ok := m.methods[method]
if !ok {
muxer = http.NewServeMux()
m.methods[method] = muxer
}
muxer.Handle(pattern, h)
}
// Handler selects a handler for a request. It will first attempt to chose a handler
// that matches the particular method. If a handler is not found, pattern will be
// the empty string.
func (m *MethodMux) Handler(req *http.Request) (h http.Handler, pattern string) {
h, pattern = m.handleMethod(req.Method, req)
if pattern != "" {
return
}
return m.handleMethod("*", req)
}
// handleMethod selects a handler for a request for a particular method, ignoring the method
// actually on the request.
func (m *MethodMux) handleMethod(method string, req *http.Request) (h http.Handler, pattern string) {
muxer, ok := m.methods[method]
if !ok {
return m.NotFoundHandler, ""
}
return muxer.Handler(req)
}