github.com/guyezi/gofrontend@v0.0.0-20200228202240-7a62a49e62c0/libgo/go/net/http/fcgi/fcgi_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 fcgi 6 7 import ( 8 "bytes" 9 "errors" 10 "io" 11 "io/ioutil" 12 "net/http" 13 "testing" 14 ) 15 16 var sizeTests = []struct { 17 size uint32 18 bytes []byte 19 }{ 20 {0, []byte{0x00}}, 21 {127, []byte{0x7F}}, 22 {128, []byte{0x80, 0x00, 0x00, 0x80}}, 23 {1000, []byte{0x80, 0x00, 0x03, 0xE8}}, 24 {33554431, []byte{0x81, 0xFF, 0xFF, 0xFF}}, 25 } 26 27 func TestSize(t *testing.T) { 28 b := make([]byte, 4) 29 for i, test := range sizeTests { 30 n := encodeSize(b, test.size) 31 if !bytes.Equal(b[:n], test.bytes) { 32 t.Errorf("%d expected %x, encoded %x", i, test.bytes, b) 33 } 34 size, n := readSize(test.bytes) 35 if size != test.size { 36 t.Errorf("%d expected %d, read %d", i, test.size, size) 37 } 38 if len(test.bytes) != n { 39 t.Errorf("%d did not consume all the bytes", i) 40 } 41 } 42 } 43 44 var streamTests = []struct { 45 desc string 46 recType recType 47 reqId uint16 48 content []byte 49 raw []byte 50 }{ 51 {"single record", typeStdout, 1, nil, 52 []byte{1, byte(typeStdout), 0, 1, 0, 0, 0, 0}, 53 }, 54 // this data will have to be split into two records 55 {"two records", typeStdin, 300, make([]byte, 66000), 56 bytes.Join([][]byte{ 57 // header for the first record 58 {1, byte(typeStdin), 0x01, 0x2C, 0xFF, 0xFF, 1, 0}, 59 make([]byte, 65536), 60 // header for the second 61 {1, byte(typeStdin), 0x01, 0x2C, 0x01, 0xD1, 7, 0}, 62 make([]byte, 472), 63 // header for the empty record 64 {1, byte(typeStdin), 0x01, 0x2C, 0, 0, 0, 0}, 65 }, 66 nil), 67 }, 68 } 69 70 type nilCloser struct { 71 io.ReadWriter 72 } 73 74 func (c *nilCloser) Close() error { return nil } 75 76 func TestStreams(t *testing.T) { 77 var rec record 78 outer: 79 for _, test := range streamTests { 80 buf := bytes.NewBuffer(test.raw) 81 var content []byte 82 for buf.Len() > 0 { 83 if err := rec.read(buf); err != nil { 84 t.Errorf("%s: error reading record: %v", test.desc, err) 85 continue outer 86 } 87 content = append(content, rec.content()...) 88 } 89 if rec.h.Type != test.recType { 90 t.Errorf("%s: got type %d expected %d", test.desc, rec.h.Type, test.recType) 91 continue 92 } 93 if rec.h.Id != test.reqId { 94 t.Errorf("%s: got request ID %d expected %d", test.desc, rec.h.Id, test.reqId) 95 continue 96 } 97 if !bytes.Equal(content, test.content) { 98 t.Errorf("%s: read wrong content", test.desc) 99 continue 100 } 101 buf.Reset() 102 c := newConn(&nilCloser{buf}) 103 w := newWriter(c, test.recType, test.reqId) 104 if _, err := w.Write(test.content); err != nil { 105 t.Errorf("%s: error writing record: %v", test.desc, err) 106 continue 107 } 108 if err := w.Close(); err != nil { 109 t.Errorf("%s: error closing stream: %v", test.desc, err) 110 continue 111 } 112 if !bytes.Equal(buf.Bytes(), test.raw) { 113 t.Errorf("%s: wrote wrong content", test.desc) 114 } 115 } 116 } 117 118 type writeOnlyConn struct { 119 buf []byte 120 } 121 122 func (c *writeOnlyConn) Write(p []byte) (int, error) { 123 c.buf = append(c.buf, p...) 124 return len(p), nil 125 } 126 127 func (c *writeOnlyConn) Read(p []byte) (int, error) { 128 return 0, errors.New("conn is write-only") 129 } 130 131 func (c *writeOnlyConn) Close() error { 132 return nil 133 } 134 135 func TestGetValues(t *testing.T) { 136 var rec record 137 rec.h.Type = typeGetValues 138 139 wc := new(writeOnlyConn) 140 c := newChild(wc, nil) 141 err := c.handleRecord(&rec) 142 if err != nil { 143 t.Fatalf("handleRecord: %v", err) 144 } 145 146 const want = "\x01\n\x00\x00\x00\x12\x06\x00" + 147 "\x0f\x01FCGI_MPXS_CONNS1" + 148 "\x00\x00\x00\x00\x00\x00\x01\n\x00\x00\x00\x00\x00\x00" 149 if got := string(wc.buf); got != want { 150 t.Errorf(" got: %q\nwant: %q\n", got, want) 151 } 152 } 153 154 func nameValuePair11(nameData, valueData string) []byte { 155 return bytes.Join( 156 [][]byte{ 157 {byte(len(nameData)), byte(len(valueData))}, 158 []byte(nameData), 159 []byte(valueData), 160 }, 161 nil, 162 ) 163 } 164 165 func makeRecord( 166 recordType recType, 167 requestId uint16, 168 contentData []byte, 169 ) []byte { 170 requestIdB1 := byte(requestId >> 8) 171 requestIdB0 := byte(requestId) 172 173 contentLength := len(contentData) 174 contentLengthB1 := byte(contentLength >> 8) 175 contentLengthB0 := byte(contentLength) 176 return bytes.Join([][]byte{ 177 {1, byte(recordType), requestIdB1, requestIdB0, contentLengthB1, 178 contentLengthB0, 0, 0}, 179 contentData, 180 }, 181 nil) 182 } 183 184 // a series of FastCGI records that start a request and begin sending the 185 // request body 186 var streamBeginTypeStdin = bytes.Join([][]byte{ 187 // set up request 1 188 makeRecord(typeBeginRequest, 1, 189 []byte{0, byte(roleResponder), 0, 0, 0, 0, 0, 0}), 190 // add required parameters to request 1 191 makeRecord(typeParams, 1, nameValuePair11("REQUEST_METHOD", "GET")), 192 makeRecord(typeParams, 1, nameValuePair11("SERVER_PROTOCOL", "HTTP/1.1")), 193 makeRecord(typeParams, 1, nil), 194 // begin sending body of request 1 195 makeRecord(typeStdin, 1, []byte("0123456789abcdef")), 196 }, 197 nil) 198 199 var cleanUpTests = []struct { 200 input []byte 201 err error 202 }{ 203 // confirm that child.handleRecord closes req.pw after aborting req 204 { 205 bytes.Join([][]byte{ 206 streamBeginTypeStdin, 207 makeRecord(typeAbortRequest, 1, nil), 208 }, 209 nil), 210 ErrRequestAborted, 211 }, 212 // confirm that child.serve closes all pipes after error reading record 213 { 214 bytes.Join([][]byte{ 215 streamBeginTypeStdin, 216 nil, 217 }, 218 nil), 219 ErrConnClosed, 220 }, 221 } 222 223 type nopWriteCloser struct { 224 io.ReadWriter 225 } 226 227 func (nopWriteCloser) Close() error { 228 return nil 229 } 230 231 // Test that child.serve closes the bodies of aborted requests and closes the 232 // bodies of all requests before returning. Causes deadlock if either condition 233 // isn't met. See issue 6934. 234 func TestChildServeCleansUp(t *testing.T) { 235 for _, tt := range cleanUpTests { 236 input := make([]byte, len(tt.input)) 237 copy(input, tt.input) 238 rc := nopWriteCloser{bytes.NewBuffer(input)} 239 done := make(chan bool) 240 c := newChild(rc, http.HandlerFunc(func( 241 w http.ResponseWriter, 242 r *http.Request, 243 ) { 244 // block on reading body of request 245 _, err := io.Copy(ioutil.Discard, r.Body) 246 if err != tt.err { 247 t.Errorf("Expected %#v, got %#v", tt.err, err) 248 } 249 // not reached if body of request isn't closed 250 done <- true 251 })) 252 go c.serve() 253 // wait for body of request to be closed or all goroutines to block 254 <-done 255 } 256 } 257 258 type rwNopCloser struct { 259 io.Reader 260 io.Writer 261 } 262 263 func (rwNopCloser) Close() error { 264 return nil 265 } 266 267 // Verifies it doesn't crash. Issue 11824. 268 func TestMalformedParams(t *testing.T) { 269 input := []byte{ 270 // beginRequest, requestId=1, contentLength=8, role=1, keepConn=1 271 1, 1, 0, 1, 0, 8, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 272 // params, requestId=1, contentLength=10, k1Len=50, v1Len=50 (malformed, wrong length) 273 1, 4, 0, 1, 0, 10, 0, 0, 50, 50, 3, 4, 5, 6, 7, 8, 9, 10, 274 // end of params 275 1, 4, 0, 1, 0, 0, 0, 0, 276 } 277 rw := rwNopCloser{bytes.NewReader(input), ioutil.Discard} 278 c := newChild(rw, http.DefaultServeMux) 279 c.serve() 280 } 281 282 // a series of FastCGI records that start and end a request 283 var streamFullRequestStdin = bytes.Join([][]byte{ 284 // set up request 285 makeRecord(typeBeginRequest, 1, 286 []byte{0, byte(roleResponder), 0, 0, 0, 0, 0, 0}), 287 // add required parameters 288 makeRecord(typeParams, 1, nameValuePair11("REQUEST_METHOD", "GET")), 289 makeRecord(typeParams, 1, nameValuePair11("SERVER_PROTOCOL", "HTTP/1.1")), 290 // set optional parameters 291 makeRecord(typeParams, 1, nameValuePair11("REMOTE_USER", "jane.doe")), 292 makeRecord(typeParams, 1, nameValuePair11("QUERY_STRING", "/foo/bar")), 293 makeRecord(typeParams, 1, nil), 294 // begin sending body of request 295 makeRecord(typeStdin, 1, []byte("0123456789abcdef")), 296 // end request 297 makeRecord(typeEndRequest, 1, nil), 298 }, 299 nil) 300 301 var envVarTests = []struct { 302 input []byte 303 envVar string 304 expectedVal string 305 expectedFilteredOut bool 306 }{ 307 { 308 streamFullRequestStdin, 309 "REMOTE_USER", 310 "jane.doe", 311 false, 312 }, 313 { 314 streamFullRequestStdin, 315 "QUERY_STRING", 316 "", 317 true, 318 }, 319 } 320 321 // Test that environment variables set for a request can be 322 // read by a handler. Ensures that variables not set will not 323 // be exposed to a handler. 324 func TestChildServeReadsEnvVars(t *testing.T) { 325 for _, tt := range envVarTests { 326 input := make([]byte, len(tt.input)) 327 copy(input, tt.input) 328 rc := nopWriteCloser{bytes.NewBuffer(input)} 329 done := make(chan bool) 330 c := newChild(rc, http.HandlerFunc(func( 331 w http.ResponseWriter, 332 r *http.Request, 333 ) { 334 env := ProcessEnv(r) 335 if _, ok := env[tt.envVar]; ok && tt.expectedFilteredOut { 336 t.Errorf("Expected environment variable %s to not be set, but set to %s", 337 tt.envVar, env[tt.envVar]) 338 } else if env[tt.envVar] != tt.expectedVal { 339 t.Errorf("Expected %s, got %s", tt.expectedVal, env[tt.envVar]) 340 } 341 done <- true 342 })) 343 go c.serve() 344 <-done 345 } 346 }