github.com/Tyktechnologies/tyk@v2.9.5+incompatible/gateway/mw_url_rewrite_test.go (about) 1 package gateway 2 3 import ( 4 "net/http/httptest" 5 "sync" 6 "testing" 7 8 "github.com/TykTechnologies/tyk/test" 9 10 "bytes" 11 "net/http" 12 13 "github.com/TykTechnologies/tyk/apidef" 14 "github.com/TykTechnologies/tyk/user" 15 ) 16 17 var testRewriterData = []struct { 18 name string 19 pattern, to string 20 in, want string 21 }{ 22 { 23 "Straight", 24 "/test/straight/rewrite", "/change/to/me", 25 "/test/straight/rewrite", "/change/to/me", 26 }, 27 { 28 "OneVal", 29 "test/val/(.*)", "change/to/$1", 30 "/test/val/VALUE", "change/to/VALUE", 31 }, 32 { 33 "ThreeVals", 34 "/test/val/(.*)/space/(.*)/and/then/(.*)", "/change/to/$1/$2/$3", 35 "/test/val/ONE/space/TWO/and/then/THREE", "/change/to/ONE/TWO/THREE", 36 }, 37 { 38 "Reverse", 39 "/test/val/(.*)/space/(.*)/and/then/(.*)", "/change/to/$3/$2/$1", 40 "/test/val/ONE/space/TWO/and/then/THREE", "/change/to/THREE/TWO/ONE", 41 }, 42 { 43 "Missing", 44 "/test/val/(.*)/space/(.*)/and/then/(.*)", "/change/to/$1/$2", 45 "/test/val/ONE/space/TWO/and/then/THREE", "/change/to/ONE/TWO", 46 }, 47 { 48 "MissingAgain", 49 "/test/val/(.*)/space/(.*)/and/then/(.*)", "/change/to/$3/$1", 50 "/test/val/ONE/space/TWO/and/then/THREE", "/change/to/THREE/ONE", 51 }, 52 { 53 "QS", 54 "(.*)", "$1&newParam=that", 55 "/foo/bar?param1=this", "/foo/bar?param1=this&newParam=that", 56 }, 57 { 58 "QS2", 59 "/test/val/(.*)/space/(.*)/and/then(.*)", "/change/to/$2/$1$3", 60 "/test/val/ONE/space/TWO/and/then?param1=this", "/change/to/TWO/ONE?param1=this", 61 }, 62 } 63 64 type testRewriterCase struct { 65 name string 66 meta *apidef.URLRewriteMeta 67 reqMaker func() *http.Request 68 want string 69 } 70 71 func prepareRewriterCases() []testRewriterCase { 72 tcs := make([]testRewriterCase, len(testRewriterData)) 73 for i, td := range testRewriterData { 74 reqTarget := td.in 75 tcs[i] = testRewriterCase{ 76 name: td.name, 77 meta: &apidef.URLRewriteMeta{ 78 MatchPattern: td.pattern, 79 RewriteTo: td.to, 80 }, 81 reqMaker: func() *http.Request { 82 return httptest.NewRequest("GET", reqTarget, nil) 83 }, 84 want: td.want, 85 } 86 } 87 return tcs 88 } 89 90 func TestRewriter(t *testing.T) { 91 cases := prepareRewriterCases() 92 for _, tc := range cases { 93 t.Run(tc.name, func(t *testing.T) { 94 r := tc.reqMaker() 95 got, err := urlRewrite(tc.meta, r) 96 if err != nil { 97 t.Error("compile failed:", err) 98 } 99 if got != tc.want { 100 t.Errorf("rewrite failed, want %q, got %q", tc.want, got) 101 } 102 }) 103 } 104 } 105 func BenchmarkRewriter(b *testing.B) { 106 cases := prepareRewriterCases() 107 //warm-up regexp caches 108 for _, tc := range cases { 109 r := tc.reqMaker() 110 urlRewrite(tc.meta, r) 111 } 112 113 b.ReportAllocs() 114 b.ResetTimer() 115 for _, tc := range cases { 116 for i := 0; i < b.N; i++ { 117 b.StopTimer() 118 r := tc.reqMaker() 119 b.StartTimer() 120 urlRewrite(tc.meta, r) 121 } 122 } 123 } 124 125 func TestRewriterTriggers(t *testing.T) { 126 type TestDef struct { 127 name string 128 pattern, to string 129 in, want string 130 triggerConf []apidef.RoutingTrigger 131 req *http.Request 132 } 133 tests := []func() TestDef{ 134 func() TestDef { 135 r, _ := http.NewRequest("GET", "/test/straight/rewrite", nil) 136 137 patt := "hello" 138 r.Header.Set("x-test", patt) 139 140 hOpt := apidef.StringRegexMap{MatchPattern: "hello"} 141 hOpt.Init() 142 143 return TestDef{ 144 "Header Single", 145 "/test/straight/rewrite", "/change/to/me/ignore", 146 "/test/straight/rewrite", "/change/to/me/hello", 147 []apidef.RoutingTrigger{ 148 { 149 On: apidef.Any, 150 Options: apidef.RoutingTriggerOptions{ 151 HeaderMatches: map[string]apidef.StringRegexMap{ 152 "x-test": hOpt, 153 }, 154 }, 155 RewriteTo: "/change/to/me/$tyk_context.trigger-0-X-Test-0", 156 }, 157 }, 158 r, 159 } 160 }, 161 func() TestDef { 162 r, _ := http.NewRequest("GET", "/test/straight/rewrite", nil) 163 164 r.Header.Set("x-test", "hello-world") 165 166 hOpt := apidef.StringRegexMap{MatchPattern: "hello-(\\w+)"} 167 hOpt.Init() 168 169 return TestDef{ 170 "Header Single Group", 171 "/test/straight/rewrite", "/change/to/me/ignore", 172 "/test/straight/rewrite", "/change/to/me/world", 173 []apidef.RoutingTrigger{ 174 { 175 On: apidef.Any, 176 Options: apidef.RoutingTriggerOptions{ 177 HeaderMatches: map[string]apidef.StringRegexMap{ 178 "x-test": hOpt, 179 }, 180 }, 181 RewriteTo: "/change/to/me/$tyk_context.trigger-0-X-Test-0-0", 182 }, 183 }, 184 r, 185 } 186 }, 187 func() TestDef { 188 r, _ := http.NewRequest("GET", "/test/straight/rewrite", nil) 189 190 patt := "bar" 191 r.Header.Set("x-test-Two", patt) 192 193 hOpt := apidef.StringRegexMap{MatchPattern: "hello"} 194 hOpt.Init() 195 hOpt2 := apidef.StringRegexMap{MatchPattern: "bar"} 196 hOpt2.Init() 197 198 return TestDef{ 199 "Header Multi Any", 200 "/test/straight/rewrite", "/change/to/me/ignore", 201 "/test/straight/rewrite", "/change/to/me/bar", 202 []apidef.RoutingTrigger{ 203 { 204 On: apidef.Any, 205 Options: apidef.RoutingTriggerOptions{ 206 HeaderMatches: map[string]apidef.StringRegexMap{ 207 "x-test": hOpt, 208 "x-test-Two": hOpt2, 209 }, 210 }, 211 RewriteTo: "/change/to/me/$tyk_context.trigger-0-X-Test-Two-0", 212 }, 213 }, 214 r, 215 } 216 }, 217 func() TestDef { 218 r, _ := http.NewRequest("GET", "/test/straight/rewrite", nil) 219 220 patt := "bar" 221 r.Header.Set("x-test-Two", patt) 222 223 hOpt := apidef.StringRegexMap{MatchPattern: "hello"} 224 hOpt.Init() 225 hOpt2 := apidef.StringRegexMap{MatchPattern: "bar"} 226 hOpt2.Init() 227 228 return TestDef{ 229 "Header Multi All Fail", 230 "/test/straight/rewrite", "/change/to/me/ignore", 231 "/test/straight/rewrite", "/change/to/me/ignore", 232 []apidef.RoutingTrigger{ 233 { 234 On: apidef.All, 235 Options: apidef.RoutingTriggerOptions{ 236 HeaderMatches: map[string]apidef.StringRegexMap{ 237 "x-test": hOpt, 238 "x-test-Two": hOpt2, 239 }, 240 }, 241 RewriteTo: "/change/to/me/$tyk_context.trigger-0-X-Test-Two-0", 242 }, 243 }, 244 r, 245 } 246 }, 247 func() TestDef { 248 r, _ := http.NewRequest("GET", "/test/straight/rewrite", nil) 249 250 r.Header.Set("x-test-Two", "bar") 251 r.Header.Set("x-test", "hello") 252 253 hOpt := apidef.StringRegexMap{MatchPattern: "hello"} 254 hOpt.Init() 255 hOpt2 := apidef.StringRegexMap{MatchPattern: "bar"} 256 hOpt2.Init() 257 258 return TestDef{ 259 "Header Multi All Pass", 260 "/test/straight/rewrite", "/change/to/me/ignore", 261 "/test/straight/rewrite", "/change/to/me/hello", 262 []apidef.RoutingTrigger{ 263 { 264 On: apidef.All, 265 Options: apidef.RoutingTriggerOptions{ 266 HeaderMatches: map[string]apidef.StringRegexMap{ 267 "x-test": hOpt, 268 "x-test-Two": hOpt2, 269 }, 270 }, 271 RewriteTo: "/change/to/me/$tyk_context.trigger-0-X-Test-0", 272 }, 273 }, 274 r, 275 } 276 }, 277 func() TestDef { 278 r, _ := http.NewRequest("GET", "/test/straight/rewrite", nil) 279 280 r.Header.Set("y-test", "baz") 281 r.Header.Set("y-test-Two", "qux") 282 283 hOpt := apidef.StringRegexMap{MatchPattern: "hello"} 284 hOpt.Init() 285 hOpt2 := apidef.StringRegexMap{MatchPattern: "bar"} 286 hOpt2.Init() 287 288 hOpt3 := apidef.StringRegexMap{MatchPattern: "baz"} 289 hOpt3.Init() 290 hOpt4 := apidef.StringRegexMap{MatchPattern: "fnee"} 291 hOpt4.Init() 292 293 return TestDef{ 294 "Header Many Multi Any Pass", 295 "/test/straight/rewrite", "/change/to/me/ignore", 296 "/test/straight/rewrite", "/change/to/me/baz", 297 []apidef.RoutingTrigger{ 298 { 299 On: apidef.Any, 300 Options: apidef.RoutingTriggerOptions{ 301 HeaderMatches: map[string]apidef.StringRegexMap{ 302 "x-test": hOpt, 303 "x-test-Two": hOpt2, 304 }, 305 }, 306 RewriteTo: "/change/to/me/$tyk_context.trigger-0-X-Test-0", 307 }, 308 { 309 On: apidef.Any, 310 Options: apidef.RoutingTriggerOptions{ 311 HeaderMatches: map[string]apidef.StringRegexMap{ 312 "y-test": hOpt3, 313 "y-test-Two": hOpt4, 314 }, 315 }, 316 RewriteTo: "/change/to/me/$tyk_context.trigger-1-Y-Test-0", 317 }, 318 }, 319 r, 320 } 321 }, 322 func() TestDef { 323 r, _ := http.NewRequest("GET", "/test/straight/rewrite", nil) 324 325 r.Header.Set("x-test", "hello") 326 r.Header.Set("x-test-Two", "world") 327 328 hOpt := apidef.StringRegexMap{MatchPattern: "hello"} 329 hOpt.Init() 330 hOpt2 := apidef.StringRegexMap{MatchPattern: "w.*", Reverse: true} 331 hOpt2.Init() 332 333 return TestDef{ 334 "Header Reverse Logic Any Pass", 335 "/test/straight/rewrite", "/change/to/me/ignore", 336 "/test/straight/rewrite", "/change/to/me/hello", 337 []apidef.RoutingTrigger{ 338 { 339 On: apidef.Any, 340 Options: apidef.RoutingTriggerOptions{ 341 HeaderMatches: map[string]apidef.StringRegexMap{ 342 "x-test": hOpt, 343 "x-test-Two": hOpt2, 344 }, 345 }, 346 RewriteTo: "/change/to/me/$tyk_context.trigger-0-X-Test-0", 347 }, 348 }, 349 r, 350 } 351 }, 352 func() TestDef { 353 r, _ := http.NewRequest("GET", "/test/straight/rewrite", nil) 354 355 r.Header.Set("x-test", "hello") 356 r.Header.Set("x-test-Two", "world") 357 358 hOpt := apidef.StringRegexMap{MatchPattern: "hello"} 359 hOpt.Init() 360 hOpt2 := apidef.StringRegexMap{MatchPattern: "w.*", Reverse: true} 361 hOpt2.Init() 362 363 return TestDef{ 364 "Header Reverse Logic All Fail", 365 "/test/straight/rewrite", "/change/to/me/ignore", 366 "/test/straight/rewrite", "/change/to/me/ignore", 367 []apidef.RoutingTrigger{ 368 { 369 On: apidef.All, 370 Options: apidef.RoutingTriggerOptions{ 371 HeaderMatches: map[string]apidef.StringRegexMap{ 372 "x-test": hOpt, 373 "x-test-Two": hOpt2, 374 }, 375 }, 376 RewriteTo: "/change/to/me/$tyk_context.trigger-0-X-Test-0", 377 }, 378 }, 379 r, 380 } 381 }, 382 func() TestDef { 383 r, _ := http.NewRequest("GET", "/test/query/rewrite?x_test=foo", nil) 384 385 hOpt := apidef.StringRegexMap{MatchPattern: "foo"} 386 hOpt.Init() 387 388 return TestDef{ 389 "Query Single", 390 "/test/query/rewrite", "/change/to/me/ignore", 391 "/test/query/rewrite", "/change/to/me/foo", 392 []apidef.RoutingTrigger{ 393 { 394 On: apidef.Any, 395 Options: apidef.RoutingTriggerOptions{ 396 QueryValMatches: map[string]apidef.StringRegexMap{ 397 "x_test": hOpt, 398 }, 399 }, 400 RewriteTo: "/change/to/me/$tyk_context.trigger-0-x_test-0", 401 }, 402 }, 403 r, 404 } 405 }, 406 func() TestDef { 407 r, _ := http.NewRequest("GET", "/test/query/rewrite?x_test=foo-bar", nil) 408 409 hOpt := apidef.StringRegexMap{MatchPattern: "foo-(\\w+)"} 410 hOpt.Init() 411 412 return TestDef{ 413 "Query Single Group", 414 "/test/query/rewrite", "/change/to/me/ignore", 415 "/test/query/rewrite", "/change/to/me/bar", 416 []apidef.RoutingTrigger{ 417 { 418 On: apidef.Any, 419 Options: apidef.RoutingTriggerOptions{ 420 QueryValMatches: map[string]apidef.StringRegexMap{ 421 "x_test": hOpt, 422 }, 423 }, 424 RewriteTo: "/change/to/me/$tyk_context.trigger-0-x_test-0-0", 425 }, 426 }, 427 r, 428 } 429 }, 430 func() TestDef { 431 r, _ := http.NewRequest("GET", "/test/query/rewrite?x_test=foo&y_test=bar", nil) 432 433 hOpt := apidef.StringRegexMap{MatchPattern: "foo"} 434 hOpt.Init() 435 hOpt2 := apidef.StringRegexMap{MatchPattern: "bar"} 436 hOpt2.Init() 437 438 return TestDef{ 439 "Query Multi All", 440 "/test/query/rewrite", "/change/to/me/ignore", 441 "/test/query/rewrite", "/change/to/me/bar", 442 []apidef.RoutingTrigger{ 443 { 444 On: apidef.All, 445 Options: apidef.RoutingTriggerOptions{ 446 QueryValMatches: map[string]apidef.StringRegexMap{ 447 "x_test": hOpt, 448 "y_test": hOpt2, 449 }, 450 }, 451 RewriteTo: "/change/to/me/$tyk_context.trigger-0-y_test-0", 452 }, 453 }, 454 r, 455 } 456 }, 457 func() TestDef { 458 r, _ := http.NewRequest("GET", "/test/query/rewrite?x_test=foo", nil) 459 r.Header.Set("y-test", "qux") 460 461 hOpt := apidef.StringRegexMap{MatchPattern: "foo"} 462 hOpt.Init() 463 hOpt2 := apidef.StringRegexMap{MatchPattern: "bar"} 464 hOpt2.Init() 465 466 return TestDef{ 467 "Multi Multi Type Any", 468 "/test/query/rewrite", "/change/to/me/ignore", 469 "/test/query/rewrite", "/change/to/me/foo", 470 []apidef.RoutingTrigger{ 471 { 472 On: apidef.Any, 473 Options: apidef.RoutingTriggerOptions{ 474 QueryValMatches: map[string]apidef.StringRegexMap{ 475 "x_test": hOpt, 476 }, 477 HeaderMatches: map[string]apidef.StringRegexMap{ 478 "y-test": hOpt2, 479 }, 480 }, 481 RewriteTo: "/change/to/me/$tyk_context.trigger-0-x_test-0", 482 }, 483 }, 484 r, 485 } 486 }, 487 func() TestDef { 488 r, _ := http.NewRequest("GET", "/test/query/rewrite?x_test=foo", nil) 489 r.Header.Set("y-test", "bar") 490 491 hOpt := apidef.StringRegexMap{MatchPattern: "foo"} 492 hOpt.Init() 493 hOpt2 := apidef.StringRegexMap{MatchPattern: "bar"} 494 hOpt2.Init() 495 496 return TestDef{ 497 "Multi Multi Type All", 498 "/test/query/rewrite", "/change/to/me/ignore", 499 "/test/query/rewrite", "/change/to/me/bar", 500 []apidef.RoutingTrigger{ 501 { 502 On: apidef.All, 503 Options: apidef.RoutingTriggerOptions{ 504 QueryValMatches: map[string]apidef.StringRegexMap{ 505 "x_test": hOpt, 506 }, 507 HeaderMatches: map[string]apidef.StringRegexMap{ 508 "y-test": hOpt2, 509 }, 510 }, 511 RewriteTo: "/change/to/me/$tyk_context.trigger-0-Y-Test-0", 512 }, 513 }, 514 r, 515 } 516 }, 517 func() TestDef { 518 r, _ := http.NewRequest("GET", "/test/query/rewrite?x_test=foo", nil) 519 r.Header.Set("y-test", "bar") 520 r.Header.Set("z-test", "fnee") 521 522 hOpt := apidef.StringRegexMap{MatchPattern: "foo"} 523 hOpt.Init() 524 hOpt2 := apidef.StringRegexMap{MatchPattern: "bar"} 525 hOpt2.Init() 526 hOpt3 := apidef.StringRegexMap{MatchPattern: "baz"} 527 hOpt3.Init() 528 529 return TestDef{ 530 "Multi Multi Type All Fail", 531 "/test/query/rewrite", "/change/to/me/ignore", 532 "/test/query/rewrite", "/change/to/me/ignore", 533 []apidef.RoutingTrigger{ 534 { 535 On: apidef.All, 536 Options: apidef.RoutingTriggerOptions{ 537 QueryValMatches: map[string]apidef.StringRegexMap{ 538 "x_test": hOpt, 539 }, 540 HeaderMatches: map[string]apidef.StringRegexMap{ 541 "y-test": hOpt2, 542 "z-test": hOpt3, 543 }, 544 }, 545 RewriteTo: "/change/to/me/$tyk_context.trigger-0-Y-Test-0", 546 }, 547 }, 548 r, 549 } 550 }, 551 func() TestDef { 552 r, _ := http.NewRequest("GET", "/test/query/rewrite?x_test=foo", nil) 553 r.Header.Set("y-test", "bar") 554 r.Header.Set("z-test", "baz") 555 556 hOpt := apidef.StringRegexMap{MatchPattern: "foo"} 557 hOpt.Init() 558 hOpt2 := apidef.StringRegexMap{MatchPattern: "bar"} 559 hOpt2.Init() 560 hOpt3 := apidef.StringRegexMap{MatchPattern: "baz", Reverse: true} 561 hOpt3.Init() 562 563 return TestDef{ 564 "Multi Multi Type Reverse Logic All Fail", 565 "/test/query/rewrite", "/change/to/me/ignore", 566 "/test/query/rewrite", "/change/to/me/ignore", 567 []apidef.RoutingTrigger{ 568 { 569 On: apidef.All, 570 Options: apidef.RoutingTriggerOptions{ 571 QueryValMatches: map[string]apidef.StringRegexMap{ 572 "x_test": hOpt, 573 }, 574 HeaderMatches: map[string]apidef.StringRegexMap{ 575 "y-test": hOpt2, 576 "z-test": hOpt3, 577 }, 578 }, 579 RewriteTo: "/change/to/me/$tyk_context.trigger-0-Y-Test-0", 580 }, 581 }, 582 r, 583 } 584 }, 585 func() TestDef { 586 r, _ := http.NewRequest("GET", "/test/query/rewrite?x_test=foo", nil) 587 r.Header.Set("y-test", "bar") 588 r.Header.Set("z-test", "baz") 589 590 hOpt := apidef.StringRegexMap{MatchPattern: "foo"} 591 hOpt.Init() 592 hOpt2 := apidef.StringRegexMap{MatchPattern: "bar"} 593 hOpt2.Init() 594 hOpt3 := apidef.StringRegexMap{MatchPattern: "baz", Reverse: true} 595 hOpt3.Init() 596 597 return TestDef{ 598 "Multi Multi Type Reverse Logic All Fail", 599 "/test/query/rewrite", "/change/to/me/ignore", 600 "/test/query/rewrite", "/change/to/me/bar", 601 []apidef.RoutingTrigger{ 602 { 603 On: apidef.Any, 604 Options: apidef.RoutingTriggerOptions{ 605 QueryValMatches: map[string]apidef.StringRegexMap{ 606 "x_test": hOpt, 607 }, 608 HeaderMatches: map[string]apidef.StringRegexMap{ 609 "y-test": hOpt2, 610 "z-test": hOpt3, 611 }, 612 }, 613 RewriteTo: "/change/to/me/$tyk_context.trigger-0-Y-Test-0", 614 }, 615 }, 616 r, 617 } 618 }, 619 func() TestDef { 620 var jsonStr = []byte(`{"foo":"bar"}`) 621 r, _ := http.NewRequest("POST", "/test/pl/rewrite", bytes.NewBuffer(jsonStr)) 622 623 hOpt := apidef.StringRegexMap{MatchPattern: "bar"} 624 hOpt.Init() 625 626 return TestDef{ 627 "Payload Single", 628 "/test/pl/rewrite", "/change/to/me/ignore", 629 "/test/pl/rewrite", "/change/to/me/bar", 630 []apidef.RoutingTrigger{ 631 { 632 On: apidef.Any, 633 Options: apidef.RoutingTriggerOptions{ 634 PayloadMatches: hOpt, 635 }, 636 RewriteTo: "/change/to/me/$tyk_context.trigger-0-payload", 637 }, 638 }, 639 r, 640 } 641 }, 642 func() TestDef { 643 var jsonStr = []byte(`{"foo":"barxxx", "fooble":"baryyy"}`) 644 r, _ := http.NewRequest("POST", "/test/pl/rewrite", bytes.NewBuffer(jsonStr)) 645 646 hOpt := apidef.StringRegexMap{MatchPattern: "bar\\w*"} 647 hOpt.Init() 648 649 return TestDef{ 650 "Payload Multiple Match", 651 "/test/pl/rewrite", "/change/to/me/ignore", 652 "/test/pl/rewrite", "/change/to/me/barxxx/baryyy", 653 []apidef.RoutingTrigger{ 654 { 655 On: apidef.Any, 656 Options: apidef.RoutingTriggerOptions{ 657 PayloadMatches: hOpt, 658 }, 659 RewriteTo: "/change/to/me/$tyk_context.trigger-0-payload-0/$tyk_context.trigger-0-payload-1", 660 }, 661 }, 662 r, 663 } 664 }, 665 func() TestDef { 666 var jsonStr = []byte(`{"foo":"barxxx", "fooble":"baryyy"}`) 667 r, _ := http.NewRequest("POST", "/test/pl/rewrite", bytes.NewBuffer(jsonStr)) 668 669 hOpt := apidef.StringRegexMap{MatchPattern: "bar(\\w*)"} 670 hOpt.Init() 671 672 return TestDef{ 673 "Payload Multiple Match Groups", 674 "/test/pl/rewrite", "/change/to/me/ignore", 675 "/test/pl/rewrite", "/change/to/me/xxx/yyy", 676 []apidef.RoutingTrigger{ 677 { 678 On: apidef.Any, 679 Options: apidef.RoutingTriggerOptions{ 680 PayloadMatches: hOpt, 681 }, 682 RewriteTo: "/change/to/me/$tyk_context.trigger-0-payload-0-0/$tyk_context.trigger-0-payload-1-0", 683 }, 684 }, 685 r, 686 } 687 }, 688 func() TestDef { 689 var jsonStr = []byte(`{"foo":"barxxx", "fooble":"baryyy"}`) 690 r, _ := http.NewRequest("POST", "/test/pl/rewrite", bytes.NewBuffer(jsonStr)) 691 692 hOpt := apidef.StringRegexMap{MatchPattern: "bar(\\w*)"} 693 hOpt.Init() 694 695 return TestDef{ 696 "Payload Multiple Match Groups", 697 "/test/pl/rewrite", "/change/to/me/ignore", 698 "/test/pl/rewrite", "/change/to/me/xxx/yyy", 699 []apidef.RoutingTrigger{ 700 { 701 On: apidef.Any, 702 Options: apidef.RoutingTriggerOptions{ 703 PayloadMatches: hOpt, 704 }, 705 RewriteTo: "/change/to/me/$tyk_context.trigger-0-payload-0-0/$tyk_context.trigger-0-payload-1-0", 706 }, 707 }, 708 r, 709 } 710 }, 711 func() TestDef { 712 var jsonStr = []byte(`{"foo":"bar"}`) 713 r, _ := http.NewRequest("POST", "/test/pl/rewrite", bytes.NewBuffer(jsonStr)) 714 r.Header.Set("x-test", "apple") 715 716 hOpt := apidef.StringRegexMap{MatchPattern: "bar"} 717 hOpt.Init() 718 hOpt2 := apidef.StringRegexMap{MatchPattern: "apple"} 719 hOpt2.Init() 720 721 return TestDef{ 722 "Multi Type All", 723 "/test/pl/rewrite", "/change/to/me/ignore", 724 "/test/pl/rewrite", "/change/to/me/bar/apple", 725 []apidef.RoutingTrigger{ 726 { 727 On: apidef.All, 728 Options: apidef.RoutingTriggerOptions{ 729 PayloadMatches: hOpt, 730 HeaderMatches: map[string]apidef.StringRegexMap{ 731 "x-test": hOpt2, 732 }, 733 }, 734 RewriteTo: "/change/to/me/$tyk_context.trigger-0-payload-0/$tyk_context.trigger-0-X-Test-0", 735 }, 736 }, 737 r, 738 } 739 }, 740 func() TestDef { 741 var jsonStr = []byte(`{"foo":"bar"}`) 742 r, _ := http.NewRequest("POST", "/test/pl/rewrite", bytes.NewBuffer(jsonStr)) 743 r.Header.Set("x-test", "apple") 744 745 hOpt := apidef.StringRegexMap{MatchPattern: "bar"} 746 hOpt.Init() 747 hOpt2 := apidef.StringRegexMap{MatchPattern: "apple", Reverse: true} 748 hOpt2.Init() 749 750 return TestDef{ 751 "Multi Multi Type Reverse Logic Any 1", 752 "/test/pl/rewrite", "/change/to/me/ignore", 753 "/test/pl/rewrite", "/change/to/me/bar/", 754 []apidef.RoutingTrigger{ 755 { 756 On: apidef.Any, 757 Options: apidef.RoutingTriggerOptions{ 758 PayloadMatches: hOpt, 759 HeaderMatches: map[string]apidef.StringRegexMap{ 760 "x-test": hOpt2, 761 }, 762 }, 763 RewriteTo: "/change/to/me/$tyk_context.trigger-0-payload-0/$tyk_context.trigger-0-X-Test-0", 764 }, 765 }, 766 r, 767 } 768 }, 769 func() TestDef { 770 r, _ := http.NewRequest("GET", "/test/foo/rewrite", nil) 771 hOpt := apidef.StringRegexMap{MatchPattern: "foo"} 772 hOpt.Init() 773 774 return TestDef{ 775 "PathPart Single", 776 "/test/foo/rewrite", "/change/to/me/ignore", 777 "/test/foo/rewrite", "/change/to/me/foo", 778 []apidef.RoutingTrigger{ 779 { 780 On: apidef.Any, 781 Options: apidef.RoutingTriggerOptions{ 782 PathPartMatches: map[string]apidef.StringRegexMap{ 783 "pathpart": hOpt, 784 }, 785 }, 786 RewriteTo: "/change/to/me/$tyk_context.trigger-0-pathpart-0", 787 }, 788 }, 789 r, 790 } 791 }, 792 func() TestDef { 793 var jsonStr = []byte(`{"foo":"bar"}`) 794 r, _ := http.NewRequest("POST", "/test/pl/rewrite", bytes.NewBuffer(jsonStr)) 795 r.Header.Set("x-test", "apple") 796 797 hOpt := apidef.StringRegexMap{MatchPattern: "bar", Reverse: true} 798 hOpt.Init() 799 hOpt2 := apidef.StringRegexMap{MatchPattern: "apple"} 800 hOpt2.Init() 801 802 return TestDef{ 803 "Multi Multi Type Reverse Logic Any 2", 804 "/test/pl/rewrite", "/change/to/me/ignore", 805 "/test/pl/rewrite", "/change/to/me//apple", 806 []apidef.RoutingTrigger{ 807 { 808 On: apidef.Any, 809 Options: apidef.RoutingTriggerOptions{ 810 PayloadMatches: hOpt, 811 HeaderMatches: map[string]apidef.StringRegexMap{ 812 "x-test": hOpt2, 813 }, 814 }, 815 RewriteTo: "/change/to/me/$tyk_context.trigger-0-payload-0/$tyk_context.trigger-0-X-Test-0", 816 }, 817 }, 818 r, 819 } 820 }, 821 func() TestDef { 822 var jsonStr = []byte(`{"foo":"bar"}`) 823 r, _ := http.NewRequest("POST", "/test/pl/rewrite", bytes.NewBuffer(jsonStr)) 824 r.Header.Set("x-test", "apple") 825 826 hOpt := apidef.StringRegexMap{MatchPattern: "bar"} 827 hOpt.Init() 828 hOpt2 := apidef.StringRegexMap{MatchPattern: "apple", Reverse: true} 829 hOpt2.Init() 830 831 return TestDef{ 832 "Multi Multi Type Reverse Logic Any 3", 833 "/test/pl/rewrite", "/change/to/me/ignore", 834 "/test/pl/rewrite", "/change/to/me/bar/", 835 []apidef.RoutingTrigger{ 836 { 837 On: apidef.Any, 838 Options: apidef.RoutingTriggerOptions{ 839 PayloadMatches: hOpt, 840 HeaderMatches: map[string]apidef.StringRegexMap{ 841 "x-test": hOpt2, 842 }, 843 }, 844 RewriteTo: "/change/to/me/$tyk_context.trigger-0-payload-0/$tyk_context.trigger-0-X-Test-0", 845 }, 846 }, 847 r, 848 } 849 }, 850 func() TestDef { 851 r, _ := http.NewRequest("GET", "/test/foobar/rewrite", nil) 852 hOpt := apidef.StringRegexMap{MatchPattern: "foo(\\w+)"} 853 hOpt.Init() 854 855 return TestDef{ 856 "PathPart Single Group", 857 "/test/foobar/rewrite", "/change/to/me/ignore", 858 "/test/foobar/rewrite", "/change/to/me/bar", 859 []apidef.RoutingTrigger{ 860 { 861 On: apidef.Any, 862 Options: apidef.RoutingTriggerOptions{ 863 PathPartMatches: map[string]apidef.StringRegexMap{ 864 "pathpart": hOpt, 865 }, 866 }, 867 RewriteTo: "/change/to/me/$tyk_context.trigger-0-pathpart-0-0", 868 }, 869 }, 870 r, 871 } 872 }, 873 func() TestDef { 874 r, _ := http.NewRequest("GET", "/test/foo/rewrite/foo", nil) 875 hOpt := apidef.StringRegexMap{MatchPattern: "foo"} 876 hOpt.Init() 877 878 return TestDef{ 879 "PathPart MoreParts", 880 "/test/foo/rewrite/foo", "/change/to/me/ignore", 881 "/test/foo/rewrite/foo", "/change/to/me/foo/biz/foo", 882 []apidef.RoutingTrigger{ 883 { 884 On: apidef.Any, 885 Options: apidef.RoutingTriggerOptions{ 886 PathPartMatches: map[string]apidef.StringRegexMap{ 887 "pathpart": hOpt, 888 }, 889 }, 890 RewriteTo: "/change/to/me/$tyk_context.trigger-0-pathpart-0/biz/$tyk_context.trigger-0-pathpart-1", 891 }, 892 }, 893 r, 894 } 895 }, 896 func() TestDef { 897 r, _ := http.NewRequest("GET", "/test/foo/rewrite", nil) 898 hOpt := apidef.StringRegexMap{MatchPattern: "bar"} 899 hOpt.Init() 900 901 ctxSetSession(r, &user.SessionState{ 902 MetaData: map[string]interface{}{ 903 "rewrite": "bar-baz", 904 }, 905 Mutex: &sync.RWMutex{}, 906 }, "", false) 907 908 return TestDef{ 909 "Meta Simple", 910 "/test/foo/rewrite", "/change/to/me/ignore", 911 "/test/foo/rewrite", "/change/to/me/bar", 912 []apidef.RoutingTrigger{ 913 { 914 On: apidef.Any, 915 Options: apidef.RoutingTriggerOptions{ 916 SessionMetaMatches: map[string]apidef.StringRegexMap{ 917 "rewrite": hOpt, 918 }, 919 }, 920 RewriteTo: "/change/to/me/$tyk_context.trigger-0-rewrite", 921 }, 922 }, 923 r, 924 } 925 }, 926 func() TestDef { 927 r, _ := http.NewRequest("GET", "/test/foo/rewrite", nil) 928 hOpt := apidef.StringRegexMap{MatchPattern: "bar-(\\w+)"} 929 hOpt.Init() 930 931 ctxSetSession(r, &user.SessionState{ 932 MetaData: map[string]interface{}{ 933 "rewrite": "bar-baz", 934 }, 935 Mutex: &sync.RWMutex{}, 936 }, "", false) 937 938 return TestDef{ 939 "Meta Simple Group", 940 "/test/foo/rewrite", "/change/to/me/ignore", 941 "/test/foo/rewrite", "/change/to/me/baz", 942 []apidef.RoutingTrigger{ 943 { 944 On: apidef.Any, 945 Options: apidef.RoutingTriggerOptions{ 946 SessionMetaMatches: map[string]apidef.StringRegexMap{ 947 "rewrite": hOpt, 948 }, 949 }, 950 RewriteTo: "/change/to/me/$tyk_context.trigger-0-rewrite-0", 951 }, 952 }, 953 r, 954 } 955 }, 956 func() TestDef { 957 r, _ := http.NewRequest("GET", "/test/foo/rewrite", nil) 958 hOpt := apidef.StringRegexMap{MatchPattern: "bar"} 959 hOpt.Init() 960 961 ctxSetSession(r, &user.SessionState{ 962 MetaData: map[string]interface{}{ 963 "rewrite": "bar-baz", 964 "somevar": "someval", 965 }, 966 Mutex: &sync.RWMutex{}, 967 }, "", false) 968 969 return TestDef{ 970 "Meta Value from Session", 971 "/test/foo/rewrite", "/change/to/me/ignore", 972 "/test/foo/rewrite", "/change/to/me/bar/someval", 973 []apidef.RoutingTrigger{ 974 { 975 On: apidef.Any, 976 Options: apidef.RoutingTriggerOptions{ 977 SessionMetaMatches: map[string]apidef.StringRegexMap{ 978 "rewrite": hOpt, 979 }, 980 }, 981 RewriteTo: "/change/to/me/$tyk_context.trigger-0-rewrite/$tyk_meta.somevar", 982 }, 983 }, 984 r, 985 } 986 }, 987 func() TestDef { 988 r, _ := http.NewRequest("GET", "/test/foo/rewrite", nil) 989 hOpt := apidef.StringRegexMap{MatchPattern: "bar"} 990 hOpt.Init() 991 992 ctxSetData(r, map[string]interface{}{ 993 "rewrite": "bar-baz", 994 }) 995 996 return TestDef{ 997 "Request context", 998 "/test/foo/rewrite", "/change/to/me/ignore", 999 "/test/foo/rewrite", "/change/to/me/bar", 1000 []apidef.RoutingTrigger{ 1001 { 1002 On: apidef.Any, 1003 Options: apidef.RoutingTriggerOptions{ 1004 RequestContextMatches: map[string]apidef.StringRegexMap{ 1005 "rewrite": hOpt, 1006 }, 1007 }, 1008 RewriteTo: "/change/to/me/$tyk_context.trigger-0-rewrite", 1009 }, 1010 }, 1011 r, 1012 } 1013 }, 1014 func() TestDef { 1015 r, _ := http.NewRequest("GET", "/test/foo/rewrite", nil) 1016 hOpt := apidef.StringRegexMap{MatchPattern: "foo"} 1017 hOpt.Init() 1018 1019 ctxSetSession(r, &user.SessionState{ 1020 MetaData: map[string]interface{}{ 1021 "rewrite": "bar-baz", 1022 }, 1023 Mutex: &sync.RWMutex{}, 1024 }, "", false) 1025 1026 return TestDef{ 1027 "Variable not found", 1028 "/test/foo/rewrite", "/change/to/me/ignore", 1029 "/test/foo/rewrite", "/change/to/me/foo//", 1030 []apidef.RoutingTrigger{ 1031 { 1032 On: apidef.Any, 1033 Options: apidef.RoutingTriggerOptions{ 1034 PathPartMatches: map[string]apidef.StringRegexMap{ 1035 "pathpart": hOpt, 1036 }, 1037 }, 1038 RewriteTo: "/change/to/me/$tyk_context.trigger-0-pathpart-0/$tyk_context.nonexistent/$tyk_meta.nonexistent", 1039 }, 1040 }, 1041 r, 1042 } 1043 }, 1044 func() TestDef { 1045 r, _ := http.NewRequest("GET", "/test/foo/rewrite", nil) 1046 hOpt := apidef.StringRegexMap{MatchPattern: "foo"} 1047 hOpt.Init() 1048 1049 return TestDef{ 1050 "Session not found", 1051 "/test/foo/rewrite", "/change/to/me/ignore", 1052 "/test/foo/rewrite", "/change/to/me/foo/", 1053 []apidef.RoutingTrigger{ 1054 { 1055 On: apidef.Any, 1056 Options: apidef.RoutingTriggerOptions{ 1057 PathPartMatches: map[string]apidef.StringRegexMap{ 1058 "pathpart": hOpt, 1059 }, 1060 }, 1061 RewriteTo: "/change/to/me/$tyk_context.trigger-0-pathpart-0/$tyk_meta.nonexistent", 1062 }, 1063 }, 1064 r, 1065 } 1066 }, 1067 } 1068 for _, tf := range tests { 1069 tc := tf() 1070 t.Run(tc.name, func(t *testing.T) { 1071 testConf := apidef.URLRewriteMeta{ 1072 MatchPattern: tc.pattern, 1073 RewriteTo: tc.to, 1074 Triggers: tc.triggerConf, 1075 } 1076 1077 got, err := urlRewrite(&testConf, tc.req) 1078 if err != nil { 1079 t.Error("compile failed:", err) 1080 } 1081 if got != tc.want { 1082 t.Errorf("rewrite failed, want %q, got %q", tc.want, got) 1083 } 1084 }) 1085 } 1086 } 1087 1088 func TestInitTriggerRx(t *testing.T) { 1089 // prepare test data 1090 testRewriteMW := &URLRewriteMiddleware{ 1091 BaseMiddleware: BaseMiddleware{ 1092 Spec: &APISpec{ 1093 APIDefinition: &apidef.APIDefinition{}, 1094 }, 1095 }, 1096 } 1097 testRewriteMW.Spec.APIDefinition.VersionData = struct { 1098 NotVersioned bool `bson:"not_versioned" json:"not_versioned"` 1099 DefaultVersion string `bson:"default_version" json:"default_version"` 1100 Versions map[string]apidef.VersionInfo `bson:"versions" json:"versions"` 1101 }{} 1102 1103 routingTriggerOptions := apidef.RoutingTriggerOptions{ 1104 HeaderMatches: map[string]apidef.StringRegexMap{ 1105 "abc": { 1106 MatchPattern: "^abc.*", 1107 }, 1108 }, 1109 QueryValMatches: map[string]apidef.StringRegexMap{ 1110 "def": { 1111 MatchPattern: "^def.*", 1112 }, 1113 }, 1114 PayloadMatches: apidef.StringRegexMap{ 1115 MatchPattern: "^ghi.*", 1116 }, 1117 } 1118 1119 extendedPathsSet := apidef.ExtendedPathsSet{ 1120 URLRewrite: []apidef.URLRewriteMeta{ 1121 { 1122 Triggers: []apidef.RoutingTrigger{ 1123 { 1124 Options: routingTriggerOptions, 1125 }, 1126 }, 1127 }, 1128 }, 1129 } 1130 testRewriteMW.Spec.APIDefinition.VersionData.Versions = map[string]apidef.VersionInfo{ 1131 "Default": { 1132 ExtendedPaths: extendedPathsSet, 1133 }, 1134 } 1135 1136 // run method under test 1137 testRewriteMW.InitTriggerRx() 1138 1139 // assert HeaderMatches 1140 headerMatch := testRewriteMW. 1141 Spec. 1142 APIDefinition. 1143 VersionData. 1144 Versions["Default"]. 1145 ExtendedPaths. 1146 URLRewrite[0]. 1147 Triggers[0]. 1148 Options. 1149 HeaderMatches["abc"] 1150 if headerMatch.Check("abc") == "" { 1151 t.Errorf("Expected HeaderMatches initalized and matched, received no match") 1152 } 1153 1154 // assert QueryValMatches 1155 queryValMatch := testRewriteMW. 1156 Spec. 1157 APIDefinition. 1158 VersionData. 1159 Versions["Default"]. 1160 ExtendedPaths. 1161 URLRewrite[0]. 1162 Triggers[0]. 1163 Options. 1164 QueryValMatches["def"] 1165 if queryValMatch.Check("def") == "" { 1166 t.Errorf("Expected QueryValMatches initalized and matched, received no match") 1167 } 1168 1169 // assert PayloadMatches 1170 payloadMatch := testRewriteMW. 1171 Spec. 1172 APIDefinition. 1173 VersionData. 1174 Versions["Default"]. 1175 ExtendedPaths. 1176 URLRewrite[0]. 1177 Triggers[0]. 1178 Options. 1179 PayloadMatches 1180 if payloadMatch.Check("ghi") == "" { 1181 t.Errorf("Expected PayloadMatches initalized and matched, received no match") 1182 } 1183 } 1184 1185 func TestURLRewriteCaseSensitivity(t *testing.T) { 1186 ts := StartTest() 1187 defer ts.Close() 1188 1189 assert := func(relativePath string, requestedPath string, bodyMatch string) { 1190 BuildAndLoadAPI(func(spec *APISpec) { 1191 spec.Proxy.ListenPath = "/" 1192 UpdateAPIVersion(spec, "v1", func(v *apidef.VersionInfo) { 1193 v.ExtendedPaths.URLRewrite = []apidef.URLRewriteMeta{{ 1194 Path: relativePath, 1195 Method: "GET", 1196 MatchPattern: requestedPath, 1197 RewriteTo: "/xyz", 1198 }} 1199 }) 1200 }) 1201 1202 ts.Run(t, test.TestCase{ 1203 Path: requestedPath, Code: 200, BodyMatch: bodyMatch, 1204 }) 1205 } 1206 1207 // Matches and rewrites 1208 t.Run("Relative path lower, requested path lower", func(t *testing.T) { 1209 assert("/get", "/get", `"Url":"/xyz"`) 1210 }) 1211 1212 // Doesn't match and doesn't rewrite 1213 t.Run("Relative path lower, requested path upper", func(t *testing.T) { 1214 assert("/get", "/Get", `"Url":"/Get"`) 1215 }) 1216 1217 // Doesn't match and doesn't rewrite 1218 t.Run("Relative path upper, requested path lower", func(t *testing.T) { 1219 assert("/Get", "/get", `"Url":"/get"`) 1220 }) 1221 1222 // Matches and rewrites 1223 t.Run("Relative path upper, requested path upper", func(t *testing.T) { 1224 assert("/Get", "/Get", `"Url":"/xyz"`) 1225 }) 1226 } 1227 1228 func TestValToStr(t *testing.T) { 1229 1230 example := []interface{}{ 1231 "abc", // string 1232 int64(456), // int64 1233 12.22, // float 1234 "abc,def", // string url encode 1235 } 1236 1237 str := valToStr(example) 1238 expected := "abc,456,12.22,abc%2Cdef" 1239 1240 if str != expected { 1241 t.Errorf("expected (%s) got (%s)", expected, str) 1242 } 1243 }