/
pathmux.go
57 lines (52 loc) · 1.9 KB
/
pathmux.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
package muxchainutil
import (
"net/http"
"strings"
)
// PathMux muxes patterns by globbing over variable components and adding those
// as query parameters to the request for handlers.
type PathMux struct {
*GlobMux
patternVariables map[string]map[int]string // maps pattern component index to variable name
}
// NewPathMux initializes a PathMux.
func NewPathMux() *PathMux {
return &PathMux{NewGlobMux(), make(map[string]map[int]string)}
}
// Handle registers a handler to a pattern. Patterns may conatain variable components
// specified by a leading colon. For instance, "/order/:id" would map to handlers the
// same as "/order/*" on a GlobMux, however, handlers will see requests as if
// the query were "/order/?id=".
//
// Handlers will also match if a partial query is provided. For instance, /order/x
// will match /order/:id/:name, and the name variable will be empty. Variables are always
// matched from left to right and the handler with the most matches wins (with static strings
// beating variables).
func (p *PathMux) Handle(pattern string, h http.Handler) {
patternParts := strings.Split(pattern, "/")
variables := make(map[int]string)
for i, part := range patternParts {
if strings.HasPrefix(part, ":") {
variables[i] = part[1:]
patternParts[i] = "*"
}
}
pattern = strings.Join(patternParts, "/")
p.patternVariables[pattern] = variables
p.GlobMux.Handle(pattern, h)
}
// ServeHTTP handles requests by adding path variables to the request and forwarding
// them to the matched handler. (See Handle)
func (p *PathMux) ServeHTTP(w http.ResponseWriter, req *http.Request) {
req.ParseForm()
h, pattern := p.Handler(req)
if variables, hasVariables := p.patternVariables[pattern]; hasVariables {
for i, part := range strings.Split(req.URL.Path, "/") {
if varname, ok := variables[i]; ok {
req.URL.Query().Set(varname, part)
req.Form.Set(varname, part)
}
}
}
h.ServeHTTP(w, req)
}