github.com/cloudwego/hertz@v0.9.3/pkg/protocol/http1/req/request_test.go (about) 1 /* 2 * Copyright 2022 CloudWeGo Authors 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 * 16 * The MIT License (MIT) 17 * 18 * Copyright (c) 2015-present Aliaksandr Valialkin, VertaMedia, Kirill Danshin, Erik Dubbelboer, FastHTTP Authors 19 * 20 * Permission is hereby granted, free of charge, to any person obtaining a copy 21 * of this software and associated documentation files (the "Software"), to deal 22 * in the Software without restriction, including without limitation the rights 23 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 24 * copies of the Software, and to permit persons to whom the Software is 25 * furnished to do so, subject to the following conditions: 26 * 27 * The above copyright notice and this permission notice shall be included in 28 * all copies or substantial portions of the Software. 29 * 30 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 31 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 32 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 33 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 34 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 35 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 36 * THE SOFTWARE. 37 * 38 * This file may have been modified by CloudWeGo authors. All CloudWeGo 39 * Modifications are Copyright 2022 CloudWeGo Authors. 40 */ 41 42 package req 43 44 import ( 45 "bufio" 46 "bytes" 47 "encoding/base64" 48 "errors" 49 "fmt" 50 "io" 51 "io/ioutil" 52 "mime/multipart" 53 "net/url" 54 "strings" 55 "testing" 56 57 "github.com/cloudwego/hertz/internal/bytesconv" 58 "github.com/cloudwego/hertz/internal/bytestr" 59 "github.com/cloudwego/hertz/pkg/common/bytebufferpool" 60 "github.com/cloudwego/hertz/pkg/common/compress" 61 errs "github.com/cloudwego/hertz/pkg/common/errors" 62 "github.com/cloudwego/hertz/pkg/common/test/assert" 63 "github.com/cloudwego/hertz/pkg/common/test/mock" 64 "github.com/cloudwego/hertz/pkg/common/utils" 65 "github.com/cloudwego/hertz/pkg/network" 66 "github.com/cloudwego/hertz/pkg/protocol" 67 "github.com/cloudwego/hertz/pkg/protocol/consts" 68 "github.com/cloudwego/hertz/pkg/protocol/http1/ext" 69 "github.com/cloudwego/netpoll" 70 ) 71 72 func TestRequestContinueReadBody(t *testing.T) { 73 t.Parallel() 74 s := "PUT /foo/bar HTTP/1.1\r\nExpect: 100-continue\r\nContent-Length: 5\r\nContent-Type: foo/bar\r\n\r\nabcdef4343" 75 zr := mock.NewZeroCopyReader(s) 76 77 var r protocol.Request 78 if err := Read(&r, zr); err != nil { 79 t.Fatalf("unexpected error: %s", err) 80 } 81 82 if err := ContinueReadBody(&r, zr, 0, true); err != nil { 83 t.Fatalf("error when reading request body: %s", err) 84 } 85 body := r.Body() 86 if string(body) != "abcde" { 87 t.Fatalf("unexpected body %q. Expecting %q", body, "abcde") 88 } 89 90 tail, err := zr.Peek(zr.Len()) 91 if err != nil { 92 t.Fatalf("unexpected error: %s", err) 93 } 94 if string(tail) != "f4343" { 95 t.Fatalf("unexpected tail %q. Expecting %q", tail, "f4343") 96 } 97 } 98 99 func TestRequestReadNoBody(t *testing.T) { 100 t.Parallel() 101 102 var r protocol.Request 103 104 s := "GET / HTTP/1.1\r\n\r\n" 105 106 zr := mock.NewZeroCopyReader(s) 107 if err := Read(&r, zr); err != nil { 108 t.Fatalf("unexpected error: %s", err) 109 } 110 r.SetHost("foobar") 111 headerStr := r.Header.String() 112 if strings.Contains(headerStr, "Content-Length: ") { 113 t.Fatalf("unexpected Content-Length") 114 } 115 } 116 117 func TestRequestRead(t *testing.T) { 118 t.Parallel() 119 120 var r protocol.Request 121 122 s := "POST / HTTP/1.1\r\n\r\n" 123 124 zr := mock.NewZeroCopyReader(s) 125 if err := Read(&r, zr); err != nil { 126 t.Fatalf("unexpected error: %s", err) 127 } 128 r.SetHost("foobar") 129 headerStr := r.Header.String() 130 if !strings.Contains(headerStr, "Content-Length: ") { 131 t.Fatalf("should contain Content-Length") 132 } 133 cLen := r.Header.Peek(consts.HeaderContentLength) 134 if string(cLen) != "0" { 135 t.Fatalf("unexpected Content-Length: %s, Expecting 0", string(cLen)) 136 } 137 } 138 139 func TestRequestReadNoBodyStreaming(t *testing.T) { 140 t.Parallel() 141 142 var r protocol.Request 143 r.Header.SetContentLength(-2) 144 r.Header.SetMethod("GET") 145 146 s := "" 147 148 zr := mock.NewZeroCopyReader(s) 149 if err := ContinueReadBodyStream(&r, zr, 2048, true); err != nil { 150 t.Fatalf("unexpected error: %s", err) 151 } 152 r.SetHost("foobar") 153 headerStr := r.Header.String() 154 if strings.Contains(headerStr, "Content-Length: ") { 155 t.Fatalf("unexpected Content-Length") 156 } 157 } 158 159 func TestRequestReadStreaming(t *testing.T) { 160 t.Parallel() 161 162 var r protocol.Request 163 r.Header.SetContentLength(-2) 164 r.Header.SetMethod("POST") 165 166 s := "" 167 168 zr := mock.NewZeroCopyReader(s) 169 if err := ContinueReadBodyStream(&r, zr, 2048, true); err != nil { 170 t.Fatalf("unexpected error: %s", err) 171 } 172 r.SetHost("foobar") 173 headerStr := r.Header.String() 174 if !strings.Contains(headerStr, "Content-Length: ") { 175 t.Fatalf("should contain Content-Length") 176 } 177 cLen := r.Header.Peek(consts.HeaderContentLength) 178 if string(cLen) != "0" { 179 t.Fatalf("unexpected Content-Length: %s, Expecting 0", string(cLen)) 180 } 181 } 182 183 func TestMethodAndPathAndQueryString(t *testing.T) { 184 s := "PUT /foo/bar?query=1 HTTP/1.1\r\nExpect: 100-continue\r\nContent-Length: 5\r\nContent-Type: foo/bar\r\n\r\nabcdef4343" 185 zr := mock.NewZeroCopyReader(s) 186 187 var r protocol.Request 188 if err := Read(&r, zr); err != nil { 189 t.Fatalf("unexpected error: %s", err) 190 } 191 if string(r.RequestURI()) != "/foo/bar?query=1" { 192 t.Fatalf("unexpected request uri %s. Expecting %s", r.RequestURI(), "/foo/bar?query=1") 193 } 194 if string(r.Method()) != "PUT" { 195 t.Fatalf("unexpected method %s. Expecting %s", r.Header.Method(), "PUT") 196 } 197 198 if string(r.Path()) != "/foo/bar" { 199 t.Fatalf("unexpected uri path %s. Expecting %s", r.URI().Path(), "/foo/bar") 200 } 201 if string(r.QueryString()) != "query=1" { 202 t.Fatalf("unexpected query string %s. Expecting %s", r.URI().QueryString(), "query=1") 203 } 204 } 205 206 func TestRequestSuccess(t *testing.T) { 207 t.Parallel() 208 209 // empty method, user-agent and body 210 testRequestSuccess(t, "", "/foo/bar", "google.com", "", "", consts.MethodGet) 211 212 // non-empty user-agent 213 testRequestSuccess(t, consts.MethodGet, "/foo/bar", "google.com", "MSIE", "", consts.MethodGet) 214 215 // non-empty method 216 testRequestSuccess(t, consts.MethodHead, "/aaa", "fobar", "", "", consts.MethodHead) 217 218 // POST method with body 219 testRequestSuccess(t, consts.MethodPost, "/bbb", "aaa.com", "Chrome aaa", "post body", consts.MethodPost) 220 221 // PUT method with body 222 testRequestSuccess(t, consts.MethodPut, "/aa/bb", "a.com", "ome aaa", "put body", consts.MethodPut) 223 224 // only host is set 225 testRequestSuccess(t, "", "", "gooble.com", "", "", consts.MethodGet) 226 227 // get with body 228 testRequestSuccess(t, consts.MethodGet, "/foo/bar", "aaa.com", "", "foobar", consts.MethodGet) 229 } 230 231 func TestRequestMultipartFormBoundary(t *testing.T) { 232 t.Parallel() 233 234 testRequestMultipartFormBoundary(t, "POST / HTTP/1.1\r\nContent-Type: multipart/form-data; boundary=foobar\r\n\r\n", "foobar") 235 236 // incorrect content-type 237 testRequestMultipartFormBoundary(t, "POST / HTTP/1.1\r\nContent-Type: foo/bar\r\n\r\n", "") 238 239 // empty boundary 240 testRequestMultipartFormBoundary(t, "POST / HTTP/1.1\r\nContent-Type: multipart/form-data; boundary=\r\n\r\n", "") 241 242 // missing boundary 243 testRequestMultipartFormBoundary(t, "POST / HTTP/1.1\r\nContent-Type: multipart/form-data\r\n\r\n", "") 244 245 // boundary after other content-type params 246 testRequestMultipartFormBoundary(t, "POST / HTTP/1.1\r\nContent-Type: multipart/form-data; foo=bar; boundary=--aaabb \r\n\r\n", "--aaabb") 247 248 // quoted boundary 249 testRequestMultipartFormBoundary(t, "POST / HTTP/1.1\r\nContent-Type: multipart/form-data; boundary=\"foobar\"\r\n\r\n", "foobar") 250 251 var h protocol.RequestHeader 252 h.SetMultipartFormBoundary("foobarbaz") 253 b := h.MultipartFormBoundary() 254 if string(b) != "foobarbaz" { 255 t.Fatalf("unexpected boundary %q. Expecting %q", b, "foobarbaz") 256 } 257 } 258 259 func testRequestSuccess(t *testing.T, method, requestURI, host, userAgent, body, expectedMethod string) { 260 var req protocol.Request 261 262 req.Header.SetMethod(method) 263 req.Header.SetRequestURI(requestURI) 264 req.Header.Set(consts.HeaderHost, host) 265 req.Header.Set(consts.HeaderUserAgent, userAgent) 266 req.SetBody([]byte(body)) 267 268 contentType := "foobar" 269 if method == consts.MethodPost { 270 req.Header.Set(consts.HeaderContentType, contentType) 271 } 272 273 w := &bytes.Buffer{} 274 zw := netpoll.NewWriter(w) 275 err := Write(&req, zw) 276 if err != nil { 277 t.Fatalf("Unexpected error when calling Write(): %s", err) 278 } 279 280 if err = zw.Flush(); err != nil { 281 t.Fatalf("Unexpected error when flushing bufio.Writer: %s", err) 282 } 283 284 var req1 protocol.Request 285 br := bufio.NewReader(w) 286 zr := netpoll.NewReader(br) 287 if err = Read(&req1, zr); err != nil { 288 t.Fatalf("Unexpected error when calling Read(): %s", err) 289 } 290 if string(req1.Header.Method()) != expectedMethod { 291 t.Fatalf("Unexpected method: %q. Expected %q", req1.Header.Method(), expectedMethod) 292 } 293 if len(requestURI) == 0 { 294 requestURI = "/" 295 } 296 if string(req1.Header.RequestURI()) != requestURI { 297 t.Fatalf("Unexpected RequestURI: %q. Expected %q", req1.Header.RequestURI(), requestURI) 298 } 299 if string(req1.Header.Peek(consts.HeaderHost)) != host { 300 t.Fatalf("Unexpected host: %q. Expected %q", req1.Header.Peek(consts.HeaderHost), host) 301 } 302 if string(req1.Header.Peek(consts.HeaderUserAgent)) != userAgent { 303 t.Fatalf("Unexpected user-agent: %q. Expected %q", req1.Header.Peek(consts.HeaderUserAgent), userAgent) 304 } 305 if !bytes.Equal(req1.Body(), []byte(body)) { 306 t.Fatalf("Unexpected body: %q. Expected %q", req1.Body(), body) 307 } 308 309 if method == consts.MethodPost && string(req1.Header.Peek(consts.HeaderContentType)) != contentType { 310 t.Fatalf("Unexpected content-type: %q. Expected %q", req1.Header.Peek(consts.HeaderContentType), contentType) 311 } 312 } 313 314 func TestRequestWriteError(t *testing.T) { 315 t.Parallel() 316 317 // no host 318 testRequestWriteError(t, "", "/foo/bar", "", "", "") 319 } 320 321 func TestRequestPostArgsSuccess(t *testing.T) { 322 t.Parallel() 323 324 var req protocol.Request 325 326 testRequestPostArgsSuccess(t, &req, "POST / HTTP/1.1\r\nHost: aaa.com\r\nContent-Type: application/x-www-form-urlencoded\r\nContent-Length: 0\r\n\r\n", 0, "foo=", "=") 327 328 testRequestPostArgsSuccess(t, &req, "POST / HTTP/1.1\r\nHost: aaa.com\r\nContent-Type: application/x-www-form-urlencoded\r\nContent-Length: 18\r\n\r\nfoo&b%20r=b+z=&qwe", 3, "foo=", "b r=b z=", "qwe=") 329 } 330 331 func testRequestPostArgsSuccess(t *testing.T, req *protocol.Request, s string, expectedArgsLen int, expectedArgs ...string) { 332 r := bytes.NewBufferString(s) 333 zr := netpoll.NewReader(r) 334 err := Read(req, zr) 335 if err != nil { 336 t.Fatalf("Unexpected error when reading %q: %s", s, err) 337 } 338 339 args := req.PostArgs() 340 if args.Len() != expectedArgsLen { 341 t.Fatalf("Unexpected args len %d. Expected %d for %q", args.Len(), expectedArgsLen, s) 342 } 343 for _, x := range expectedArgs { 344 tmp := strings.SplitN(x, "=", 2) 345 k := tmp[0] 346 v := tmp[1] 347 vv := string(args.Peek(k)) 348 if vv != v { 349 t.Fatalf("Unexpected value for key %q: %q. Expected %q for %q", k, vv, v, s) 350 } 351 } 352 } 353 354 func TestRequestPostArgsBodyStream(t *testing.T) { 355 var req protocol.Request 356 s := "POST / HTTP/1.1\r\nHost: aaa.com\r\nContent-Type: application/x-www-form-urlencoded\r\nContent-Length: 8196\r\n\r\n" 357 contentB := make([]byte, 8192) 358 for i := 0; i < len(contentB); i++ { 359 contentB[i] = 'a' 360 } 361 content := string(contentB) 362 requestString := s + url.Values{"key": []string{content}}.Encode() 363 364 r := bytes.NewBufferString(requestString) 365 zr := netpoll.NewReader(r) 366 if err := ReadHeader(&req.Header, zr); err != nil { 367 t.Fatalf("Unexpected error when reading header %q: %s", s, err) 368 } 369 370 err := ReadBodyStream(&req, zr, 1024*4, false, false) 371 if err != nil { 372 t.Fatalf("Unexpected error when reading bodystream %q: %s", s, err) 373 } 374 if string(req.PostArgs().Peek("key")) != content { 375 assert.DeepEqual(t, content, string(req.PostArgs().Peek("key"))) 376 } 377 } 378 379 func testRequestWriteError(t *testing.T, method, requestURI, host, userAgent, body string) { 380 var req protocol.Request 381 382 req.Header.SetMethod(method) 383 req.Header.SetRequestURI(requestURI) 384 req.Header.Set(consts.HeaderHost, host) 385 req.Header.Set(consts.HeaderUserAgent, userAgent) 386 req.SetBody([]byte(body)) 387 388 w := &bytebufferpool.ByteBuffer{} 389 zw := netpoll.NewWriter(w) 390 err := Write(&req, zw) 391 if err == nil { 392 t.Fatalf("Expecting error when writing request=%#v", &req) 393 } 394 } 395 396 func TestChunkedUnexpectedEOF(t *testing.T) { 397 reader := &mock.EOFReader{} 398 399 _, err := ext.ReadBody(reader, -1, 0, nil) 400 if err != io.ErrUnexpectedEOF { 401 assert.DeepEqual(t, io.ErrUnexpectedEOF, err) 402 } 403 404 var pool bytebufferpool.Pool 405 var req1 protocol.Request 406 bs := ext.AcquireBodyStream(pool.Get(), reader, req1.Header.Trailer(), -1) 407 byteSlice := make([]byte, 4096) 408 _, err = bs.Read(byteSlice) 409 if err != io.ErrUnexpectedEOF { 410 assert.DeepEqual(t, io.ErrUnexpectedEOF, err) 411 } 412 } 413 414 func TestReadBodyChunked(t *testing.T) { 415 t.Parallel() 416 417 // zero-size body 418 testReadBodyChunked(t, 0) 419 420 // small-size body 421 testReadBodyChunked(t, 5) 422 423 // medium-size body 424 testReadBodyChunked(t, 43488) 425 426 // big body 427 testReadBodyChunked(t, 3*1024*1024) 428 429 // smaller body after big one 430 testReadBodyChunked(t, 12343) 431 } 432 433 func TestReadBodyFixedSize(t *testing.T) { 434 t.Parallel() 435 436 // zero-size body 437 testReadBodyFixedSize(t, 0) 438 439 // small-size body 440 testReadBodyFixedSize(t, 3) 441 442 // medium-size body 443 testReadBodyFixedSize(t, 1024) 444 445 // large-size body 446 testReadBodyFixedSize(t, 1024*1024) 447 448 // smaller body after big one 449 testReadBodyFixedSize(t, 34345) 450 } 451 452 func TestRequestWriteRequestURINoHost(t *testing.T) { 453 t.Parallel() 454 455 var req protocol.Request 456 req.Header.SetRequestURI("http://user:pass@google.com/foo/bar?baz=aaa") 457 var w bytes.Buffer 458 zw := netpoll.NewWriter(&w) 459 if err := Write(&req, zw); err != nil { 460 t.Fatalf("unexpected error: %s", err) 461 } 462 463 if err := zw.Flush(); err != nil { 464 t.Fatalf("unexpected error: %s", err) 465 } 466 467 var req1 protocol.Request 468 br := bufio.NewReader(&w) 469 zr := netpoll.NewReader(br) 470 if err := Read(&req1, zr); err != nil { 471 t.Fatalf("unexpected error: %s", err) 472 } 473 if string(req1.Header.Host()) != "google.com" { 474 t.Fatalf("unexpected host: %q. Expecting %q", req1.Header.Host(), "google.com") 475 } 476 if string(req.Header.RequestURI()) != "/foo/bar?baz=aaa" { 477 t.Fatalf("unexpected requestURI: %q. Expecting %q", req.Header.RequestURI(), "/foo/bar?baz=aaa") 478 } 479 // authorization 480 authorization := req.Header.Get(string(bytestr.StrAuthorization)) 481 author, err := base64.StdEncoding.DecodeString(authorization[len(bytestr.StrBasicSpace):]) 482 if err != nil { 483 t.Fatalf("expecting error") 484 } 485 486 if string(author) != "user:pass" { 487 t.Fatalf("unexpected Authorization: %q. Expecting %q", authorization, "user:pass") 488 } 489 490 // verify that Write returns error on non-absolute RequestURI 491 req.Reset() 492 req.Header.SetRequestURI("/foo/bar") 493 w.Reset() 494 if err := Write(&req, zw); err == nil { 495 t.Fatalf("expecting error") 496 } 497 } 498 499 func TestRequestWriteMultipartFile(t *testing.T) { 500 t.Parallel() 501 502 var req protocol.Request 503 req.Header.SetHost("foobar.com") 504 req.Header.SetMethod(consts.MethodPost) 505 req.SetFileReader("filea", "filea.txt", bytes.NewReader([]byte("This is filea."))) 506 req.SetMultipartField("fileb", "fileb.txt", "text/plain", bytes.NewReader([]byte("This is fileb."))) 507 508 var w bytes.Buffer 509 zw := netpoll.NewWriter(&w) 510 if err := Write(&req, zw); err != nil { 511 t.Fatalf("unexpected error: %s", err) 512 } 513 if err := zw.Flush(); err != nil { 514 t.Fatalf("unexpected error: %s", err) 515 } 516 517 var req1 protocol.Request 518 zr := mock.NewZeroCopyReader(w.String()) 519 if err := Read(&req1, zr); err != nil { 520 t.Fatalf("unexpected error: %s", err) 521 } 522 523 filea, err := req1.FormFile("filea") 524 assert.Nil(t, err) 525 assert.DeepEqual(t, "filea.txt", filea.Filename) 526 fileb, err := req1.FormFile("fileb") 527 assert.Nil(t, err) 528 assert.DeepEqual(t, "fileb.txt", fileb.Filename) 529 } 530 531 func TestSetRequestBodyStreamChunked(t *testing.T) { 532 t.Parallel() 533 534 testSetRequestBodyStreamChunked(t, "", map[string]string{"Foo": "bar"}) 535 536 body := "foobar baz aaa bbb ccc" 537 testSetRequestBodyStreamChunked(t, body, nil) 538 539 body = string(mock.CreateFixedBody(10001)) 540 testSetRequestBodyStreamChunked(t, body, map[string]string{"Foo": "test", "Bar": "test"}) 541 } 542 543 func TestSetRequestBodyStreamFixedSize(t *testing.T) { 544 t.Parallel() 545 546 testSetRequestBodyStream(t, "a") 547 testSetRequestBodyStream(t, string(mock.CreateFixedBody(4097))) 548 testSetRequestBodyStream(t, string(mock.CreateFixedBody(100500))) 549 } 550 551 func TestRequestHostFromRequestURI(t *testing.T) { 552 t.Parallel() 553 554 hExpected := "foobar.com" 555 var req protocol.Request 556 req.SetRequestURI("http://proxy-host:123/foobar?baz") 557 req.SetHost(hExpected) 558 h := bytesconv.B2s(req.Host()) 559 if h != hExpected { 560 t.Fatalf("unexpected host set: %q. Expecting %q", h, hExpected) 561 } 562 } 563 564 func TestRequestHostFromHeader(t *testing.T) { 565 t.Parallel() 566 567 hExpected := "foobar.com" 568 var req protocol.Request 569 req.Header.SetHost(hExpected) 570 h := bytesconv.B2s(req.Host()) 571 if h != hExpected { 572 t.Fatalf("unexpected host set: %q. Expecting %q", h, hExpected) 573 } 574 } 575 576 func TestRequestContentTypeWithCharset(t *testing.T) { 577 t.Parallel() 578 579 expectedContentType := consts.MIMEApplicationHTMLFormUTF8 580 expectedBody := "0123=56789" 581 s := fmt.Sprintf("POST / HTTP/1.1\r\nContent-Type: %s\r\nContent-Length: %d\r\n\r\n%s", 582 expectedContentType, len(expectedBody), expectedBody) 583 584 zr := mock.NewZeroCopyReader(s) 585 var r protocol.Request 586 if err := Read(&r, zr); err != nil { 587 t.Fatalf("unexpected error: %s", err) 588 } 589 590 body := r.Body() 591 if string(body) != expectedBody { 592 t.Fatalf("unexpected body %q. Expecting %q", body, expectedBody) 593 } 594 ct := r.Header.ContentType() 595 if string(ct) != expectedContentType { 596 t.Fatalf("unexpected content-type %q. Expecting %q", ct, expectedContentType) 597 } 598 args := r.PostArgs() 599 if args.Len() != 1 { 600 t.Fatalf("unexpected number of POST args: %d. Expecting 1", args.Len()) 601 } 602 av := args.Peek("0123") 603 if string(av) != "56789" { 604 t.Fatalf("unexpected POST arg value: %q. Expecting %q", av, "56789") 605 } 606 } 607 608 func TestRequestBodyStreamMultipleBodyCalls(t *testing.T) { 609 t.Parallel() 610 611 var r protocol.Request 612 613 s := "foobar baz abc" 614 if r.IsBodyStream() { 615 t.Fatalf("IsBodyStream must return false") 616 } 617 r.SetBodyStream(bytes.NewBufferString(s), len(s)) 618 if !r.IsBodyStream() { 619 t.Fatalf("IsBodyStream must return true") 620 } 621 for i := 0; i < 10; i++ { 622 body := r.Body() 623 if string(body) != s { 624 t.Fatalf("unexpected body %q. Expecting %q. iteration %d", body, s, i) 625 } 626 } 627 } 628 629 func TestRequestNoContentLength(t *testing.T) { 630 t.Parallel() 631 632 var r protocol.Request 633 634 r.Header.SetMethod(consts.MethodHead) 635 r.Header.SetHost("foobar") 636 637 s := GetHTTP1Request(&r).String() 638 if strings.Contains(s, "Content-Length: ") { 639 t.Fatalf("unexpected content-length in HEAD request %q", s) 640 } 641 642 r.Header.SetMethod(consts.MethodPost) 643 fmt.Fprintf(r.BodyWriter(), "foobar body") 644 s = GetHTTP1Request(&r).String() 645 if !strings.Contains(s, "Content-Length: ") { 646 t.Fatalf("missing content-length header in non-GET request %q", s) 647 } 648 } 649 650 func TestRequestReadGzippedBody(t *testing.T) { 651 t.Parallel() 652 653 var r protocol.Request 654 655 bodyOriginal := "foo bar baz compress me better!" 656 body := compress.AppendGzipBytes(nil, []byte(bodyOriginal)) 657 s := fmt.Sprintf("POST /foobar HTTP/1.1\r\nContent-Type: foo/bar\r\nContent-Encoding: gzip\r\nContent-Length: %d\r\n\r\n%s", 658 len(body), body) 659 zr := mock.NewZeroCopyReader(s) 660 if err := Read(&r, zr); err != nil { 661 t.Fatalf("unexpected error: %s", err) 662 } 663 664 if string(r.Header.Peek(consts.HeaderContentEncoding)) != "gzip" { 665 t.Fatalf("unexpected content-encoding: %q. Expecting %q", r.Header.Peek(consts.HeaderContentEncoding), "gzip") 666 } 667 if r.Header.ContentLength() != len(body) { 668 t.Fatalf("unexpected content-length: %d. Expecting %d", r.Header.ContentLength(), len(body)) 669 } 670 if string(r.Body()) != string(body) { 671 t.Fatalf("unexpected body: %q. Expecting %q", r.Body(), body) 672 } 673 674 bodyGunzipped, err := compress.AppendGunzipBytes(nil, r.Body()) 675 if err != nil { 676 t.Fatalf("unexpected error when uncompressing data: %s", err) 677 } 678 if string(bodyGunzipped) != bodyOriginal { 679 t.Fatalf("unexpected uncompressed body %q. Expecting %q", bodyGunzipped, bodyOriginal) 680 } 681 } 682 683 func TestRequestReadPostNoBody(t *testing.T) { 684 t.Parallel() 685 686 var r protocol.Request 687 688 s := "POST /foo/bar HTTP/1.1\r\nContent-Type: aaa/bbb\r\n\r\naaaa" 689 zr := mock.NewZeroCopyReader(s) 690 if err := Read(&r, zr); err != nil { 691 t.Fatalf("unexpected error: %s", err) 692 } 693 694 if string(r.Header.RequestURI()) != "/foo/bar" { 695 t.Fatalf("unexpected request uri %q. Expecting %q", r.Header.RequestURI(), "/foo/bar") 696 } 697 if string(r.Header.ContentType()) != "aaa/bbb" { 698 t.Fatalf("unexpected content-type %q. Expecting %q", r.Header.ContentType(), "aaa/bbb") 699 } 700 if len(r.Body()) != 0 { 701 t.Fatalf("unexpected body found %q. Expecting empty body", r.Body()) 702 } 703 if r.Header.ContentLength() != 0 { 704 t.Fatalf("unexpected content-length: %d. Expecting 0", r.Header.ContentLength()) 705 } 706 707 tail, err := ioutil.ReadAll(zr) 708 if err != nil { 709 t.Fatalf("unexpected error: %s", err) 710 } 711 if string(tail) != "aaaa" { 712 t.Fatalf("unexpected tail %q. Expecting %q", tail, "aaaa") 713 } 714 } 715 716 func TestRequestContinueReadBodyDisablePrereadMultipartForm(t *testing.T) { 717 t.Parallel() 718 719 var w bytes.Buffer 720 mw := multipart.NewWriter(&w) 721 for i := 0; i < 10; i++ { 722 k := fmt.Sprintf("key_%d", i) 723 v := fmt.Sprintf("value_%d", i) 724 if err := mw.WriteField(k, v); err != nil { 725 t.Fatalf("unexpected error: %s", err) 726 } 727 } 728 boundary := mw.Boundary() 729 if err := mw.Close(); err != nil { 730 t.Fatalf("unexpected error: %s", err) 731 } 732 formData := w.Bytes() 733 734 s := fmt.Sprintf("POST / HTTP/1.1\r\nHost: aaa\r\nContent-Type: multipart/form-data; boundary=%s\r\nContent-Length: %d\r\n\r\n%s", 735 boundary, len(formData), formData) 736 zr := mock.NewZeroCopyReader(s) 737 738 var r protocol.Request 739 740 if err := ReadHeader(&r.Header, zr); err != nil { 741 t.Fatalf("unexpected error reading headers: %s", err) 742 } 743 744 if err := ReadLimitBody(&r, zr, 10000, false, false); err != nil { 745 t.Fatalf("unexpected error reading body: %s", err) 746 } 747 748 if r.HasMultipartForm() { 749 t.Fatalf("The multipartForm of the Request must be nil") 750 } 751 752 if string(formData) != string(r.Body()) { 753 t.Fatalf("The body given must equal the body in the Request") 754 } 755 } 756 757 func TestRequestReadLimitBody(t *testing.T) { 758 t.Parallel() 759 760 testRequestReadLimitBodyReadOnly(t, "POST /foo HTTP/1.1\r\nHost: aaa.com\r\nContent-Length: 9\r\nContent-Type: aaa\r\n\r\n123456789") 761 // request with content-length 762 testRequestReadLimitBodySuccess(t, "POST /foo HTTP/1.1\r\nHost: aaa.com\r\nContent-Length: 9\r\nContent-Type: aaa\r\n\r\n123456789", 9) 763 testRequestReadLimitBodySuccess(t, "POST /foo HTTP/1.1\r\nHost: aaa.com\r\nContent-Length: 9\r\nContent-Type: aaa\r\n\r\n123456789", 92) 764 testRequestReadLimitBodyError(t, "POST /foo HTTP/1.1\r\nHost: aaa.com\r\nContent-Length: 9\r\nContent-Type: aaa\r\n\r\n123456789", 5) 765 766 // chunked request 767 testRequestReadLimitBodySuccess(t, "POST /a HTTP/1.1\r\nHost: a.com\r\nTransfer-Encoding: chunked\r\nContent-Type: aa\r\n\r\n6\r\nfoobar\r\n3\r\nbaz\r\n0\r\n\r\n", 9) 768 testRequestReadLimitBodySuccess(t, "POST /a HTTP/1.1\r\nHost: a.com\r\nTransfer-Encoding: chunked\r\nContent-Type: aa\r\n\r\n6\r\nfoobar\r\n3\r\nbaz\r\n0\r\n\r\n", 999) 769 testRequestReadLimitBodyError(t, "POST /a HTTP/1.1\r\nHost: a.com\r\nTransfer-Encoding: chunked\r\nContent-Type: aa\r\n\r\n6\r\nfoobar\r\n3\r\nbaz\r\n0\r\n\r\n", 8) 770 } 771 772 func testRequestReadLimitBodyReadOnly(t *testing.T, s string) { 773 var req protocol.Request 774 zr := mock.NewZeroCopyReader(s) 775 776 ReadHeader(&req.Header, zr) 777 if err := ReadLimitBody(&req, zr, 10, true, false); err == nil { 778 t.Fatalf("expected error: %s", errGetOnly.Error()) 779 } 780 } 781 782 func TestRequestString(t *testing.T) { 783 t.Parallel() 784 785 var r protocol.Request 786 r.SetRequestURI("http://foobar.com/aaa") 787 s := GetHTTP1Request(&r).String() 788 expectedS := "GET /aaa HTTP/1.1\r\nHost: foobar.com\r\n\r\n" 789 if s != expectedS { 790 t.Fatalf("unexpected request: %q. Expecting %q", s, expectedS) 791 } 792 } 793 794 func TestRequestReadChunked(t *testing.T) { 795 t.Parallel() 796 797 var req protocol.Request 798 799 s := "POST /foo HTTP/1.1\r\nHost: google.com\r\nTransfer-Encoding: chunked\r\nContent-Type: aa/bb\r\n\r\n3\r\nabc\r\n5\r\n12345\r\n0\r\n\r\nTrail: test\r\n\r\n" 800 zr := netpoll.NewReader(bytes.NewBufferString(s)) 801 err := Read(&req, zr) 802 if err != nil { 803 t.Fatalf("Unexpected error when reading chunked request: %s", err) 804 } 805 expectedBody := "abc12345" 806 if string(req.Body()) != expectedBody { 807 t.Fatalf("Unexpected body %q. Expected %q", req.Body(), expectedBody) 808 } 809 verifyRequestHeader(t, &req.Header, 8, "/foo", "google.com", "", "aa/bb") 810 verifyTrailer(t, zr, map[string]string{"Trail": "test"}) 811 } 812 813 func verifyTrailer(t *testing.T, r network.Reader, exceptedTrailers map[string]string) { 814 trailer := protocol.Trailer{} 815 keys := make([]string, 0, len(exceptedTrailers)) 816 for k := range exceptedTrailers { 817 keys = append(keys, k) 818 } 819 trailer.SetTrailers([]byte(strings.Join(keys, ", "))) 820 err := ext.ReadTrailer(&trailer, r) 821 if err == io.EOF && exceptedTrailers == nil { 822 return 823 } 824 if err != nil { 825 t.Fatalf("Cannot read trailer: %v", err) 826 } 827 828 for k, v := range exceptedTrailers { 829 got := trailer.Peek(k) 830 if !bytes.Equal(got, []byte(v)) { 831 t.Fatalf("Unexpected trailer %q. Expected %q. Got %q", k, v, got) 832 } 833 } 834 } 835 836 func TestRequestChunkedWhitespace(t *testing.T) { 837 t.Parallel() 838 839 var req protocol.Request 840 841 s := "POST /foo HTTP/1.1\r\nHost: google.com\r\nTransfer-Encoding: chunked\r\nContent-Type: aa/bb\r\n\r\n3 \r\nabc\r\n0\r\n\r\n" 842 zr := mock.NewZeroCopyReader(s) 843 844 err := Read(&req, zr) 845 if err != nil { 846 t.Fatalf("Unexpected error when reading chunked request: %s", err) 847 } 848 expectedBody := "abc" 849 if string(req.Body()) != expectedBody { 850 t.Fatalf("Unexpected body %q. Expected %q", req.Body(), expectedBody) 851 } 852 } 853 854 func testRequestReadLimitBodyError(t *testing.T, s string, maxBodySize int) { 855 var req protocol.Request 856 zr := mock.NewZeroCopyReader(s) 857 858 err := ReadHeaderAndLimitBody(&req, zr, maxBodySize) 859 if err == nil { 860 t.Fatalf("expecting error. s=%q, maxBodySize=%d", s, maxBodySize) 861 } 862 if !errors.Is(err, errs.ErrBodyTooLarge) { 863 t.Fatalf("unexpected error: %s. Expecting %s. s=%q, maxBodySize=%d", err, errBodyTooLarge, s, maxBodySize) 864 } 865 } 866 867 func testRequestReadLimitBodySuccess(t *testing.T, s string, maxBodySize int) { 868 var req protocol.Request 869 zr := mock.NewZeroCopyReader(s) 870 if err := ReadHeaderAndLimitBody(&req, zr, maxBodySize); err != nil { 871 t.Fatalf("unexpected error: %s. s=%q, maxBodySize=%d", err, s, maxBodySize) 872 } 873 } 874 875 func testSetRequestBodyStream(t *testing.T, body string) { 876 var req protocol.Request 877 req.Header.SetHost("foobar.com") 878 req.Header.SetMethod(consts.MethodPost) 879 880 bodySize := len(body) 881 if req.IsBodyStream() { 882 t.Fatalf("IsBodyStream must return false") 883 } 884 req.SetBodyStream(bytes.NewBufferString(body), bodySize) 885 if !req.IsBodyStream() { 886 t.Fatalf("IsBodyStream must return true") 887 } 888 889 var w bytes.Buffer 890 zw := netpoll.NewWriter(&w) 891 if err := Write(&req, zw); err != nil { 892 t.Fatalf("unexpected error when writing request: %s. body=%q", err, body) 893 } 894 895 if err := zw.Flush(); err != nil { 896 t.Fatalf("unexpected error when flushing request: %s. body=%q", err, body) 897 } 898 899 var req1 protocol.Request 900 br := bufio.NewReader(&w) 901 zr := netpoll.NewReader(br) 902 if err := Read(&req1, zr); err != nil { 903 t.Fatalf("unexpected error when reading request: %s. body=%q", err, body) 904 } 905 if string(req1.Body()) != body { 906 fmt.Println(string(req1.Body())) 907 fmt.Println(body) 908 t.Fatalf("unexpected body %q. Expecting %q", req1.Body(), body) 909 } 910 } 911 912 func testSetRequestBodyStreamChunked(t *testing.T, body string, trailer map[string]string) { 913 var req protocol.Request 914 req.Header.SetHost("foobar.com") 915 req.Header.SetMethod(consts.MethodPost) 916 917 if req.IsBodyStream() { 918 t.Fatalf("IsBodyStream must return false") 919 } 920 req.SetBodyStream(bytes.NewBufferString(body), -1) 921 if !req.IsBodyStream() { 922 t.Fatalf("IsBodyStream must return true") 923 } 924 925 var w bytes.Buffer 926 zw := netpoll.NewWriter(&w) 927 for k, v := range trailer { 928 err := req.Header.Trailer().Add(k, v) 929 if err != nil { 930 t.Fatalf("unexpected error: %v", err) 931 } 932 } 933 if err := Write(&req, zw); err != nil { 934 t.Fatalf("unexpected error when writing request: %v, body=%q", err, body) 935 } 936 if err := zw.Flush(); err != nil { 937 t.Fatalf("unexpected error when flushing request: %v, body=%q", err, body) 938 } 939 940 var req1 protocol.Request 941 br := bufio.NewReader(&w) 942 zr := netpoll.NewReader(br) 943 if err := Read(&req1, zr); err != nil { 944 t.Fatalf("unexpected error when reading request: %v. body=%q", err, body) 945 } 946 if string(req1.Body()) != body { 947 t.Fatalf("unexpected body %q. Expecting %q", req1.Body(), body) 948 } 949 for k, v := range trailer { 950 r := req.Header.Trailer().Peek(k) 951 if string(r) != v { 952 t.Fatalf("unexpected trailer %q. Expecting %q. Got %q", k, v, r) 953 } 954 } 955 } 956 957 func TestRequestMultipartForm(t *testing.T) { 958 t.Parallel() 959 960 var w bytes.Buffer 961 mw := multipart.NewWriter(&w) 962 for i := 0; i < 10; i++ { 963 k := fmt.Sprintf("key_%d", i) 964 v := fmt.Sprintf("value_%d", i) 965 if err := mw.WriteField(k, v); err != nil { 966 t.Fatalf("unexpected error: %s", err) 967 } 968 } 969 boundary := mw.Boundary() 970 if err := mw.Close(); err != nil { 971 t.Fatalf("unexpected error: %s", err) 972 } 973 974 formData := w.Bytes() 975 for i := 0; i < 5; i++ { 976 formData = testRequestMultipartForm(t, boundary, formData, 10) 977 testRequestMultipartFormNotPreParse(t, boundary, formData, 10) 978 } 979 980 // verify request unmarshalling / marshalling 981 s := "POST / HTTP/1.1\r\nHost: aaa\r\nContent-Type: multipart/form-data; boundary=foobar\r\nContent-Length: 213\r\n\r\n--foobar\r\nContent-Disposition: form-data; name=\"key_0\"\r\n\r\nvalue_0\r\n--foobar\r\nContent-Disposition: form-data; name=\"key_1\"\r\n\r\nvalue_1\r\n--foobar\r\nContent-Disposition: form-data; name=\"key_2\"\r\n\r\nvalue_2\r\n--foobar--\r\n" 982 var r protocol.Request 983 zr := mock.NewZeroCopyReader(s) 984 if err := Read(&r, zr); err != nil { 985 t.Fatalf("unexpected error: %s", err) 986 } 987 988 s = GetHTTP1Request(&r).String() 989 zr = mock.NewZeroCopyReader(s) 990 if err := Read(&r, zr); err != nil { 991 t.Fatalf("unexpected error: %s", err) 992 } 993 testRequestMultipartForm(t, "foobar", r.Body(), 3) 994 } 995 996 func testRequestMultipartForm(t *testing.T, boundary string, formData []byte, partsCount int) []byte { 997 s := fmt.Sprintf("POST / HTTP/1.1\r\nHost: aaa\r\nContent-Type: multipart/form-data; boundary=%s\r\nContent-Length: %d\r\n\r\n%s", 998 boundary, len(formData), formData) 999 var req protocol.Request 1000 1001 zr := mock.NewZeroCopyReader(s) 1002 if err := Read(&req, zr); err != nil { 1003 t.Fatalf("unexpected error: %s", err) 1004 } 1005 1006 f, err := req.MultipartForm() 1007 if err != nil { 1008 t.Fatalf("unexpected error: %s", err) 1009 } 1010 defer req.RemoveMultipartFormFiles() 1011 1012 if len(f.File) > 0 { 1013 t.Fatalf("unexpected files found in the multipart form: %d", len(f.File)) 1014 } 1015 1016 if len(f.Value) != partsCount { 1017 t.Fatalf("unexpected number of values found: %d. Expecting %d", len(f.Value), partsCount) 1018 } 1019 1020 for k, vv := range f.Value { 1021 if len(vv) != 1 { 1022 t.Fatalf("unexpected number of values found for key=%q: %d. Expecting 1", k, len(vv)) 1023 } 1024 if !strings.HasPrefix(k, "key_") { 1025 t.Fatalf("unexpected key prefix=%q. Expecting %q", k, "key_") 1026 } 1027 v := vv[0] 1028 if !strings.HasPrefix(v, "value_") { 1029 t.Fatalf("unexpected value prefix=%q. expecting %q", v, "value_") 1030 } 1031 if k[len("key_"):] != v[len("value_"):] { 1032 t.Fatalf("key and value suffixes don't match: %q vs %q", k, v) 1033 } 1034 } 1035 1036 return req.Body() 1037 } 1038 1039 func testRequestMultipartFormNotPreParse(t *testing.T, boundary string, formData []byte, partsCount int) []byte { 1040 s := fmt.Sprintf("POST / HTTP/1.1\r\nHost: aaa\r\nContent-Type: multipart/form-data; boundary=%s\r\nContent-Length: %d\r\n\r\n%s", 1041 boundary, len(formData), formData) 1042 var req protocol.Request 1043 1044 zr := mock.NewZeroCopyReader(s) 1045 if err := Read(&req, zr, false); err != nil { 1046 t.Fatalf("unexpected error: %s", err) 1047 } 1048 f, err := req.MultipartForm() 1049 if err != nil { 1050 t.Fatalf("unexpected error: %s", err) 1051 } 1052 defer req.RemoveMultipartFormFiles() 1053 1054 if len(f.File) > 0 { 1055 t.Fatalf("unexpected files found in the multipart form: %d", len(f.File)) 1056 } 1057 1058 if len(f.Value) != partsCount { 1059 t.Fatalf("unexpected number of values found: %d. Expecting %d", len(f.Value), partsCount) 1060 } 1061 1062 for k, vv := range f.Value { 1063 if len(vv) != 1 { 1064 t.Fatalf("unexpected number of values found for key=%q: %d. Expecting 1", k, len(vv)) 1065 } 1066 if !strings.HasPrefix(k, "key_") { 1067 t.Fatalf("unexpected key prefix=%q. Expecting %q", k, "key_") 1068 } 1069 v := vv[0] 1070 if !strings.HasPrefix(v, "value_") { 1071 t.Fatalf("unexpected value prefix=%q. expecting %q", v, "value_") 1072 } 1073 if k[len("key_"):] != v[len("value_"):] { 1074 t.Fatalf("key and value suffixes don't match: %q vs %q", k, v) 1075 } 1076 } 1077 1078 return req.Body() 1079 } 1080 1081 func testReadBodyChunked(t *testing.T, bodySize int) { 1082 body := mock.CreateFixedBody(bodySize) 1083 expectedTrailer := map[string]string{"Foo": "chunked shit"} 1084 chunkedBody := mock.CreateChunkedBody(body, expectedTrailer, true) 1085 1086 zr := mock.NewZeroCopyReader(string(chunkedBody)) 1087 1088 // p,_ := mr.Next(3687) 1089 b, err := ext.ReadBody(zr, -1, 0, nil) 1090 if err != nil { 1091 t.Fatalf("Unexpected error for bodySize=%d: %s. body=%q, chunkedBody=%q", bodySize, err, body, chunkedBody) 1092 } 1093 if !bytes.Equal(b, body) { 1094 t.Fatalf("Unexpected response read for bodySize=%d: %q. Expected %q. chunkedBody=%q", bodySize, b, body, chunkedBody) 1095 } 1096 verifyTrailer(t, zr, expectedTrailer) 1097 } 1098 1099 func testReadBodyFixedSize(t *testing.T, bodySize int) { 1100 body := mock.CreateFixedBody(bodySize) 1101 1102 zr := mock.NewZeroCopyReader(string(body)) 1103 b, err := ext.ReadBody(zr, bodySize, 0, nil) 1104 if err != nil { 1105 t.Fatalf("Unexpected error in ReadResponseBody(%d): %s", bodySize, err) 1106 } 1107 if !bytes.Equal(b, body) { 1108 t.Fatalf("Unexpected response read for bodySize=%d: %q. Expected %q", bodySize, b, body) 1109 } 1110 verifyTrailer(t, zr, nil) 1111 } 1112 1113 func TestRequestFormFile(t *testing.T) { 1114 t.Parallel() 1115 1116 s := `POST /upload HTTP/1.1 1117 Host: localhost:10000 1118 Content-Length: 521 1119 Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryJwfATyF8tmxSJnLg 1120 1121 ------WebKitFormBoundaryJwfATyF8tmxSJnLg 1122 Content-Disposition: form-data; name="f1" 1123 1124 value1 1125 ------WebKitFormBoundaryJwfATyF8tmxSJnLg 1126 Content-Disposition: form-data; name="fileaaa"; filename="TODO" 1127 Content-Type: application/octet-stream 1128 1129 - SessionClient with referer and cookies support. 1130 - Client with requests' pipelining support. 1131 - ProxyHandler similar to FSHandler. 1132 - WebSockets. See https://tools.ietf.org/html/rfc6455 . 1133 - HTTP/2.0. See https://tools.ietf.org/html/rfc7540 . 1134 1135 ------WebKitFormBoundaryJwfATyF8tmxSJnLg-- 1136 tailfoobar` 1137 1138 mr := mock.NewZeroCopyReader(s) 1139 1140 var r protocol.Request 1141 if err := Read(&r, mr); err != nil { 1142 t.Fatalf("unexpected error: %s", err) 1143 } 1144 1145 tail, err := ioutil.ReadAll(mr) 1146 if err != nil { 1147 t.Fatalf("unexpected error: %s", err) 1148 } 1149 if string(tail) != "tailfoobar" { 1150 t.Fatalf("unexpected tail %q. Expecting %q", tail, "tailfoobar") 1151 } 1152 fh, err := r.FormFile("fileaaa") 1153 if err != nil { 1154 t.Fatalf("TestRequestFormFile error: %#v", err.Error()) 1155 } 1156 if fh == nil { 1157 t.Fatalf("fh unexpected nil") 1158 } 1159 } 1160 1161 func TestRequest_ContinueReadBodyStream(t *testing.T) { 1162 // small body 1163 genBody := "abcdef4343" 1164 s := "PUT /foo/bar HTTP/1.1\r\nExpect: 100-continue\r\nContent-Length: 5\r\nContent-Type: foo/bar\r\n\r\n" 1165 testContinueReadBodyStream(t, s, genBody, 10, 5, 0, 5) 1166 testContinueReadBodyStream(t, s, genBody, 1, 5, 0, 0) 1167 1168 // big body (> 8193) 1169 s1 := "PUT /foo/bar HTTP/1.1\r\nExpect: 100-continue\r\nContent-Length: 9216\r\nContent-Type: foo/bar\r\n\r\n" 1170 genBody = strings.Repeat("1", 9*1024) 1171 testContinueReadBodyStream(t, s1, genBody, 10*1024, 5*1024, 4*1024, 0) 1172 testContinueReadBodyStream(t, s1, genBody, 10*1024, 1*1024, 8*1024, 0) 1173 testContinueReadBodyStream(t, s1, genBody, 10*1024, 9*1024, 0*1024, 0) 1174 1175 // normal stream 1176 testContinueReadBodyStream(t, s1, genBody, 1*1024, 5*1024, 4*1024, 0) 1177 testContinueReadBodyStream(t, s1, genBody, 1*1024, 1*1024, 8*1024, 0) 1178 testContinueReadBodyStream(t, s1, genBody, 1*1024, 9*1024, 0*1024, 0) 1179 testContinueReadBodyStream(t, s1, genBody, 5, 5*1024, 4*1024, 0) 1180 testContinueReadBodyStream(t, s1, genBody, 5, 1*1024, 8*1024, 0) 1181 testContinueReadBodyStream(t, s1, genBody, 5, 9*1024, 0, 0) 1182 1183 // critical point 1184 testContinueReadBodyStream(t, s1, genBody, 8*1024+1, 5*1024, 4*1024, 0) 1185 testContinueReadBodyStream(t, s1, genBody, 8*1024+1, 1*1024, 8*1024, 0) 1186 testContinueReadBodyStream(t, s1, genBody, 8*1024+1, 9*1024, 0*1024, 0) 1187 1188 // chunked body 1189 s2 := "POST /foo HTTP/1.1\r\nHost: google.com\r\nTransfer-Encoding: chunked\r\nContent-Type: aa/bb\r\n\r\n3\r\nabc\r\n5\r\n12345\r\n0\r\n\r\ntrail" 1190 testContinueReadBodyStream(t, s2, "", 10*1024, 3, 5, 5) 1191 s3 := "POST /foo HTTP/1.1\r\nHost: google.com\r\nTransfer-Encoding: chunked\r\nContent-Type: aa/bb\r\n\r\n3\r\nabc\r\n5\r\n12345\r\n0\r\n\r\n" 1192 testContinueReadBodyStream(t, s3, "", 10*1024, 3, 5, 0) 1193 } 1194 1195 func TestRequest_Chunked(t *testing.T) { 1196 t.Parallel() 1197 s4 := "POST /foo HTTP/1.1\r\nHost: google.com\r\nTransfer-Encoding: chunked\r\nContent-Type: aa/bb\r\n\r\n5\r\n12345\r\n0\r\n\r\n" 1198 testReadChunked(t, s4, "", 3, 2) 1199 1200 s5 := "POST /foo HTTP/1.1\r\nHost: google.com\r\nTransfer-Encoding: chunked\r\nContent-Type: aa/bb\r\n\r\n5\r\n12345\r\n3\r\n1230\r\n\r\n" 1201 testReadChunked(t, s5, "", 3, 5) 1202 } 1203 1204 func TestRequest_ReadIncompleteStream(t *testing.T) { 1205 t.Parallel() 1206 // small body 1207 genBody := "abcdef4343" 1208 s := "PUT /foo/bar HTTP/1.1\r\nExpect: 100-continue\r\nContent-Length: 100\r\nContent-Type: foo/bar\r\n\r\n" 1209 testReadIncompleteStream(t, s, genBody) 1210 1211 // big body (> 8193) 1212 s1 := "PUT /foo/bar HTTP/1.1\r\nExpect: 100-continue\r\nContent-Length: 10000\r\nContent-Type: foo/bar\r\n\r\n" 1213 genBody = strings.Repeat("1", 9*1024) 1214 testReadIncompleteStream(t, s1, genBody) 1215 } 1216 1217 func testReadIncompleteStream(t *testing.T, header, body string) { 1218 mr := mock.NewZeroCopyReader(header + body) 1219 var r protocol.Request 1220 if err := ReadHeader(&r.Header, mr); err != nil { 1221 t.Fatalf("unexpected error: %s", err) 1222 } 1223 if err := ContinueReadBodyStream(&r, mr, 1, true); err != nil { 1224 t.Fatalf("error when reading request body stream: %s", err) 1225 } 1226 readBody, err := ioutil.ReadAll(r.BodyStream()) 1227 if !bytes.Equal(readBody, []byte(body)) || len(readBody) != len(body) { 1228 t.Fatalf("readBody is not equal to the rawBody: %b(len: %d)", readBody, len(readBody)) 1229 } 1230 if err != io.ErrUnexpectedEOF { 1231 t.Fatalf("error should be io.ErrUnexpectedEOF, but got: %s", err) 1232 } 1233 } 1234 1235 func testReadChunked(t *testing.T, header, body string, firstRead, leftBytes int) { 1236 mr := mock.NewZeroCopyReader(header + body) 1237 1238 var r protocol.Request 1239 if err := ReadHeader(&r.Header, mr); err != nil { 1240 t.Fatalf("unexpected error: %s", err) 1241 } 1242 if err := ContinueReadBodyStream(&r, mr, 2048, true); err != nil { 1243 t.Fatalf("error when reading request body stream: %s", err) 1244 } 1245 if r.Header.ContentLength() >= 0 { 1246 t.Fatalf("expect a chunked body") 1247 } 1248 streamRead := make([]byte, firstRead) 1249 fr, err := r.BodyStream().Read(streamRead) 1250 if err != nil { 1251 t.Fatalf("read stream error=%v", err) 1252 } 1253 if fr != firstRead { 1254 t.Fatalf("should read %d from stream body, but got %d", streamRead, fr) 1255 } 1256 leftB, _ := ioutil.ReadAll(r.BodyStream()) 1257 if len(leftB) != leftBytes { 1258 t.Fatalf("should left %d bytes from stream body, but left %d", leftBytes, len(leftB)) 1259 } 1260 } 1261 1262 func testContinueReadBodyStream(t *testing.T, header, body string, maxBodySize, firstRead, leftBytes, bytesLeftInReader int) { 1263 mr := mock.NewZeroCopyReader(header + body) 1264 var r protocol.Request 1265 if err := ReadHeader(&r.Header, mr); err != nil { 1266 t.Fatalf("unexpected error: %s", err) 1267 } 1268 if err := ContinueReadBodyStream(&r, mr, maxBodySize, true); err != nil { 1269 t.Fatalf("error when reading request body stream: %s", err) 1270 } 1271 fRead := firstRead 1272 streamRead := make([]byte, fRead) 1273 sR, _ := r.BodyStream().Read(streamRead) 1274 1275 if sR != firstRead { 1276 t.Fatalf("should read %d from stream body, but got %d", firstRead, sR) 1277 } 1278 1279 leftB, _ := ioutil.ReadAll(r.BodyStream()) 1280 if len(leftB) != leftBytes { 1281 t.Fatalf("should left %d bytes from stream body, but left %d", leftBytes, len(leftB)) 1282 } 1283 if r.Header.ContentLength() > 0 { 1284 gotBody := append(streamRead, leftB...) 1285 if !bytes.Equal([]byte(body[:r.Header.ContentLength()]), gotBody) { 1286 t.Fatalf("body read from stream is not equal to the origin. Got: %s", gotBody) 1287 } 1288 } 1289 1290 left, _ := mr.Peek(mr.Len()) 1291 1292 if len(left) != bytesLeftInReader { 1293 fmt.Printf("##########header:%s,body:%s,%d:max,first:%d,left:%d,leftin:%d\n", header, body, maxBodySize, firstRead, leftBytes, bytesLeftInReader) 1294 fmt.Printf("##########left: %s\n", left) 1295 t.Fatalf("should left %d bytes in original reader. got %q", bytesLeftInReader, len(left)) 1296 } 1297 } 1298 1299 func verifyRequestHeader(t *testing.T, h *protocol.RequestHeader, expectedContentLength int, 1300 expectedRequestURI, expectedHost, expectedReferer, expectedContentType string, 1301 ) { 1302 if h.ContentLength() != expectedContentLength { 1303 t.Fatalf("Unexpected Content-Length %d. Expected %d", h.ContentLength(), expectedContentLength) 1304 } 1305 if string(h.RequestURI()) != expectedRequestURI { 1306 t.Fatalf("Unexpected RequestURI %q. Expected %q", h.RequestURI(), expectedRequestURI) 1307 } 1308 if string(h.Peek(consts.HeaderHost)) != expectedHost { 1309 t.Fatalf("Unexpected host %q. Expected %q", h.Peek(consts.HeaderHost), expectedHost) 1310 } 1311 if string(h.Peek(consts.HeaderReferer)) != expectedReferer { 1312 t.Fatalf("Unexpected referer %q. Expected %q", h.Peek(consts.HeaderReferer), expectedReferer) 1313 } 1314 if string(h.Peek(consts.HeaderContentType)) != expectedContentType { 1315 t.Fatalf("Unexpected content-type %q. Expected %q", h.Peek(consts.HeaderContentType), expectedContentType) 1316 } 1317 } 1318 1319 func TestRequestReadMultipartFormWithFile(t *testing.T) { 1320 t.Parallel() 1321 1322 s := `POST /upload HTTP/1.1 1323 Host: localhost:10000 1324 Content-Length: 521 1325 Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryJwfATyF8tmxSJnLg 1326 1327 ------WebKitFormBoundaryJwfATyF8tmxSJnLg 1328 Content-Disposition: form-data; name="f1" 1329 1330 value1 1331 ------WebKitFormBoundaryJwfATyF8tmxSJnLg 1332 Content-Disposition: form-data; name="fileaaa"; filename="TODO" 1333 Content-Type: application/octet-stream 1334 1335 - SessionClient with referer and cookies support. 1336 - Client with requests' pipelining support. 1337 - ProxyHandler similar to FSHandler. 1338 - WebSockets. See https://tools.ietf.org/html/rfc6455 . 1339 - HTTP/2.0. See https://tools.ietf.org/html/rfc7540 . 1340 1341 ------WebKitFormBoundaryJwfATyF8tmxSJnLg-- 1342 tailfoobar` 1343 1344 mr := mock.NewZeroCopyReader(s) 1345 1346 var r protocol.Request 1347 if err := Read(&r, mr); err != nil { 1348 t.Fatalf("unexpected error: %s", err) 1349 } 1350 1351 tail, err := ioutil.ReadAll(mr) 1352 if err != nil { 1353 t.Fatalf("unexpected error: %s", err) 1354 } 1355 if string(tail) != "tailfoobar" { 1356 t.Fatalf("unexpected tail %q. Expecting %q", tail, "tailfoobar") 1357 } 1358 1359 f, err := r.MultipartForm() 1360 if err != nil { 1361 t.Fatalf("unexpected error: %s", err) 1362 } 1363 defer r.RemoveMultipartFormFiles() 1364 1365 // verify values 1366 if len(f.Value) != 1 { 1367 t.Fatalf("unexpected number of values in multipart form: %d. Expecting 1", len(f.Value)) 1368 } 1369 for k, vv := range f.Value { 1370 if k != "f1" { 1371 t.Fatalf("unexpected value name %q. Expecting %q", k, "f1") 1372 } 1373 if len(vv) != 1 { 1374 t.Fatalf("unexpected number of values %d. Expecting 1", len(vv)) 1375 } 1376 v := vv[0] 1377 if v != "value1" { 1378 t.Fatalf("unexpected value %q. Expecting %q", v, "value1") 1379 } 1380 } 1381 1382 // verify files 1383 if len(f.File) != 1 { 1384 t.Fatalf("unexpected number of file values in multipart form: %d. Expecting 1", len(f.File)) 1385 } 1386 for k, vv := range f.File { 1387 if k != "fileaaa" { 1388 t.Fatalf("unexpected file value name %q. Expecting %q", k, "fileaaa") 1389 } 1390 if len(vv) != 1 { 1391 t.Fatalf("unexpected number of file values %d. Expecting 1", len(vv)) 1392 } 1393 v := vv[0] 1394 if v.Filename != "TODO" { 1395 t.Fatalf("unexpected filename %q. Expecting %q", v.Filename, "TODO") 1396 } 1397 ct := v.Header.Get("Content-Type") 1398 if ct != "application/octet-stream" { 1399 t.Fatalf("unexpected content-type %q. Expecting %q", ct, "application/octet-stream") 1400 } 1401 } 1402 } 1403 1404 func testRequestMultipartFormBoundary(t *testing.T, s, boundary string) { 1405 var h protocol.RequestHeader 1406 zr := mock.NewZeroCopyReader(s) 1407 1408 if err := ReadHeader(&h, zr); err != nil { 1409 t.Fatalf("unexpected error: %s. s=%q, boundary=%q", err, s, boundary) 1410 } 1411 1412 b := h.MultipartFormBoundary() 1413 if string(b) != boundary { 1414 t.Fatalf("unexpected boundary %q. Expecting %q. s=%q", b, boundary, s) 1415 } 1416 } 1417 1418 func TestStreamNotEnoughData(t *testing.T) { 1419 req := protocol.AcquireRequest() 1420 req.Header.SetContentLength(1 << 16) 1421 conn := mock.NewStreamConn() 1422 const maxBodySize = 4 * 1024 * 1024 1423 err := ContinueReadBodyStream(req, conn, maxBodySize) 1424 assert.Nil(t, err) 1425 err = ext.ReleaseBodyStream(req.BodyStream()) 1426 assert.Nil(t, err) 1427 assert.DeepEqual(t, 0, len(conn.Data)) 1428 } 1429 1430 func TestRequestBodyStreamWithTrailer(t *testing.T) { 1431 t.Parallel() 1432 1433 testRequestBodyStreamWithTrailer(t, []byte("test"), false) 1434 testRequestBodyStreamWithTrailer(t, mock.CreateFixedBody(4097), false) 1435 testRequestBodyStreamWithTrailer(t, mock.CreateFixedBody(105000), false) 1436 } 1437 1438 func testRequestBodyStreamWithTrailer(t *testing.T, body []byte, disableNormalizing bool) { 1439 expectedTrailer := map[string]string{ 1440 "foo": "testfoo", 1441 "bar": "testbar", 1442 } 1443 1444 var req1 protocol.Request 1445 if disableNormalizing { 1446 req1.Header.DisableNormalizing() 1447 } 1448 req1.SetHost("google.com") 1449 req1.SetBodyStream(bytes.NewBuffer(body), -1) 1450 for k, v := range expectedTrailer { 1451 err := req1.Header.Trailer().Set(k, v) 1452 if err != nil { 1453 t.Fatalf("unexpected error: %s", err) 1454 } 1455 } 1456 1457 w := &bytes.Buffer{} 1458 zw := netpoll.NewWriter(w) 1459 if err := Write(&req1, zw); err != nil { 1460 t.Fatalf("unexpected error: %s", err) 1461 } 1462 if err := zw.Flush(); err != nil { 1463 t.Fatalf("unexpected error: %s", err) 1464 } 1465 1466 var req2 protocol.Request 1467 if disableNormalizing { 1468 req2.Header.DisableNormalizing() 1469 } 1470 1471 br := netpoll.NewReader(w) 1472 if err := Read(&req2, br); err != nil { 1473 t.Fatalf("unexpected error: %s", err) 1474 } 1475 1476 reqBody := req2.Body() 1477 if !bytes.Equal(reqBody, body) { 1478 t.Fatalf("unexpected body: %q. Excepting %q", reqBody, body) 1479 } 1480 1481 for k, v := range expectedTrailer { 1482 kBytes := []byte(k) 1483 utils.NormalizeHeaderKey(kBytes, disableNormalizing) 1484 r := req2.Header.Trailer().Peek(k) 1485 if string(r) != v { 1486 t.Fatalf("unexpected trailer header %q: %q. Expecting %s", kBytes, r, v) 1487 } 1488 } 1489 }