github.com/gramework/gramework@v1.8.1-0.20231027140105-82555c9057f5/fasthttprouter_router_test.go (about) 1 // Copyright 2013 Julien Schmidt. All rights reserved. 2 // Copyright (c) 2015-2016, 招牌疯子 3 // Copyright (c) 2017, Kirill Danshin 4 // Use of this source code is governed by a BSD-style license that can be found 5 // in the 3rd-Party License/fasthttprouter file. 6 7 package gramework 8 9 import ( 10 "bufio" 11 "bytes" 12 "fmt" 13 "net" 14 "net/http" 15 "os" 16 "runtime/debug" 17 "strings" 18 "testing" 19 "time" 20 21 "github.com/valyala/fasthttp" 22 ) 23 24 type ( 25 // handlerStruct struct { 26 // handeled *bool 27 // } 28 29 // mockFileSystem struct { 30 // opened bool 31 // } 32 33 readWriter struct { 34 net.Conn 35 r bytes.Buffer 36 w bytes.Buffer 37 } 38 ) 39 40 var zeroTCPAddr = &net.TCPAddr{ 41 IP: net.IPv4zero, 42 } 43 44 func TestRouter(t *testing.T) { 45 router := New() 46 47 routed := false 48 router.Handle("GET", "/user/:name", func(ctx *Context) { 49 routed = true 50 want := map[string]string{"name": "gopher"} 51 52 if ctx.UserValue("name") != want["name"] { 53 t.Fatalf("wrong wildcard values: want %v, got %v", want["name"], ctx.UserValue("name")) 54 } 55 ctx.Success("foo/bar", []byte("success")) 56 }) 57 58 s := &fasthttp.Server{ 59 Handler: router.handler(), 60 } 61 62 rw := new(readWriter) 63 rw.r.WriteString("GET /user/gopher?baz HTTP/1.1\r\n\r\n") 64 65 ch := make(chan error) 66 go func() { 67 ch <- s.ServeConn(rw) 68 }() 69 70 select { 71 case err := <-ch: 72 if err != nil { 73 t.Fatalf("return error %s", err) 74 } 75 case <-time.After(100 * time.Millisecond): 76 t.Fatalf("timeout") 77 } 78 79 if !routed { 80 t.Fatal("routing failed") 81 } 82 } 83 84 // func (h handlerStruct) ServeHTTP(w http.ResponseWriter, r *http.Request) { 85 // *h.handeled = true 86 // } 87 88 func TestRouterAPI(t *testing.T) { 89 var get, head, options, post, put, patch, deleted bool 90 91 app := New() 92 app.GET("/GET", func(ctx *Context) { 93 get = true 94 }) 95 app.HEAD("/GET", func(ctx *Context) { 96 head = true 97 }) 98 app.OPTIONS("/GET", func(ctx *Context) { 99 options = true 100 }) 101 app.POST("/POST", func(ctx *Context) { 102 post = true 103 }) 104 app.PUT("/PUT", func(ctx *Context) { 105 put = true 106 }) 107 app.PATCH("/PATCH", func(ctx *Context) { 108 patch = true 109 }) 110 app.DELETE("/DELETE", func(ctx *Context) { 111 deleted = true 112 }) 113 114 s := &fasthttp.Server{ 115 Handler: app.handler(), 116 } 117 118 rw := new(readWriter) 119 ch := make(chan error) 120 121 rw.r.WriteString("GET /GET HTTP/1.1\r\n\r\n") 122 go func() { 123 ch <- s.ServeConn(rw) 124 }() 125 select { 126 case err := <-ch: 127 if err != nil { 128 t.Fatalf("return error %s", err) 129 } 130 case <-time.After(100 * time.Millisecond): 131 t.Fatalf("timeout") 132 } 133 if !get { 134 t.Error("routing GET failed") 135 } 136 137 rw.r.WriteString("HEAD /GET HTTP/1.1\r\n\r\n") 138 go func() { 139 ch <- s.ServeConn(rw) 140 }() 141 select { 142 case err := <-ch: 143 if err != nil { 144 t.Fatalf("return error %s", err) 145 } 146 case <-time.After(100 * time.Millisecond): 147 t.Fatalf("timeout") 148 } 149 if !head { 150 t.Error("routing HEAD failed") 151 } 152 153 rw.r.WriteString("OPTIONS /GET HTTP/1.1\r\n\r\n") 154 go func() { 155 ch <- s.ServeConn(rw) 156 }() 157 select { 158 case err := <-ch: 159 if err != nil { 160 t.Fatalf("return error %s", err) 161 } 162 case <-time.After(100 * time.Millisecond): 163 t.Fatalf("timeout") 164 } 165 if !options { 166 t.Error("routing OPTIONS failed") 167 } 168 169 rw.r.WriteString("POST /POST HTTP/1.1\r\n\r\n") 170 go func() { 171 ch <- s.ServeConn(rw) 172 }() 173 select { 174 case err := <-ch: 175 if err != nil { 176 t.Fatalf("return error %s", err) 177 } 178 case <-time.After(100 * time.Millisecond): 179 t.Fatalf("timeout") 180 } 181 if !post { 182 t.Error("routing POST failed") 183 } 184 185 rw.r.WriteString("PUT /PUT HTTP/1.1\r\n\r\n") 186 go func() { 187 ch <- s.ServeConn(rw) 188 }() 189 select { 190 case err := <-ch: 191 if err != nil { 192 t.Fatalf("return error %s", err) 193 } 194 case <-time.After(100 * time.Millisecond): 195 t.Fatalf("timeout") 196 } 197 if !put { 198 t.Error("routing PUT failed") 199 } 200 201 rw.r.WriteString("PATCH /PATCH HTTP/1.1\r\n\r\n") 202 go func() { 203 ch <- s.ServeConn(rw) 204 }() 205 select { 206 case err := <-ch: 207 if err != nil { 208 t.Fatalf("return error %s", err) 209 } 210 case <-time.After(100 * time.Millisecond): 211 t.Fatalf("timeout") 212 } 213 if !patch { 214 t.Error("routing PATCH failed") 215 } 216 217 rw.r.WriteString("DELETE /DELETE HTTP/1.1\r\n\r\n") 218 go func() { 219 ch <- s.ServeConn(rw) 220 }() 221 select { 222 case err := <-ch: 223 if err != nil { 224 t.Fatalf("return error %s", err) 225 } 226 case <-time.After(100 * time.Millisecond): 227 t.Fatalf("timeout") 228 } 229 if !deleted { 230 t.Error("routing DELETE failed") 231 } 232 } 233 234 func TestRouterWildAnyCache(t *testing.T) { 235 var get bool 236 237 app := New() 238 app.GET("/*any", func(ctx *Context) { 239 get = true 240 }) 241 s := &fasthttp.Server{ 242 Handler: app.handler(), 243 } 244 245 rw := new(readWriter) 246 ch := make(chan error) 247 248 boilCache := 64 // It works on values greater than the cache threshold (32). 249 for i := 0; i < boilCache; i++ { 250 app.defaultRouter.Allowed("/GET", "OPTIONS") 251 } 252 253 rw.r.WriteString("GET /GET HTTP/1.1\r\n\r\n") 254 go func() { 255 ch <- s.ServeConn(rw) 256 }() 257 select { 258 case err := <-ch: 259 if err != nil { 260 t.Fatalf("return error %s", err) 261 } 262 case <-time.After(100 * time.Millisecond): 263 t.Fatalf("timeout") 264 } 265 if !get { 266 t.Error("routing GET failed") 267 } 268 } 269 270 func TestRouterWildAnyWithArgsCache(t *testing.T) { 271 var get bool 272 var getArgs map[string][]string 273 var green bool 274 var greenValue string 275 276 app := New() 277 app.GET("/GET/*any", func(ctx *Context) { 278 get = true 279 getArgs = ctx.GETParams() 280 }) 281 app.GET("/GREEN/:CORN", func(ctx *Context) { 282 green = true 283 greenValue = ctx.UserValue("CORN").(string) 284 }) 285 286 s := &fasthttp.Server{ 287 Handler: app.handler(), 288 } 289 290 rw := new(readWriter) 291 ch := make(chan error) 292 293 boilCache := 64 // It works on values greater than the cache threshold (32). 294 for i := 0; i < boilCache; i++ { 295 app.defaultRouter.Allowed("/GET/ANY?foo=bar&fizz=buzz&fish", "OPTIONS") 296 app.defaultRouter.Allowed("/GET/ANY", "OPTIONS") 297 app.defaultRouter.Allowed("/GET", "OPTIONS") 298 app.defaultRouter.Allowed("/GREEN/CORN", "OPTIONS") 299 app.defaultRouter.Allowed("/GREEN", "OPTIONS") 300 } 301 302 rw.r.WriteString("GET /GET/ANY?foo=bar&fizz=buzz&fish HTTP/1.1\r\n\r\n") 303 go func() { 304 ch <- s.ServeConn(rw) 305 }() 306 select { 307 case err := <-ch: 308 if err != nil { 309 t.Fatalf("return error %s", err) 310 } 311 case <-time.After(100 * time.Millisecond): 312 t.Fatalf("timeout") 313 } 314 if !get { 315 t.Error("routing GET failed") 316 } 317 if getArgs == nil { 318 t.Error("get args should not be empty") 319 } 320 if foo, ok := getArgs["foo"]; ok { 321 if len(foo) != 1 || foo[0] != "bar" { 322 t.Error("the foo arg lost its bar value") 323 } 324 } else { 325 t.Error("the foo arg must exist") 326 } 327 if fizz, ok := getArgs["fizz"]; ok { 328 if len(fizz) != 1 || fizz[0] != "buzz" { 329 t.Error("the fizz arg lost its buzz value") 330 } 331 } else { 332 t.Error("the fizz arg must exist") 333 } 334 if fish, ok := getArgs["fish"]; ok { 335 if len(fish) > 0 && len(strings.Join(fish, "")) > 0 { 336 t.Error("how much is the fish?", fish) 337 } 338 } else { 339 t.Error("the fish arg must exist") 340 } 341 342 rw.r.WriteString("GET /GREEN/CORN HTTP/1.1\r\n\r\n") 343 go func() { 344 ch <- s.ServeConn(rw) 345 }() 346 select { 347 case err := <-ch: 348 if err != nil { 349 t.Fatalf("return error %s", err) 350 } 351 case <-time.After(100 * time.Millisecond): 352 t.Fatalf("timeout") 353 } 354 if !green { 355 t.Error("routing GREEN failed") 356 } 357 if len(greenValue) == 0 { 358 t.Error("the green value must exist") 359 } 360 if greenValue != "CORN" { 361 t.Errorf("the green value must be equal to 'CORN', but have '%s'", greenValue) 362 } 363 } 364 365 func TestRouterRoot(t *testing.T) { 366 router := New() 367 recv := catchPanic(func() { 368 router.GET("noSlashRoot", nil) 369 }) 370 if recv == nil { 371 t.Fatal("registering path not beginning with '/' did not panic") 372 } 373 } 374 375 // func TestRouterOPTIONS(t *testing.T) { 376 // // TODO: because fasthttp is not support OPTIONS method now, 377 // // these test cases will be used in the future. 378 // handlerFunc := func(_ *fasthttp.RequestCtx) {} 379 380 // router := New() 381 // router.POST("/path", handlerFunc) 382 383 // // test not allowed 384 // // * (server) 385 // s := &fasthttp.Server{ 386 // Handler: router.handler(), 387 // } 388 389 // rw := new(readWriter{}) 390 // ch := make(chan error) 391 392 // rw.r.WriteString("OPTIONS * HTTP/1.1\r\nHost:\r\n\r\n") 393 // go func() { 394 // ch <- s.ServeConn(rw) 395 // }() 396 // select { 397 // case err := <-ch: 398 // if err != nil { 399 // t.Fatalf("return error %s", err) 400 // } 401 // case <-time.After(100 * time.Millisecond): 402 // t.Fatalf("timeout") 403 // } 404 // br := bufio.NewReader(&rw.w) 405 // var resp fasthttp.Response 406 // if err := resp.Read(br); err != nil { 407 // t.Fatalf("Unexpected error when reading response: %s", err) 408 // } 409 // if resp.Header.StatusCode() != fasthttp.StatusOK { 410 // t.Errorf("OPTIONS handling failed: Code=%d, Header=%v", 411 // resp.Header.StatusCode(), resp.Header.String()) 412 // } else if allow := string(resp.Header.Peek("Allow")); allow != "POST, OPTIONS" { 413 // t.Error("unexpected Allow header value: " + allow) 414 // } 415 416 // // path 417 // rw.r.WriteString("OPTIONS /path HTTP/1.1\r\n\r\n") 418 // go func() { 419 // ch <- s.ServeConn(rw) 420 // }() 421 // select { 422 // case err := <-ch: 423 // if err != nil { 424 // t.Fatalf("return error %s", err) 425 // } 426 // case <-time.After(100 * time.Millisecond): 427 // t.Fatalf("timeout") 428 // } 429 // if err := resp.Read(br); err != nil { 430 // t.Fatalf("Unexpected error when reading response: %s", err) 431 // } 432 // if resp.Header.StatusCode() != fasthttp.StatusOK { 433 // t.Errorf("OPTIONS handling failed: Code=%d, Header=%v", 434 // resp.Header.StatusCode(), resp.Header.String()) 435 // } else if allow := string(resp.Header.Peek("Allow")); allow != "POST, OPTIONS" { 436 // t.Error("unexpected Allow header value: " + allow) 437 // } 438 439 // rw.r.WriteString("OPTIONS /doesnotexist HTTP/1.1\r\n\r\n") 440 // go func() { 441 // ch <- s.ServeConn(rw) 442 // }() 443 // select { 444 // case err := <-ch: 445 // if err != nil { 446 // t.Fatalf("return error %s", err) 447 // } 448 // case <-time.After(100 * time.Millisecond): 449 // t.Fatalf("timeout") 450 // } 451 // if err := resp.Read(br); err != nil { 452 // t.Fatalf("Unexpected error when reading response: %s", err) 453 // } 454 // if !(resp.Header.StatusCode() == fasthttp.StatusNotFound) { 455 // t.Errorf("OPTIONS handling failed: Code=%d, Header=%v", 456 // resp.Header.StatusCode(), resp.Header.String()) 457 // } 458 459 // // add another method 460 // router.GET("/path", handlerFunc) 461 462 // // test again 463 // // * (server) 464 // rw.r.WriteString("OPTIONS * HTTP/1.1\r\n\r\n") 465 // go func() { 466 // ch <- s.ServeConn(rw) 467 // }() 468 // select { 469 // case err := <-ch: 470 // if err != nil { 471 // t.Fatalf("return error %s", err) 472 // } 473 // case <-time.After(100 * time.Millisecond): 474 // t.Fatalf("timeout") 475 // } 476 // if err := resp.Read(br); err != nil { 477 // t.Fatalf("Unexpected error when reading response: %s", err) 478 // } 479 // if resp.Header.StatusCode() != fasthttp.StatusOK { 480 // t.Errorf("OPTIONS handling failed: Code=%d, Header=%v", 481 // resp.Header.StatusCode(), resp.Header.String()) 482 // } else if allow := string(resp.Header.Peek("Allow")); allow != "POST, GET, OPTIONS" && allow != "GET, POST, OPTIONS" { 483 // t.Error("unexpected Allow header value: " + allow) 484 // } 485 486 // // path 487 // rw.r.WriteString("OPTIONS /path HTTP/1.1\r\n\r\n") 488 // go func() { 489 // ch <- s.ServeConn(rw) 490 // }() 491 // select { 492 // case err := <-ch: 493 // if err != nil { 494 // t.Fatalf("return error %s", err) 495 // } 496 // case <-time.After(100 * time.Millisecond): 497 // t.Fatalf("timeout") 498 // } 499 // if err := resp.Read(br); err != nil { 500 // t.Fatalf("Unexpected error when reading response: %s", err) 501 // } 502 // if resp.Header.StatusCode() != fasthttp.StatusOK { 503 // t.Errorf("OPTIONS handling failed: Code=%d, Header=%v", 504 // resp.Header.StatusCode(), resp.Header.String()) 505 // } else if allow := string(resp.Header.Peek("Allow")); allow != "POST, GET, OPTIONS" && allow != "GET, POST, OPTIONS" { 506 // t.Error("unexpected Allow header value: " + allow) 507 // } 508 509 // // custom handler 510 // var custom bool 511 // router.OPTIONS("/path", func(_ *fasthttp.RequestCtx) { 512 // custom = true 513 // }) 514 515 // // test again 516 // // * (server) 517 // rw.r.WriteString("OPTIONS * HTTP/1.1\r\n\r\n") 518 // go func() { 519 // ch <- s.ServeConn(rw) 520 // }() 521 // select { 522 // case err := <-ch: 523 // if err != nil { 524 // t.Fatalf("return error %s", err) 525 // } 526 // case <-time.After(100 * time.Millisecond): 527 // t.Fatalf("timeout") 528 // } 529 // if err := resp.Read(br); err != nil { 530 // t.Fatalf("Unexpected error when reading response: %s", err) 531 // } 532 // if resp.Header.StatusCode() != fasthttp.StatusOK { 533 // t.Errorf("OPTIONS handling failed: Code=%d, Header=%v", 534 // resp.Header.StatusCode(), resp.Header.String()) 535 // } else if allow := string(resp.Header.Peek("Allow")); allow != "POST, GET, OPTIONS" && allow != "GET, POST, OPTIONS" { 536 // t.Error("unexpected Allow header value: " + allow) 537 // } 538 // if custom { 539 // t.Error("custom handler called on *") 540 // } 541 542 // // path 543 // rw.r.WriteString("OPTIONS /path HTTP/1.1\r\n\r\n") 544 // go func() { 545 // ch <- s.ServeConn(rw) 546 // }() 547 // select { 548 // case err := <-ch: 549 // if err != nil { 550 // t.Fatalf("return error %s", err) 551 // } 552 // case <-time.After(100 * time.Millisecond): 553 // t.Fatalf("timeout") 554 // } 555 // if err := resp.Read(br); err != nil { 556 // t.Fatalf("Unexpected error when reading response: %s", err) 557 // } 558 // if resp.Header.StatusCode() != fasthttp.StatusOK { 559 // t.Errorf("OPTIONS handling failed: Code=%d, Header=%v", 560 // resp.Header.StatusCode(), resp.Header.String()) 561 // } 562 // if !custom { 563 // t.Error("custom handler not called") 564 // } 565 // } 566 567 func TestRouterNotAllowed(t *testing.T) { 568 handlerFunc := func(_ *fasthttp.RequestCtx) {} 569 570 router := New() 571 router.POST("/path", handlerFunc) 572 573 // Test not allowed 574 s := &fasthttp.Server{ 575 Handler: router.handler(), 576 } 577 578 rw := new(readWriter) 579 ch := make(chan error) 580 581 rw.r.WriteString("GET /path HTTP/1.1\r\n\r\n") 582 go func() { 583 ch <- s.ServeConn(rw) 584 }() 585 select { 586 case err := <-ch: 587 if err != nil { 588 t.Fatalf("return error %s", err) 589 } 590 case <-time.After(100 * time.Millisecond): 591 t.Fatalf("timeout") 592 } 593 br := bufio.NewReader(&rw.w) 594 var resp fasthttp.Response 595 if err := resp.Read(br); err != nil { 596 t.Fatalf("Unexpected error when reading response: %s", err) 597 } 598 if !(resp.Header.StatusCode() == fasthttp.StatusMethodNotAllowed) { 599 t.Errorf("NotAllowed handling failed: Code=%d. Actual=%d", resp.Header.StatusCode(), fasthttp.StatusMethodNotAllowed) 600 } else if allow := string(resp.Header.Peek("Allow")); allow != "POST, OPTIONS" { 601 t.Error("unexpected Allow header value: " + allow) 602 } 603 604 // add another method 605 router.DELETE("/path", handlerFunc) 606 router.OPTIONS("/path", handlerFunc) // must be ignored 607 608 // test again 609 rw.r.WriteString("GET /path HTTP/1.1\r\n\r\n") 610 go func() { 611 ch <- s.ServeConn(rw) 612 }() 613 select { 614 case err := <-ch: 615 if err != nil { 616 t.Fatalf("return error %s", err) 617 } 618 case <-time.After(100 * time.Millisecond): 619 t.Fatalf("timeout") 620 } 621 if err := resp.Read(br); err != nil { 622 t.Fatalf("Unexpected error when reading response: %s", err) 623 } 624 if !(resp.Header.StatusCode() == fasthttp.StatusMethodNotAllowed) { 625 t.Errorf("NotAllowed handling failed: Code=%d. Actual=%d", resp.Header.StatusCode(), fasthttp.StatusMethodNotAllowed) 626 } else if allow := string(resp.Header.Peek("Allow")); allow != "POST, DELETE, OPTIONS" && allow != "DELETE, POST, OPTIONS" { 627 t.Error("unexpected Allow header value: " + allow) 628 } 629 630 responseText := "custom method" 631 router.MethodNotAllowed(func(ctx *Context) { 632 ctx.SetStatusCode(fasthttp.StatusTeapot) 633 _, e := ctx.Write([]byte(responseText)) 634 _ = e 635 }) 636 rw.r.WriteString("GET /path HTTP/1.1\r\n\r\n") 637 go func() { 638 ch <- s.ServeConn(rw) 639 }() 640 select { 641 case err := <-ch: 642 if err != nil { 643 t.Fatalf("return error %s", err) 644 } 645 case <-time.After(100 * time.Millisecond): 646 t.Fatalf("timeout") 647 } 648 if err := resp.Read(br); err != nil { 649 t.Fatalf("Unexpected error when reading response: %s", err) 650 } 651 if !bytes.Equal(resp.Body(), []byte(responseText)) { 652 t.Errorf("unexpected response got %q want %q", string(resp.Body()), responseText) 653 } 654 if resp.Header.StatusCode() != fasthttp.StatusTeapot { 655 t.Errorf("unexpected response code %d want %d", resp.Header.StatusCode(), fasthttp.StatusTeapot) 656 } 657 if allow := string(resp.Header.Peek("Allow")); allow != "POST, DELETE, OPTIONS" && allow != "DELETE, POST, OPTIONS" { 658 t.Error("unexpected Allow header value: " + allow) 659 } 660 } 661 662 func TestRouterNotFound(t *testing.T) { 663 handlerFunc := func(_ *fasthttp.RequestCtx) {} 664 665 router := New() 666 router.GET("/path", handlerFunc) 667 router.GET("/dir/", handlerFunc) 668 router.GET("/", handlerFunc) 669 router.GET("/path/:user", handlerFunc) 670 router.Sub("/abc").GET("/:user", handlerFunc) 671 672 testRoutes := []struct { 673 route string 674 code int 675 location string 676 }{ 677 {"/path/", 301, "/path"}, // TSR -/ 678 {"/dir", 200, ""}, // TSR -/ 679 {"/", 200, ""}, // TSR +/ 680 {"/PATH", 301, "/path"}, // Fixed Case 681 {"/DIR", 301, "/dir"}, // Fixed Case 682 {"/PATH/", 301, "/path"}, // Fixed Case -/ 683 {"/DIR/", 301, "/dir"}, // Fixed Case +/ 684 {"/paTh/?name=foo", 301, "/path?name=foo"}, // Fixed Case With Params +/ 685 {"/paTh?name=foo", 301, "/path?name=foo"}, // Fixed Case With Params +/ 686 {"/../path", 200, ""}, // CleanPath 687 {"/nope", 404, ""}, // NotFound 688 {"/path/?name=foo", 301, "/path?name=foo"}, // TSR Case With Params 689 {"/path/u/?name=foo", 301, "/path/u?name=foo"}, // Dynamic TSR -/ 690 {"/abc/u/?name=foo", 301, "/abc/u?name=foo"}, // Sub Dynamic TSR -/ 691 {"/AbC/u/?name=foo", 301, "/abc/u?name=foo"}, // Sub Dynamic Fixed Case -/ 692 } 693 694 s := &fasthttp.Server{ 695 Handler: router.handler(), 696 } 697 698 rw := new(readWriter) 699 br := bufio.NewReader(&rw.w) 700 var resp fasthttp.Response 701 ch := make(chan error) 702 for _, tr := range testRoutes { 703 t.Logf("testing %v, want %v code", tr.route, tr.code) 704 rw.r.WriteString(fmt.Sprintf("GET %s HTTP/1.1\r\n\r\n", tr.route)) 705 go func() { 706 ch <- s.ServeConn(rw) 707 }() 708 select { 709 case err := <-ch: 710 if err != nil { 711 t.Fatalf("return error %s", err) 712 } 713 case <-time.After(100 * time.Millisecond): 714 t.Fatalf("timeout") 715 } 716 if err := resp.Read(br); err != nil { 717 t.Fatalf("Unexpected error when reading response: %s", err) 718 } 719 if !(resp.Header.StatusCode() == tr.code) { 720 t.Errorf("NotFound handling route %s failed: Code=%d want=%d", 721 tr.route, resp.Header.StatusCode(), tr.code) 722 } 723 respLocation := string(resp.Header.Peek("Location")) 724 if tr.code == 301 && respLocation != tr.location { 725 t.Errorf("Wrong location header %s failed: Location=%s want=%s", 726 tr.route, respLocation, tr.location) 727 } 728 } 729 t.Log("not found test") 730 // Test custom not found handler 731 var notFound bool 732 router.NotFound(func(ctx *Context) { 733 ctx.SetStatusCode(404) 734 notFound = true 735 }) 736 rw.r.WriteString("GET /nope HTTP/1.1\r\n\r\n") 737 go func() { 738 ch <- s.ServeConn(rw) 739 }() 740 select { 741 case err := <-ch: 742 if err != nil { 743 t.Fatalf("return error %s", err) 744 } 745 case <-time.After(100 * time.Millisecond): 746 t.Fatalf("timeout") 747 } 748 if err := resp.Read(br); err != nil { 749 t.Fatalf("Unexpected error when reading response: %s", err) 750 } 751 if !(resp.Header.StatusCode() == http.StatusNotFound && notFound) { 752 t.Errorf( 753 "Custom NotFound handler failed: Code=%d, Header=%v, url=/nope", 754 resp.Header.StatusCode(), 755 string(resp.Header.Peek("Location")), 756 ) 757 } 758 759 // Test other method than GET (want 307 instead of 301) 760 router.PATCH("/path", handlerFunc) 761 rw.r.WriteString("PATCH /path/ HTTP/1.1\r\n\r\n") 762 go func() { 763 ch <- s.ServeConn(rw) 764 }() 765 select { 766 case err := <-ch: 767 if err != nil { 768 t.Fatalf("return error %s", err) 769 } 770 case <-time.After(100 * time.Millisecond): 771 t.Fatalf("timeout") 772 } 773 if err := resp.Read(br); err != nil { 774 t.Fatalf("Unexpected error when reading response: %s", err) 775 } 776 if resp.Header.StatusCode() != 307 { 777 t.Errorf("Custom NotFound handler failed: Code=%d, Header=%v, url=/path", 778 resp.Header.StatusCode(), 779 string(resp.Header.Peek("Location")), 780 ) 781 } 782 783 // Test special case where no node for the prefix "/" exists 784 router = New() 785 router.GET("/a", handlerFunc) 786 s.Handler = router.handler() 787 rw.r.WriteString("GET / HTTP/1.1\r\n\r\n") 788 go func() { 789 ch <- s.ServeConn(rw) 790 }() 791 select { 792 case err := <-ch: 793 if err != nil { 794 t.Fatalf("return error %s", err) 795 } 796 case <-time.After(100 * time.Millisecond): 797 t.Fatalf("timeout") 798 } 799 if err := resp.Read(br); err != nil { 800 t.Fatalf("Unexpected error when reading response: %s", err) 801 } 802 if !(resp.Header.StatusCode() == 404) { 803 t.Errorf("NotFound handling route / failed: Code=%d, Header=%v, url=/", 804 resp.Header.StatusCode(), 805 string(resp.Header.Peek("Location")), 806 ) 807 } 808 } 809 810 func TestRouterPanicHandler(t *testing.T) { 811 router := New() 812 panicHandled := false 813 814 router.PanicHandler(func(ctx *Context, p interface{}) { 815 panicHandled = true 816 }) 817 818 router.Handle("PUT", "/user/:name", func(_ *fasthttp.RequestCtx) { 819 panic("oops!") 820 }) 821 822 defer func() { 823 if rcv := recover(); rcv != nil { 824 t.Fatal("handling panic failed") 825 } 826 }() 827 828 s := &fasthttp.Server{ 829 Handler: router.handler(), 830 } 831 832 rw := new(readWriter) 833 ch := make(chan error) 834 835 rw.r.WriteString(string("PUT /user/gopher HTTP/1.1\r\n\r\n")) 836 go func() { 837 ch <- s.ServeConn(rw) 838 }() 839 select { 840 case err := <-ch: 841 if err != nil { 842 t.Fatalf("return error %s", err) 843 } 844 case <-time.After(100 * time.Millisecond): 845 t.Fatalf("timeout") 846 } 847 848 if !panicHandled { 849 t.Fatal("simulating failed") 850 } 851 } 852 853 func TestRouterLookup(t *testing.T) { 854 855 defer func() { 856 if r := recover(); r != nil { 857 Logger.Errorf("panic handled: %v", r) 858 debug.PrintStack() 859 } 860 }() 861 routed := false 862 wantHandle := func(_ *fasthttp.RequestCtx) { 863 routed = true 864 } 865 866 router := New() 867 ctx := &Context{ 868 RequestCtx: &fasthttp.RequestCtx{}, 869 Logger: Logger, 870 App: router, 871 } 872 873 // try empty router first 874 handle, tsr := router.defaultRouter.Lookup("GET", "/nope", ctx) 875 if handle != nil { 876 t.Fatalf("Got handle for unregistered pattern: %v", handle) 877 } 878 if tsr { 879 t.Error("Got wrong TSR recommendation!") 880 } 881 882 // insert route and try again 883 router.GET("/user/:name", wantHandle) 884 885 handle, _ = router.defaultRouter.Lookup("GET", "/user/gopher", ctx) 886 if handle == nil { 887 t.Fatal("Got no handle!") 888 } else { 889 handle(nil) 890 if !routed { 891 t.Fatal("Routing failed!") 892 } 893 } 894 if ctx.UserValue("name") != "gopher" { 895 t.Error("Param not set!") 896 } 897 898 handle, tsr = router.defaultRouter.Lookup("GET", "/user/gopher/", ctx) 899 if handle != nil { 900 t.Fatalf("Got handle for unregistered pattern: %v", handle) 901 } 902 if !tsr { 903 t.Error("Got no TSR recommendation!") 904 } 905 906 handle, tsr = router.defaultRouter.Lookup("GET", "/nope", ctx) 907 if handle != nil { 908 t.Fatalf("Got handle for unregistered pattern: %v", handle) 909 } 910 if tsr { 911 t.Error("Got wrong TSR recommendation!") 912 } 913 } 914 915 // func (mfs *mockFileSystem) Open(name string) (http.File, error) { 916 // mfs.opened = true 917 // return nil, errors.New("this is just a mock") 918 // } 919 920 func TestRouterServeFiles(t *testing.T) { 921 router := New() 922 923 recv := catchPanic(func() { 924 router.defaultRouter.ServeFiles("/noFilepath", os.TempDir()) 925 }) 926 if recv == nil { 927 t.Fatal("registering path not ending with '*filepath' did not panic") 928 } 929 body := []byte("fake ico") 930 err := os.WriteFile(os.TempDir()+"/favicon.ico", body, 0644) 931 if err != nil { 932 t.Fatal(err) 933 } 934 935 router.defaultRouter.ServeFiles("/*filepath", os.TempDir()) 936 937 s := &fasthttp.Server{ 938 Handler: router.handler(), 939 } 940 941 rw := new(readWriter) 942 ch := make(chan error) 943 944 rw.r.WriteString(string("GET /favicon.ico HTTP/1.1\r\n\r\n")) 945 go func() { 946 ch <- s.ServeConn(rw) 947 }() 948 select { 949 case err := <-ch: 950 if err != nil { 951 t.Fatalf("return error %s", err) 952 } 953 case <-time.After(500 * time.Millisecond): 954 t.Fatalf("timeout") 955 } 956 957 br := bufio.NewReader(&rw.w) 958 var resp fasthttp.Response 959 if err := resp.Read(br); err != nil { 960 t.Fatalf("Unexpected error when reading response: %s", err) 961 } 962 if resp.Header.StatusCode() != 200 { 963 t.Fatalf("Unexpected status code %d. Expected %d", resp.Header.StatusCode(), 423) 964 } 965 if !bytes.Equal(resp.Body(), body) { 966 t.Fatalf("Unexpected body %q. Expected %q", resp.Body(), string(body)) 967 } 968 } 969 970 func (rw *readWriter) Close() error { 971 return nil 972 } 973 974 func (rw *readWriter) Read(b []byte) (int, error) { 975 return rw.r.Read(b) 976 } 977 978 func (rw *readWriter) Write(b []byte) (int, error) { 979 return rw.w.Write(b) 980 } 981 982 func (rw *readWriter) RemoteAddr() net.Addr { 983 return zeroTCPAddr 984 } 985 986 func (rw *readWriter) LocalAddr() net.Addr { 987 return zeroTCPAddr 988 } 989 990 func (rw *readWriter) SetReadDeadline(t time.Time) error { 991 return nil 992 } 993 994 func (rw *readWriter) SetWriteDeadline(t time.Time) error { 995 return nil 996 }