1package router 2 3import ( 4 "context" 5 "io" 6 "net/http" 7 "net/http/httptest" 8 "strings" 9 "testing" 10 11 "github.com/stretchr/testify/assert" 12 "github.com/stretchr/testify/require" 13 "github.com/traefik/traefik/v2/pkg/config/dynamic" 14 "github.com/traefik/traefik/v2/pkg/config/runtime" 15 "github.com/traefik/traefik/v2/pkg/config/static" 16 "github.com/traefik/traefik/v2/pkg/metrics" 17 "github.com/traefik/traefik/v2/pkg/middlewares/accesslog" 18 "github.com/traefik/traefik/v2/pkg/middlewares/requestdecorator" 19 "github.com/traefik/traefik/v2/pkg/server/middleware" 20 "github.com/traefik/traefik/v2/pkg/server/service" 21 "github.com/traefik/traefik/v2/pkg/testhelpers" 22 "github.com/traefik/traefik/v2/pkg/types" 23) 24 25func TestRouterManager_Get(t *testing.T) { 26 server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {})) 27 28 t.Cleanup(func() { server.Close() }) 29 30 type expectedResult struct { 31 StatusCode int 32 RequestHeaders map[string]string 33 } 34 35 testCases := []struct { 36 desc string 37 routersConfig map[string]*dynamic.Router 38 serviceConfig map[string]*dynamic.Service 39 middlewaresConfig map[string]*dynamic.Middleware 40 entryPoints []string 41 expected expectedResult 42 }{ 43 { 44 desc: "no middleware", 45 routersConfig: map[string]*dynamic.Router{ 46 "foo": { 47 EntryPoints: []string{"web"}, 48 Service: "foo-service", 49 Rule: "Host(`foo.bar`)", 50 }, 51 }, 52 serviceConfig: map[string]*dynamic.Service{ 53 "foo-service": { 54 LoadBalancer: &dynamic.ServersLoadBalancer{ 55 Servers: []dynamic.Server{ 56 { 57 URL: server.URL, 58 }, 59 }, 60 }, 61 }, 62 }, 63 entryPoints: []string{"web"}, 64 expected: expectedResult{StatusCode: http.StatusOK}, 65 }, 66 { 67 desc: "empty host", 68 routersConfig: map[string]*dynamic.Router{ 69 "foo": { 70 EntryPoints: []string{"web"}, 71 Service: "foo-service", 72 Rule: "Host(``)", 73 }, 74 }, 75 serviceConfig: map[string]*dynamic.Service{ 76 "foo-service": { 77 LoadBalancer: &dynamic.ServersLoadBalancer{ 78 Servers: []dynamic.Server{ 79 { 80 URL: server.URL, 81 }, 82 }, 83 }, 84 }, 85 }, 86 entryPoints: []string{"web"}, 87 expected: expectedResult{StatusCode: http.StatusNotFound}, 88 }, 89 { 90 desc: "no load balancer", 91 routersConfig: map[string]*dynamic.Router{ 92 "foo": { 93 EntryPoints: []string{"web"}, 94 Service: "foo-service", 95 Rule: "Host(`foo.bar`)", 96 }, 97 }, 98 serviceConfig: map[string]*dynamic.Service{ 99 "foo-service": {}, 100 }, 101 entryPoints: []string{"web"}, 102 expected: expectedResult{StatusCode: http.StatusNotFound}, 103 }, 104 { 105 desc: "no middleware, no matching", 106 routersConfig: map[string]*dynamic.Router{ 107 "foo": { 108 EntryPoints: []string{"web"}, 109 Service: "foo-service", 110 Rule: "Host(`bar.bar`)", 111 }, 112 }, 113 serviceConfig: map[string]*dynamic.Service{ 114 "foo-service": { 115 LoadBalancer: &dynamic.ServersLoadBalancer{ 116 Servers: []dynamic.Server{ 117 { 118 URL: server.URL, 119 }, 120 }, 121 }, 122 }, 123 }, 124 entryPoints: []string{"web"}, 125 expected: expectedResult{StatusCode: http.StatusNotFound}, 126 }, 127 { 128 desc: "middleware: headers > auth", 129 routersConfig: map[string]*dynamic.Router{ 130 "foo": { 131 EntryPoints: []string{"web"}, 132 Middlewares: []string{"headers-middle", "auth-middle"}, 133 Service: "foo-service", 134 Rule: "Host(`foo.bar`)", 135 }, 136 }, 137 serviceConfig: map[string]*dynamic.Service{ 138 "foo-service": { 139 LoadBalancer: &dynamic.ServersLoadBalancer{ 140 Servers: []dynamic.Server{ 141 { 142 URL: server.URL, 143 }, 144 }, 145 }, 146 }, 147 }, 148 middlewaresConfig: map[string]*dynamic.Middleware{ 149 "auth-middle": { 150 BasicAuth: &dynamic.BasicAuth{ 151 Users: []string{"toto:titi"}, 152 }, 153 }, 154 "headers-middle": { 155 Headers: &dynamic.Headers{ 156 CustomRequestHeaders: map[string]string{"X-Apero": "beer"}, 157 }, 158 }, 159 }, 160 entryPoints: []string{"web"}, 161 expected: expectedResult{ 162 StatusCode: http.StatusUnauthorized, 163 RequestHeaders: map[string]string{ 164 "X-Apero": "beer", 165 }, 166 }, 167 }, 168 { 169 desc: "middleware: auth > header", 170 routersConfig: map[string]*dynamic.Router{ 171 "foo": { 172 EntryPoints: []string{"web"}, 173 Middlewares: []string{"auth-middle", "headers-middle"}, 174 Service: "foo-service", 175 Rule: "Host(`foo.bar`)", 176 }, 177 }, 178 serviceConfig: map[string]*dynamic.Service{ 179 "foo-service": { 180 LoadBalancer: &dynamic.ServersLoadBalancer{ 181 Servers: []dynamic.Server{ 182 { 183 URL: server.URL, 184 }, 185 }, 186 }, 187 }, 188 }, 189 middlewaresConfig: map[string]*dynamic.Middleware{ 190 "auth-middle": { 191 BasicAuth: &dynamic.BasicAuth{ 192 Users: []string{"toto:titi"}, 193 }, 194 }, 195 "headers-middle": { 196 Headers: &dynamic.Headers{ 197 CustomRequestHeaders: map[string]string{"X-Apero": "beer"}, 198 }, 199 }, 200 }, 201 entryPoints: []string{"web"}, 202 expected: expectedResult{ 203 StatusCode: http.StatusUnauthorized, 204 RequestHeaders: map[string]string{ 205 "X-Apero": "", 206 }, 207 }, 208 }, 209 { 210 desc: "no middleware with provider name", 211 routersConfig: map[string]*dynamic.Router{ 212 "foo@provider-1": { 213 EntryPoints: []string{"web"}, 214 Service: "foo-service", 215 Rule: "Host(`foo.bar`)", 216 }, 217 }, 218 serviceConfig: map[string]*dynamic.Service{ 219 "foo-service@provider-1": { 220 LoadBalancer: &dynamic.ServersLoadBalancer{ 221 Servers: []dynamic.Server{ 222 { 223 URL: server.URL, 224 }, 225 }, 226 }, 227 }, 228 }, 229 entryPoints: []string{"web"}, 230 expected: expectedResult{StatusCode: http.StatusOK}, 231 }, 232 { 233 desc: "no middleware with specified provider name", 234 routersConfig: map[string]*dynamic.Router{ 235 "foo@provider-1": { 236 EntryPoints: []string{"web"}, 237 Service: "foo-service@provider-2", 238 Rule: "Host(`foo.bar`)", 239 }, 240 }, 241 serviceConfig: map[string]*dynamic.Service{ 242 "foo-service@provider-2": { 243 LoadBalancer: &dynamic.ServersLoadBalancer{ 244 Servers: []dynamic.Server{ 245 { 246 URL: server.URL, 247 }, 248 }, 249 }, 250 }, 251 }, 252 entryPoints: []string{"web"}, 253 expected: expectedResult{StatusCode: http.StatusOK}, 254 }, 255 { 256 desc: "middleware: chain with provider name", 257 routersConfig: map[string]*dynamic.Router{ 258 "foo@provider-1": { 259 EntryPoints: []string{"web"}, 260 Middlewares: []string{"chain-middle@provider-2", "headers-middle"}, 261 Service: "foo-service", 262 Rule: "Host(`foo.bar`)", 263 }, 264 }, 265 serviceConfig: map[string]*dynamic.Service{ 266 "foo-service@provider-1": { 267 LoadBalancer: &dynamic.ServersLoadBalancer{ 268 Servers: []dynamic.Server{ 269 { 270 URL: server.URL, 271 }, 272 }, 273 }, 274 }, 275 }, 276 middlewaresConfig: map[string]*dynamic.Middleware{ 277 "chain-middle@provider-2": { 278 Chain: &dynamic.Chain{Middlewares: []string{"auth-middle"}}, 279 }, 280 "auth-middle@provider-2": { 281 BasicAuth: &dynamic.BasicAuth{ 282 Users: []string{"toto:titi"}, 283 }, 284 }, 285 "headers-middle@provider-1": { 286 Headers: &dynamic.Headers{ 287 CustomRequestHeaders: map[string]string{"X-Apero": "beer"}, 288 }, 289 }, 290 }, 291 entryPoints: []string{"web"}, 292 expected: expectedResult{ 293 StatusCode: http.StatusUnauthorized, 294 RequestHeaders: map[string]string{ 295 "X-Apero": "", 296 }, 297 }, 298 }, 299 } 300 301 for _, test := range testCases { 302 test := test 303 t.Run(test.desc, func(t *testing.T) { 304 t.Parallel() 305 306 rtConf := runtime.NewConfig(dynamic.Configuration{ 307 HTTP: &dynamic.HTTPConfiguration{ 308 Services: test.serviceConfig, 309 Routers: test.routersConfig, 310 Middlewares: test.middlewaresConfig, 311 }, 312 }) 313 314 roundTripperManager := service.NewRoundTripperManager() 315 roundTripperManager.Update(map[string]*dynamic.ServersTransport{"default@internal": {}}) 316 serviceManager := service.NewManager(rtConf.Services, nil, nil, roundTripperManager) 317 middlewaresBuilder := middleware.NewBuilder(rtConf.Middlewares, serviceManager, nil) 318 chainBuilder := middleware.NewChainBuilder(static.Configuration{}, nil, nil) 319 320 routerManager := NewManager(rtConf, serviceManager, middlewaresBuilder, chainBuilder, metrics.NewVoidRegistry()) 321 322 handlers := routerManager.BuildHandlers(context.Background(), test.entryPoints, false) 323 324 w := httptest.NewRecorder() 325 req := testhelpers.MustNewRequest(http.MethodGet, "http://foo.bar/", nil) 326 327 reqHost := requestdecorator.New(nil) 328 reqHost.ServeHTTP(w, req, handlers["web"].ServeHTTP) 329 330 assert.Equal(t, test.expected.StatusCode, w.Code) 331 332 for key, value := range test.expected.RequestHeaders { 333 assert.Equal(t, value, req.Header.Get(key)) 334 } 335 }) 336 } 337} 338 339func TestAccessLog(t *testing.T) { 340 server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {})) 341 342 t.Cleanup(func() { server.Close() }) 343 344 testCases := []struct { 345 desc string 346 routersConfig map[string]*dynamic.Router 347 serviceConfig map[string]*dynamic.Service 348 middlewaresConfig map[string]*dynamic.Middleware 349 entryPoints []string 350 expected string 351 }{ 352 { 353 desc: "apply routerName in accesslog (first match)", 354 routersConfig: map[string]*dynamic.Router{ 355 "foo": { 356 EntryPoints: []string{"web"}, 357 Service: "foo-service", 358 Rule: "Host(`foo.bar`)", 359 }, 360 "bar": { 361 EntryPoints: []string{"web"}, 362 Service: "foo-service", 363 Rule: "Host(`bar.foo`)", 364 }, 365 }, 366 serviceConfig: map[string]*dynamic.Service{ 367 "foo-service": { 368 LoadBalancer: &dynamic.ServersLoadBalancer{ 369 Servers: []dynamic.Server{ 370 { 371 URL: server.URL, 372 }, 373 }, 374 }, 375 }, 376 }, 377 entryPoints: []string{"web"}, 378 expected: "foo", 379 }, 380 { 381 desc: "apply routerName in accesslog (second match)", 382 routersConfig: map[string]*dynamic.Router{ 383 "foo": { 384 EntryPoints: []string{"web"}, 385 Service: "foo-service", 386 Rule: "Host(`bar.foo`)", 387 }, 388 "bar": { 389 EntryPoints: []string{"web"}, 390 Service: "foo-service", 391 Rule: "Host(`foo.bar`)", 392 }, 393 }, 394 serviceConfig: map[string]*dynamic.Service{ 395 "foo-service": { 396 LoadBalancer: &dynamic.ServersLoadBalancer{ 397 Servers: []dynamic.Server{ 398 { 399 URL: server.URL, 400 }, 401 }, 402 }, 403 }, 404 }, 405 entryPoints: []string{"web"}, 406 expected: "bar", 407 }, 408 } 409 410 for _, test := range testCases { 411 t.Run(test.desc, func(t *testing.T) { 412 rtConf := runtime.NewConfig(dynamic.Configuration{ 413 HTTP: &dynamic.HTTPConfiguration{ 414 Services: test.serviceConfig, 415 Routers: test.routersConfig, 416 Middlewares: test.middlewaresConfig, 417 }, 418 }) 419 420 roundTripperManager := service.NewRoundTripperManager() 421 roundTripperManager.Update(map[string]*dynamic.ServersTransport{"default@internal": {}}) 422 serviceManager := service.NewManager(rtConf.Services, nil, nil, roundTripperManager) 423 middlewaresBuilder := middleware.NewBuilder(rtConf.Middlewares, serviceManager, nil) 424 chainBuilder := middleware.NewChainBuilder(static.Configuration{}, nil, nil) 425 426 routerManager := NewManager(rtConf, serviceManager, middlewaresBuilder, chainBuilder, metrics.NewVoidRegistry()) 427 428 handlers := routerManager.BuildHandlers(context.Background(), test.entryPoints, false) 429 430 w := httptest.NewRecorder() 431 req := testhelpers.MustNewRequest(http.MethodGet, "http://foo.bar/", nil) 432 433 accesslogger, err := accesslog.NewHandler(&types.AccessLog{ 434 Format: "json", 435 }) 436 require.NoError(t, err) 437 438 reqHost := requestdecorator.New(nil) 439 440 accesslogger.ServeHTTP(w, req, http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) { 441 reqHost.ServeHTTP(w, req, handlers["web"].ServeHTTP) 442 443 data := accesslog.GetLogData(req) 444 require.NotNil(t, data) 445 446 assert.Equal(t, test.expected, data.Core[accesslog.RouterName]) 447 })) 448 }) 449 } 450} 451 452func TestRuntimeConfiguration(t *testing.T) { 453 testCases := []struct { 454 desc string 455 serviceConfig map[string]*dynamic.Service 456 routerConfig map[string]*dynamic.Router 457 middlewareConfig map[string]*dynamic.Middleware 458 expectedError int 459 }{ 460 { 461 desc: "No error", 462 serviceConfig: map[string]*dynamic.Service{ 463 "foo-service": { 464 LoadBalancer: &dynamic.ServersLoadBalancer{ 465 Servers: []dynamic.Server{ 466 { 467 URL: "http://127.0.0.1:8085", 468 }, 469 { 470 URL: "http://127.0.0.1:8086", 471 }, 472 }, 473 HealthCheck: &dynamic.ServerHealthCheck{ 474 Interval: "500ms", 475 Path: "/health", 476 }, 477 }, 478 }, 479 }, 480 routerConfig: map[string]*dynamic.Router{ 481 "foo": { 482 EntryPoints: []string{"web"}, 483 Service: "foo-service", 484 Rule: "Host(`bar.foo`)", 485 }, 486 "bar": { 487 EntryPoints: []string{"web"}, 488 Service: "foo-service", 489 Rule: "Host(`foo.bar`)", 490 }, 491 }, 492 expectedError: 0, 493 }, 494 { 495 desc: "One router with wrong rule", 496 serviceConfig: map[string]*dynamic.Service{ 497 "foo-service": { 498 LoadBalancer: &dynamic.ServersLoadBalancer{ 499 Servers: []dynamic.Server{ 500 { 501 URL: "http://127.0.0.1", 502 }, 503 }, 504 }, 505 }, 506 }, 507 routerConfig: map[string]*dynamic.Router{ 508 "foo": { 509 EntryPoints: []string{"web"}, 510 Service: "foo-service", 511 Rule: "WrongRule(`bar.foo`)", 512 }, 513 "bar": { 514 EntryPoints: []string{"web"}, 515 Service: "foo-service", 516 Rule: "Host(`foo.bar`)", 517 }, 518 }, 519 expectedError: 1, 520 }, 521 { 522 desc: "All router with wrong rule", 523 serviceConfig: map[string]*dynamic.Service{ 524 "foo-service": { 525 LoadBalancer: &dynamic.ServersLoadBalancer{ 526 Servers: []dynamic.Server{ 527 { 528 URL: "http://127.0.0.1", 529 }, 530 }, 531 }, 532 }, 533 }, 534 routerConfig: map[string]*dynamic.Router{ 535 "foo": { 536 EntryPoints: []string{"web"}, 537 Service: "foo-service", 538 Rule: "WrongRule(`bar.foo`)", 539 }, 540 "bar": { 541 EntryPoints: []string{"web"}, 542 Service: "foo-service", 543 Rule: "WrongRule(`foo.bar`)", 544 }, 545 }, 546 expectedError: 2, 547 }, 548 { 549 desc: "Router with unknown service", 550 serviceConfig: map[string]*dynamic.Service{ 551 "foo-service": { 552 LoadBalancer: &dynamic.ServersLoadBalancer{ 553 Servers: []dynamic.Server{ 554 { 555 URL: "http://127.0.0.1", 556 }, 557 }, 558 }, 559 }, 560 }, 561 routerConfig: map[string]*dynamic.Router{ 562 "foo": { 563 EntryPoints: []string{"web"}, 564 Service: "wrong-service", 565 Rule: "Host(`bar.foo`)", 566 }, 567 "bar": { 568 EntryPoints: []string{"web"}, 569 Service: "foo-service", 570 Rule: "Host(`foo.bar`)", 571 }, 572 }, 573 expectedError: 1, 574 }, 575 { 576 desc: "Router with broken service", 577 serviceConfig: map[string]*dynamic.Service{ 578 "foo-service": { 579 LoadBalancer: nil, 580 }, 581 }, 582 routerConfig: map[string]*dynamic.Router{ 583 "bar": { 584 EntryPoints: []string{"web"}, 585 Service: "foo-service", 586 Rule: "Host(`foo.bar`)", 587 }, 588 }, 589 expectedError: 2, 590 }, 591 { 592 desc: "Router with middleware", 593 serviceConfig: map[string]*dynamic.Service{ 594 "foo-service": { 595 LoadBalancer: &dynamic.ServersLoadBalancer{ 596 Servers: []dynamic.Server{ 597 { 598 URL: "http://127.0.0.1", 599 }, 600 }, 601 }, 602 }, 603 }, 604 middlewareConfig: map[string]*dynamic.Middleware{ 605 "auth": { 606 BasicAuth: &dynamic.BasicAuth{ 607 Users: []string{"admin:admin"}, 608 }, 609 }, 610 "addPrefixTest": { 611 AddPrefix: &dynamic.AddPrefix{ 612 Prefix: "/toto", 613 }, 614 }, 615 }, 616 routerConfig: map[string]*dynamic.Router{ 617 "bar": { 618 EntryPoints: []string{"web"}, 619 Service: "foo-service", 620 Rule: "Host(`foo.bar`)", 621 Middlewares: []string{"auth", "addPrefixTest"}, 622 }, 623 "test": { 624 EntryPoints: []string{"web"}, 625 Service: "foo-service", 626 Rule: "Host(`foo.bar.other`)", 627 Middlewares: []string{"addPrefixTest", "auth"}, 628 }, 629 }, 630 }, 631 { 632 desc: "Router with unknown middleware", 633 serviceConfig: map[string]*dynamic.Service{ 634 "foo-service": { 635 LoadBalancer: &dynamic.ServersLoadBalancer{ 636 Servers: []dynamic.Server{ 637 { 638 URL: "http://127.0.0.1", 639 }, 640 }, 641 }, 642 }, 643 }, 644 middlewareConfig: map[string]*dynamic.Middleware{ 645 "auth": { 646 BasicAuth: &dynamic.BasicAuth{ 647 Users: []string{"admin:admin"}, 648 }, 649 }, 650 }, 651 routerConfig: map[string]*dynamic.Router{ 652 "bar": { 653 EntryPoints: []string{"web"}, 654 Service: "foo-service", 655 Rule: "Host(`foo.bar`)", 656 Middlewares: []string{"unknown"}, 657 }, 658 }, 659 expectedError: 1, 660 }, 661 662 { 663 desc: "Router with broken middleware", 664 serviceConfig: map[string]*dynamic.Service{ 665 "foo-service": { 666 LoadBalancer: &dynamic.ServersLoadBalancer{ 667 Servers: []dynamic.Server{ 668 { 669 URL: "http://127.0.0.1", 670 }, 671 }, 672 }, 673 }, 674 }, 675 middlewareConfig: map[string]*dynamic.Middleware{ 676 "auth": { 677 BasicAuth: &dynamic.BasicAuth{ 678 Users: []string{"foo"}, 679 }, 680 }, 681 }, 682 routerConfig: map[string]*dynamic.Router{ 683 "bar": { 684 EntryPoints: []string{"web"}, 685 Service: "foo-service", 686 Rule: "Host(`foo.bar`)", 687 Middlewares: []string{"auth"}, 688 }, 689 }, 690 expectedError: 2, 691 }, 692 } 693 694 for _, test := range testCases { 695 test := test 696 t.Run(test.desc, func(t *testing.T) { 697 t.Parallel() 698 699 entryPoints := []string{"web"} 700 701 rtConf := runtime.NewConfig(dynamic.Configuration{ 702 HTTP: &dynamic.HTTPConfiguration{ 703 Services: test.serviceConfig, 704 Routers: test.routerConfig, 705 Middlewares: test.middlewareConfig, 706 }, 707 }) 708 709 roundTripperManager := service.NewRoundTripperManager() 710 roundTripperManager.Update(map[string]*dynamic.ServersTransport{"default@internal": {}}) 711 serviceManager := service.NewManager(rtConf.Services, nil, nil, roundTripperManager) 712 middlewaresBuilder := middleware.NewBuilder(rtConf.Middlewares, serviceManager, nil) 713 chainBuilder := middleware.NewChainBuilder(static.Configuration{}, nil, nil) 714 715 routerManager := NewManager(rtConf, serviceManager, middlewaresBuilder, chainBuilder, metrics.NewVoidRegistry()) 716 717 _ = routerManager.BuildHandlers(context.Background(), entryPoints, false) 718 719 // even though rtConf was passed by argument to the manager builders above, 720 // it's ok to use it as the result we check, because everything worth checking 721 // can be accessed by pointers in it. 722 var allErrors int 723 for _, v := range rtConf.Services { 724 if v.Err != nil { 725 allErrors++ 726 } 727 } 728 for _, v := range rtConf.Routers { 729 if len(v.Err) > 0 { 730 allErrors++ 731 } 732 } 733 for _, v := range rtConf.Middlewares { 734 if v.Err != nil { 735 allErrors++ 736 } 737 } 738 assert.Equal(t, test.expectedError, allErrors) 739 }) 740 } 741} 742 743func TestProviderOnMiddlewares(t *testing.T) { 744 entryPoints := []string{"web"} 745 746 staticCfg := static.Configuration{ 747 EntryPoints: map[string]*static.EntryPoint{ 748 "web": { 749 Address: ":80", 750 }, 751 }, 752 } 753 754 rtConf := runtime.NewConfig(dynamic.Configuration{ 755 HTTP: &dynamic.HTTPConfiguration{ 756 Services: map[string]*dynamic.Service{ 757 "test@file": { 758 LoadBalancer: &dynamic.ServersLoadBalancer{ 759 Servers: []dynamic.Server{}, 760 }, 761 }, 762 }, 763 Routers: map[string]*dynamic.Router{ 764 "router@file": { 765 EntryPoints: []string{"web"}, 766 Rule: "Host(`test`)", 767 Service: "test@file", 768 Middlewares: []string{"chain@file", "m1"}, 769 }, 770 "router@docker": { 771 EntryPoints: []string{"web"}, 772 Rule: "Host(`test`)", 773 Service: "test@file", 774 Middlewares: []string{"chain", "m1@file"}, 775 }, 776 }, 777 Middlewares: map[string]*dynamic.Middleware{ 778 "chain@file": { 779 Chain: &dynamic.Chain{Middlewares: []string{"m1", "m2", "m1@file"}}, 780 }, 781 "chain@docker": { 782 Chain: &dynamic.Chain{Middlewares: []string{"m1", "m2", "m1@file"}}, 783 }, 784 "m1@file": {AddPrefix: &dynamic.AddPrefix{Prefix: "/m1"}}, 785 "m2@file": {AddPrefix: &dynamic.AddPrefix{Prefix: "/m2"}}, 786 "m1@docker": {AddPrefix: &dynamic.AddPrefix{Prefix: "/m1"}}, 787 "m2@docker": {AddPrefix: &dynamic.AddPrefix{Prefix: "/m2"}}, 788 }, 789 }, 790 }) 791 792 roundTripperManager := service.NewRoundTripperManager() 793 roundTripperManager.Update(map[string]*dynamic.ServersTransport{"default@internal": {}}) 794 serviceManager := service.NewManager(rtConf.Services, nil, nil, roundTripperManager) 795 middlewaresBuilder := middleware.NewBuilder(rtConf.Middlewares, serviceManager, nil) 796 chainBuilder := middleware.NewChainBuilder(staticCfg, nil, nil) 797 798 routerManager := NewManager(rtConf, serviceManager, middlewaresBuilder, chainBuilder, metrics.NewVoidRegistry()) 799 800 _ = routerManager.BuildHandlers(context.Background(), entryPoints, false) 801 802 assert.Equal(t, []string{"chain@file", "m1@file"}, rtConf.Routers["router@file"].Middlewares) 803 assert.Equal(t, []string{"m1@file", "m2@file", "m1@file"}, rtConf.Middlewares["chain@file"].Chain.Middlewares) 804 assert.Equal(t, []string{"chain@docker", "m1@file"}, rtConf.Routers["router@docker"].Middlewares) 805 assert.Equal(t, []string{"m1@docker", "m2@docker", "m1@file"}, rtConf.Middlewares["chain@docker"].Chain.Middlewares) 806} 807 808type staticRoundTripperGetter struct { 809 res *http.Response 810} 811 812func (s staticRoundTripperGetter) Get(name string) (http.RoundTripper, error) { 813 return &staticTransport{res: s.res}, nil 814} 815 816type staticTransport struct { 817 res *http.Response 818} 819 820func (t *staticTransport) RoundTrip(_ *http.Request) (*http.Response, error) { 821 return t.res, nil 822} 823 824func BenchmarkRouterServe(b *testing.B) { 825 server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {})) 826 827 b.Cleanup(func() { server.Close() }) 828 829 res := &http.Response{ 830 StatusCode: 200, 831 Body: io.NopCloser(strings.NewReader("")), 832 } 833 834 routersConfig := map[string]*dynamic.Router{ 835 "foo": { 836 EntryPoints: []string{"web"}, 837 Service: "foo-service", 838 Rule: "Host(`foo.bar`) && Path(`/`)", 839 }, 840 } 841 serviceConfig := map[string]*dynamic.Service{ 842 "foo-service": { 843 LoadBalancer: &dynamic.ServersLoadBalancer{ 844 Servers: []dynamic.Server{ 845 { 846 URL: server.URL, 847 }, 848 }, 849 }, 850 }, 851 } 852 entryPoints := []string{"web"} 853 854 rtConf := runtime.NewConfig(dynamic.Configuration{ 855 HTTP: &dynamic.HTTPConfiguration{ 856 Services: serviceConfig, 857 Routers: routersConfig, 858 Middlewares: map[string]*dynamic.Middleware{}, 859 }, 860 }) 861 862 serviceManager := service.NewManager(rtConf.Services, nil, nil, staticRoundTripperGetter{res}) 863 middlewaresBuilder := middleware.NewBuilder(rtConf.Middlewares, serviceManager, nil) 864 chainBuilder := middleware.NewChainBuilder(static.Configuration{}, nil, nil) 865 866 routerManager := NewManager(rtConf, serviceManager, middlewaresBuilder, chainBuilder, metrics.NewVoidRegistry()) 867 868 handlers := routerManager.BuildHandlers(context.Background(), entryPoints, false) 869 870 w := httptest.NewRecorder() 871 req := testhelpers.MustNewRequest(http.MethodGet, "http://foo.bar/", nil) 872 873 reqHost := requestdecorator.New(nil) 874 b.ReportAllocs() 875 for i := 0; i < b.N; i++ { 876 reqHost.ServeHTTP(w, req, handlers["web"].ServeHTTP) 877 } 878} 879 880func BenchmarkService(b *testing.B) { 881 res := &http.Response{ 882 StatusCode: 200, 883 Body: io.NopCloser(strings.NewReader("")), 884 } 885 886 serviceConfig := map[string]*dynamic.Service{ 887 "foo-service": { 888 LoadBalancer: &dynamic.ServersLoadBalancer{ 889 Servers: []dynamic.Server{ 890 { 891 URL: "tchouck", 892 }, 893 }, 894 }, 895 }, 896 } 897 898 rtConf := runtime.NewConfig(dynamic.Configuration{ 899 HTTP: &dynamic.HTTPConfiguration{ 900 Services: serviceConfig, 901 }, 902 }) 903 904 serviceManager := service.NewManager(rtConf.Services, nil, nil, staticRoundTripperGetter{res}) 905 w := httptest.NewRecorder() 906 req := testhelpers.MustNewRequest(http.MethodGet, "http://foo.bar/", nil) 907 908 handler, _ := serviceManager.BuildHTTP(context.Background(), "foo-service") 909 b.ReportAllocs() 910 for i := 0; i < b.N; i++ { 911 handler.ServeHTTP(w, req) 912 } 913} 914