-
Notifications
You must be signed in to change notification settings - Fork 0
/
method.go
128 lines (112 loc) · 2.68 KB
/
method.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
package web
import (
"net/http"
"strings"
)
// Method is an http.Handler that routes requests according to the HTTP verb.
type Method struct {
// GetAsHead sets the Get handler to be used for HEAD requests if the Head
// handler is not defined.
GetAsHead bool
// Optional Method Handlers
Delete,
Get,
Head,
Options,
Patch,
Post,
Put http.Handler
// Any handler will respond to any method.
Any http.Handler
// MethodNotAllowed handler is called if the appropriate method handler is
// not defined. Defaults to list of defined methods.
MethodNotAllowed http.Handler
}
// ServeHTTP implements the http.Handler interface for Method.
// Explicit methods are tried first, then Any is used as a fallback.
// MethodNotAllowed is used for any missing method with defaults.
func (m *Method) ServeHTTP(w http.ResponseWriter, r *http.Request) {
var f http.Handler
switch r.Method {
case "DELETE":
f = m.Delete
case "HEAD":
f = m.Head
if f == nil && m.GetAsHead {
f = m.Get
}
case "GET":
f = m.Get
case "PATCH":
f = m.Patch
case "POST":
f = m.Post
case "PUT":
f = m.Put
case "OPTIONS":
f = m.Options
if f == nil {
// The default OPTIONS response.
// rfc2616 9.2
allowed := allowedMethods(m)
setAllowHeader(w, allowed...)
// empty body
return
}
}
if f == nil {
f = m.Any
}
if f == nil {
f = m.MethodNotAllowed
}
if f == nil {
allowed := allowedMethods(m)
MethodNotAllowed(w, r, allowed...)
return
}
f.ServeHTTP(w, r)
}
// MethodNotAllowed replies to the request with an HTTP 405 method not allowed
// error. An optional list of allowed methods will be set in the Allow header.
func MethodNotAllowed(w http.ResponseWriter, r *http.Request, allowed ...string) {
// rfc2616 14.7
setAllowHeader(w, allowed...)
http.Error(w, "405 method not allowed", http.StatusMethodNotAllowed)
}
// MethodNotAllowedHandler returns a http.Handler with a list of allowed
// methods set.
func MethodNotAllowedHandler(allowed ...string) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
MethodNotAllowed(w, r, allowed...)
})
}
func setAllowHeader(w http.ResponseWriter, allowed ...string) {
w.Header().Set("Allow", strings.Join(allowed, ", "))
}
func allowedMethods(m *Method) []string {
a := make([]string, 0, 6)
// not including OPTIONS for now, but open to discussion.
if m.Delete != nil {
a = append(a, "DELETE")
}
if m.Get != nil {
a = append(a, "GET")
if m.Head == nil && m.GetAsHead {
a = append(a, "HEAD")
}
}
if m.Head != nil {
a = append(a, "HEAD")
}
if m.Patch != nil {
a = append(a, "PATCH")
}
if m.Post != nil {
a = append(a, "POST")
}
if m.Put != nil {
a = append(a, "PUT")
}
return a
}