-
Notifications
You must be signed in to change notification settings - Fork 24
/
pat.go
128 lines (110 loc) · 3.31 KB
/
pat.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
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
// Copyright 2012 The Gorilla Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package pat
import (
"net/http"
"net/url"
"path"
"strings"
"github.com/gorilla/context"
"github.com/gorilla/mux"
)
// New returns a new router.
func New() *Router {
return &Router{
Router: *mux.NewRouter(),
}
}
// Router is a request router that implements a pat-like API.
//
// pat docs: http://godoc.org/github.com/bmizerany/pat
type Router struct {
mux.Router
}
// Add registers a pattern with a handler for the given request method.
func (r *Router) Add(meth, pat string, h http.Handler) *mux.Route {
return r.NewRoute().PathPrefix(pat).Handler(h).Methods(meth)
}
// Options registers a pattern with a handler for OPTIONS requests.
func (r *Router) Options(pat string, h http.HandlerFunc) *mux.Route {
return r.Add("OPTIONS", pat, h)
}
// Delete registers a pattern with a handler for DELETE requests.
func (r *Router) Delete(pat string, h http.HandlerFunc) *mux.Route {
return r.Add("DELETE", pat, h)
}
// Head registers a pattern with a handler for HEAD requests.
func (r *Router) Head(pat string, h http.HandlerFunc) *mux.Route {
return r.Add("HEAD", pat, h)
}
// Get registers a pattern with a handler for GET requests.
func (r *Router) Get(pat string, h http.HandlerFunc) *mux.Route {
return r.Add("GET", pat, h)
}
// Post registers a pattern with a handler for POST requests.
func (r *Router) Post(pat string, h http.HandlerFunc) *mux.Route {
return r.Add("POST", pat, h)
}
// Put registers a pattern with a handler for PUT requests.
func (r *Router) Put(pat string, h http.HandlerFunc) *mux.Route {
return r.Add("PUT", pat, h)
}
// Patch registers a pattern with a handler for PATCH requests.
func (r *Router) Patch(pat string, h http.HandlerFunc) *mux.Route {
return r.Add("PATCH", pat, h)
}
// ServeHTTP dispatches the handler registered in the matched route.
func (r *Router) ServeHTTP(w http.ResponseWriter, req *http.Request) {
// Clean path to canonical form and redirect.
if p := cleanPath(req.URL.Path); p != req.URL.Path {
w.Header().Set("Location", p)
w.WriteHeader(http.StatusMovedPermanently)
return
}
var match mux.RouteMatch
var handler http.Handler
if matched := r.Match(req, &match); matched {
handler = match.Handler
registerVars(req, match.Vars)
}
if handler == nil {
if r.NotFoundHandler == nil {
r.NotFoundHandler = http.NotFoundHandler()
}
handler = r.NotFoundHandler
}
defer context.Clear(req)
handler.ServeHTTP(w, req)
}
// registerVars adds the matched route variables to the URL query.
func registerVars(r *http.Request, vars map[string]string) {
parts, i := make([]string, len(vars)), 0
for key, value := range vars {
parts[i] = url.QueryEscape(":"+key) + "=" + url.QueryEscape(value)
i++
}
q := strings.Join(parts, "&")
if r.URL.RawQuery == "" {
r.URL.RawQuery = q
} else {
r.URL.RawQuery += "&" + q
}
}
// cleanPath returns the canonical path for p, eliminating . and .. elements.
// Borrowed from the net/http package.
func cleanPath(p string) string {
if p == "" {
return "/"
}
if p[0] != '/' {
p = "/" + p
}
np := path.Clean(p)
// path.Clean removes trailing slash except for root;
// put the trailing slash back if necessary.
if p[len(p)-1] == '/' && np != "/" {
np += "/"
}
return np
}