-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathinterceptor.go
154 lines (133 loc) · 3.26 KB
/
interceptor.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
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
package gnock
import (
"bytes"
"encoding/json"
"fmt"
"io/ioutil"
"net/http"
"regexp"
)
type Interceptor struct {
scope *Scope
method string
path string
pathRegexp *regexp.Regexp
responder Responder
times int
}
type Responder func(*http.Request) (*http.Response, error)
func NewInterceptor(scope *Scope, method string, path string) *Interceptor {
return &Interceptor{
scope: scope,
method: method,
path: path,
times: 1,
}
}
func NewRegexpInterceptor(scope *Scope, method string, pathRegexp *regexp.Regexp) *Interceptor {
return &Interceptor{
scope: scope,
method: method,
pathRegexp: pathRegexp,
times: 1,
}
}
func (i *Interceptor) Times(times int) *Interceptor {
i.times = times
return i
}
func (i *Interceptor) Reply(status int, body string) *Scope {
return i.Respond(func(req *http.Request) (*http.Response, error) {
return &http.Response{
Request: req,
StatusCode: status,
Body: ioutil.NopCloser(bytes.NewBufferString(body)),
}, nil
})
}
func (i *Interceptor) ReplyError(err error) *Scope {
return i.Respond(func(req *http.Request) (*http.Response, error) {
return nil, err
})
}
func (i *Interceptor) ReplyJSON(status int, json interface{}) *Scope {
return i.Respond(func(req *http.Request) (*http.Response, error) {
return &http.Response{
Request: req,
StatusCode: status,
Body: ioutil.NopCloser(bytes.NewBufferString(jsonToString(json))),
Header: http.Header{"Content-Type": []string{"application/json"}},
}, nil
})
}
func (i *Interceptor) Respond(responder Responder) *Scope {
i.responder = responder
return i.scope
}
func (i *Interceptor) String() string {
methodAndURL := fmt.Sprintf("%s %s%s", i.method, i.scope.String(), i.describePath())
if i.whollyDefined() {
return methodAndURL + "\n"
}
return methodAndURL + " (partially defined)\n"
}
func (i *Interceptor) describePath() string {
if i.pathRegexp != nil {
return i.pathRegexp.String()
}
return i.path
}
func (i *Interceptor) intercepts(req *http.Request) bool {
if i.partiallyDefined() {
return false
}
if i.times < 1 {
return false
}
if !i.scope.intercepts(req) {
return false
}
if req.Method != i.method {
return false
}
if i.pathRegexp != nil {
return i.pathRegexp.MatchString(req.URL.Path)
}
return i.path == req.URL.Path
}
func (i *Interceptor) whollyDefined() bool {
return i.responder != nil
}
func (i *Interceptor) partiallyDefined() bool {
return !i.whollyDefined()
}
func (i *Interceptor) respond(req *http.Request) (*http.Response, error) {
i.times--
res, err := i.responder(req)
if err != nil {
// We must return res here since real HTTP requests might do that in some cases
return res, err
}
return i.setDefaultHeaders(res), nil
}
func (i *Interceptor) setDefaultHeaders(res *http.Response) *http.Response {
if len(i.scope.defaultHeaders) > 0 && res.Header == nil {
res.Header = make(http.Header, 0)
}
for headerKey, headerValues := range i.scope.defaultHeaders {
if len(res.Header[headerKey]) == 0 {
res.Header[headerKey] = headerValues
}
}
return res
}
func jsonToString(input interface{}) string {
if str, ok := input.(string); ok {
return str
}
buf, err := json.Marshal(input)
if err != nil {
panic(err.Error())
}
return string(buf)
}