forked from mccutchen/go-httpbin
-
Notifications
You must be signed in to change notification settings - Fork 0
/
httpbin.go
197 lines (160 loc) · 5.59 KB
/
httpbin.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
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
package httpbin
import (
"net/http"
"net/url"
"time"
)
// Default configuration values
const (
DefaultMaxMemory int64 = 1024 * 1024
DefaultMaxDuration = 10 * time.Second
)
const jsonContentType = "application/json; encoding=utf-8"
const htmlContentType = "text/html; charset=utf-8"
type headersResponse struct {
Headers http.Header `json:"headers"`
}
type ipResponse struct {
Origin string `json:"origin"`
}
type userAgentResponse struct {
UserAgent string `json:"user-agent"`
}
type getResponse struct {
Args url.Values `json:"args"`
Headers http.Header `json:"headers"`
Origin string `json:"origin"`
URL string `json:"url"`
}
// A generic response for any incoming request that might contain a body
type bodyResponse struct {
Args url.Values `json:"args"`
Headers http.Header `json:"headers"`
Origin string `json:"origin"`
URL string `json:"url"`
Data string `json:"data"`
Files map[string][]string `json:"files"`
Form map[string][]string `json:"form"`
JSON interface{} `json:"json"`
}
type cookiesResponse map[string]string
type authResponse struct {
Authorized bool `json:"authorized"`
User string `json:"user"`
}
type gzipResponse struct {
Headers http.Header `json:"headers"`
Origin string `json:"origin"`
Gzipped bool `json:"gzipped"`
}
type deflateResponse struct {
Headers http.Header `json:"headers"`
Origin string `json:"origin"`
Deflated bool `json:"deflated"`
}
// An actual stream response body will be made up of one or more of these
// structs, encoded as JSON and separated by newlines
type streamResponse struct {
ID int `json:"id"`
Args url.Values `json:"args"`
Headers http.Header `json:"headers"`
Origin string `json:"origin"`
URL string `json:"url"`
}
// Options are used to configure HTTPBin
type Options struct {
// How much memory a request is allowed to consume in bytes, as a limit on
// the size of incoming request bodies and on responses generated
MaxMemory int64
// Maximum duration of a request, for those requests that allow user
// control over timing (e.g. /delay)
MaxDuration time.Duration
}
// HTTPBin contains the business logic
type HTTPBin struct {
options *Options
}
// Handler returns an http.Handler that exposes all HTTPBin endpoints
func (h *HTTPBin) Handler() http.Handler {
mux := http.NewServeMux()
mux.HandleFunc("/", methods(h.Index, "GET"))
mux.HandleFunc("/forms/post", methods(h.FormsPost, "GET"))
mux.HandleFunc("/encoding/utf8", methods(h.UTF8, "GET"))
mux.HandleFunc("/get", methods(h.Get, "GET"))
mux.HandleFunc("/post", methods(h.RequestWithBody, "POST"))
mux.HandleFunc("/put", methods(h.RequestWithBody, "PUT"))
mux.HandleFunc("/patch", methods(h.RequestWithBody, "PATCH"))
mux.HandleFunc("/delete", methods(h.RequestWithBody, "DELETE"))
mux.HandleFunc("/ip", h.IP)
mux.HandleFunc("/user-agent", h.UserAgent)
mux.HandleFunc("/headers", h.Headers)
mux.HandleFunc("/response-headers", h.ResponseHeaders)
mux.HandleFunc("/status/", h.Status)
mux.HandleFunc("/redirect/", h.Redirect)
mux.HandleFunc("/relative-redirect/", h.RelativeRedirect)
mux.HandleFunc("/absolute-redirect/", h.AbsoluteRedirect)
mux.HandleFunc("/redirect-to", h.RedirectTo)
mux.HandleFunc("/cookies", h.Cookies)
mux.HandleFunc("/cookies/set", h.SetCookies)
mux.HandleFunc("/cookies/delete", h.DeleteCookies)
mux.HandleFunc("/basic-auth/", h.BasicAuth)
mux.HandleFunc("/hidden-basic-auth/", h.HiddenBasicAuth)
mux.HandleFunc("/digest-auth/", h.DigestAuth)
mux.HandleFunc("/deflate", h.Deflate)
mux.HandleFunc("/gzip", h.Gzip)
mux.HandleFunc("/stream/", h.Stream)
mux.HandleFunc("/delay/", h.Delay)
mux.HandleFunc("/drip", h.Drip)
mux.HandleFunc("/range/", h.Range)
mux.HandleFunc("/bytes/", h.Bytes)
mux.HandleFunc("/stream-bytes/", h.StreamBytes)
mux.HandleFunc("/html", h.HTML)
mux.HandleFunc("/robots.txt", h.Robots)
mux.HandleFunc("/deny", h.Deny)
mux.HandleFunc("/cache", h.Cache)
mux.HandleFunc("/cache/", h.CacheControl)
mux.HandleFunc("/etag/", h.ETag)
mux.HandleFunc("/links/", h.Links)
mux.HandleFunc("/image", h.ImageAccept)
mux.HandleFunc("/image/", h.Image)
mux.HandleFunc("/xml", h.XML)
// existing httpbin endpoints that we do not support
mux.HandleFunc("/brotli", notImplementedHandler)
// Make sure our ServeMux doesn't "helpfully" redirect these invalid
// endpoints by adding a trailing slash. See the ServeMux docs for more
// info: https://golang.org/pkg/net/http/#ServeMux
mux.HandleFunc("/absolute-redirect", http.NotFound)
mux.HandleFunc("/basic-auth", http.NotFound)
mux.HandleFunc("/delay", http.NotFound)
mux.HandleFunc("/digest-auth", http.NotFound)
mux.HandleFunc("/hidden-basic-auth", http.NotFound)
mux.HandleFunc("/redirect", http.NotFound)
mux.HandleFunc("/relative-redirect", http.NotFound)
mux.HandleFunc("/status", http.NotFound)
mux.HandleFunc("/stream", http.NotFound)
mux.HandleFunc("/bytes", http.NotFound)
mux.HandleFunc("/stream-bytes", http.NotFound)
mux.HandleFunc("/links", http.NotFound)
// Apply global middleware
var handler http.Handler
handler = mux
handler = limitRequestSize(h.options.MaxMemory, handler)
handler = logger(handler)
handler = cors(handler)
return handler
}
// NewHTTPBin creates a new HTTPBin instance with default options
func NewHTTPBin() *HTTPBin {
return &HTTPBin{
options: &Options{
MaxMemory: DefaultMaxMemory,
MaxDuration: DefaultMaxDuration,
},
}
}
// NewHTTPBinWithOptions creates a new HTTPBin instance with the given options
func NewHTTPBinWithOptions(options *Options) *HTTPBin {
return &HTTPBin{
options: options,
}
}