github.com/ader1990/go@v0.0.0-20140630135419-8c24447fa791/src/pkg/net/http/httputil/dump_test.go (about) 1 // Copyright 2011 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package httputil 6 7 import ( 8 "bytes" 9 "fmt" 10 "io" 11 "io/ioutil" 12 "net/http" 13 "net/url" 14 "runtime" 15 "strings" 16 "testing" 17 ) 18 19 type dumpTest struct { 20 Req http.Request 21 Body interface{} // optional []byte or func() io.ReadCloser to populate Req.Body 22 23 WantDump string 24 WantDumpOut string 25 NoBody bool // if true, set DumpRequest{,Out} body to false 26 } 27 28 var dumpTests = []dumpTest{ 29 30 // HTTP/1.1 => chunked coding; body; empty trailer 31 { 32 Req: http.Request{ 33 Method: "GET", 34 URL: &url.URL{ 35 Scheme: "http", 36 Host: "www.google.com", 37 Path: "/search", 38 }, 39 ProtoMajor: 1, 40 ProtoMinor: 1, 41 TransferEncoding: []string{"chunked"}, 42 }, 43 44 Body: []byte("abcdef"), 45 46 WantDump: "GET /search HTTP/1.1\r\n" + 47 "Host: www.google.com\r\n" + 48 "Transfer-Encoding: chunked\r\n\r\n" + 49 chunk("abcdef") + chunk(""), 50 }, 51 52 // Verify that DumpRequest preserves the HTTP version number, doesn't add a Host, 53 // and doesn't add a User-Agent. 54 { 55 Req: http.Request{ 56 Method: "GET", 57 URL: mustParseURL("/foo"), 58 ProtoMajor: 1, 59 ProtoMinor: 0, 60 Header: http.Header{ 61 "X-Foo": []string{"X-Bar"}, 62 }, 63 }, 64 65 WantDump: "GET /foo HTTP/1.0\r\n" + 66 "X-Foo: X-Bar\r\n\r\n", 67 }, 68 69 { 70 Req: *mustNewRequest("GET", "http://example.com/foo", nil), 71 72 WantDumpOut: "GET /foo HTTP/1.1\r\n" + 73 "Host: example.com\r\n" + 74 "User-Agent: Go 1.1 package http\r\n" + 75 "Accept-Encoding: gzip\r\n\r\n", 76 }, 77 78 // Test that an https URL doesn't try to do an SSL negotiation 79 // with a bytes.Buffer and hang with all goroutines not 80 // runnable. 81 { 82 Req: *mustNewRequest("GET", "https://example.com/foo", nil), 83 84 WantDumpOut: "GET /foo HTTP/1.1\r\n" + 85 "Host: example.com\r\n" + 86 "User-Agent: Go 1.1 package http\r\n" + 87 "Accept-Encoding: gzip\r\n\r\n", 88 }, 89 90 // Request with Body, but Dump requested without it. 91 { 92 Req: http.Request{ 93 Method: "POST", 94 URL: &url.URL{ 95 Scheme: "http", 96 Host: "post.tld", 97 Path: "/", 98 }, 99 ContentLength: 6, 100 ProtoMajor: 1, 101 ProtoMinor: 1, 102 }, 103 104 Body: []byte("abcdef"), 105 106 WantDumpOut: "POST / HTTP/1.1\r\n" + 107 "Host: post.tld\r\n" + 108 "User-Agent: Go 1.1 package http\r\n" + 109 "Content-Length: 6\r\n" + 110 "Accept-Encoding: gzip\r\n\r\n", 111 112 NoBody: true, 113 }, 114 } 115 116 func TestDumpRequest(t *testing.T) { 117 numg0 := runtime.NumGoroutine() 118 for i, tt := range dumpTests { 119 setBody := func() { 120 if tt.Body == nil { 121 return 122 } 123 switch b := tt.Body.(type) { 124 case []byte: 125 tt.Req.Body = ioutil.NopCloser(bytes.NewReader(b)) 126 case func() io.ReadCloser: 127 tt.Req.Body = b() 128 } 129 } 130 setBody() 131 if tt.Req.Header == nil { 132 tt.Req.Header = make(http.Header) 133 } 134 135 if tt.WantDump != "" { 136 setBody() 137 dump, err := DumpRequest(&tt.Req, !tt.NoBody) 138 if err != nil { 139 t.Errorf("DumpRequest #%d: %s", i, err) 140 continue 141 } 142 if string(dump) != tt.WantDump { 143 t.Errorf("DumpRequest %d, expecting:\n%s\nGot:\n%s\n", i, tt.WantDump, string(dump)) 144 continue 145 } 146 } 147 148 if tt.WantDumpOut != "" { 149 setBody() 150 dump, err := DumpRequestOut(&tt.Req, !tt.NoBody) 151 if err != nil { 152 t.Errorf("DumpRequestOut #%d: %s", i, err) 153 continue 154 } 155 if string(dump) != tt.WantDumpOut { 156 t.Errorf("DumpRequestOut %d, expecting:\n%s\nGot:\n%s\n", i, tt.WantDumpOut, string(dump)) 157 continue 158 } 159 } 160 } 161 if dg := runtime.NumGoroutine() - numg0; dg > 4 { 162 t.Errorf("Unexpectedly large number of new goroutines: %d new", dg) 163 } 164 } 165 166 func chunk(s string) string { 167 return fmt.Sprintf("%x\r\n%s\r\n", len(s), s) 168 } 169 170 func mustParseURL(s string) *url.URL { 171 u, err := url.Parse(s) 172 if err != nil { 173 panic(fmt.Sprintf("Error parsing URL %q: %v", s, err)) 174 } 175 return u 176 } 177 178 func mustNewRequest(method, url string, body io.Reader) *http.Request { 179 req, err := http.NewRequest(method, url, body) 180 if err != nil { 181 panic(fmt.Sprintf("NewRequest(%q, %q, %p) err = %v", method, url, body, err)) 182 } 183 return req 184 } 185 186 var dumpResTests = []struct { 187 res *http.Response 188 body bool 189 want string 190 }{ 191 { 192 res: &http.Response{ 193 Status: "200 OK", 194 StatusCode: 200, 195 Proto: "HTTP/1.1", 196 ProtoMajor: 1, 197 ProtoMinor: 1, 198 ContentLength: 50, 199 Header: http.Header{ 200 "Foo": []string{"Bar"}, 201 }, 202 Body: ioutil.NopCloser(strings.NewReader("foo")), // shouldn't be used 203 }, 204 body: false, // to verify we see 50, not empty or 3. 205 want: `HTTP/1.1 200 OK 206 Content-Length: 50 207 Foo: Bar`, 208 }, 209 210 { 211 res: &http.Response{ 212 Status: "200 OK", 213 StatusCode: 200, 214 Proto: "HTTP/1.1", 215 ProtoMajor: 1, 216 ProtoMinor: 1, 217 ContentLength: 3, 218 Body: ioutil.NopCloser(strings.NewReader("foo")), 219 }, 220 body: true, 221 want: `HTTP/1.1 200 OK 222 Content-Length: 3 223 224 foo`, 225 }, 226 227 { 228 res: &http.Response{ 229 Status: "200 OK", 230 StatusCode: 200, 231 Proto: "HTTP/1.1", 232 ProtoMajor: 1, 233 ProtoMinor: 1, 234 ContentLength: -1, 235 Body: ioutil.NopCloser(strings.NewReader("foo")), 236 TransferEncoding: []string{"chunked"}, 237 }, 238 body: true, 239 want: `HTTP/1.1 200 OK 240 Transfer-Encoding: chunked 241 242 3 243 foo 244 0`, 245 }, 246 } 247 248 func TestDumpResponse(t *testing.T) { 249 for i, tt := range dumpResTests { 250 gotb, err := DumpResponse(tt.res, tt.body) 251 if err != nil { 252 t.Errorf("%d. DumpResponse = %v", i, err) 253 continue 254 } 255 got := string(gotb) 256 got = strings.TrimSpace(got) 257 got = strings.Replace(got, "\r", "", -1) 258 259 if got != tt.want { 260 t.Errorf("%d.\nDumpResponse got:\n%s\n\nWant:\n%s\n", i, got, tt.want) 261 } 262 } 263 }