@cryptotaxi247 / kubo / commits / d7913c893

Migrate rs/cors to gx

License: MIT Signed-off-by: Jakub Sztandera <kubuxu@protonmail.ch>

Jakub Sztandera committed May 25, 2016 at 19:55 UTC d7913c893ae71f825d7bee5811ebf8fb010b117d
19 files changed +10 -1139
Godeps/Godeps.json
-4
@@ -69,10 +69,6 @@
69 "ImportPath": "github.com/mtchavez/jenkins",
70 "Rev": "5a816af6ef21ef401bff5e4b7dd255d63400f497"
71 },
72 - {
73 - "ImportPath": "github.com/rs/cors",
74 - "Rev": "5e4ce6bc0ecd3472f6f943666d84876691be2ced"
75 - },
72 {
73 "ImportPath": "github.com/syndtr/goleveldb/leveldb",
74 "Rev": "4875955338b0a434238a31165cb87255ab6e9e4a"
Godeps/_workspace/src/github.com/rs/cors/.travis.yml deleted
-4
@@ -1,4 +0,0 @@
1 -language: go
2 -go:
3 -- 1.3
4 -- 1.4
Godeps/_workspace/src/github.com/rs/cors/LICENSE deleted
-19
@@ -1,19 +0,0 @@
1 -Copyright (c) 2014 Olivier Poitrey <rs@dailymotion.com>
2 -
3 -Permission is hereby granted, free of charge, to any person obtaining a copy
4 -of this software and associated documentation files (the "Software"), to deal
5 -in the Software without restriction, including without limitation the rights
6 -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 -copies of the Software, and to permit persons to whom the Software is furnished
8 -to do so, subject to the following conditions:
9 -
10 -The above copyright notice and this permission notice shall be included in all
11 -copies or substantial portions of the Software.
12 -
13 -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19 -THE SOFTWARE.
Godeps/_workspace/src/github.com/rs/cors/README.md deleted
-96
@@ -1,96 +0,0 @@
1 -# Go CORS handler [![godoc](http://img.shields.io/badge/godoc-reference-blue.svg?style=flat)](https://godoc.org/github.com/rs/cors) [![license](http://img.shields.io/badge/license-MIT-red.svg?style=flat)](https://raw.githubusercontent.com/rs/cors/master/LICENSE) [![build](https://img.shields.io/travis/rs/cors.svg?style=flat)](https://travis-ci.org/rs/cors)
2 -
3 -CORS is a `net/http` handler implementing [Cross Origin Resource Sharing W3 specification](http://www.w3.org/TR/cors/) in Golang.
4 -
5 -## Getting Started
6 -
7 -After installing Go and setting up your [GOPATH](http://golang.org/doc/code.html#GOPATH), create your first `.go` file. We'll call it `server.go`.
8 -
9 -```go
10 -package main
11 -
12 -import (
13 - "net/http"
14 -
15 - "github.com/rs/cors"
16 -)
17 -
18 -func main() {
19 - h := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
20 - w.Header().Set("Content-Type", "application/json")
21 - w.Write([]byte("{\"hello\": \"world\"}"))
22 - })
23 -
24 - // cors.Default() setup the middleware with default options being
25 - // all origins accepted with simple methods (GET, POST). See
26 - // documentation below for more options.
27 - handler := cors.Default().Handler(h)
28 - http.ListenAndServe(":8080", handler)
29 -}
30 -```
31 -
32 -Install `cors`:
33 -
34 - go get github.com/rs/cors
35 -
36 -Then run your server:
37 -
38 - go run server.go
39 -
40 -The server now runs on `localhost:8080`:
41 -
42 - $ curl -D - -H 'Origin: http://foo.com' http://localhost:8080/
43 - HTTP/1.1 200 OK
44 - Access-Control-Allow-Origin: foo.com
45 - Content-Type: application/json
46 - Date: Sat, 25 Oct 2014 03:43:57 GMT
47 - Content-Length: 18
48 -
49 - {"hello": "world"}
50 -
51 -### More Examples
52 -
53 -* `net/http`: [examples/nethttp/server.go](https://github.com/rs/cors/blob/master/examples/nethttp/server.go)
54 -* [Goji](https://goji.io): [examples/goji/server.go](https://github.com/rs/cors/blob/master/examples/goji/server.go)
55 -* [Martini](http://martini.codegangsta.io): [examples/martini/server.go](https://github.com/rs/cors/blob/master/examples/martini/server.go)
56 -* [Negroni](https://github.com/codegangsta/negroni): [examples/negroni/server.go](https://github.com/rs/cors/blob/master/examples/negroni/server.go)
57 -* [Alice](https://github.com/justinas/alice): [examples/alice/server.go](https://github.com/rs/cors/blob/master/examples/alice/server.go)
58 -
59 -## Parameters
60 -
61 -Parameters are passed to the middleware thru the `cors.New` method as follow:
62 -
63 -```go
64 -c := cors.New(cors.Options{
65 - AllowedOrigins: []string{"http://foo.com"},
66 - AllowCredentials: true,
67 -})
68 -
69 -// Insert the middleware
70 -handler = c.Handler(handler)
71 -```
72 -
73 -* **AllowedOrigins** `[]string`: A list of origins a cross-domain request can be executed from. If the special `*` value is present in the list, all origins will be allowed. The default value is `*`.
74 -* **AllowOriginFunc** `func (origin string) bool`: A custom function to validate the origin. It take the origin as argument and returns true if allowed or false otherwise. If this option is set, the content of `AllowedOrigins` is ignored
75 -* **AllowedMethods** `[]string`: A list of methods the client is allowed to use with cross-domain requests.
76 -* **AllowedHeaders** `[]string`: A list of non simple headers the client is allowed to use with cross-domain requests. Default value is simple methods (`GET` and `POST`)
77 -* **ExposedHeaders** `[]string`: Indicates which headers are safe to expose to the API of a CORS API specification
78 -* **AllowCredentials** `bool`: Indicates whether the request can include user credentials like cookies, HTTP authentication or client side SSL certificates. The default is `false`.
79 -* **MaxAge** `int`: Indicates how long (in seconds) the results of a preflight request can be cached. The default is `0` which stands for no max age.
80 -
81 -See [API documentation](http://godoc.org/github.com/rs/cors) for more info.
82 -
83 -## Benchmarks
84 -
85 - BenchmarkWithout 20000000 64.6 ns/op 8 B/op 1 allocs/op
86 - BenchmarkDefault 3000000 469 ns/op 114 B/op 2 allocs/op
87 - BenchmarkAllowedOrigin 3000000 608 ns/op 114 B/op 2 allocs/op
88 - BenchmarkPreflight 20000000 73.2 ns/op 0 B/op 0 allocs/op
89 - BenchmarkPreflightHeader 20000000 73.6 ns/op 0 B/op 0 allocs/op
90 - BenchmarkParseHeaderList 2000000 847 ns/op 184 B/op 6 allocs/op
91 - BenchmarkParse…Single 5000000 290 ns/op 32 B/op 3 allocs/op
92 - BenchmarkParse…Normalized 2000000 776 ns/op 160 B/op 6 allocs/op
93 -
94 -## Licenses
95 -
96 -All source code is licensed under the [MIT License](https://raw.github.com/rs/cors/master/LICENSE).
Godeps/_workspace/src/github.com/rs/cors/bench_test.go deleted
-88
@@ -1,88 +0,0 @@
1 -package cors
2 -
3 -import (
4 - "net/http"
5 - "testing"
6 -)
7 -
8 -type FakeResponse struct {
9 - header http.Header
10 -}
11 -
12 -func (r FakeResponse) Header() http.Header {
13 - return r.header
14 -}
15 -
16 -func (r FakeResponse) WriteHeader(n int) {
17 -}
18 -
19 -func (r FakeResponse) Write(b []byte) (n int, err error) {
20 - return len(b), nil
21 -}
22 -
23 -func BenchmarkWithout(b *testing.B) {
24 - res := FakeResponse{http.Header{}}
25 - req, _ := http.NewRequest("GET", "http://example.com/foo", nil)
26 -
27 - b.ReportAllocs()
28 - b.ResetTimer()
29 - for i := 0; i < b.N; i++ {
30 - testHandler.ServeHTTP(res, req)
31 - }
32 -}
33 -
34 -func BenchmarkDefault(b *testing.B) {
35 - res := FakeResponse{http.Header{}}
36 - req, _ := http.NewRequest("GET", "http://example.com/foo", nil)
37 - req.Header.Add("Origin", "somedomain.com")
38 - handler := Default().Handler(testHandler)
39 -
40 - b.ReportAllocs()
41 - b.ResetTimer()
42 - for i := 0; i < b.N; i++ {
43 - handler.ServeHTTP(res, req)
44 - }
45 -}
46 -
47 -func BenchmarkAllowedOrigin(b *testing.B) {
48 - res := FakeResponse{http.Header{}}
49 - req, _ := http.NewRequest("GET", "http://example.com/foo", nil)
50 - req.Header.Add("Origin", "somedomain.com")
51 - c := New(Options{
52 - AllowedOrigins: []string{"somedomain.com"},
53 - })
54 - handler := c.Handler(testHandler)
55 -
56 - b.ReportAllocs()
57 - b.ResetTimer()
58 - for i := 0; i < b.N; i++ {
59 - handler.ServeHTTP(res, req)
60 - }
61 -}
62 -
63 -func BenchmarkPreflight(b *testing.B) {
64 - res := FakeResponse{http.Header{}}
65 - req, _ := http.NewRequest("OPTIONS", "http://example.com/foo", nil)
66 - req.Header.Add("Access-Control-Request-Method", "GET")
67 - handler := Default().Handler(testHandler)
68 -
69 - b.ReportAllocs()
70 - b.ResetTimer()
71 - for i := 0; i < b.N; i++ {
72 - handler.ServeHTTP(res, req)
73 - }
74 -}
75 -
76 -func BenchmarkPreflightHeader(b *testing.B) {
77 - res := FakeResponse{http.Header{}}
78 - req, _ := http.NewRequest("OPTIONS", "http://example.com/foo", nil)
79 - req.Header.Add("Access-Control-Request-Method", "GET")
80 - req.Header.Add("Access-Control-Request-Headers", "Accept")
81 - handler := Default().Handler(testHandler)
82 -
83 - b.ReportAllocs()
84 - b.ResetTimer()
85 - for i := 0; i < b.N; i++ {
86 - handler.ServeHTTP(res, req)
87 - }
88 -}
Godeps/_workspace/src/github.com/rs/cors/cors.go deleted
-345
@@ -1,345 +0,0 @@
1 -/*
2 -Package cors is net/http handler to handle CORS related requests
3 -as defined by http://www.w3.org/TR/cors/
4 -
5 -You can configure it by passing an option struct to cors.New:
6 -
7 - c := cors.New(cors.Options{
8 - AllowedOrigins: []string{"foo.com"},
9 - AllowedMethods: []string{"GET", "POST", "DELETE"},
10 - AllowCredentials: true,
11 - })
12 -
13 -Then insert the handler in the chain:
14 -
15 - handler = c.Handler(handler)
16 -
17 -See Options documentation for more options.
18 -
19 -The resulting handler is a standard net/http handler.
20 -*/
21 -package cors
22 -
23 -import (
24 - "log"
25 - "net/http"
26 - "os"
27 - "strconv"
28 - "strings"
29 -)
30 -
31 -// Options is a configuration container to setup the CORS middleware.
32 -type Options struct {
33 - // AllowedOrigins is a list of origins a cross-domain request can be executed from.
34 - // If the special "*" value is present in the list, all origins will be allowed.
35 - // Default value is ["*"]
36 - AllowedOrigins []string
37 - // AllowOriginFunc is a custom function to validate the origin. It take the origin
38 - // as argument and returns true if allowed or false otherwise. If this option is
39 - // set, the content of AllowedOrigins is ignored.
40 - AllowOriginFunc func(origin string) bool
41 - // AllowedMethods is a list of methods the client is allowed to use with
42 - // cross-domain requests. Default value is simple methods (GET and POST)
43 - AllowedMethods []string
44 - // AllowedHeaders is list of non simple headers the client is allowed to use with
45 - // cross-domain requests.
46 - // If the special "*" value is present in the list, all headers will be allowed.
47 - // Default value is [] but "Origin" is always appended to the list.
48 - AllowedHeaders []string
49 - // ExposedHeaders indicates which headers are safe to expose to the API of a CORS
50 - // API specification
51 - ExposedHeaders []string
52 - // AllowCredentials indicates whether the request can include user credentials like
53 - // cookies, HTTP authentication or client side SSL certificates.
54 - AllowCredentials bool
55 - // MaxAge indicates how long (in seconds) the results of a preflight request
56 - // can be cached
57 - MaxAge int
58 - // Debugging flag adds additional output to debug server side CORS issues
59 - Debug bool
60 -}
61 -
62 -type Cors struct {
63 - // Debug logger
64 - log *log.Logger
65 - // Set to true when allowed origins contains a "*"
66 - allowedOriginsAll bool
67 - // Normalized list of allowed origins
68 - allowedOrigins []string
69 - // Optional origin validator function
70 - allowOriginFunc func(origin string) bool
71 - // Set to true when allowed headers contains a "*"
72 - allowedHeadersAll bool
73 - // Normalized list of allowed headers
74 - allowedHeaders []string
75 - // Normalized list of allowed methods
76 - allowedMethods []string
77 - // Normalized list of exposed headers
78 - exposedHeaders []string
79 - allowCredentials bool
80 - maxAge int
81 -}
82 -
83 -// New creates a new Cors handler with the provided options.
84 -func New(options Options) *Cors {
85 - c := &Cors{
86 - exposedHeaders: convert(options.ExposedHeaders, http.CanonicalHeaderKey),
87 - allowOriginFunc: options.AllowOriginFunc,
88 - allowCredentials: options.AllowCredentials,
89 - maxAge: options.MaxAge,
90 - }
91 - if options.Debug {
92 - c.log = log.New(os.Stdout, "[cors] ", log.LstdFlags)
93 - }
94 -
95 - // Normalize options
96 - // NOTE: For origins and methods matching, the spec requires a case-sensitive matching.
97 - // As it may error prone, we chose to ignore the spec here.
98 -
99 - // Allowed Origins
100 - if len(options.AllowedOrigins) == 0 {
101 - // Default is all origins
102 - c.allowedOriginsAll = true
103 - } else {
104 - c.allowedOrigins = convert(options.AllowedOrigins, strings.ToLower)
105 - for _, o := range c.allowedOrigins {
106 - if o == "*" {
107 - c.allowedOriginsAll = true
108 - c.allowedOrigins = nil
109 - break
110 - }
111 - }
112 - }
113 -
114 - // Allowed Headers
115 - if len(options.AllowedHeaders) == 0 {
116 - // Use sensible defaults
117 - c.allowedHeaders = []string{"Origin", "Accept", "Content-Type"}
118 - } else {
119 - // Origin is always appended as some browsers will always request for this header at preflight
120 - c.allowedHeaders = convert(append(options.AllowedHeaders, "Origin"), http.CanonicalHeaderKey)
121 - for _, h := range options.AllowedHeaders {
122 - if h == "*" {
123 - c.allowedHeadersAll = true
124 - c.allowedHeaders = nil
125 - break
126 - }
127 - }
128 - }
129 -
130 - // Allowed Methods
131 - if len(options.AllowedMethods) == 0 {
132 - // Default is spec's "simple" methods
133 - c.allowedMethods = []string{"GET", "POST"}
134 - } else {
135 - c.allowedMethods = convert(options.AllowedMethods, strings.ToUpper)
136 - }
137 -
138 - return c
139 -}
140 -
141 -// Default creates a new Cors handler with default options
142 -func Default() *Cors {
143 - return New(Options{})
144 -}
145 -
146 -// Handler apply the CORS specification on the request, and add relevant CORS headers
147 -// as necessary.
148 -func (c *Cors) Handler(h http.Handler) http.Handler {
149 - return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
150 - if r.Method == "OPTIONS" {
151 - c.logf("Handler: Preflight request")
152 - c.handlePreflight(w, r)
153 - // Preflight requests are standalone and should stop the chain as some other
154 - // middleware may not handle OPTIONS requests correctly. One typical example
155 - // is authentication middleware ; OPTIONS requests won't carry authentication
156 - // headers (see #1)
157 - } else {
158 - c.logf("Handler: Actual request")
159 - c.handleActualRequest(w, r)
160 - h.ServeHTTP(w, r)
161 - }
162 - })
163 -}
164 -
165 -// Martini compatible handler
166 -func (c *Cors) HandlerFunc(w http.ResponseWriter, r *http.Request) {
167 - if r.Method == "OPTIONS" {
168 - c.logf("HandlerFunc: Preflight request")
169 - c.handlePreflight(w, r)
170 - } else {
171 - c.logf("HandlerFunc: Actual request")
172 - c.handleActualRequest(w, r)
173 - }
174 -}
175 -
176 -// Negroni compatible interface
177 -func (c *Cors) ServeHTTP(w http.ResponseWriter, r *http.Request, next http.HandlerFunc) {
178 - if r.Method == "OPTIONS" {
179 - c.logf("ServeHTTP: Preflight request")
180 - c.handlePreflight(w, r)
181 - // Preflight requests are standalone and should stop the chain as some other
182 - // middleware may not handle OPTIONS requests correctly. One typical example
183 - // is authentication middleware ; OPTIONS requests won't carry authentication
184 - // headers (see #1)
185 - } else {
186 - c.logf("ServeHTTP: Actual request")
187 - c.handleActualRequest(w, r)
188 - next(w, r)
189 - }
190 -}
191 -
192 -// handlePreflight handles pre-flight CORS requests
193 -func (c *Cors) handlePreflight(w http.ResponseWriter, r *http.Request) {
194 - headers := w.Header()
195 - origin := r.Header.Get("Origin")
196 -
197 - if r.Method != "OPTIONS" {
198 - c.logf(" Preflight aborted: %s!=OPTIONS", r.Method)
199 - return
200 - }
201 - if origin == "" {
202 - c.logf(" Preflight aborted: empty origin")
203 - return
204 - }
205 - if !c.isOriginAllowed(origin) {
206 - c.logf(" Preflight aborted: origin '%s' not allowed", origin)
207 - return
208 - }
209 -
210 - reqMethod := r.Header.Get("Access-Control-Request-Method")
211 - if !c.isMethodAllowed(reqMethod) {
212 - c.logf(" Preflight aborted: method '%s' not allowed", reqMethod)
213 - return
214 - }
215 - reqHeaders := parseHeaderList(r.Header.Get("Access-Control-Request-Headers"))
216 - if !c.areHeadersAllowed(reqHeaders) {
217 - c.logf(" Preflight aborted: headers '%v' not allowed", reqHeaders)
218 - return
219 - }
220 - headers.Set("Access-Control-Allow-Origin", origin)
221 - headers.Add("Vary", "Origin")
222 - // Spec says: Since the list of methods can be unbounded, simply returning the method indicated
223 - // by Access-Control-Request-Method (if supported) can be enough
224 - headers.Set("Access-Control-Allow-Methods", strings.ToUpper(reqMethod))
225 - if len(reqHeaders) > 0 {
226 -
227 - // Spec says: Since the list of headers can be unbounded, simply returning supported headers
228 - // from Access-Control-Request-Headers can be enough
229 - headers.Set("Access-Control-Allow-Headers", strings.Join(reqHeaders, ", "))
230 - }
231 - if c.allowCredentials {
232 - headers.Set("Access-Control-Allow-Credentials", "true")
233 - }
234 - if c.maxAge > 0 {
235 - headers.Set("Access-Control-Max-Age", strconv.Itoa(c.maxAge))
236 - }
237 - c.logf(" Preflight response headers: %v", headers)
238 -}
239 -
240 -// handleActualRequest handles simple cross-origin requests, actual request or redirects
241 -func (c *Cors) handleActualRequest(w http.ResponseWriter, r *http.Request) {
242 - headers := w.Header()
243 - origin := r.Header.Get("Origin")
244 -
245 - if r.Method == "OPTIONS" {
246 - c.logf(" Actual request no headers added: method == %s", r.Method)
247 - return
248 - }
249 - if origin == "" {
250 - c.logf(" Actual request no headers added: missing origin")
251 - return
252 - }
253 - if !c.isOriginAllowed(origin) {
254 - c.logf(" Actual request no headers added: origin '%s' not allowed", origin)
255 - return
256 - }
257 -
258 - // Note that spec does define a way to specifically disallow a simple method like GET or
259 - // POST. Access-Control-Allow-Methods is only used for pre-flight requests and the
260 - // spec doesn't instruct to check the allowed methods for simple cross-origin requests.
261 - // We think it's a nice feature to be able to have control on those methods though.
262 - if !c.isMethodAllowed(r.Method) {
263 - if c.log != nil {
264 - c.logf(" Actual request no headers added: method '%s' not allowed",
265 - r.Method)
266 - }
267 -
268 - return
269 - }
270 - headers.Set("Access-Control-Allow-Origin", origin)
271 - headers.Add("Vary", "Origin")
272 - if len(c.exposedHeaders) > 0 {
273 - headers.Set("Access-Control-Expose-Headers", strings.Join(c.exposedHeaders, ", "))
274 - }
275 - if c.allowCredentials {
276 - headers.Set("Access-Control-Allow-Credentials", "true")
277 - }
278 - c.logf(" Actual response added headers: %v", headers)
279 -}
280 -
281 -// convenience method. checks if debugging is turned on before printing
282 -func (c *Cors) logf(format string, a ...interface{}) {
283 - if c.log != nil {
284 - c.log.Printf(format, a...)
285 - }
286 -}
287 -
288 -// isOriginAllowed checks if a given origin is allowed to perform cross-domain requests
289 -// on the endpoint
290 -func (c *Cors) isOriginAllowed(origin string) bool {
291 - if c.allowOriginFunc != nil {
292 - return c.allowOriginFunc(origin)
293 - }
294 - if c.allowedOriginsAll {
295 - return true
296 - }
297 - origin = strings.ToLower(origin)
298 - for _, o := range c.allowedOrigins {
299 - if o == origin {
300 - return true
301 - }
302 - }
303 - return false
304 -}
305 -
306 -// isMethodAllowed checks if a given method can be used as part of a cross-domain request
307 -// on the endpoing
308 -func (c *Cors) isMethodAllowed(method string) bool {
309 - if len(c.allowedMethods) == 0 {
310 - // If no method allowed, always return false, even for preflight request
311 - return false
312 - }
313 - method = strings.ToUpper(method)
314 - if method == "OPTIONS" {
315 - // Always allow preflight requests
316 - return true
317 - }
318 - for _, m := range c.allowedMethods {
319 - if m == method {
320 - return true
321 - }
322 - }
323 - return false
324 -}
325 -
326 -// areHeadersAllowed checks if a given list of headers are allowed to used within
327 -// a cross-domain request.
328 -func (c *Cors) areHeadersAllowed(requestedHeaders []string) bool {
329 - if c.allowedHeadersAll || len(requestedHeaders) == 0 {
330 - return true
331 - }
332 - for _, header := range requestedHeaders {
333 - header = http.CanonicalHeaderKey(header)
334 - found := false
335 - for _, h := range c.allowedHeaders {
336 - if h == header {
337 - found = true
338 - }
339 - }
340 - if !found {
341 - return false
342 - }
343 - }
344 - return true
345 -}
Godeps/_workspace/src/github.com/rs/cors/cors_test.go deleted
-315
@@ -1,315 +0,0 @@
1 -package cors
2 -
3 -import (
4 - "net/http"
5 - "net/http/httptest"
6 - "regexp"
7 - "testing"
8 -)
9 -
10 -var testHandler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
11 - w.Write([]byte("bar"))
12 -})
13 -
14 -func assertHeaders(t *testing.T, resHeaders http.Header, reqHeaders map[string]string) {
15 - for name, value := range reqHeaders {
16 - if resHeaders.Get(name) != value {
17 - t.Errorf("Invalid header `%s', wanted `%s', got `%s'", name, value, resHeaders.Get(name))
18 - }
19 - }
20 -}
21 -
22 -func TestNoConfig(t *testing.T) {
23 - s := New(Options{
24 - // Intentionally left blank.
25 - })
26 -
27 - res := httptest.NewRecorder()
28 - req, _ := http.NewRequest("GET", "http://example.com/foo", nil)
29 -
30 - s.Handler(testHandler).ServeHTTP(res, req)
31 -
32 - assertHeaders(t, res.Header(), map[string]string{
33 - "Access-Control-Allow-Origin": "",
34 - "Access-Control-Allow-Methods": "",
35 - "Access-Control-Allow-Headers": "",
36 - "Access-Control-Allow-Credentials": "",
37 - "Access-Control-Max-Age": "",
38 - "Access-Control-Expose-Headers": "",
39 - })
40 -}
41 -
42 -func TestWildcardOrigin(t *testing.T) {
43 - s := New(Options{
44 - AllowedOrigins: []string{"*"},
45 - })
46 -
47 - res := httptest.NewRecorder()
48 - req, _ := http.NewRequest("GET", "http://example.com/foo", nil)
49 - req.Header.Add("Origin", "http://foobar.com")
50 -
51 - s.Handler(testHandler).ServeHTTP(res, req)
52 -
53 - assertHeaders(t, res.Header(), map[string]string{
54 - "Access-Control-Allow-Origin": "http://foobar.com",
55 - "Access-Control-Allow-Methods": "",
56 - "Access-Control-Allow-Headers": "",
57 - "Access-Control-Allow-Credentials": "",
58 - "Access-Control-Max-Age": "",
59 - "Access-Control-Expose-Headers": "",
60 - })
61 -}
62 -
63 -func TestAllowedOrigin(t *testing.T) {
64 - s := New(Options{
65 - AllowedOrigins: []string{"http://foobar.com"},
66 - })
67 -
68 - res := httptest.NewRecorder()
69 - req, _ := http.NewRequest("GET", "http://example.com/foo", nil)
70 - req.Header.Add("Origin", "http://foobar.com")
71 -
72 - s.Handler(testHandler).ServeHTTP(res, req)
73 -
74 - assertHeaders(t, res.Header(), map[string]string{
75 - "Access-Control-Allow-Origin": "http://foobar.com",
76 - "Access-Control-Allow-Methods": "",
77 - "Access-Control-Allow-Headers": "",
78 - "Access-Control-Allow-Credentials": "",
79 - "Access-Control-Max-Age": "",
80 - "Access-Control-Expose-Headers": "",
81 - })
82 -}
83 -
84 -func TestDisallowedOrigin(t *testing.T) {
85 - s := New(Options{
86 - AllowedOrigins: []string{"http://foobar.com"},
87 - })
88 -
89 - res := httptest.NewRecorder()
90 - req, _ := http.NewRequest("GET", "http://example.com/foo", nil)
91 - req.Header.Add("Origin", "http://barbaz.com")
92 -
93 - s.Handler(testHandler).ServeHTTP(res, req)
94 -
95 - assertHeaders(t, res.Header(), map[string]string{
96 - "Access-Control-Allow-Origin": "",
97 - "Access-Control-Allow-Methods": "",
98 - "Access-Control-Allow-Headers": "",
99 - "Access-Control-Allow-Credentials": "",
100 - "Access-Control-Max-Age": "",
101 - "Access-Control-Expose-Headers": "",
102 - })
103 -}
104 -
105 -func TestAllowedOriginFunc(t *testing.T) {
106 - r, _ := regexp.Compile("^http://foo")
107 - s := New(Options{
108 - AllowOriginFunc: func(o string) bool {
109 - println(r.MatchString(o))
110 - return r.MatchString(o)
111 - },
112 - })
113 -
114 - req, _ := http.NewRequest("GET", "http://example.com/foo", nil)
115 -
116 - res := httptest.NewRecorder()
117 - req.Header.Set("Origin", "http://foobar.com")
118 - s.Handler(testHandler).ServeHTTP(res, req)
119 - assertHeaders(t, res.Header(), map[string]string{
120 - "Access-Control-Allow-Origin": "http://foobar.com",
121 - })
122 -
123 - res = httptest.NewRecorder()
124 - req.Header.Set("Origin", "http://barfoo.com")
125 - s.Handler(testHandler).ServeHTTP(res, req)
126 - assertHeaders(t, res.Header(), map[string]string{
127 - "Access-Control-Allow-Origin": "",
128 - })
129 -}
130 -
131 -func TestAllowedMethod(t *testing.T) {
132 - s := New(Options{
133 - AllowedOrigins: []string{"http://foobar.com"},
134 - AllowedMethods: []string{"PUT", "DELETE"},
135 - })
136 -
137 - res := httptest.NewRecorder()
138 - req, _ := http.NewRequest("OPTIONS", "http://example.com/foo", nil)
139 - req.Header.Add("Origin", "http://foobar.com")
140 - req.Header.Add("Access-Control-Request-Method", "PUT")
141 -
142 - s.Handler(testHandler).ServeHTTP(res, req)
143 -
144 - assertHeaders(t, res.Header(), map[string]string{
145 - "Access-Control-Allow-Origin": "http://foobar.com",
146 - "Access-Control-Allow-Methods": "PUT",
147 - "Access-Control-Allow-Headers": "",
148 - "Access-Control-Allow-Credentials": "",
149 - "Access-Control-Max-Age": "",
150 - "Access-Control-Expose-Headers": "",
151 - })
152 -}
153 -
154 -func TestDisallowedMethod(t *testing.T) {
155 - s := New(Options{
156 - AllowedOrigins: []string{"http://foobar.com"},
157 - AllowedMethods: []string{"PUT", "DELETE"},
158 - })
159 -
160 - res := httptest.NewRecorder()
161 - req, _ := http.NewRequest("OPTIONS", "http://example.com/foo", nil)
162 - req.Header.Add("Origin", "http://foobar.com")
163 - req.Header.Add("Access-Control-Request-Method", "PATCH")
164 -
165 - s.Handler(testHandler).ServeHTTP(res, req)
166 -
167 - assertHeaders(t, res.Header(), map[string]string{
168 - "Access-Control-Allow-Origin": "",
169 - "Access-Control-Allow-Methods": "",
170 - "Access-Control-Allow-Headers": "",
171 - "Access-Control-Allow-Credentials": "",
172 - "Access-Control-Max-Age": "",
173 - "Access-Control-Expose-Headers": "",
174 - })
175 -}
176 -
177 -func TestAllowedHeader(t *testing.T) {
178 - s := New(Options{
179 - AllowedOrigins: []string{"http://foobar.com"},
180 - AllowedHeaders: []string{"X-Header-1", "x-header-2"},
181 - })
182 -
183 - res := httptest.NewRecorder()
184 - req, _ := http.NewRequest("OPTIONS", "http://example.com/foo", nil)
185 - req.Header.Add("Origin", "http://foobar.com")
186 - req.Header.Add("Access-Control-Request-Method", "GET")
187 - req.Header.Add("Access-Control-Request-Headers", "X-Header-2, X-HEADER-1")
188 -
189 - s.Handler(testHandler).ServeHTTP(res, req)
190 -
191 - assertHeaders(t, res.Header(), map[string]string{
192 - "Access-Control-Allow-Origin": "http://foobar.com",
193 - "Access-Control-Allow-Methods": "GET",
194 - "Access-Control-Allow-Headers": "X-Header-2, X-Header-1",
195 - "Access-Control-Allow-Credentials": "",
196 - "Access-Control-Max-Age": "",
197 - "Access-Control-Expose-Headers": "",
198 - })
199 -}
200 -
201 -func TestAllowedWildcardHeader(t *testing.T) {
202 - s := New(Options{
203 - AllowedOrigins: []string{"http://foobar.com"},
204 - AllowedHeaders: []string{"*"},
205 - })
206 -
207 - res := httptest.NewRecorder()
208 - req, _ := http.NewRequest("OPTIONS", "http://example.com/foo", nil)
209 - req.Header.Add("Origin", "http://foobar.com")
210 - req.Header.Add("Access-Control-Request-Method", "GET")
211 - req.Header.Add("Access-Control-Request-Headers", "X-Header-2, X-HEADER-1")
212 -
213 - s.Handler(testHandler).ServeHTTP(res, req)
214 -
215 - assertHeaders(t, res.Header(), map[string]string{
216 - "Access-Control-Allow-Origin": "http://foobar.com",
217 - "Access-Control-Allow-Methods": "GET",
218 - "Access-Control-Allow-Headers": "X-Header-2, X-Header-1",
219 - "Access-Control-Allow-Credentials": "",
220 - "Access-Control-Max-Age": "",
221 - "Access-Control-Expose-Headers": "",
222 - })
223 -}
224 -
225 -func TestDisallowedHeader(t *testing.T) {
226 - s := New(Options{
227 - AllowedOrigins: []string{"http://foobar.com"},
228 - AllowedHeaders: []string{"X-Header-1", "x-header-2"},
229 - })
230 -
231 - res := httptest.NewRecorder()
232 - req, _ := http.NewRequest("OPTIONS", "http://example.com/foo", nil)
233 - req.Header.Add("Origin", "http://foobar.com")
234 - req.Header.Add("Access-Control-Request-Method", "GET")
235 - req.Header.Add("Access-Control-Request-Headers", "X-Header-3, X-Header-1")
236 -
237 - s.Handler(testHandler).ServeHTTP(res, req)
238 -
239 - assertHeaders(t, res.Header(), map[string]string{
240 - "Access-Control-Allow-Origin": "",
241 - "Access-Control-Allow-Methods": "",
242 - "Access-Control-Allow-Headers": "",
243 - "Access-Control-Allow-Credentials": "",
244 - "Access-Control-Max-Age": "",
245 - "Access-Control-Expose-Headers": "",
246 - })
247 -}
248 -
249 -func TestOriginHeader(t *testing.T) {
250 - s := New(Options{
251 - AllowedOrigins: []string{"http://foobar.com"},
252 - })
253 -
254 - res := httptest.NewRecorder()
255 - req, _ := http.NewRequest("OPTIONS", "http://example.com/foo", nil)
256 - req.Header.Add("Origin", "http://foobar.com")
257 - req.Header.Add("Access-Control-Request-Method", "GET")
258 - req.Header.Add("Access-Control-Request-Headers", "origin")
259 -
260 - s.Handler(testHandler).ServeHTTP(res, req)
261 -
262 - assertHeaders(t, res.Header(), map[string]string{
263 - "Access-Control-Allow-Origin": "http://foobar.com",
264 - "Access-Control-Allow-Methods": "GET",
265 - "Access-Control-Allow-Headers": "Origin",
266 - "Access-Control-Allow-Credentials": "",
267 - "Access-Control-Max-Age": "",
268 - "Access-Control-Expose-Headers": "",
269 - })
270 -}
271 -
272 -func TestExposedHeader(t *testing.T) {
273 - s := New(Options{
274 - AllowedOrigins: []string{"http://foobar.com"},
275 - ExposedHeaders: []string{"X-Header-1", "x-header-2"},
276 - })
277 -
278 - res := httptest.NewRecorder()
279 - req, _ := http.NewRequest("GET", "http://example.com/foo", nil)
280 - req.Header.Add("Origin", "http://foobar.com")
281 -
282 - s.Handler(testHandler).ServeHTTP(res, req)
283 -
284 - assertHeaders(t, res.Header(), map[string]string{
285 - "Access-Control-Allow-Origin": "http://foobar.com",
286 - "Access-Control-Allow-Methods": "",
287 - "Access-Control-Allow-Headers": "",
288 - "Access-Control-Allow-Credentials": "",
289 - "Access-Control-Max-Age": "",
290 - "Access-Control-Expose-Headers": "X-Header-1, X-Header-2",
291 - })
292 -}
293 -
294 -func TestAllowedCredentials(t *testing.T) {
295 - s := New(Options{
296 - AllowedOrigins: []string{"http://foobar.com"},
297 - AllowCredentials: true,
298 - })
299 -
300 - res := httptest.NewRecorder()
301 - req, _ := http.NewRequest("OPTIONS", "http://example.com/foo", nil)
302 - req.Header.Add("Origin", "http://foobar.com")
303 - req.Header.Add("Access-Control-Request-Method", "GET")
304 -
305 - s.Handler(testHandler).ServeHTTP(res, req)
306 -
307 - assertHeaders(t, res.Header(), map[string]string{
308 - "Access-Control-Allow-Origin": "http://foobar.com",
309 - "Access-Control-Allow-Methods": "GET",
310 - "Access-Control-Allow-Headers": "",
311 - "Access-Control-Allow-Credentials": "true",
312 - "Access-Control-Max-Age": "",
313 - "Access-Control-Expose-Headers": "",
314 - })
315 -}
Godeps/_workspace/src/github.com/rs/cors/examples/alice/server.go deleted
-24
@@ -1,24 +0,0 @@
1 -package main
2 -
3 -import (
4 - "net/http"
5 -
6 - "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/rs/cors"
7 - "github.com/justinas/alice"
8 -)
9 -
10 -func main() {
11 - c := cors.New(cors.Options{
12 - AllowedOrigins: []string{"http://foo.com"},
13 - })
14 -
15 - mux := http.NewServeMux()
16 -
17 - mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
18 - w.Header().Set("Content-Type", "application/json")
19 - w.Write([]byte("{\"hello\": \"world\"}"))
20 - })
21 -
22 - chain := alice.New(c.Handler).Then(mux)
23 - http.ListenAndServe(":8080", chain)
24 -}
Godeps/_workspace/src/github.com/rs/cors/examples/default/server.go deleted
-18
@@ -1,18 +0,0 @@
1 -package main
2 -
3 -import (
4 - "net/http"
5 -
6 - "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/rs/cors"
7 -)
8 -
9 -func main() {
10 - h := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
11 - w.Header().Set("Content-Type", "application/json")
12 - w.Write([]byte("{\"hello\": \"world\"}"))
13 - })
14 -
15 - // Use default options
16 - handler := cors.Default().Handler(h)
17 - http.ListenAndServe(":8080", handler)
18 -}
Godeps/_workspace/src/github.com/rs/cors/examples/goji/server.go deleted
-22
@@ -1,22 +0,0 @@
1 -package main
2 -
3 -import (
4 - "net/http"
5 -
6 - "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/rs/cors"
7 - "github.com/zenazn/goji"
8 -)
9 -
10 -func main() {
11 - c := cors.New(cors.Options{
12 - AllowedOrigins: []string{"http://foo.com"},
13 - })
14 - goji.Use(c.Handler)
15 -
16 - goji.Get("/", func(w http.ResponseWriter, r *http.Request) {
17 - w.Header().Set("Content-Type", "application/json")
18 - w.Write([]byte("{\"hello\": \"world\"}"))
19 - })
20 -
21 - goji.Serve()
22 -}
Godeps/_workspace/src/github.com/rs/cors/examples/martini/server.go deleted
-23
@@ -1,23 +0,0 @@
1 -package main
2 -
3 -import (
4 - "github.com/go-martini/martini"
5 - "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/rs/cors"
6 - "github.com/martini-contrib/render"
7 -)
8 -
9 -func main() {
10 - c := cors.New(cors.Options{
11 - AllowedOrigins: []string{"http://foo.com"},
12 - })
13 -
14 - m := martini.Classic()
15 - m.Use(render.Renderer())
16 - m.Use(c.HandlerFunc)
17 -
18 - m.Get("/", func(r render.Render) {
19 - r.JSON(200, map[string]interface{}{"hello": "world"})
20 - })
21 -
22 - m.Run()
23 -}
Godeps/_workspace/src/github.com/rs/cors/examples/negroni/server.go deleted
-26
@@ -1,26 +0,0 @@
1 -package main
2 -
3 -import (
4 - "net/http"
5 -
6 - "github.com/codegangsta/negroni"
7 - "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/rs/cors"
8 -)
9 -
10 -func main() {
11 - c := cors.New(cors.Options{
12 - AllowedOrigins: []string{"http://foo.com"},
13 - })
14 -
15 - mux := http.NewServeMux()
16 -
17 - mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
18 - w.Header().Set("Content-Type", "application/json")
19 - w.Write([]byte("{\"hello\": \"world\"}"))
20 - })
21 -
22 - n := negroni.Classic()
23 - n.Use(c)
24 - n.UseHandler(mux)
25 - n.Run(":3000")
26 -}
Godeps/_workspace/src/github.com/rs/cors/examples/nethttp/server.go deleted
-20
@@ -1,20 +0,0 @@
1 -package main
2 -
3 -import (
4 - "net/http"
5 -
6 - "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/rs/cors"
7 -)
8 -
9 -func main() {
10 - c := cors.New(cors.Options{
11 - AllowedOrigins: []string{"http://foo.com"},
12 - })
13 -
14 - handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
15 - w.Header().Set("Content-Type", "application/json")
16 - w.Write([]byte("{\"hello\": \"world\"}"))
17 - })
18 -
19 - http.ListenAndServe(":8080", c.Handler(handler))
20 -}
Godeps/_workspace/src/github.com/rs/cors/examples/openbar/server.go deleted
-22
@@ -1,22 +0,0 @@
1 -package main
2 -
3 -import (
4 - "net/http"
5 -
6 - "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/rs/cors"
7 -)
8 -
9 -func main() {
10 - c := cors.New(cors.Options{
11 - AllowedOrigins: []string{"*"},
12 - AllowedMethods: []string{"GET", "POST", "PUT", "DELETE"},
13 - AllowCredentials: true,
14 - })
15 -
16 - h := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
17 - w.Header().Set("Content-Type", "application/json")
18 - w.Write([]byte("{\"hello\": \"world\"}"))
19 - })
20 -
21 - http.ListenAndServe(":8080", c.Handler(h))
22 -}
Godeps/_workspace/src/github.com/rs/cors/utils.go deleted
-59
@@ -1,59 +0,0 @@
1 -package cors
2 -
3 -const toLower = 'a' - 'A'
4 -
5 -type converter func(string) string
6 -
7 -// convert converts a list of string using the passed converter function
8 -func convert(s []string, c converter) []string {
9 - out := []string{}
10 - for _, i := range s {
11 - out = append(out, c(i))
12 - }
13 - return out
14 -}
15 -
16 -// parseHeaderList tokenize + normalize a string containing a list of headers
17 -func parseHeaderList(headerList string) []string {
18 - l := len(headerList)
19 - h := make([]byte, 0, l)
20 - upper := true
21 - // Estimate the number headers in order to allocate the right splice size
22 - t := 0
23 - for i := 0; i < l; i++ {
24 - if headerList[i] == ',' {
25 - t++
26 - }
27 - }
28 - headers := make([]string, 0, t)
29 - for i := 0; i < l; i++ {
30 - b := headerList[i]
31 - if b >= 'a' && b <= 'z' {
32 - if upper {
33 - h = append(h, b-toLower)
34 - } else {
35 - h = append(h, b)
36 - }
37 - } else if b >= 'A' && b <= 'Z' {
38 - if !upper {
39 - h = append(h, b+toLower)
40 - } else {
41 - h = append(h, b)
42 - }
43 - } else if b == '-' || (b >= '0' && b <= '9') {
44 - h = append(h, b)
45 - }
46 -
47 - if b == ' ' || b == ',' || i == l-1 {
48 - if len(h) > 0 {
49 - // Flush the found header
50 - headers = append(headers, string(h))
51 - h = h[:0]
52 - upper = true
53 - }
54 - } else {
55 - upper = b == '-'
56 - }
57 - }
58 - return headers
59 -}
Godeps/_workspace/src/github.com/rs/cors/utils_test.go deleted
-52
@@ -1,52 +0,0 @@
1 -package cors
2 -
3 -import (
4 - "strings"
5 - "testing"
6 -)
7 -
8 -func TestConvert(t *testing.T) {
9 - s := convert([]string{"A", "b", "C"}, strings.ToLower)
10 - e := []string{"a", "b", "c"}
11 - if s[0] != e[0] || s[1] != e[1] || s[2] != e[2] {
12 - t.Errorf("%v != %v", s, e)
13 - }
14 -}
15 -
16 -func TestParseHeaderList(t *testing.T) {
17 - h := parseHeaderList("header, second-header, THIRD-HEADER, Numb3r3d-H34d3r")
18 - e := []string{"Header", "Second-Header", "Third-Header", "Numb3r3d-H34d3r"}
19 - if h[0] != e[0] || h[1] != e[1] || h[2] != e[2] {
20 - t.Errorf("%v != %v", h, e)
21 - }
22 -}
23 -
24 -func TestParseHeaderListEmpty(t *testing.T) {
25 - if len(parseHeaderList("")) != 0 {
26 - t.Error("should be empty sclice")
27 - }
28 - if len(parseHeaderList(" , ")) != 0 {
29 - t.Error("should be empty sclice")
30 - }
31 -}
32 -
33 -func BenchmarkParseHeaderList(b *testing.B) {
34 - b.ReportAllocs()
35 - for i := 0; i < b.N; i++ {
36 - parseHeaderList("header, second-header, THIRD-HEADER")
37 - }
38 -}
39 -
40 -func BenchmarkParseHeaderListSingle(b *testing.B) {
41 - b.ReportAllocs()
42 - for i := 0; i < b.N; i++ {
43 - parseHeaderList("header")
44 - }
45 -}
46 -
47 -func BenchmarkParseHeaderListNormalized(b *testing.B) {
48 - b.ReportAllocs()
49 - for i := 0; i < b.N; i++ {
50 - parseHeaderList("Header1, Header2, Third-Header")
51 - }
52 -}
commands/http/handler.go
+1 -1
@@ -11,8 +11,8 @@ import (
11 "strings"
12 "sync"
13
14 - cors "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/rs/cors"
14 "github.com/ipfs/go-ipfs/repo/config"
15 + cors "gx/ipfs/QmQzTLDsi3a37CJyMDBXnjiHKQpth3AGS1yqwU57FfLwfG/cors"
16 context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context"
17
18 cmds "github.com/ipfs/go-ipfs/commands"
package.json
+7 -1
@@ -105,6 +105,12 @@
105 "hash": "QmX6DhWrpBB5NtadXmPSXYNdVvuLfJXoFNMvUMoVvP5UJa",
106 "name": "go-context",
107 "version": "0.0.0"
108 + },
109 + {
110 + "author": "rs",
111 + "hash": "QmQzTLDsi3a37CJyMDBXnjiHKQpth3AGS1yqwU57FfLwfG",
112 + "name": "cors",
113 + "version": "0.0.0"
114 }
115 ],
116 "gxVersion": "0.4.0",
@@ -112,4 +118,4 @@
118 "license": "MIT",
119 "name": "go-ipfs",
120 "version": "0.4.0"
115 -}
121 +}
\ No newline at end of file
test/sharness/t0230-channel-streaming-http-content-type.sh
+2
@@ -26,6 +26,7 @@ test_ls_cmd() {
26 printf "Content-Type: text/plain\r\n" >>expected_output &&
27 printf "Server: go-ipfs/%s\r\n" $(ipfs version -n) >>expected_output &&
28 printf "Trailer: X-Stream-Error\r\n" >>expected_output &&
29 + printf "Vary: Origin\r\n" >>expected_output &&
30 printf "X-Chunked-Output: 1\r\n" >>expected_output &&
31 printf "Transfer-Encoding: chunked\r\n" >>expected_output &&
32 printf "\r\n" >>expected_output &&
@@ -48,6 +49,7 @@ test_ls_cmd() {
49 printf "Content-Type: application/json\r\n" >>expected_output &&
50 printf "Server: go-ipfs/%s\r\n" $(ipfs version -n) >>expected_output &&
51 printf "Trailer: X-Stream-Error\r\n" >>expected_output &&
52 + printf "Vary: Origin\r\n" >>expected_output &&
53 printf "X-Chunked-Output: 1\r\n" >>expected_output &&
54 printf "Transfer-Encoding: chunked\r\n" >>expected_output &&
55 printf "\r\n" >>expected_output &&