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 5package httputil 6 7import ( 8 "bytes" 9 "fmt" 10 "io" 11 "io/ioutil" 12 "net/http" 13 "net/url" 14 "testing" 15) 16 17type dumpTest struct { 18 Req http.Request 19 Body interface{} // optional []byte or func() io.ReadCloser to populate Req.Body 20 21 WantDump string 22 WantDumpOut string 23 NoBody bool // if true, set DumpRequest{,Out} body to false 24} 25 26var dumpTests = []dumpTest{ 27 28 // HTTP/1.1 => chunked coding; body; empty trailer 29 { 30 Req: http.Request{ 31 Method: "GET", 32 URL: &url.URL{ 33 Scheme: "http", 34 Host: "www.google.com", 35 Path: "/search", 36 }, 37 ProtoMajor: 1, 38 ProtoMinor: 1, 39 TransferEncoding: []string{"chunked"}, 40 }, 41 42 Body: []byte("abcdef"), 43 44 WantDump: "GET /search HTTP/1.1\r\n" + 45 "Host: www.google.com\r\n" + 46 "Transfer-Encoding: chunked\r\n\r\n" + 47 chunk("abcdef") + chunk(""), 48 }, 49 50 // Verify that DumpRequest preserves the HTTP version number, doesn't add a Host, 51 // and doesn't add a User-Agent. 52 { 53 Req: http.Request{ 54 Method: "GET", 55 URL: mustParseURL("/foo"), 56 ProtoMajor: 1, 57 ProtoMinor: 0, 58 Header: http.Header{ 59 "X-Foo": []string{"X-Bar"}, 60 }, 61 }, 62 63 WantDump: "GET /foo HTTP/1.0\r\n" + 64 "X-Foo: X-Bar\r\n\r\n", 65 }, 66 67 { 68 Req: *mustNewRequest("GET", "http://example.com/foo", nil), 69 70 WantDumpOut: "GET /foo HTTP/1.1\r\n" + 71 "Host: example.com\r\n" + 72 "User-Agent: Go 1.1 package http\r\n" + 73 "Accept-Encoding: gzip\r\n\r\n", 74 }, 75 76 // Test that an https URL doesn't try to do an SSL negotiation 77 // with a bytes.Buffer and hang with all goroutines not 78 // runnable. 79 { 80 Req: *mustNewRequest("GET", "https://example.com/foo", nil), 81 82 WantDumpOut: "GET /foo HTTP/1.1\r\n" + 83 "Host: example.com\r\n" + 84 "User-Agent: Go 1.1 package http\r\n" + 85 "Accept-Encoding: gzip\r\n\r\n", 86 }, 87 88 // Request with Body, but Dump requested without it. 89 { 90 Req: http.Request{ 91 Method: "POST", 92 URL: &url.URL{ 93 Scheme: "http", 94 Host: "post.tld", 95 Path: "/", 96 }, 97 ContentLength: 6, 98 ProtoMajor: 1, 99 ProtoMinor: 1, 100 }, 101 102 Body: []byte("abcdef"), 103 104 WantDumpOut: "POST / HTTP/1.1\r\n" + 105 "Host: post.tld\r\n" + 106 "User-Agent: Go 1.1 package http\r\n" + 107 "Content-Length: 6\r\n" + 108 "Accept-Encoding: gzip\r\n\r\n", 109 110 NoBody: true, 111 }, 112} 113 114func TestDumpRequest(t *testing.T) { 115 for i, tt := range dumpTests { 116 setBody := func() { 117 if tt.Body == nil { 118 return 119 } 120 switch b := tt.Body.(type) { 121 case []byte: 122 tt.Req.Body = ioutil.NopCloser(bytes.NewBuffer(b)) 123 case func() io.ReadCloser: 124 tt.Req.Body = b() 125 } 126 } 127 setBody() 128 if tt.Req.Header == nil { 129 tt.Req.Header = make(http.Header) 130 } 131 132 if tt.WantDump != "" { 133 setBody() 134 dump, err := DumpRequest(&tt.Req, !tt.NoBody) 135 if err != nil { 136 t.Errorf("DumpRequest #%d: %s", i, err) 137 continue 138 } 139 if string(dump) != tt.WantDump { 140 t.Errorf("DumpRequest %d, expecting:\n%s\nGot:\n%s\n", i, tt.WantDump, string(dump)) 141 continue 142 } 143 } 144 145 if tt.WantDumpOut != "" { 146 setBody() 147 dump, err := DumpRequestOut(&tt.Req, !tt.NoBody) 148 if err != nil { 149 t.Errorf("DumpRequestOut #%d: %s", i, err) 150 continue 151 } 152 if string(dump) != tt.WantDumpOut { 153 t.Errorf("DumpRequestOut %d, expecting:\n%s\nGot:\n%s\n", i, tt.WantDumpOut, string(dump)) 154 continue 155 } 156 } 157 } 158} 159 160func chunk(s string) string { 161 return fmt.Sprintf("%x\r\n%s\r\n", len(s), s) 162} 163 164func mustParseURL(s string) *url.URL { 165 u, err := url.Parse(s) 166 if err != nil { 167 panic(fmt.Sprintf("Error parsing URL %q: %v", s, err)) 168 } 169 return u 170} 171 172func mustNewRequest(method, url string, body io.Reader) *http.Request { 173 req, err := http.NewRequest(method, url, body) 174 if err != nil { 175 panic(fmt.Sprintf("NewRequest(%q, %q, %p) err = %v", method, url, body, err)) 176 } 177 return req 178} 179