github.com/gofiber/fiber/v2@v2.47.0/client_test.go (about) 1 //nolint:wrapcheck // We must not wrap errors in tests 2 package fiber 3 4 import ( 5 "bytes" 6 "crypto/tls" 7 "encoding/base64" 8 "encoding/json" 9 "errors" 10 "fmt" 11 "io" 12 "mime/multipart" 13 "net" 14 "os" 15 "path/filepath" 16 "regexp" 17 "strings" 18 "testing" 19 "time" 20 21 "github.com/gofiber/fiber/v2/internal/tlstest" 22 "github.com/gofiber/fiber/v2/utils" 23 24 "github.com/valyala/fasthttp/fasthttputil" 25 ) 26 27 func Test_Client_Invalid_URL(t *testing.T) { 28 t.Parallel() 29 30 ln := fasthttputil.NewInmemoryListener() 31 32 app := New(Config{DisableStartupMessage: true}) 33 34 app.Get("/", func(c *Ctx) error { 35 return c.SendString(c.Hostname()) 36 }) 37 38 go func() { utils.AssertEqual(t, nil, app.Listener(ln)) }() 39 40 a := Get("http://example.com\r\n\r\nGET /\r\n\r\n") 41 42 a.HostClient.Dial = func(addr string) (net.Conn, error) { return ln.Dial() } 43 44 _, body, errs := a.String() 45 46 utils.AssertEqual(t, "", body) 47 utils.AssertEqual(t, 1, len(errs)) 48 utils.AssertEqual(t, "missing required Host header in request", errs[0].Error()) 49 } 50 51 func Test_Client_Unsupported_Protocol(t *testing.T) { 52 t.Parallel() 53 54 a := Get("ftp://example.com") 55 56 _, body, errs := a.String() 57 58 utils.AssertEqual(t, "", body) 59 utils.AssertEqual(t, 1, len(errs)) 60 utils.AssertEqual(t, `unsupported protocol "ftp". http and https are supported`, 61 errs[0].Error()) 62 } 63 64 func Test_Client_Get(t *testing.T) { 65 t.Parallel() 66 67 ln := fasthttputil.NewInmemoryListener() 68 69 app := New(Config{DisableStartupMessage: true}) 70 71 app.Get("/", func(c *Ctx) error { 72 return c.SendString(c.Hostname()) 73 }) 74 75 go func() { utils.AssertEqual(t, nil, app.Listener(ln)) }() 76 77 for i := 0; i < 5; i++ { 78 a := Get("http://example.com") 79 80 a.HostClient.Dial = func(addr string) (net.Conn, error) { return ln.Dial() } 81 82 code, body, errs := a.String() 83 84 utils.AssertEqual(t, StatusOK, code) 85 utils.AssertEqual(t, "example.com", body) 86 utils.AssertEqual(t, 0, len(errs)) 87 } 88 } 89 90 func Test_Client_Head(t *testing.T) { 91 t.Parallel() 92 93 ln := fasthttputil.NewInmemoryListener() 94 95 app := New(Config{DisableStartupMessage: true}) 96 97 app.Get("/", func(c *Ctx) error { 98 return c.SendString(c.Hostname()) 99 }) 100 101 go func() { utils.AssertEqual(t, nil, app.Listener(ln)) }() 102 103 for i := 0; i < 5; i++ { 104 a := Head("http://example.com") 105 106 a.HostClient.Dial = func(addr string) (net.Conn, error) { return ln.Dial() } 107 108 code, body, errs := a.String() 109 110 utils.AssertEqual(t, StatusOK, code) 111 utils.AssertEqual(t, "", body) 112 utils.AssertEqual(t, 0, len(errs)) 113 } 114 } 115 116 func Test_Client_Post(t *testing.T) { 117 t.Parallel() 118 119 ln := fasthttputil.NewInmemoryListener() 120 121 app := New(Config{DisableStartupMessage: true}) 122 123 app.Post("/", func(c *Ctx) error { 124 return c.Status(StatusCreated). 125 SendString(c.FormValue("foo")) 126 }) 127 128 go func() { utils.AssertEqual(t, nil, app.Listener(ln)) }() 129 130 for i := 0; i < 5; i++ { 131 args := AcquireArgs() 132 133 args.Set("foo", "bar") 134 135 a := Post("http://example.com"). 136 Form(args) 137 138 a.HostClient.Dial = func(addr string) (net.Conn, error) { return ln.Dial() } 139 140 code, body, errs := a.String() 141 142 utils.AssertEqual(t, StatusCreated, code) 143 utils.AssertEqual(t, "bar", body) 144 utils.AssertEqual(t, 0, len(errs)) 145 146 ReleaseArgs(args) 147 } 148 } 149 150 func Test_Client_Put(t *testing.T) { 151 t.Parallel() 152 153 ln := fasthttputil.NewInmemoryListener() 154 155 app := New(Config{DisableStartupMessage: true}) 156 157 app.Put("/", func(c *Ctx) error { 158 return c.SendString(c.FormValue("foo")) 159 }) 160 161 go func() { utils.AssertEqual(t, nil, app.Listener(ln)) }() 162 163 for i := 0; i < 5; i++ { 164 args := AcquireArgs() 165 166 args.Set("foo", "bar") 167 168 a := Put("http://example.com"). 169 Form(args) 170 171 a.HostClient.Dial = func(addr string) (net.Conn, error) { return ln.Dial() } 172 173 code, body, errs := a.String() 174 175 utils.AssertEqual(t, StatusOK, code) 176 utils.AssertEqual(t, "bar", body) 177 utils.AssertEqual(t, 0, len(errs)) 178 179 ReleaseArgs(args) 180 } 181 } 182 183 func Test_Client_Patch(t *testing.T) { 184 t.Parallel() 185 186 ln := fasthttputil.NewInmemoryListener() 187 188 app := New(Config{DisableStartupMessage: true}) 189 190 app.Patch("/", func(c *Ctx) error { 191 return c.SendString(c.FormValue("foo")) 192 }) 193 194 go func() { utils.AssertEqual(t, nil, app.Listener(ln)) }() 195 196 for i := 0; i < 5; i++ { 197 args := AcquireArgs() 198 199 args.Set("foo", "bar") 200 201 a := Patch("http://example.com"). 202 Form(args) 203 204 a.HostClient.Dial = func(addr string) (net.Conn, error) { return ln.Dial() } 205 206 code, body, errs := a.String() 207 208 utils.AssertEqual(t, StatusOK, code) 209 utils.AssertEqual(t, "bar", body) 210 utils.AssertEqual(t, 0, len(errs)) 211 212 ReleaseArgs(args) 213 } 214 } 215 216 func Test_Client_Delete(t *testing.T) { 217 t.Parallel() 218 219 ln := fasthttputil.NewInmemoryListener() 220 221 app := New(Config{DisableStartupMessage: true}) 222 223 app.Delete("/", func(c *Ctx) error { 224 return c.Status(StatusNoContent). 225 SendString("deleted") 226 }) 227 228 go func() { utils.AssertEqual(t, nil, app.Listener(ln)) }() 229 230 for i := 0; i < 5; i++ { 231 args := AcquireArgs() 232 233 a := Delete("http://example.com") 234 235 a.HostClient.Dial = func(addr string) (net.Conn, error) { return ln.Dial() } 236 237 code, body, errs := a.String() 238 239 utils.AssertEqual(t, StatusNoContent, code) 240 utils.AssertEqual(t, "", body) 241 utils.AssertEqual(t, 0, len(errs)) 242 243 ReleaseArgs(args) 244 } 245 } 246 247 func Test_Client_UserAgent(t *testing.T) { 248 t.Parallel() 249 250 ln := fasthttputil.NewInmemoryListener() 251 252 app := New(Config{DisableStartupMessage: true}) 253 254 app.Get("/", func(c *Ctx) error { 255 return c.Send(c.Request().Header.UserAgent()) 256 }) 257 258 go func() { utils.AssertEqual(t, nil, app.Listener(ln)) }() 259 260 t.Run("default", func(t *testing.T) { 261 t.Parallel() 262 for i := 0; i < 5; i++ { 263 a := Get("http://example.com") 264 265 a.HostClient.Dial = func(addr string) (net.Conn, error) { return ln.Dial() } 266 267 code, body, errs := a.String() 268 269 utils.AssertEqual(t, StatusOK, code) 270 utils.AssertEqual(t, defaultUserAgent, body) 271 utils.AssertEqual(t, 0, len(errs)) 272 } 273 }) 274 275 t.Run("custom", func(t *testing.T) { 276 t.Parallel() 277 for i := 0; i < 5; i++ { 278 c := AcquireClient() 279 c.UserAgent = "ua" 280 281 a := c.Get("http://example.com") 282 283 a.HostClient.Dial = func(addr string) (net.Conn, error) { return ln.Dial() } 284 285 code, body, errs := a.String() 286 287 utils.AssertEqual(t, StatusOK, code) 288 utils.AssertEqual(t, "ua", body) 289 utils.AssertEqual(t, 0, len(errs)) 290 ReleaseClient(c) 291 } 292 }) 293 } 294 295 func Test_Client_Agent_Set_Or_Add_Headers(t *testing.T) { 296 t.Parallel() 297 handler := func(c *Ctx) error { 298 c.Request().Header.VisitAll(func(key, value []byte) { 299 if k := string(key); k == "K1" || k == "K2" { 300 _, err := c.Write(key) 301 utils.AssertEqual(t, nil, err) 302 _, err = c.Write(value) 303 utils.AssertEqual(t, nil, err) 304 } 305 }) 306 return nil 307 } 308 309 wrapAgent := func(a *Agent) { 310 a.Set("k1", "v1"). 311 SetBytesK([]byte("k1"), "v1"). 312 SetBytesV("k1", []byte("v1")). 313 AddBytesK([]byte("k1"), "v11"). 314 AddBytesV("k1", []byte("v22")). 315 AddBytesKV([]byte("k1"), []byte("v33")). 316 SetBytesKV([]byte("k2"), []byte("v2")). 317 Add("k2", "v22") 318 } 319 320 testAgent(t, handler, wrapAgent, "K1v1K1v11K1v22K1v33K2v2K2v22") 321 } 322 323 func Test_Client_Agent_Connection_Close(t *testing.T) { 324 t.Parallel() 325 handler := func(c *Ctx) error { 326 if c.Request().Header.ConnectionClose() { 327 return c.SendString("close") 328 } 329 return c.SendString("not close") 330 } 331 332 wrapAgent := func(a *Agent) { 333 a.ConnectionClose() 334 } 335 336 testAgent(t, handler, wrapAgent, "close") 337 } 338 339 func Test_Client_Agent_UserAgent(t *testing.T) { 340 t.Parallel() 341 handler := func(c *Ctx) error { 342 return c.Send(c.Request().Header.UserAgent()) 343 } 344 345 wrapAgent := func(a *Agent) { 346 a.UserAgent("ua"). 347 UserAgentBytes([]byte("ua")) 348 } 349 350 testAgent(t, handler, wrapAgent, "ua") 351 } 352 353 func Test_Client_Agent_Cookie(t *testing.T) { 354 t.Parallel() 355 handler := func(c *Ctx) error { 356 return c.SendString( 357 c.Cookies("k1") + c.Cookies("k2") + c.Cookies("k3") + c.Cookies("k4")) 358 } 359 360 wrapAgent := func(a *Agent) { 361 a.Cookie("k1", "v1"). 362 CookieBytesK([]byte("k2"), "v2"). 363 CookieBytesKV([]byte("k2"), []byte("v2")). 364 Cookies("k3", "v3", "k4", "v4"). 365 CookiesBytesKV([]byte("k3"), []byte("v3"), []byte("k4"), []byte("v4")) 366 } 367 368 testAgent(t, handler, wrapAgent, "v1v2v3v4") 369 } 370 371 func Test_Client_Agent_Referer(t *testing.T) { 372 t.Parallel() 373 handler := func(c *Ctx) error { 374 return c.Send(c.Request().Header.Referer()) 375 } 376 377 wrapAgent := func(a *Agent) { 378 a.Referer("http://referer.com"). 379 RefererBytes([]byte("http://referer.com")) 380 } 381 382 testAgent(t, handler, wrapAgent, "http://referer.com") 383 } 384 385 func Test_Client_Agent_ContentType(t *testing.T) { 386 t.Parallel() 387 handler := func(c *Ctx) error { 388 return c.Send(c.Request().Header.ContentType()) 389 } 390 391 wrapAgent := func(a *Agent) { 392 a.ContentType("custom-type"). 393 ContentTypeBytes([]byte("custom-type")) 394 } 395 396 testAgent(t, handler, wrapAgent, "custom-type") 397 } 398 399 func Test_Client_Agent_Host(t *testing.T) { 400 t.Parallel() 401 402 ln := fasthttputil.NewInmemoryListener() 403 404 app := New(Config{DisableStartupMessage: true}) 405 406 app.Get("/", func(c *Ctx) error { 407 return c.SendString(c.Hostname()) 408 }) 409 410 go func() { utils.AssertEqual(t, nil, app.Listener(ln)) }() 411 412 a := Get("http://1.1.1.1:8080"). 413 Host("example.com"). 414 HostBytes([]byte("example.com")) 415 416 utils.AssertEqual(t, "1.1.1.1:8080", a.HostClient.Addr) 417 418 a.HostClient.Dial = func(addr string) (net.Conn, error) { return ln.Dial() } 419 420 code, body, errs := a.String() 421 422 utils.AssertEqual(t, StatusOK, code) 423 utils.AssertEqual(t, "example.com", body) 424 utils.AssertEqual(t, 0, len(errs)) 425 } 426 427 func Test_Client_Agent_QueryString(t *testing.T) { 428 t.Parallel() 429 handler := func(c *Ctx) error { 430 return c.Send(c.Request().URI().QueryString()) 431 } 432 433 wrapAgent := func(a *Agent) { 434 a.QueryString("foo=bar&bar=baz"). 435 QueryStringBytes([]byte("foo=bar&bar=baz")) 436 } 437 438 testAgent(t, handler, wrapAgent, "foo=bar&bar=baz") 439 } 440 441 func Test_Client_Agent_BasicAuth(t *testing.T) { 442 t.Parallel() 443 handler := func(c *Ctx) error { 444 // Get authorization header 445 auth := c.Get(HeaderAuthorization) 446 // Decode the header contents 447 raw, err := base64.StdEncoding.DecodeString(auth[6:]) 448 utils.AssertEqual(t, nil, err) 449 450 return c.Send(raw) 451 } 452 453 wrapAgent := func(a *Agent) { 454 a.BasicAuth("foo", "bar"). 455 BasicAuthBytes([]byte("foo"), []byte("bar")) 456 } 457 458 testAgent(t, handler, wrapAgent, "foo:bar") 459 } 460 461 func Test_Client_Agent_BodyString(t *testing.T) { 462 t.Parallel() 463 handler := func(c *Ctx) error { 464 return c.Send(c.Request().Body()) 465 } 466 467 wrapAgent := func(a *Agent) { 468 a.BodyString("foo=bar&bar=baz") 469 } 470 471 testAgent(t, handler, wrapAgent, "foo=bar&bar=baz") 472 } 473 474 func Test_Client_Agent_Body(t *testing.T) { 475 t.Parallel() 476 handler := func(c *Ctx) error { 477 return c.Send(c.Request().Body()) 478 } 479 480 wrapAgent := func(a *Agent) { 481 a.Body([]byte("foo=bar&bar=baz")) 482 } 483 484 testAgent(t, handler, wrapAgent, "foo=bar&bar=baz") 485 } 486 487 func Test_Client_Agent_BodyStream(t *testing.T) { 488 t.Parallel() 489 handler := func(c *Ctx) error { 490 return c.Send(c.Request().Body()) 491 } 492 493 wrapAgent := func(a *Agent) { 494 a.BodyStream(strings.NewReader("body stream"), -1) 495 } 496 497 testAgent(t, handler, wrapAgent, "body stream") 498 } 499 500 func Test_Client_Agent_Custom_Response(t *testing.T) { 501 t.Parallel() 502 503 ln := fasthttputil.NewInmemoryListener() 504 505 app := New(Config{DisableStartupMessage: true}) 506 507 app.Get("/", func(c *Ctx) error { 508 return c.SendString("custom") 509 }) 510 511 go func() { utils.AssertEqual(t, nil, app.Listener(ln)) }() 512 513 for i := 0; i < 5; i++ { 514 a := AcquireAgent() 515 resp := AcquireResponse() 516 517 req := a.Request() 518 req.Header.SetMethod(MethodGet) 519 req.SetRequestURI("http://example.com") 520 521 utils.AssertEqual(t, nil, a.Parse()) 522 523 a.HostClient.Dial = func(addr string) (net.Conn, error) { return ln.Dial() } 524 525 code, body, errs := a.SetResponse(resp). 526 String() 527 528 utils.AssertEqual(t, StatusOK, code) 529 utils.AssertEqual(t, "custom", body) 530 utils.AssertEqual(t, "custom", string(resp.Body())) 531 utils.AssertEqual(t, 0, len(errs)) 532 533 ReleaseResponse(resp) 534 } 535 } 536 537 func Test_Client_Agent_Dest(t *testing.T) { 538 t.Parallel() 539 540 ln := fasthttputil.NewInmemoryListener() 541 542 app := New(Config{DisableStartupMessage: true}) 543 544 app.Get("/", func(c *Ctx) error { 545 return c.SendString("dest") 546 }) 547 548 go func() { utils.AssertEqual(t, nil, app.Listener(ln)) }() 549 550 t.Run("small dest", func(t *testing.T) { 551 t.Parallel() 552 dest := []byte("de") 553 554 a := Get("http://example.com") 555 556 a.HostClient.Dial = func(addr string) (net.Conn, error) { return ln.Dial() } 557 558 code, body, errs := a.Dest(dest[:0]).String() 559 560 utils.AssertEqual(t, StatusOK, code) 561 utils.AssertEqual(t, "dest", body) 562 utils.AssertEqual(t, "de", string(dest)) 563 utils.AssertEqual(t, 0, len(errs)) 564 }) 565 566 t.Run("enough dest", func(t *testing.T) { 567 t.Parallel() 568 dest := []byte("foobar") 569 570 a := Get("http://example.com") 571 572 a.HostClient.Dial = func(addr string) (net.Conn, error) { return ln.Dial() } 573 574 code, body, errs := a.Dest(dest[:0]).String() 575 576 utils.AssertEqual(t, StatusOK, code) 577 utils.AssertEqual(t, "dest", body) 578 utils.AssertEqual(t, "destar", string(dest)) 579 utils.AssertEqual(t, 0, len(errs)) 580 }) 581 } 582 583 // readErrorConn is a struct for testing retryIf 584 type readErrorConn struct { 585 net.Conn 586 } 587 588 func (*readErrorConn) Read(_ []byte) (int, error) { 589 return 0, fmt.Errorf("error") 590 } 591 592 func (*readErrorConn) Write(p []byte) (int, error) { 593 return len(p), nil 594 } 595 596 func (*readErrorConn) Close() error { 597 return nil 598 } 599 600 func (*readErrorConn) LocalAddr() net.Addr { 601 return nil 602 } 603 604 func (*readErrorConn) RemoteAddr() net.Addr { 605 return nil 606 } 607 608 func Test_Client_Agent_RetryIf(t *testing.T) { 609 t.Parallel() 610 611 ln := fasthttputil.NewInmemoryListener() 612 613 app := New(Config{DisableStartupMessage: true}) 614 615 go func() { utils.AssertEqual(t, nil, app.Listener(ln)) }() 616 617 a := Post("http://example.com"). 618 RetryIf(func(req *Request) bool { 619 return true 620 }) 621 dialsCount := 0 622 a.HostClient.Dial = func(addr string) (net.Conn, error) { 623 dialsCount++ 624 switch dialsCount { 625 case 1: 626 return &readErrorConn{}, nil 627 case 2: 628 return &readErrorConn{}, nil 629 case 3: 630 return &readErrorConn{}, nil 631 case 4: 632 return ln.Dial() 633 default: 634 t.Fatalf("unexpected number of dials: %d", dialsCount) 635 } 636 panic("unreachable") 637 } 638 639 _, _, errs := a.String() 640 utils.AssertEqual(t, dialsCount, 4) 641 utils.AssertEqual(t, 0, len(errs)) 642 } 643 644 func Test_Client_Agent_Json(t *testing.T) { 645 t.Parallel() 646 handler := func(c *Ctx) error { 647 utils.AssertEqual(t, MIMEApplicationJSON, string(c.Request().Header.ContentType())) 648 649 return c.Send(c.Request().Body()) 650 } 651 652 wrapAgent := func(a *Agent) { 653 a.JSON(data{Success: true}) 654 } 655 656 testAgent(t, handler, wrapAgent, `{"success":true}`) 657 } 658 659 func Test_Client_Agent_Json_Error(t *testing.T) { 660 t.Parallel() 661 a := Get("http://example.com"). 662 JSONEncoder(json.Marshal). 663 JSON(complex(1, 1)) 664 665 _, body, errs := a.String() 666 667 utils.AssertEqual(t, "", body) 668 utils.AssertEqual(t, 1, len(errs)) 669 utils.AssertEqual(t, "json: unsupported type: complex128", errs[0].Error()) 670 } 671 672 func Test_Client_Agent_XML(t *testing.T) { 673 t.Parallel() 674 handler := func(c *Ctx) error { 675 utils.AssertEqual(t, MIMEApplicationXML, string(c.Request().Header.ContentType())) 676 677 return c.Send(c.Request().Body()) 678 } 679 680 wrapAgent := func(a *Agent) { 681 a.XML(data{Success: true}) 682 } 683 684 testAgent(t, handler, wrapAgent, "<data><success>true</success></data>") 685 } 686 687 func Test_Client_Agent_XML_Error(t *testing.T) { 688 t.Parallel() 689 a := Get("http://example.com"). 690 XML(complex(1, 1)) 691 692 _, body, errs := a.String() 693 694 utils.AssertEqual(t, "", body) 695 utils.AssertEqual(t, 1, len(errs)) 696 utils.AssertEqual(t, "xml: unsupported type: complex128", errs[0].Error()) 697 } 698 699 func Test_Client_Agent_Form(t *testing.T) { 700 t.Parallel() 701 handler := func(c *Ctx) error { 702 utils.AssertEqual(t, MIMEApplicationForm, string(c.Request().Header.ContentType())) 703 704 return c.Send(c.Request().Body()) 705 } 706 707 args := AcquireArgs() 708 709 args.Set("foo", "bar") 710 711 wrapAgent := func(a *Agent) { 712 a.Form(args) 713 } 714 715 testAgent(t, handler, wrapAgent, "foo=bar") 716 717 ReleaseArgs(args) 718 } 719 720 func Test_Client_Agent_MultipartForm(t *testing.T) { 721 t.Parallel() 722 723 ln := fasthttputil.NewInmemoryListener() 724 725 app := New(Config{DisableStartupMessage: true}) 726 727 app.Post("/", func(c *Ctx) error { 728 utils.AssertEqual(t, "multipart/form-data; boundary=myBoundary", c.Get(HeaderContentType)) 729 730 mf, err := c.MultipartForm() 731 utils.AssertEqual(t, nil, err) 732 utils.AssertEqual(t, "bar", mf.Value["foo"][0]) 733 734 return c.Send(c.Request().Body()) 735 }) 736 737 go func() { utils.AssertEqual(t, nil, app.Listener(ln)) }() 738 739 args := AcquireArgs() 740 741 args.Set("foo", "bar") 742 743 a := Post("http://example.com"). 744 Boundary("myBoundary"). 745 MultipartForm(args) 746 747 a.HostClient.Dial = func(addr string) (net.Conn, error) { return ln.Dial() } 748 749 code, body, errs := a.String() 750 751 utils.AssertEqual(t, StatusOK, code) 752 utils.AssertEqual(t, "--myBoundary\r\nContent-Disposition: form-data; name=\"foo\"\r\n\r\nbar\r\n--myBoundary--\r\n", body) 753 utils.AssertEqual(t, 0, len(errs)) 754 ReleaseArgs(args) 755 } 756 757 func Test_Client_Agent_MultipartForm_Errors(t *testing.T) { 758 t.Parallel() 759 760 a := AcquireAgent() 761 a.mw = &errorMultipartWriter{} 762 763 args := AcquireArgs() 764 args.Set("foo", "bar") 765 766 ff1 := &FormFile{"", "name1", []byte("content"), false} 767 ff2 := &FormFile{"", "name2", []byte("content"), false} 768 a.FileData(ff1, ff2). 769 MultipartForm(args) 770 771 utils.AssertEqual(t, 4, len(a.errs)) 772 ReleaseArgs(args) 773 } 774 775 func Test_Client_Agent_MultipartForm_SendFiles(t *testing.T) { 776 t.Parallel() 777 778 ln := fasthttputil.NewInmemoryListener() 779 780 app := New(Config{DisableStartupMessage: true}) 781 782 app.Post("/", func(c *Ctx) error { 783 utils.AssertEqual(t, "multipart/form-data; boundary=myBoundary", c.Get(HeaderContentType)) 784 785 fh1, err := c.FormFile("field1") 786 utils.AssertEqual(t, nil, err) 787 utils.AssertEqual(t, fh1.Filename, "name") 788 buf := make([]byte, fh1.Size) 789 f, err := fh1.Open() 790 utils.AssertEqual(t, nil, err) 791 defer func() { 792 err := f.Close() 793 utils.AssertEqual(t, nil, err) 794 }() 795 _, err = f.Read(buf) 796 utils.AssertEqual(t, nil, err) 797 utils.AssertEqual(t, "form file", string(buf)) 798 799 fh2, err := c.FormFile("index") 800 utils.AssertEqual(t, nil, err) 801 checkFormFile(t, fh2, ".github/testdata/index.html") 802 803 fh3, err := c.FormFile("file3") 804 utils.AssertEqual(t, nil, err) 805 checkFormFile(t, fh3, ".github/testdata/index.tmpl") 806 807 return c.SendString("multipart form files") 808 }) 809 810 go func() { utils.AssertEqual(t, nil, app.Listener(ln)) }() 811 812 for i := 0; i < 5; i++ { 813 ff := AcquireFormFile() 814 ff.Fieldname = "field1" 815 ff.Name = "name" 816 ff.Content = []byte("form file") 817 818 a := Post("http://example.com"). 819 Boundary("myBoundary"). 820 FileData(ff). 821 SendFiles(".github/testdata/index.html", "index", ".github/testdata/index.tmpl"). 822 MultipartForm(nil) 823 824 a.HostClient.Dial = func(addr string) (net.Conn, error) { return ln.Dial() } 825 826 code, body, errs := a.String() 827 828 utils.AssertEqual(t, StatusOK, code) 829 utils.AssertEqual(t, "multipart form files", body) 830 utils.AssertEqual(t, 0, len(errs)) 831 832 ReleaseFormFile(ff) 833 } 834 } 835 836 func checkFormFile(t *testing.T, fh *multipart.FileHeader, filename string) { 837 t.Helper() 838 839 basename := filepath.Base(filename) 840 utils.AssertEqual(t, fh.Filename, basename) 841 842 b1, err := os.ReadFile(filename) //nolint:gosec // We're in a test so reading user-provided files by name is fine 843 utils.AssertEqual(t, nil, err) 844 845 b2 := make([]byte, fh.Size) 846 f, err := fh.Open() 847 utils.AssertEqual(t, nil, err) 848 defer func() { 849 err := f.Close() 850 utils.AssertEqual(t, nil, err) 851 }() 852 _, err = f.Read(b2) 853 utils.AssertEqual(t, nil, err) 854 utils.AssertEqual(t, b1, b2) 855 } 856 857 func Test_Client_Agent_Multipart_Random_Boundary(t *testing.T) { 858 t.Parallel() 859 860 a := Post("http://example.com"). 861 MultipartForm(nil) 862 863 reg := regexp.MustCompile(`multipart/form-data; boundary=\w{30}`) 864 865 utils.AssertEqual(t, true, reg.Match(a.req.Header.Peek(HeaderContentType))) 866 } 867 868 func Test_Client_Agent_Multipart_Invalid_Boundary(t *testing.T) { 869 t.Parallel() 870 871 a := Post("http://example.com"). 872 Boundary("*"). 873 MultipartForm(nil) 874 875 utils.AssertEqual(t, 1, len(a.errs)) 876 utils.AssertEqual(t, "mime: invalid boundary character", a.errs[0].Error()) 877 } 878 879 func Test_Client_Agent_SendFile_Error(t *testing.T) { 880 t.Parallel() 881 882 a := Post("http://example.com"). 883 SendFile("non-exist-file!", "") 884 885 utils.AssertEqual(t, 1, len(a.errs)) 886 utils.AssertEqual(t, true, strings.Contains(a.errs[0].Error(), "open non-exist-file!")) 887 } 888 889 func Test_Client_Debug(t *testing.T) { 890 t.Parallel() 891 handler := func(c *Ctx) error { 892 return c.SendString("debug") 893 } 894 895 var output bytes.Buffer 896 897 wrapAgent := func(a *Agent) { 898 a.Debug(&output) 899 } 900 901 testAgent(t, handler, wrapAgent, "debug", 1) 902 903 str := output.String() 904 905 utils.AssertEqual(t, true, strings.Contains(str, "Connected to example.com(InmemoryListener)")) 906 utils.AssertEqual(t, true, strings.Contains(str, "GET / HTTP/1.1")) 907 utils.AssertEqual(t, true, strings.Contains(str, "User-Agent: fiber")) 908 utils.AssertEqual(t, true, strings.Contains(str, "Host: example.com\r\n\r\n")) 909 utils.AssertEqual(t, true, strings.Contains(str, "HTTP/1.1 200 OK")) 910 utils.AssertEqual(t, true, strings.Contains(str, "Content-Type: text/plain; charset=utf-8\r\nContent-Length: 5\r\n\r\ndebug")) 911 } 912 913 func Test_Client_Agent_Timeout(t *testing.T) { 914 t.Parallel() 915 916 ln := fasthttputil.NewInmemoryListener() 917 918 app := New(Config{DisableStartupMessage: true}) 919 920 app.Get("/", func(c *Ctx) error { 921 time.Sleep(time.Millisecond * 200) 922 return c.SendString("timeout") 923 }) 924 925 go func() { utils.AssertEqual(t, nil, app.Listener(ln)) }() 926 927 a := Get("http://example.com"). 928 Timeout(time.Millisecond * 50) 929 930 a.HostClient.Dial = func(addr string) (net.Conn, error) { return ln.Dial() } 931 932 _, body, errs := a.String() 933 934 utils.AssertEqual(t, "", body) 935 utils.AssertEqual(t, 1, len(errs)) 936 utils.AssertEqual(t, "timeout", errs[0].Error()) 937 } 938 939 func Test_Client_Agent_Reuse(t *testing.T) { 940 t.Parallel() 941 942 ln := fasthttputil.NewInmemoryListener() 943 944 app := New(Config{DisableStartupMessage: true}) 945 946 app.Get("/", func(c *Ctx) error { 947 return c.SendString("reuse") 948 }) 949 950 go func() { utils.AssertEqual(t, nil, app.Listener(ln)) }() 951 952 a := Get("http://example.com"). 953 Reuse() 954 955 a.HostClient.Dial = func(addr string) (net.Conn, error) { return ln.Dial() } 956 957 code, body, errs := a.String() 958 959 utils.AssertEqual(t, StatusOK, code) 960 utils.AssertEqual(t, "reuse", body) 961 utils.AssertEqual(t, 0, len(errs)) 962 963 code, body, errs = a.String() 964 965 utils.AssertEqual(t, StatusOK, code) 966 utils.AssertEqual(t, "reuse", body) 967 utils.AssertEqual(t, 0, len(errs)) 968 } 969 970 func Test_Client_Agent_InsecureSkipVerify(t *testing.T) { 971 t.Parallel() 972 973 cer, err := tls.LoadX509KeyPair("./.github/testdata/ssl.pem", "./.github/testdata/ssl.key") 974 utils.AssertEqual(t, nil, err) 975 976 //nolint:gosec // We're in a test so using old ciphers is fine 977 serverTLSConf := &tls.Config{ 978 Certificates: []tls.Certificate{cer}, 979 } 980 981 ln, err := net.Listen(NetworkTCP4, "127.0.0.1:0") 982 utils.AssertEqual(t, nil, err) 983 984 ln = tls.NewListener(ln, serverTLSConf) 985 986 app := New(Config{DisableStartupMessage: true}) 987 988 app.Get("/", func(c *Ctx) error { 989 return c.SendString("ignore tls") 990 }) 991 992 go func() { utils.AssertEqual(t, nil, app.Listener(ln)) }() 993 994 code, body, errs := Get("https://" + ln.Addr().String()). 995 InsecureSkipVerify(). 996 InsecureSkipVerify(). 997 String() 998 999 utils.AssertEqual(t, 0, len(errs)) 1000 utils.AssertEqual(t, StatusOK, code) 1001 utils.AssertEqual(t, "ignore tls", body) 1002 } 1003 1004 func Test_Client_Agent_TLS(t *testing.T) { 1005 t.Parallel() 1006 1007 serverTLSConf, clientTLSConf, err := tlstest.GetTLSConfigs() 1008 utils.AssertEqual(t, nil, err) 1009 1010 ln, err := net.Listen(NetworkTCP4, "127.0.0.1:0") 1011 utils.AssertEqual(t, nil, err) 1012 1013 ln = tls.NewListener(ln, serverTLSConf) 1014 1015 app := New(Config{DisableStartupMessage: true}) 1016 1017 app.Get("/", func(c *Ctx) error { 1018 return c.SendString("tls") 1019 }) 1020 1021 go func() { utils.AssertEqual(t, nil, app.Listener(ln)) }() 1022 1023 code, body, errs := Get("https://" + ln.Addr().String()). 1024 TLSConfig(clientTLSConf). 1025 String() 1026 1027 utils.AssertEqual(t, 0, len(errs)) 1028 utils.AssertEqual(t, StatusOK, code) 1029 utils.AssertEqual(t, "tls", body) 1030 } 1031 1032 func Test_Client_Agent_MaxRedirectsCount(t *testing.T) { 1033 t.Parallel() 1034 1035 ln := fasthttputil.NewInmemoryListener() 1036 1037 app := New(Config{DisableStartupMessage: true}) 1038 1039 app.Get("/", func(c *Ctx) error { 1040 if c.Request().URI().QueryArgs().Has("foo") { 1041 return c.Redirect("/foo") 1042 } 1043 return c.Redirect("/") 1044 }) 1045 app.Get("/foo", func(c *Ctx) error { 1046 return c.SendString("redirect") 1047 }) 1048 1049 go func() { utils.AssertEqual(t, nil, app.Listener(ln)) }() 1050 1051 t.Run("success", func(t *testing.T) { 1052 t.Parallel() 1053 a := Get("http://example.com?foo"). 1054 MaxRedirectsCount(1) 1055 1056 a.HostClient.Dial = func(addr string) (net.Conn, error) { return ln.Dial() } 1057 1058 code, body, errs := a.String() 1059 1060 utils.AssertEqual(t, 200, code) 1061 utils.AssertEqual(t, "redirect", body) 1062 utils.AssertEqual(t, 0, len(errs)) 1063 }) 1064 1065 t.Run("error", func(t *testing.T) { 1066 t.Parallel() 1067 a := Get("http://example.com"). 1068 MaxRedirectsCount(1) 1069 1070 a.HostClient.Dial = func(addr string) (net.Conn, error) { return ln.Dial() } 1071 1072 _, body, errs := a.String() 1073 1074 utils.AssertEqual(t, "", body) 1075 utils.AssertEqual(t, 1, len(errs)) 1076 utils.AssertEqual(t, "too many redirects detected when doing the request", errs[0].Error()) 1077 }) 1078 } 1079 1080 func Test_Client_Agent_Struct(t *testing.T) { 1081 t.Parallel() 1082 1083 ln := fasthttputil.NewInmemoryListener() 1084 1085 app := New(Config{DisableStartupMessage: true}) 1086 1087 app.Get("/", func(c *Ctx) error { 1088 return c.JSON(data{true}) 1089 }) 1090 1091 app.Get("/error", func(c *Ctx) error { 1092 return c.SendString(`{"success"`) 1093 }) 1094 1095 go func() { utils.AssertEqual(t, nil, app.Listener(ln)) }() 1096 1097 t.Run("success", func(t *testing.T) { 1098 t.Parallel() 1099 1100 a := Get("http://example.com") 1101 1102 a.HostClient.Dial = func(addr string) (net.Conn, error) { return ln.Dial() } 1103 1104 var d data 1105 1106 code, body, errs := a.Struct(&d) 1107 1108 utils.AssertEqual(t, StatusOK, code) 1109 utils.AssertEqual(t, `{"success":true}`, string(body)) 1110 utils.AssertEqual(t, 0, len(errs)) 1111 utils.AssertEqual(t, true, d.Success) 1112 }) 1113 1114 t.Run("pre error", func(t *testing.T) { 1115 t.Parallel() 1116 a := Get("http://example.com") 1117 1118 a.HostClient.Dial = func(addr string) (net.Conn, error) { return ln.Dial() } 1119 a.errs = append(a.errs, errors.New("pre errors")) 1120 1121 var d data 1122 _, body, errs := a.Struct(&d) 1123 1124 utils.AssertEqual(t, "", string(body)) 1125 utils.AssertEqual(t, 1, len(errs)) 1126 utils.AssertEqual(t, "pre errors", errs[0].Error()) 1127 utils.AssertEqual(t, false, d.Success) 1128 }) 1129 1130 t.Run("error", func(t *testing.T) { 1131 t.Parallel() 1132 a := Get("http://example.com/error") 1133 1134 a.HostClient.Dial = func(addr string) (net.Conn, error) { return ln.Dial() } 1135 1136 var d data 1137 1138 code, body, errs := a.JSONDecoder(json.Unmarshal).Struct(&d) 1139 1140 utils.AssertEqual(t, StatusOK, code) 1141 utils.AssertEqual(t, `{"success"`, string(body)) 1142 utils.AssertEqual(t, 1, len(errs)) 1143 utils.AssertEqual(t, "unexpected end of JSON input", errs[0].Error()) 1144 }) 1145 1146 t.Run("nil jsonDecoder", func(t *testing.T) { 1147 t.Parallel() 1148 a := AcquireAgent() 1149 defer ReleaseAgent(a) 1150 defer a.ConnectionClose() 1151 request := a.Request() 1152 request.Header.SetMethod(MethodGet) 1153 request.SetRequestURI("http://example.com") 1154 err := a.Parse() 1155 utils.AssertEqual(t, nil, err) 1156 a.HostClient.Dial = func(addr string) (net.Conn, error) { return ln.Dial() } 1157 var d data 1158 code, body, errs := a.Struct(&d) 1159 utils.AssertEqual(t, StatusOK, code) 1160 utils.AssertEqual(t, `{"success":true}`, string(body)) 1161 utils.AssertEqual(t, 0, len(errs)) 1162 utils.AssertEqual(t, true, d.Success) 1163 }) 1164 } 1165 1166 func Test_Client_Agent_Parse(t *testing.T) { 1167 t.Parallel() 1168 1169 a := Get("https://example.com:10443") 1170 1171 utils.AssertEqual(t, nil, a.Parse()) 1172 } 1173 1174 func testAgent(t *testing.T, handler Handler, wrapAgent func(agent *Agent), excepted string, count ...int) { 1175 t.Helper() 1176 1177 ln := fasthttputil.NewInmemoryListener() 1178 1179 app := New(Config{DisableStartupMessage: true}) 1180 1181 app.Get("/", handler) 1182 1183 go func() { utils.AssertEqual(t, nil, app.Listener(ln)) }() 1184 1185 c := 1 1186 if len(count) > 0 { 1187 c = count[0] 1188 } 1189 1190 for i := 0; i < c; i++ { 1191 a := Get("http://example.com") 1192 1193 wrapAgent(a) 1194 1195 a.HostClient.Dial = func(addr string) (net.Conn, error) { return ln.Dial() } 1196 1197 code, body, errs := a.String() 1198 1199 utils.AssertEqual(t, StatusOK, code) 1200 utils.AssertEqual(t, excepted, body) 1201 utils.AssertEqual(t, 0, len(errs)) 1202 } 1203 } 1204 1205 type data struct { 1206 Success bool `json:"success" xml:"success"` 1207 } 1208 1209 type errorMultipartWriter struct { 1210 count int 1211 } 1212 1213 func (*errorMultipartWriter) Boundary() string { return "myBoundary" } 1214 func (*errorMultipartWriter) SetBoundary(_ string) error { return nil } 1215 func (e *errorMultipartWriter) CreateFormFile(_, _ string) (io.Writer, error) { 1216 if e.count == 0 { 1217 e.count++ 1218 return nil, errors.New("CreateFormFile error") 1219 } 1220 return errorWriter{}, nil 1221 } 1222 func (*errorMultipartWriter) WriteField(_, _ string) error { return errors.New("WriteField error") } 1223 func (*errorMultipartWriter) Close() error { return errors.New("Close error") } 1224 1225 type errorWriter struct{} 1226 1227 func (errorWriter) Write(_ []byte) (int, error) { return 0, errors.New("Write error") }