github.com/ice-blockchain/go/src@v0.0.0-20240403114104-1564d284e521/net/http/responsewrite_test.go (about) 1 // Copyright 2010 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 http 6 7 import ( 8 "io" 9 "strings" 10 "testing" 11 ) 12 13 type respWriteTest struct { 14 Resp Response 15 Raw string 16 } 17 18 func TestResponseWrite(t *testing.T) { 19 respWriteTests := []respWriteTest{ 20 // HTTP/1.0, identity coding; no trailer 21 { 22 Response{ 23 StatusCode: 503, 24 ProtoMajor: 1, 25 ProtoMinor: 0, 26 Request: dummyReq("GET"), 27 Header: Header{}, 28 Body: io.NopCloser(strings.NewReader("abcdef")), 29 ContentLength: 6, 30 }, 31 32 "HTTP/1.0 503 Service Unavailable\r\n" + 33 "Content-Length: 6\r\n\r\n" + 34 "abcdef", 35 }, 36 // Unchunked response without Content-Length. 37 { 38 Response{ 39 StatusCode: 200, 40 ProtoMajor: 1, 41 ProtoMinor: 0, 42 Request: dummyReq("GET"), 43 Header: Header{}, 44 Body: io.NopCloser(strings.NewReader("abcdef")), 45 ContentLength: -1, 46 }, 47 "HTTP/1.0 200 OK\r\n" + 48 "\r\n" + 49 "abcdef", 50 }, 51 // HTTP/1.1 response with unknown length and Connection: close 52 { 53 Response{ 54 StatusCode: 200, 55 ProtoMajor: 1, 56 ProtoMinor: 1, 57 Request: dummyReq("GET"), 58 Header: Header{}, 59 Body: io.NopCloser(strings.NewReader("abcdef")), 60 ContentLength: -1, 61 Close: true, 62 }, 63 "HTTP/1.1 200 OK\r\n" + 64 "Connection: close\r\n" + 65 "\r\n" + 66 "abcdef", 67 }, 68 // HTTP/1.1 response with unknown length and not setting connection: close 69 { 70 Response{ 71 StatusCode: 200, 72 ProtoMajor: 1, 73 ProtoMinor: 1, 74 Request: dummyReq11("GET"), 75 Header: Header{}, 76 Body: io.NopCloser(strings.NewReader("abcdef")), 77 ContentLength: -1, 78 Close: false, 79 }, 80 "HTTP/1.1 200 OK\r\n" + 81 "Connection: close\r\n" + 82 "\r\n" + 83 "abcdef", 84 }, 85 // HTTP/1.1 response with unknown length and not setting connection: close, but 86 // setting chunked. 87 { 88 Response{ 89 StatusCode: 200, 90 ProtoMajor: 1, 91 ProtoMinor: 1, 92 Request: dummyReq11("GET"), 93 Header: Header{}, 94 Body: io.NopCloser(strings.NewReader("abcdef")), 95 ContentLength: -1, 96 TransferEncoding: []string{"chunked"}, 97 Close: false, 98 }, 99 "HTTP/1.1 200 OK\r\n" + 100 "Transfer-Encoding: chunked\r\n\r\n" + 101 "6\r\nabcdef\r\n0\r\n\r\n", 102 }, 103 // HTTP/1.1 response 0 content-length, and nil body 104 { 105 Response{ 106 StatusCode: 200, 107 ProtoMajor: 1, 108 ProtoMinor: 1, 109 Request: dummyReq11("GET"), 110 Header: Header{}, 111 Body: nil, 112 ContentLength: 0, 113 Close: false, 114 }, 115 "HTTP/1.1 200 OK\r\n" + 116 "Content-Length: 0\r\n" + 117 "\r\n", 118 }, 119 // HTTP/1.1 response 0 content-length, and non-nil empty body 120 { 121 Response{ 122 StatusCode: 200, 123 ProtoMajor: 1, 124 ProtoMinor: 1, 125 Request: dummyReq11("GET"), 126 Header: Header{}, 127 Body: io.NopCloser(strings.NewReader("")), 128 ContentLength: 0, 129 Close: false, 130 }, 131 "HTTP/1.1 200 OK\r\n" + 132 "Content-Length: 0\r\n" + 133 "\r\n", 134 }, 135 // HTTP/1.1 response 0 content-length, and non-nil non-empty body 136 { 137 Response{ 138 StatusCode: 200, 139 ProtoMajor: 1, 140 ProtoMinor: 1, 141 Request: dummyReq11("GET"), 142 Header: Header{}, 143 Body: io.NopCloser(strings.NewReader("foo")), 144 ContentLength: 0, 145 Close: false, 146 }, 147 "HTTP/1.1 200 OK\r\n" + 148 "Connection: close\r\n" + 149 "\r\nfoo", 150 }, 151 // HTTP/1.1, chunked coding; empty trailer; close 152 { 153 Response{ 154 StatusCode: 200, 155 ProtoMajor: 1, 156 ProtoMinor: 1, 157 Request: dummyReq("GET"), 158 Header: Header{}, 159 Body: io.NopCloser(strings.NewReader("abcdef")), 160 ContentLength: 6, 161 TransferEncoding: []string{"chunked"}, 162 Close: true, 163 }, 164 165 "HTTP/1.1 200 OK\r\n" + 166 "Connection: close\r\n" + 167 "Transfer-Encoding: chunked\r\n\r\n" + 168 "6\r\nabcdef\r\n0\r\n\r\n", 169 }, 170 171 // Header value with a newline character (Issue 914). 172 // Also tests removal of leading and trailing whitespace. 173 { 174 Response{ 175 StatusCode: 204, 176 ProtoMajor: 1, 177 ProtoMinor: 1, 178 Request: dummyReq("GET"), 179 Header: Header{ 180 "Foo": []string{" Bar\nBaz "}, 181 }, 182 Body: nil, 183 ContentLength: 0, 184 TransferEncoding: []string{"chunked"}, 185 Close: true, 186 }, 187 188 "HTTP/1.1 204 No Content\r\n" + 189 "Connection: close\r\n" + 190 "Foo: Bar Baz\r\n" + 191 "\r\n", 192 }, 193 194 // Want a single Content-Length header. Fixing issue 8180 where 195 // there were two. 196 { 197 Response{ 198 StatusCode: StatusOK, 199 ProtoMajor: 1, 200 ProtoMinor: 1, 201 Request: &Request{Method: "POST"}, 202 Header: Header{}, 203 ContentLength: 0, 204 TransferEncoding: nil, 205 Body: nil, 206 }, 207 "HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n", 208 }, 209 210 // When a response to a POST has Content-Length: -1, make sure we don't 211 // write the Content-Length as -1. 212 { 213 Response{ 214 StatusCode: StatusOK, 215 ProtoMajor: 1, 216 ProtoMinor: 1, 217 Request: &Request{Method: "POST"}, 218 Header: Header{}, 219 ContentLength: -1, 220 Body: io.NopCloser(strings.NewReader("abcdef")), 221 }, 222 "HTTP/1.1 200 OK\r\nConnection: close\r\n\r\nabcdef", 223 }, 224 225 // Status code under 100 should be zero-padded to 226 // three digits. Still bogus, but less bogus. (be 227 // consistent with generating three digits, since the 228 // Transport requires it) 229 { 230 Response{ 231 StatusCode: 7, 232 Status: "license to violate specs", 233 ProtoMajor: 1, 234 ProtoMinor: 0, 235 Request: dummyReq("GET"), 236 Header: Header{}, 237 Body: nil, 238 }, 239 240 "HTTP/1.0 007 license to violate specs\r\nContent-Length: 0\r\n\r\n", 241 }, 242 243 // No stutter. Status code in 1xx range response should 244 // not include a Content-Length header. See issue #16942. 245 { 246 Response{ 247 StatusCode: 123, 248 Status: "123 Sesame Street", 249 ProtoMajor: 1, 250 ProtoMinor: 0, 251 Request: dummyReq("GET"), 252 Header: Header{}, 253 Body: nil, 254 }, 255 256 "HTTP/1.0 123 Sesame Street\r\n\r\n", 257 }, 258 259 // Status code 204 (No content) response should not include a 260 // Content-Length header. See issue #16942. 261 { 262 Response{ 263 StatusCode: 204, 264 Status: "No Content", 265 ProtoMajor: 1, 266 ProtoMinor: 0, 267 Request: dummyReq("GET"), 268 Header: Header{}, 269 Body: nil, 270 }, 271 272 "HTTP/1.0 204 No Content\r\n\r\n", 273 }, 274 } 275 276 for i := range respWriteTests { 277 tt := &respWriteTests[i] 278 var braw strings.Builder 279 err := tt.Resp.Write(&braw) 280 if err != nil { 281 t.Errorf("error writing #%d: %s", i, err) 282 continue 283 } 284 sraw := braw.String() 285 if sraw != tt.Raw { 286 t.Errorf("Test %d, expecting:\n%q\nGot:\n%q\n", i, tt.Raw, sraw) 287 continue 288 } 289 } 290 }