1# -*- coding: utf-8 -*- 2import pytest 3 4from unit.applications.proto import TestApplicationProto 5from unit.option import option 6 7 8class TestRouting(TestApplicationProto): 9 prerequisites = {'modules': {'python': 'any'}} 10 11 def setup_method(self): 12 assert 'success' in self.conf( 13 { 14 "listeners": {"*:7080": {"pass": "routes"}}, 15 "routes": [ 16 {"match": {"method": "GET"}, "action": {"return": 200},} 17 ], 18 "applications": {}, 19 } 20 ), 'routing configure' 21 22 def route(self, route): 23 return self.conf([route], 'routes') 24 25 def route_match(self, match): 26 assert 'success' in self.route( 27 {"match": match, "action": {"return": 200}} 28 ), 'route match configure' 29 30 def route_match_invalid(self, match): 31 assert 'error' in self.route( 32 {"match": match, "action": {"return": 200}} 33 ), 'route match configure invalid' 34 35 def host(self, host, status): 36 assert ( 37 self.get(headers={'Host': host, 'Connection': 'close'})['status'] 38 == status 39 ), 'match host' 40 41 def cookie(self, cookie, status): 42 assert ( 43 self.get( 44 headers={ 45 'Host': 'localhost', 46 'Cookie': cookie, 47 'Connection': 'close', 48 }, 49 )['status'] 50 == status 51 ), 'match cookie' 52 53 def test_routes_match_method_positive(self): 54 assert self.get()['status'] == 200, 'GET' 55 assert self.post()['status'] == 404, 'POST' 56 57 def test_routes_match_method_positive_many(self): 58 self.route_match({"method": ["GET", "POST"]}) 59 60 assert self.get()['status'] == 200, 'GET' 61 assert self.post()['status'] == 200, 'POST' 62 assert self.delete()['status'] == 404, 'DELETE' 63 64 def test_routes_match_method_negative(self): 65 self.route_match({"method": "!GET"}) 66 67 assert self.get()['status'] == 404, 'GET' 68 assert self.post()['status'] == 200, 'POST' 69 70 def test_routes_match_method_negative_many(self): 71 self.route_match({"method": ["!GET", "!POST"]}) 72 73 assert self.get()['status'] == 404, 'GET' 74 assert self.post()['status'] == 404, 'POST' 75 assert self.delete()['status'] == 200, 'DELETE' 76 77 def test_routes_match_method_wildcard_left(self): 78 self.route_match({"method": "*ET"}) 79 80 assert self.get()['status'] == 200, 'GET' 81 assert self.post()['status'] == 404, 'POST' 82 83 def test_routes_match_method_wildcard_right(self): 84 self.route_match({"method": "GE*"}) 85 86 assert self.get()['status'] == 200, 'GET' 87 assert self.post()['status'] == 404, 'POST' 88 89 def test_routes_match_method_wildcard_left_right(self): 90 self.route_match({"method": "*GET*"}) 91 92 assert self.get()['status'] == 200, 'GET' 93 assert self.post()['status'] == 404, 'POST' 94 95 def test_routes_match_method_wildcard(self): 96 self.route_match({"method": "*"}) 97 98 assert self.get()['status'] == 200, 'GET' 99 100 def test_routes_match_invalid(self): 101 self.route_match_invalid({"method": "**"}) 102 103 def test_routes_match_valid(self): 104 self.route_match({"method": "blah*"}) 105 self.route_match({"host": "*blah*blah"}) 106 self.route_match({"host": "blah*blah*blah"}) 107 self.route_match({"host": "blah*blah*"}) 108 109 def test_routes_match_empty_exact(self): 110 self.route_match({"uri": ""}) 111 assert self.get()['status'] == 404 112 113 self.route_match({"uri": "/"}) 114 assert self.get()['status'] == 200 115 assert self.get(url='/blah')['status'] == 404 116 117 def test_routes_match_negative(self): 118 self.route_match({"uri": "!"}) 119 assert self.get()['status'] == 200 120 121 self.route_match({"uri": "!*"}) 122 assert self.get()['status'] == 404 123 124 self.route_match({"uri": "!/"}) 125 assert self.get()['status'] == 404 126 assert self.get(url='/blah')['status'] == 200 127 128 self.route_match({"uri": "!*blah"}) 129 assert self.get()['status'] == 200 130 assert self.get(url='/bla')['status'] == 200 131 assert self.get(url='/blah')['status'] == 404 132 assert self.get(url='/blah1')['status'] == 200 133 134 self.route_match({"uri": "!/blah*1*"}) 135 assert self.get()['status'] == 200 136 assert self.get(url='/blah')['status'] == 200 137 assert self.get(url='/blah1')['status'] == 404 138 assert self.get(url='/blah12')['status'] == 404 139 assert self.get(url='/blah2')['status'] == 200 140 141 def test_routes_match_wildcard_middle(self): 142 self.route_match({"host": "ex*le"}) 143 144 self.host('example', 200) 145 self.host('www.example', 404) 146 self.host('example.com', 404) 147 self.host('exampl', 404) 148 149 def test_routes_match_method_case_insensitive(self): 150 self.route_match({"method": "get"}) 151 152 assert self.get()['status'] == 200, 'GET' 153 154 def test_routes_match_wildcard_left_case_insensitive(self): 155 self.route_match({"method": "*get"}) 156 assert self.get()['status'] == 200, 'GET' 157 158 self.route_match({"method": "*et"}) 159 assert self.get()['status'] == 200, 'GET' 160 161 def test_routes_match_wildcard_middle_case_insensitive(self): 162 self.route_match({"method": "g*t"}) 163 164 assert self.get()['status'] == 200, 'GET' 165 166 def test_routes_match_wildcard_right_case_insensitive(self): 167 self.route_match({"method": "get*"}) 168 assert self.get()['status'] == 200, 'GET' 169 170 self.route_match({"method": "ge*"}) 171 assert self.get()['status'] == 200, 'GET' 172 173 def test_routes_match_wildcard_substring_case_insensitive(self): 174 self.route_match({"method": "*et*"}) 175 176 assert self.get()['status'] == 200, 'GET' 177 178 def test_routes_match_wildcard_left_case_sensitive(self): 179 self.route_match({"uri": "*blah"}) 180 181 assert self.get(url='/blah')['status'] == 200, '/blah' 182 assert self.get(url='/BLAH')['status'] == 404, '/BLAH' 183 184 def test_routes_match_wildcard_middle_case_sensitive(self): 185 self.route_match({"uri": "/b*h"}) 186 187 assert self.get(url='/blah')['status'] == 200, '/blah' 188 assert self.get(url='/BLAH')['status'] == 404, '/BLAH' 189 190 def test_route_match_wildcards_ordered(self): 191 self.route_match({"uri": "/a*x*y*"}) 192 193 assert self.get(url='/axy')['status'] == 200, '/axy' 194 assert self.get(url='/ayx')['status'] == 404, '/ayx' 195 196 def test_route_match_wildcards_adjust_start(self): 197 self.route_match({"uri": "/bla*bla*"}) 198 199 assert self.get(url='/bla_foo')['status'] == 404, '/bla_foo' 200 201 def test_route_match_wildcards_adjust_start_substr(self): 202 self.route_match({"uri": "*bla*bla*"}) 203 204 assert self.get(url='/bla_foo')['status'] == 404, '/bla_foo' 205 206 def test_route_match_wildcards_adjust_end(self): 207 self.route_match({"uri": "/bla*bla"}) 208 209 assert self.get(url='/foo_bla')['status'] == 404, '/foo_bla' 210 211 def test_routes_match_wildcard_right_case_sensitive(self): 212 self.route_match({"uri": "/bla*"}) 213 214 assert self.get(url='/blah')['status'] == 200, '/blah' 215 assert self.get(url='/BLAH')['status'] == 404, '/BLAH' 216 217 def test_routes_match_wildcard_substring_case_sensitive(self): 218 self.route_match({"uri": "*bla*"}) 219 220 assert self.get(url='/blah')['status'] == 200, '/blah' 221 assert self.get(url='/BLAH')['status'] == 404, '/BLAH' 222 223 def test_routes_match_many_wildcard_substrings_case_sensitive(self): 224 self.route_match({"uri": "*a*B*c*"}) 225 226 assert self.get(url='/blah-a-B-c-blah')['status'] == 200 227 assert self.get(url='/a-B-c')['status'] == 200 228 assert self.get(url='/aBc')['status'] == 200 229 assert self.get(url='/aBCaBbc')['status'] == 200 230 assert self.get(url='/ABc')['status'] == 404 231 232 def test_routes_empty_regex(self): 233 if not option.available['modules']['regex']: 234 pytest.skip('requires regex') 235 236 self.route_match({"uri": "~"}) 237 assert self.get(url='/')['status'] == 200, 'empty regexp' 238 assert self.get(url='/anything')['status'] == 200, '/anything' 239 240 self.route_match({"uri": "!~"}) 241 assert self.get(url='/')['status'] == 404, 'empty regexp 2' 242 assert self.get(url='/nothing')['status'] == 404, '/nothing' 243 244 def test_routes_bad_regex(self): 245 if not option.available['modules']['regex']: 246 pytest.skip('requires regex') 247 248 assert 'error' in self.route( 249 {"match": {"uri": "~/bl[ah"}, "action": {"return": 200}} 250 ), 'bad regex' 251 252 status = self.route( 253 {"match": {"uri": "~(?R)?z"}, "action": {"return": 200}} 254 ) 255 if 'error' not in status: 256 assert self.get(url='/nothing_z')['status'] == 500, '/nothing_z' 257 258 status = self.route( 259 {"match": {"uri": "~((?1)?z)"}, "action": {"return": 200}} 260 ) 261 if 'error' not in status: 262 assert self.get(url='/nothing_z')['status'] == 500, '/nothing_z' 263 264 def test_routes_match_regex_case_sensitive(self): 265 if not option.available['modules']['regex']: 266 pytest.skip('requires regex') 267 268 self.route_match({"uri": "~/bl[ah]"}) 269 270 assert self.get(url='/rlah')['status'] == 404, '/rlah' 271 assert self.get(url='/blah')['status'] == 200, '/blah' 272 assert self.get(url='/blh')['status'] == 200, '/blh' 273 assert self.get(url='/BLAH')['status'] == 404, '/BLAH' 274 275 def test_routes_match_regex_negative_case_sensitive(self): 276 if not option.available['modules']['regex']: 277 pytest.skip('requires regex') 278 279 self.route_match({"uri": "!~/bl[ah]"}) 280 281 assert self.get(url='/rlah')['status'] == 200, '/rlah' 282 assert self.get(url='/blah')['status'] == 404, '/blah' 283 assert self.get(url='/blh')['status'] == 404, '/blh' 284 assert self.get(url='/BLAH')['status'] == 200, '/BLAH' 285 286 def test_routes_pass_encode(self): 287 def check_pass(path, name): 288 assert 'success' in self.conf( 289 { 290 "listeners": {"*:7080": {"pass": "applications/" + path}}, 291 "applications": { 292 name: { 293 "type": "python", 294 "processes": {"spare": 0}, 295 "path": option.test_dir + '/python/empty', 296 "working_directory": option.test_dir 297 + '/python/empty', 298 "module": "wsgi", 299 } 300 }, 301 } 302 ) 303 304 assert self.get()['status'] == 200 305 306 check_pass("%25", "%") 307 check_pass("blah%2Fblah", "blah/blah") 308 check_pass("%2Fblah%2F%2Fblah%2F", "/blah//blah/") 309 check_pass("%20blah%252Fblah%7E", " blah%2Fblah~") 310 311 def check_pass_error(path, name): 312 assert 'error' in self.conf( 313 { 314 "listeners": {"*:7080": {"pass": "applications/" + path}}, 315 "applications": { 316 name: { 317 "type": "python", 318 "processes": {"spare": 0}, 319 "path": option.test_dir + '/python/empty', 320 "working_directory": option.test_dir 321 + '/python/empty', 322 "module": "wsgi", 323 } 324 }, 325 } 326 ) 327 328 check_pass_error("%", "%") 329 check_pass_error("%1", "%1") 330 331 def test_routes_absent(self): 332 assert 'success' in self.conf( 333 { 334 "listeners": {"*:7081": {"pass": "applications/empty"}}, 335 "applications": { 336 "empty": { 337 "type": "python", 338 "processes": {"spare": 0}, 339 "path": option.test_dir + '/python/empty', 340 "working_directory": option.test_dir + '/python/empty', 341 "module": "wsgi", 342 } 343 }, 344 } 345 ) 346 347 assert self.get(port=7081)['status'] == 200, 'routes absent' 348 349 def test_routes_pass_invalid(self): 350 assert 'error' in self.conf( 351 {"pass": "routes/blah"}, 'listeners/*:7080' 352 ), 'routes invalid' 353 354 def test_route_empty(self): 355 assert 'success' in self.conf( 356 { 357 "listeners": {"*:7080": {"pass": "routes/main"}}, 358 "routes": {"main": []}, 359 "applications": {}, 360 } 361 ), 'route empty configure' 362 363 assert self.get()['status'] == 404, 'route empty' 364 365 def test_routes_route_empty(self): 366 assert 'success' in self.conf( 367 {}, 'listeners' 368 ), 'routes empty listeners configure' 369 370 assert 'success' in self.conf({}, 'routes'), 'routes empty configure' 371 372 def test_routes_route_match_absent(self): 373 assert 'success' in self.conf( 374 [{"action": {"return": 200}}], 'routes' 375 ), 'route match absent configure' 376 377 assert self.get()['status'] == 200, 'route match absent' 378 379 def test_routes_route_action_absent(self, skip_alert): 380 skip_alert(r'failed to apply new conf') 381 382 assert 'error' in self.conf( 383 [{"match": {"method": "GET"}}], 'routes' 384 ), 'route pass absent configure' 385 386 def test_routes_route_pass(self): 387 assert 'success' in self.conf( 388 { 389 "applications": { 390 "app": { 391 "type": "python", 392 "processes": {"spare": 0}, 393 "path": "/app", 394 "module": "wsgi", 395 } 396 }, 397 "upstreams": { 398 "one": { 399 "servers": { 400 "127.0.0.1:7081": {}, 401 "127.0.0.1:7082": {}, 402 }, 403 }, 404 "two": { 405 "servers": { 406 "127.0.0.1:7081": {}, 407 "127.0.0.1:7082": {}, 408 }, 409 }, 410 }, 411 } 412 ) 413 414 assert 'success' in self.conf( 415 [{"action": {"pass": "routes"}}], 'routes' 416 ) 417 assert 'success' in self.conf( 418 [{"action": {"pass": "applications/app"}}], 'routes' 419 ) 420 assert 'success' in self.conf( 421 [{"action": {"pass": "upstreams/one"}}], 'routes' 422 ) 423 424 def test_routes_route_pass_absent(self): 425 assert 'error' in self.conf( 426 [{"match": {"method": "GET"}, "action": {}}], 'routes' 427 ), 'route pass absent configure' 428 429 def test_routes_route_pass_invalid(self): 430 assert 'success' in self.conf( 431 { 432 "applications": { 433 "app": { 434 "type": "python", 435 "processes": {"spare": 0}, 436 "path": "/app", 437 "module": "wsgi", 438 } 439 }, 440 "upstreams": { 441 "one": { 442 "servers": { 443 "127.0.0.1:7081": {}, 444 "127.0.0.1:7082": {}, 445 }, 446 }, 447 "two": { 448 "servers": { 449 "127.0.0.1:7081": {}, 450 "127.0.0.1:7082": {}, 451 }, 452 }, 453 }, 454 } 455 ) 456 457 assert 'error' in self.conf( 458 [{"action": {"pass": "blah"}}], 'routes' 459 ), 'route pass invalid' 460 assert 'error' in self.conf( 461 [{"action": {"pass": "routes/blah"}}], 'routes' 462 ), 'route pass routes invalid' 463 assert 'error' in self.conf( 464 [{"action": {"pass": "applications/blah"}}], 'routes' 465 ), 'route pass applications invalid' 466 assert 'error' in self.conf( 467 [{"action": {"pass": "upstreams/blah"}}], 'routes' 468 ), 'route pass upstreams invalid' 469 470 def test_routes_action_unique(self, temp_dir): 471 assert 'success' in self.conf( 472 { 473 "listeners": { 474 "*:7080": {"pass": "routes"}, 475 "*:7081": {"pass": "applications/app"}, 476 }, 477 "routes": [{"action": {"proxy": "http://127.0.0.1:7081"}}], 478 "applications": { 479 "app": { 480 "type": "python", 481 "processes": {"spare": 0}, 482 "path": "/app", 483 "module": "wsgi", 484 } 485 }, 486 } 487 ) 488 489 assert 'error' in self.conf( 490 {"proxy": "http://127.0.0.1:7081", "share": temp_dir}, 491 'routes/0/action', 492 ), 'proxy share' 493 assert 'error' in self.conf( 494 {"proxy": "http://127.0.0.1:7081", "pass": "applications/app",}, 495 'routes/0/action', 496 ), 'proxy pass' 497 assert 'error' in self.conf( 498 {"share": temp_dir, "pass": "applications/app"}, 'routes/0/action', 499 ), 'share pass' 500 501 def test_routes_rules_two(self): 502 assert 'success' in self.conf( 503 [ 504 {"match": {"method": "GET"}, "action": {"return": 200}}, 505 {"match": {"method": "POST"}, "action": {"return": 201}}, 506 ], 507 'routes', 508 ), 'rules two configure' 509 510 assert self.get()['status'] == 200, 'rules two match first' 511 assert self.post()['status'] == 201, 'rules two match second' 512 513 def test_routes_two(self): 514 assert 'success' in self.conf( 515 { 516 "listeners": {"*:7080": {"pass": "routes/first"}}, 517 "routes": { 518 "first": [ 519 { 520 "match": {"method": "GET"}, 521 "action": {"pass": "routes/second"}, 522 } 523 ], 524 "second": [ 525 { 526 "match": {"host": "localhost"}, 527 "action": {"return": 200}, 528 } 529 ], 530 }, 531 "applications": {}, 532 } 533 ), 'routes two configure' 534 535 assert self.get()['status'] == 200, 'routes two' 536 537 def test_routes_match_host_positive(self): 538 self.route_match({"host": "localhost"}) 539 540 assert self.get()['status'] == 200, 'localhost' 541 self.host('localhost.', 200) 542 self.host('localhost.', 200) 543 self.host('.localhost', 404) 544 self.host('www.localhost', 404) 545 self.host('localhost1', 404) 546 547 @pytest.mark.skip('not yet') 548 def test_routes_match_host_absent(self): 549 self.route_match({"host": "localhost"}) 550 551 assert ( 552 self.get(headers={'Connection': 'close'})['status'] == 400 553 ), 'match host absent' 554 555 def test_routes_match_host_ipv4(self): 556 self.route_match({"host": "127.0.0.1"}) 557 558 self.host('127.0.0.1', 200) 559 self.host('127.0.0.1:7080', 200) 560 561 def test_routes_match_host_ipv6(self): 562 self.route_match({"host": "[::1]"}) 563 564 self.host('[::1]', 200) 565 self.host('[::1]:7080', 200) 566 567 def test_routes_match_host_positive_many(self): 568 self.route_match({"host": ["localhost", "example.com"]}) 569 570 assert self.get()['status'] == 200, 'localhost' 571 self.host('example.com', 200) 572 573 def test_routes_match_host_positive_and_negative(self): 574 self.route_match({"host": ["*example.com", "!www.example.com"]}) 575 576 assert self.get()['status'] == 404, 'localhost' 577 self.host('example.com', 200) 578 self.host('www.example.com', 404) 579 self.host('!www.example.com', 200) 580 581 def test_routes_match_host_positive_and_negative_wildcard(self): 582 self.route_match({"host": ["*example*", "!www.example*"]}) 583 584 self.host('example.com', 200) 585 self.host('www.example.com', 404) 586 587 def test_routes_match_host_case_insensitive(self): 588 self.route_match({"host": "Example.com"}) 589 590 self.host('example.com', 200) 591 self.host('EXAMPLE.COM', 200) 592 593 def test_routes_match_host_port(self): 594 self.route_match({"host": "example.com"}) 595 596 self.host('example.com:7080', 200) 597 598 def test_routes_match_host_empty(self): 599 self.route_match({"host": ""}) 600 601 self.host('', 200) 602 assert ( 603 self.get(http_10=True, headers={})['status'] == 200 604 ), 'match host empty 2' 605 assert self.get()['status'] == 404, 'match host empty 3' 606 607 def test_routes_match_uri_positive(self): 608 self.route_match({"uri": ["/blah", "/slash/"]}) 609 610 assert self.get()['status'] == 404, '/' 611 assert self.get(url='/blah')['status'] == 200, '/blah' 612 assert self.get(url='/blah#foo')['status'] == 200, '/blah#foo' 613 assert self.get(url='/blah?var')['status'] == 200, '/blah?var' 614 assert self.get(url='//blah')['status'] == 200, '//blah' 615 assert self.get(url='/slash/foo/../')['status'] == 200, 'relative' 616 assert self.get(url='/slash/./')['status'] == 200, '/slash/./' 617 assert self.get(url='/slash//.//')['status'] == 200, 'adjacent slashes' 618 assert self.get(url='/%')['status'] == 400, 'percent' 619 assert self.get(url='/%1')['status'] == 400, 'percent digit' 620 assert self.get(url='/%A')['status'] == 400, 'percent letter' 621 assert self.get(url='/slash/.?args')['status'] == 200, 'dot args' 622 assert self.get(url='/slash/.#frag')['status'] == 200, 'dot frag' 623 assert ( 624 self.get(url='/slash/foo/..?args')['status'] == 200 625 ), 'dot dot args' 626 assert ( 627 self.get(url='/slash/foo/..#frag')['status'] == 200 628 ), 'dot dot frag' 629 assert self.get(url='/slash/.')['status'] == 200, 'trailing dot' 630 assert ( 631 self.get(url='/slash/foo/..')['status'] == 200 632 ), 'trailing dot dot' 633 634 def test_routes_match_uri_case_sensitive(self): 635 self.route_match({"uri": "/BLAH"}) 636 637 assert self.get(url='/blah')['status'] == 404, '/blah' 638 assert self.get(url='/BlaH')['status'] == 404, '/BlaH' 639 assert self.get(url='/BLAH')['status'] == 200, '/BLAH' 640 641 def test_routes_match_uri_normalize(self): 642 self.route_match({"uri": "/blah"}) 643 644 assert self.get(url='/%62%6c%61%68')['status'] == 200, 'normalize' 645 646 def test_routes_match_empty_array(self): 647 self.route_match({"uri": []}) 648 649 assert self.get(url='/blah')['status'] == 200, 'empty array' 650 651 def test_routes_reconfigure(self): 652 assert 'success' in self.conf([], 'routes'), 'redefine' 653 assert self.get()['status'] == 404, 'redefine request' 654 655 assert 'success' in self.conf( 656 [{"action": {"return": 200}}], 'routes' 657 ), 'redefine 2' 658 assert self.get()['status'] == 200, 'redefine request 2' 659 660 assert 'success' in self.conf([], 'routes'), 'redefine 3' 661 assert self.get()['status'] == 404, 'redefine request 3' 662 663 assert 'success' in self.conf( 664 { 665 "listeners": {"*:7080": {"pass": "routes/main"}}, 666 "routes": {"main": [{"action": {"return": 200}}]}, 667 "applications": {}, 668 } 669 ), 'redefine 4' 670 assert self.get()['status'] == 200, 'redefine request 4' 671 672 assert 'success' in self.conf_delete('routes/main/0'), 'redefine 5' 673 assert self.get()['status'] == 404, 'redefine request 5' 674 675 assert 'success' in self.conf_post( 676 {"action": {"return": 200}}, 'routes/main' 677 ), 'redefine 6' 678 assert self.get()['status'] == 200, 'redefine request 6' 679 680 assert 'error' in self.conf( 681 {"action": {"return": 200}}, 'routes/main/2' 682 ), 'redefine 7' 683 assert 'success' in self.conf( 684 {"action": {"return": 201}}, 'routes/main/1' 685 ), 'redefine 8' 686 687 assert len(self.conf_get('routes/main')) == 2, 'redefine conf 8' 688 assert self.get()['status'] == 200, 'redefine request 8' 689 690 def test_routes_edit(self): 691 self.route_match({"method": "GET"}) 692 693 assert self.get()['status'] == 200, 'routes edit GET' 694 assert self.post()['status'] == 404, 'routes edit POST' 695 696 assert 'success' in self.conf_post( 697 {"match": {"method": "POST"}, "action": {"return": 200}}, 'routes', 698 ), 'routes edit configure 2' 699 assert 'GET' == self.conf_get( 700 'routes/0/match/method' 701 ), 'routes edit configure 2 check' 702 assert 'POST' == self.conf_get( 703 'routes/1/match/method' 704 ), 'routes edit configure 2 check 2' 705 706 assert self.get()['status'] == 200, 'routes edit GET 2' 707 assert self.post()['status'] == 200, 'routes edit POST 2' 708 709 assert 'success' in self.conf_delete( 710 'routes/0' 711 ), 'routes edit configure 3' 712 713 assert self.get()['status'] == 404, 'routes edit GET 3' 714 assert self.post()['status'] == 200, 'routes edit POST 3' 715 716 assert 'error' in self.conf_delete( 717 'routes/1' 718 ), 'routes edit configure invalid' 719 assert 'error' in self.conf_delete( 720 'routes/-1' 721 ), 'routes edit configure invalid 2' 722 assert 'error' in self.conf_delete( 723 'routes/blah' 724 ), 'routes edit configure invalid 3' 725 726 assert self.get()['status'] == 404, 'routes edit GET 4' 727 assert self.post()['status'] == 200, 'routes edit POST 4' 728 729 assert 'success' in self.conf_delete( 730 'routes/0' 731 ), 'routes edit configure 5' 732 733 assert self.get()['status'] == 404, 'routes edit GET 5' 734 assert self.post()['status'] == 404, 'routes edit POST 5' 735 736 assert 'success' in self.conf_post( 737 {"match": {"method": "POST"}, "action": {"return": 200}}, 'routes', 738 ), 'routes edit configure 6' 739 740 assert self.get()['status'] == 404, 'routes edit GET 6' 741 assert self.post()['status'] == 200, 'routes edit POST 6' 742 743 assert 'success' in self.conf( 744 { 745 "listeners": {"*:7080": {"pass": "routes/main"}}, 746 "routes": {"main": [{"action": {"return": 200}}]}, 747 "applications": {}, 748 } 749 ), 'route edit configure 7' 750 751 assert 'error' in self.conf_delete( 752 'routes/0' 753 ), 'routes edit configure invalid 4' 754 assert 'error' in self.conf_delete( 755 'routes/main' 756 ), 'routes edit configure invalid 5' 757 758 assert self.get()['status'] == 200, 'routes edit GET 7' 759 760 assert 'success' in self.conf_delete( 761 'listeners/*:7080' 762 ), 'route edit configure 8' 763 assert 'success' in self.conf_delete( 764 'routes/main' 765 ), 'route edit configure 9' 766 767 def test_match_edit(self, skip_alert): 768 skip_alert(r'failed to apply new conf') 769 770 self.route_match({"method": ["GET", "POST"]}) 771 772 assert self.get()['status'] == 200, 'match edit GET' 773 assert self.post()['status'] == 200, 'match edit POST' 774 assert self.put()['status'] == 404, 'match edit PUT' 775 776 assert 'success' in self.conf_post( 777 '\"PUT\"', 'routes/0/match/method' 778 ), 'match edit configure 2' 779 assert ['GET', 'POST', 'PUT'] == self.conf_get( 780 'routes/0/match/method' 781 ), 'match edit configure 2 check' 782 783 assert self.get()['status'] == 200, 'match edit GET 2' 784 assert self.post()['status'] == 200, 'match edit POST 2' 785 assert self.put()['status'] == 200, 'match edit PUT 2' 786 787 assert 'success' in self.conf_delete( 788 'routes/0/match/method/1' 789 ), 'match edit configure 3' 790 assert ['GET', 'PUT'] == self.conf_get( 791 'routes/0/match/method' 792 ), 'match edit configure 3 check' 793 794 assert self.get()['status'] == 200, 'match edit GET 3' 795 assert self.post()['status'] == 404, 'match edit POST 3' 796 assert self.put()['status'] == 200, 'match edit PUT 3' 797 798 assert 'success' in self.conf_delete( 799 'routes/0/match/method/1' 800 ), 'match edit configure 4' 801 assert ['GET'] == self.conf_get( 802 'routes/0/match/method' 803 ), 'match edit configure 4 check' 804 805 assert self.get()['status'] == 200, 'match edit GET 4' 806 assert self.post()['status'] == 404, 'match edit POST 4' 807 assert self.put()['status'] == 404, 'match edit PUT 4' 808 809 assert 'error' in self.conf_delete( 810 'routes/0/match/method/1' 811 ), 'match edit configure invalid' 812 assert 'error' in self.conf_delete( 813 'routes/0/match/method/-1' 814 ), 'match edit configure invalid 2' 815 assert 'error' in self.conf_delete( 816 'routes/0/match/method/blah' 817 ), 'match edit configure invalid 3' 818 assert ['GET'] == self.conf_get( 819 'routes/0/match/method' 820 ), 'match edit configure 5 check' 821 822 assert self.get()['status'] == 200, 'match edit GET 5' 823 assert self.post()['status'] == 404, 'match edit POST 5' 824 assert self.put()['status'] == 404, 'match edit PUT 5' 825 826 assert 'success' in self.conf_delete( 827 'routes/0/match/method/0' 828 ), 'match edit configure 6' 829 assert [] == self.conf_get( 830 'routes/0/match/method' 831 ), 'match edit configure 6 check' 832 833 assert self.get()['status'] == 200, 'match edit GET 6' 834 assert self.post()['status'] == 200, 'match edit POST 6' 835 assert self.put()['status'] == 200, 'match edit PUT 6' 836 837 assert 'success' in self.conf( 838 '"GET"', 'routes/0/match/method' 839 ), 'match edit configure 7' 840 841 assert self.get()['status'] == 200, 'match edit GET 7' 842 assert self.post()['status'] == 404, 'match edit POST 7' 843 assert self.put()['status'] == 404, 'match edit PUT 7' 844 845 assert 'error' in self.conf_delete( 846 'routes/0/match/method/0' 847 ), 'match edit configure invalid 5' 848 assert 'error' in self.conf( 849 {}, 'routes/0/action' 850 ), 'match edit configure invalid 6' 851 852 assert 'success' in self.conf( 853 {}, 'routes/0/match' 854 ), 'match edit configure 8' 855 856 assert self.get()['status'] == 200, 'match edit GET 8' 857 858 def test_routes_match_rules(self): 859 self.route_match({"method": "GET", "host": "localhost", "uri": "/"}) 860 861 assert self.get()['status'] == 200, 'routes match rules' 862 863 def test_routes_loop(self): 864 assert 'success' in self.route( 865 {"match": {"uri": "/"}, "action": {"pass": "routes"}} 866 ), 'routes loop configure' 867 868 assert self.get()['status'] == 500, 'routes loop' 869 870 def test_routes_match_headers(self): 871 self.route_match({"headers": {"host": "localhost"}}) 872 873 assert self.get()['status'] == 200, 'match headers' 874 self.host('Localhost', 200) 875 self.host('localhost.com', 404) 876 self.host('llocalhost', 404) 877 self.host('host', 404) 878 879 def test_routes_match_headers_multiple(self): 880 self.route_match({"headers": {"host": "localhost", "x-blah": "test"}}) 881 882 assert self.get()['status'] == 404, 'match headers multiple' 883 assert ( 884 self.get( 885 headers={ 886 "Host": "localhost", 887 "X-blah": "test", 888 "Connection": "close", 889 } 890 )['status'] 891 == 200 892 ), 'match headers multiple 2' 893 894 assert ( 895 self.get( 896 headers={ 897 "Host": "localhost", 898 "X-blah": "", 899 "Connection": "close", 900 } 901 )['status'] 902 == 404 903 ), 'match headers multiple 3' 904 905 def test_routes_match_headers_multiple_values(self): 906 self.route_match({"headers": {"x-blah": "test"}}) 907 908 assert ( 909 self.get( 910 headers={ 911 "Host": "localhost", 912 "X-blah": ["test", "test", "test"], 913 "Connection": "close", 914 } 915 )['status'] 916 == 200 917 ), 'match headers multiple values' 918 assert ( 919 self.get( 920 headers={ 921 "Host": "localhost", 922 "X-blah": ["test", "blah", "test"], 923 "Connection": "close", 924 } 925 )['status'] 926 == 404 927 ), 'match headers multiple values 2' 928 assert ( 929 self.get( 930 headers={ 931 "Host": "localhost", 932 "X-blah": ["test", "", "test"], 933 "Connection": "close", 934 } 935 )['status'] 936 == 404 937 ), 'match headers multiple values 3' 938 939 def test_routes_match_headers_multiple_rules(self): 940 self.route_match({"headers": {"x-blah": ["test", "blah"]}}) 941 942 assert self.get()['status'] == 404, 'match headers multiple rules' 943 assert ( 944 self.get( 945 headers={ 946 "Host": "localhost", 947 "X-blah": "test", 948 "Connection": "close", 949 } 950 )['status'] 951 == 200 952 ), 'match headers multiple rules 2' 953 assert ( 954 self.get( 955 headers={ 956 "Host": "localhost", 957 "X-blah": "blah", 958 "Connection": "close", 959 } 960 )['status'] 961 == 200 962 ), 'match headers multiple rules 3' 963 assert ( 964 self.get( 965 headers={ 966 "Host": "localhost", 967 "X-blah": ["test", "blah", "test"], 968 "Connection": "close", 969 } 970 )['status'] 971 == 200 972 ), 'match headers multiple rules 4' 973 974 assert ( 975 self.get( 976 headers={ 977 "Host": "localhost", 978 "X-blah": ["blah", ""], 979 "Connection": "close", 980 } 981 )['status'] 982 == 404 983 ), 'match headers multiple rules 5' 984 985 def test_routes_match_headers_case_insensitive(self): 986 self.route_match({"headers": {"X-BLAH": "TEST"}}) 987 988 assert ( 989 self.get( 990 headers={ 991 "Host": "localhost", 992 "x-blah": "test", 993 "Connection": "close", 994 } 995 )['status'] 996 == 200 997 ), 'match headers case insensitive' 998 999 def test_routes_match_headers_invalid(self): 1000 self.route_match_invalid({"headers": ["blah"]}) 1001 self.route_match_invalid({"headers": {"foo": ["bar", {}]}}) 1002 self.route_match_invalid({"headers": {"": "blah"}}) 1003 1004 def test_routes_match_headers_empty_rule(self): 1005 self.route_match({"headers": {"host": ""}}) 1006 1007 assert self.get()['status'] == 404, 'localhost' 1008 self.host('', 200) 1009 1010 def test_routes_match_headers_empty(self): 1011 self.route_match({"headers": {}}) 1012 assert self.get()['status'] == 200, 'empty' 1013 1014 self.route_match({"headers": []}) 1015 assert self.get()['status'] == 200, 'empty 2' 1016 1017 def test_routes_match_headers_rule_array_empty(self): 1018 self.route_match({"headers": {"blah": []}}) 1019 1020 assert self.get()['status'] == 404, 'array empty' 1021 assert ( 1022 self.get( 1023 headers={ 1024 "Host": "localhost", 1025 "blah": "foo", 1026 "Connection": "close", 1027 } 1028 )['status'] 1029 == 200 1030 ), 'match headers rule array empty 2' 1031 1032 def test_routes_match_headers_array(self): 1033 self.route_match( 1034 { 1035 "headers": [ 1036 {"x-header1": "foo*"}, 1037 {"x-header2": "bar"}, 1038 {"x-header3": ["foo", "bar"]}, 1039 {"x-header1": "bar", "x-header4": "foo"}, 1040 ] 1041 } 1042 ) 1043 1044 def check_headers(hds): 1045 hds = dict({"Host": "localhost", "Connection": "close"}, **hds) 1046 assert ( 1047 self.get(headers=hds)['status'] == 200 1048 ), 'headers array match' 1049 1050 def check_headers_404(hds): 1051 hds = dict({"Host": "localhost", "Connection": "close"}, **hds) 1052 assert ( 1053 self.get(headers=hds)['status'] == 404 1054 ), 'headers array no match' 1055 1056 assert self.get()['status'] == 404, 'match headers array' 1057 check_headers({"x-header1": "foo123"}) 1058 check_headers({"x-header2": "bar"}) 1059 check_headers({"x-header3": "bar"}) 1060 check_headers_404({"x-header1": "bar"}) 1061 check_headers({"x-header1": "bar", "x-header4": "foo"}) 1062 1063 assert 'success' in self.conf_delete( 1064 'routes/0/match/headers/1' 1065 ), 'match headers array configure 2' 1066 1067 check_headers_404({"x-header2": "bar"}) 1068 check_headers({"x-header3": "foo"}) 1069 1070 def test_routes_match_arguments(self): 1071 self.route_match({"arguments": {"foo": "bar"}}) 1072 1073 assert self.get()['status'] == 404, 'args' 1074 assert self.get(url='/?foo=bar')['status'] == 200, 'args 2' 1075 assert self.get(url='/?foo=bar1')['status'] == 404, 'args 3' 1076 assert self.get(url='/?1foo=bar')['status'] == 404, 'args 4' 1077 assert self.get(url='/?Foo=bar')['status'] == 404, 'case' 1078 assert self.get(url='/?foo=Bar')['status'] == 404, 'case 2' 1079 1080 def test_routes_match_arguments_chars(self): 1081 chars = ( 1082 " !\"%23$%25%26'()*%2B,-./0123456789:;<%3D>?@" 1083 "ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~" 1084 ) 1085 1086 chars_enc = "" 1087 for h1 in ["2", "3", "4", "5", "6", "7"]: 1088 for h2 in [ 1089 "0", 1090 "1", 1091 "2", 1092 "3", 1093 "4", 1094 "5", 1095 "6", 1096 "7", 1097 "8", 1098 "9", 1099 "A", 1100 "B", 1101 "C", 1102 "D", 1103 "E", 1104 "F", 1105 ]: 1106 chars_enc += "%" + h1 + h2 1107 chars_enc = chars_enc[:-3] 1108 1109 def check_args(args, query): 1110 self.route_match({"arguments": args}) 1111 assert self.get(url='/?' + query)['status'] == 200 1112 1113 check_args({chars: chars}, chars + '=' + chars) 1114 check_args({chars: chars}, chars + '=' + chars_enc) 1115 check_args({chars: chars}, chars_enc + '=' + chars) 1116 check_args({chars: chars}, chars_enc + '=' + chars_enc) 1117 check_args({chars_enc: chars_enc}, chars + '=' + chars) 1118 check_args({chars_enc: chars_enc}, chars + '=' + chars_enc) 1119 check_args({chars_enc: chars_enc}, chars_enc + '=' + chars) 1120 check_args({chars_enc: chars_enc}, chars_enc + '=' + chars_enc) 1121 1122 def test_routes_match_arguments_empty(self): 1123 self.route_match({"arguments": {}}) 1124 assert self.get()['status'] == 200, 'arguments empty' 1125 1126 self.route_match({"arguments": []}) 1127 assert self.get()['status'] == 200, 'arguments empty 2' 1128 1129 def test_routes_match_arguments_space(self): 1130 self.route_match({"arguments": {"+fo o%20": "%20b+a r"}}) 1131 assert self.get(url='/? fo o = b a r&')['status'] == 200 1132 assert self.get(url='/?+fo+o+=+b+a+r&')['status'] == 200 1133 assert self.get(url='/?%20fo%20o%20=%20b%20a%20r&')['status'] == 200 1134 1135 self.route_match({"arguments": {"%20foo": " bar"}}) 1136 assert self.get(url='/? foo= bar')['status'] == 200 1137 assert self.get(url='/?+foo=+bar')['status'] == 200 1138 assert self.get(url='/?%20foo=%20bar')['status'] == 200 1139 assert self.get(url='/?+foo= bar')['status'] == 200 1140 assert self.get(url='/?%20foo=+bar')['status'] == 200 1141 1142 def test_routes_match_arguments_equal(self): 1143 self.route_match({"arguments": {"=": "="}}) 1144 assert self.get(url='/?%3D=%3D')['status'] == 200 1145 assert self.get(url='/?%3D==')['status'] == 200 1146 assert self.get(url='/?===')['status'] == 404 1147 assert self.get(url='/?%3D%3D%3D')['status'] == 404 1148 assert self.get(url='/?==%3D')['status'] == 404 1149 1150 def test_routes_match_arguments_enc(self): 1151 self.route_match({"arguments": {"Ю": "н"}}) 1152 assert self.get(url='/?%D0%AE=%D0%BD')['status'] == 200 1153 assert self.get(url='/?%d0%ae=%d0%Bd')['status'] == 200 1154 1155 def test_routes_match_arguments_hash(self): 1156 self.route_match({"arguments": {"#": "#"}}) 1157 assert self.get(url='/?%23=%23')['status'] == 200 1158 assert self.get(url='/?%23=%23#')['status'] == 200 1159 assert self.get(url='/?#=#')['status'] == 404 1160 assert self.get(url='/?%23=#')['status'] == 404 1161 1162 def test_routes_match_arguments_wildcard(self): 1163 self.route_match({"arguments": {"foo": "*"}}) 1164 assert self.get(url='/?foo')['status'] == 200 1165 assert self.get(url='/?foo=')['status'] == 200 1166 assert self.get(url='/?foo=blah')['status'] == 200 1167 assert self.get(url='/?blah=foo')['status'] == 404 1168 1169 self.route_match({"arguments": {"foo": "%25*"}}) 1170 assert self.get(url='/?foo=%xx')['status'] == 200 1171 1172 self.route_match({"arguments": {"foo": "%2A*"}}) 1173 assert self.get(url='/?foo=*xx')['status'] == 200 1174 assert self.get(url='/?foo=xx')['status'] == 404 1175 1176 self.route_match({"arguments": {"foo": "*%2A"}}) 1177 assert self.get(url='/?foo=xx*')['status'] == 200 1178 assert self.get(url='/?foo=xx*x')['status'] == 404 1179 1180 self.route_match({"arguments": {"foo": "1*2"}}) 1181 assert self.get(url='/?foo=12')['status'] == 200 1182 assert self.get(url='/?foo=1blah2')['status'] == 200 1183 assert self.get(url='/?foo=1%2A2')['status'] == 200 1184 assert self.get(url='/?foo=x12')['status'] == 404 1185 1186 self.route_match({"arguments": {"foo": "bar*", "%25": "%25"}}) 1187 assert self.get(url='/?foo=barxx&%=%')['status'] == 200 1188 assert self.get(url='/?foo=barxx&x%=%')['status'] == 404 1189 1190 def test_routes_match_arguments_negative(self): 1191 self.route_match({"arguments": {"foo": "!"}}) 1192 assert self.get(url='/?bar')['status'] == 404 1193 assert self.get(url='/?foo')['status'] == 404 1194 assert self.get(url='/?foo=')['status'] == 404 1195 assert self.get(url='/?foo=%25')['status'] == 200 1196 1197 self.route_match({"arguments": {"foo": "!*"}}) 1198 assert self.get(url='/?bar')['status'] == 404 1199 assert self.get(url='/?foo')['status'] == 404 1200 assert self.get(url='/?foo=')['status'] == 404 1201 assert self.get(url='/?foo=blah')['status'] == 404 1202 1203 self.route_match({"arguments": {"foo": "!%25"}}) 1204 assert self.get(url='/?foo=blah')['status'] == 200 1205 assert self.get(url='/?foo=%')['status'] == 404 1206 1207 self.route_match({"arguments": {"foo": "%21blah"}}) 1208 assert self.get(url='/?foo=%21blah')['status'] == 200 1209 assert self.get(url='/?foo=!blah')['status'] == 200 1210 assert self.get(url='/?foo=bar')['status'] == 404 1211 1212 self.route_match({"arguments": {"foo": "!!%21*a"}}) 1213 assert self.get(url='/?foo=blah')['status'] == 200 1214 assert self.get(url='/?foo=!blah')['status'] == 200 1215 assert self.get(url='/?foo=!!a')['status'] == 404 1216 assert self.get(url='/?foo=!!bla')['status'] == 404 1217 1218 def test_routes_match_arguments_percent(self): 1219 self.route_match({"arguments": {"%25": "%25"}}) 1220 assert self.get(url='/?%=%')['status'] == 200 1221 assert self.get(url='/?%25=%25')['status'] == 200 1222 assert self.get(url='/?%25=%')['status'] == 200 1223 1224 self.route_match({"arguments": {"%251": "%252"}}) 1225 assert self.get(url='/?%1=%2')['status'] == 200 1226 assert self.get(url='/?%251=%252')['status'] == 200 1227 assert self.get(url='/?%251=%2')['status'] == 200 1228 1229 self.route_match({"arguments": {"%25%21%251": "%25%24%252"}}) 1230 assert self.get(url='/?%!%1=%$%2')['status'] == 200 1231 assert self.get(url='/?%25!%251=%25$%252')['status'] == 200 1232 assert self.get(url='/?%25!%1=%$%2')['status'] == 200 1233 1234 def test_routes_match_arguments_ampersand(self): 1235 self.route_match({"arguments": {"foo": "&"}}) 1236 assert self.get(url='/?foo=%26')['status'] == 200 1237 assert self.get(url='/?foo=%26&')['status'] == 200 1238 assert self.get(url='/?foo=%26%26')['status'] == 404 1239 assert self.get(url='/?foo=&')['status'] == 404 1240 1241 self.route_match({"arguments": {"&": ""}}) 1242 assert self.get(url='/?%26=')['status'] == 200 1243 assert self.get(url='/?%26=&')['status'] == 200 1244 assert self.get(url='/?%26=%26')['status'] == 404 1245 assert self.get(url='/?&=')['status'] == 404 1246 1247 def test_routes_match_arguments_complex(self): 1248 self.route_match({"arguments": {"foo": ""}}) 1249 1250 assert self.get(url='/?foo')['status'] == 200, 'complex' 1251 assert self.get(url='/?blah=blah&foo=')['status'] == 200, 'complex 2' 1252 assert self.get(url='/?&&&foo&&&')['status'] == 200, 'complex 3' 1253 assert self.get(url='/?foo&foo=bar&foo')['status'] == 404, 'complex 4' 1254 assert self.get(url='/?foo=&foo')['status'] == 200, 'complex 5' 1255 assert self.get(url='/?&=&foo&==&')['status'] == 200, 'complex 6' 1256 assert self.get(url='/?&=&bar&==&')['status'] == 404, 'complex 7' 1257 1258 def test_routes_match_arguments_multiple(self): 1259 self.route_match({"arguments": {"foo": "bar", "blah": "test"}}) 1260 1261 assert self.get()['status'] == 404, 'multiple' 1262 assert ( 1263 self.get(url='/?foo=bar&blah=test')['status'] == 200 1264 ), 'multiple 2' 1265 assert self.get(url='/?foo=bar&blah')['status'] == 404, 'multiple 3' 1266 assert ( 1267 self.get(url='/?foo=bar&blah=tes')['status'] == 404 1268 ), 'multiple 4' 1269 assert ( 1270 self.get(url='/?foo=b%61r&bl%61h=t%65st')['status'] == 200 1271 ), 'multiple 5' 1272 1273 def test_routes_match_arguments_multiple_rules(self): 1274 self.route_match({"arguments": {"foo": ["bar", "blah"]}}) 1275 1276 assert self.get()['status'] == 404, 'rules' 1277 assert self.get(url='/?foo=bar')['status'] == 200, 'rules 2' 1278 assert self.get(url='/?foo=blah')['status'] == 200, 'rules 3' 1279 assert ( 1280 self.get(url='/?foo=blah&foo=bar&foo=blah')['status'] == 200 1281 ), 'rules 4' 1282 assert ( 1283 self.get(url='/?foo=blah&foo=bar&foo=')['status'] == 404 1284 ), 'rules 5' 1285 1286 def test_routes_match_arguments_array(self): 1287 self.route_match( 1288 { 1289 "arguments": [ 1290 {"var1": "val1*"}, 1291 {"var2": "val2"}, 1292 {"var3": ["foo", "bar"]}, 1293 {"var1": "bar", "var4": "foo"}, 1294 ] 1295 } 1296 ) 1297 1298 assert self.get()['status'] == 404, 'arr' 1299 assert self.get(url='/?var1=val123')['status'] == 200, 'arr 2' 1300 assert self.get(url='/?var2=val2')['status'] == 200, 'arr 3' 1301 assert self.get(url='/?var3=bar')['status'] == 200, 'arr 4' 1302 assert self.get(url='/?var1=bar')['status'] == 404, 'arr 5' 1303 assert self.get(url='/?var1=bar&var4=foo')['status'] == 200, 'arr 6' 1304 1305 assert 'success' in self.conf_delete( 1306 'routes/0/match/arguments/1' 1307 ), 'match arguments array configure 2' 1308 1309 assert self.get(url='/?var2=val2')['status'] == 404, 'arr 7' 1310 assert self.get(url='/?var3=foo')['status'] == 200, 'arr 8' 1311 1312 def test_routes_match_arguments_invalid(self): 1313 self.route_match_invalid({"arguments": ["var"]}) 1314 self.route_match_invalid({"arguments": [{"var1": {}}]}) 1315 self.route_match_invalid({"arguments": {"": "bar"}}) 1316 self.route_match_invalid({"arguments": {"foo": "%"}}) 1317 self.route_match_invalid({"arguments": {"foo": "%1G"}}) 1318 self.route_match_invalid({"arguments": {"%": "bar"}}) 1319 self.route_match_invalid({"arguments": {"foo": "%0"}}) 1320 self.route_match_invalid({"arguments": {"foo": "%%1F"}}) 1321 self.route_match_invalid({"arguments": {"%%1F": ""}}) 1322 self.route_match_invalid({"arguments": {"%7%F": ""}}) 1323 1324 def test_routes_match_cookies(self): 1325 self.route_match({"cookies": {"foO": "bar"}}) 1326 1327 assert self.get()['status'] == 404, 'cookie' 1328 self.cookie('foO=bar', 200) 1329 self.cookie('foO=bar;1', 200) 1330 self.cookie(['foO=bar', 'blah=blah'], 200) 1331 self.cookie('foO=bar; blah=blah', 200) 1332 self.cookie('Foo=bar', 404) 1333 self.cookie('foO=Bar', 404) 1334 self.cookie('foO=bar1', 404) 1335 self.cookie('1foO=bar;', 404) 1336 1337 def test_routes_match_cookies_empty(self): 1338 self.route_match({"cookies": {}}) 1339 assert self.get()['status'] == 200, 'cookies empty' 1340 1341 self.route_match({"cookies": []}) 1342 assert self.get()['status'] == 200, 'cookies empty 2' 1343 1344 def test_routes_match_cookies_invalid(self): 1345 self.route_match_invalid({"cookies": ["var"]}) 1346 self.route_match_invalid({"cookies": [{"foo": {}}]}) 1347 1348 def test_routes_match_cookies_multiple(self): 1349 self.route_match({"cookies": {"foo": "bar", "blah": "blah"}}) 1350 1351 assert self.get()['status'] == 404, 'multiple' 1352 self.cookie('foo=bar; blah=blah', 200) 1353 self.cookie(['foo=bar', 'blah=blah'], 200) 1354 self.cookie(['foo=bar; blah', 'blah'], 404) 1355 self.cookie(['foo=bar; blah=test', 'blah=blah'], 404) 1356 1357 def test_routes_match_cookies_multiple_values(self): 1358 self.route_match({"cookies": {"blah": "blah"}}) 1359 1360 self.cookie(['blah=blah', 'blah=blah', 'blah=blah'], 200) 1361 self.cookie(['blah=blah', 'blah=test', 'blah=blah'], 404) 1362 self.cookie(['blah=blah; blah=', 'blah=blah'], 404) 1363 1364 def test_routes_match_cookies_multiple_rules(self): 1365 self.route_match({"cookies": {"blah": ["test", "blah"]}}) 1366 1367 assert self.get()['status'] == 404, 'multiple rules' 1368 self.cookie('blah=test', 200) 1369 self.cookie('blah=blah', 200) 1370 self.cookie(['blah=blah', 'blah=test', 'blah=blah'], 200) 1371 self.cookie(['blah=blah; blah=test', 'blah=blah'], 200) 1372 self.cookie(['blah=blah', 'blah'], 200) # invalid cookie 1373 1374 def test_routes_match_cookies_array(self): 1375 self.route_match( 1376 { 1377 "cookies": [ 1378 {"var1": "val1*"}, 1379 {"var2": "val2"}, 1380 {"var3": ["foo", "bar"]}, 1381 {"var1": "bar", "var4": "foo"}, 1382 ] 1383 } 1384 ) 1385 1386 assert self.get()['status'] == 404, 'cookies array' 1387 self.cookie('var1=val123', 200) 1388 self.cookie('var2=val2', 200) 1389 self.cookie(' var2=val2 ', 200) 1390 self.cookie('var3=bar', 200) 1391 self.cookie('var3=bar;', 200) 1392 self.cookie('var1=bar', 404) 1393 self.cookie('var1=bar; var4=foo;', 200) 1394 self.cookie(['var1=bar', 'var4=foo'], 200) 1395 1396 assert 'success' in self.conf_delete( 1397 'routes/0/match/cookies/1' 1398 ), 'match cookies array configure 2' 1399 1400 self.cookie('var2=val2', 404) 1401 self.cookie('var3=foo', 200) 1402 1403 def test_routes_match_scheme(self): 1404 self.route_match({"scheme": "http"}) 1405 self.route_match({"scheme": "https"}) 1406 self.route_match({"scheme": "HtTp"}) 1407 self.route_match({"scheme": "HtTpS"}) 1408 1409 def test_routes_match_scheme_invalid(self): 1410 self.route_match_invalid({"scheme": ["http"]}) 1411 self.route_match_invalid({"scheme": "ftp"}) 1412 self.route_match_invalid({"scheme": "ws"}) 1413 self.route_match_invalid({"scheme": "*"}) 1414 self.route_match_invalid({"scheme": ""}) 1415 1416 def test_routes_source_port(self): 1417 def sock_port(): 1418 _, sock = self.http(b'', start=True, raw=True, no_recv=True) 1419 port = sock.getsockname()[1] 1420 return (sock, port) 1421 1422 sock, port = sock_port() 1423 sock2, port2 = sock_port() 1424 1425 self.route_match({"source": "127.0.0.1:" + str(port)}) 1426 assert self.get(sock=sock)['status'] == 200, 'exact' 1427 assert self.get(sock=sock2)['status'] == 404, 'exact 2' 1428 1429 sock, port = sock_port() 1430 sock2, port2 = sock_port() 1431 1432 self.route_match({"source": "!127.0.0.1:" + str(port)}) 1433 assert self.get(sock=sock)['status'] == 404, 'negative' 1434 assert self.get(sock=sock2)['status'] == 200, 'negative 2' 1435 1436 sock, port = sock_port() 1437 sock2, port2 = sock_port() 1438 1439 self.route_match({"source": ["*:" + str(port), "!127.0.0.1"]}) 1440 assert self.get(sock=sock)['status'] == 404, 'negative 3' 1441 assert self.get(sock=sock2)['status'] == 404, 'negative 4' 1442 1443 sock, port = sock_port() 1444 sock2, port2 = sock_port() 1445 1446 self.route_match( 1447 {"source": "127.0.0.1:" + str(port) + "-" + str(port)} 1448 ) 1449 assert self.get(sock=sock)['status'] == 200, 'range single' 1450 assert self.get(sock=sock2)['status'] == 404, 'range single 2' 1451 1452 socks = [ 1453 sock_port(), 1454 sock_port(), 1455 sock_port(), 1456 sock_port(), 1457 sock_port(), 1458 ] 1459 socks.sort(key=lambda sock: sock[1]) 1460 1461 self.route_match( 1462 { 1463 "source": "127.0.0.1:" 1464 + str(socks[1][1]) # second port number 1465 + "-" 1466 + str(socks[3][1]) # fourth port number 1467 } 1468 ) 1469 assert self.get(sock=socks[0][0])['status'] == 404, 'range' 1470 assert self.get(sock=socks[1][0])['status'] == 200, 'range 2' 1471 assert self.get(sock=socks[2][0])['status'] == 200, 'range 3' 1472 assert self.get(sock=socks[3][0])['status'] == 200, 'range 4' 1473 assert self.get(sock=socks[4][0])['status'] == 404, 'range 5' 1474 1475 socks = [ 1476 sock_port(), 1477 sock_port(), 1478 sock_port(), 1479 ] 1480 socks.sort(key=lambda sock: sock[1]) 1481 1482 self.route_match( 1483 { 1484 "source": [ 1485 "127.0.0.1:" + str(socks[0][1]), 1486 "127.0.0.1:" + str(socks[2][1]), 1487 ] 1488 } 1489 ) 1490 assert self.get(sock=socks[0][0])['status'] == 200, 'array' 1491 assert self.get(sock=socks[1][0])['status'] == 404, 'array 2' 1492 assert self.get(sock=socks[2][0])['status'] == 200, 'array 3' 1493 1494 def test_routes_source_addr(self): 1495 assert 'success' in self.conf( 1496 {"*:7080": {"pass": "routes"}, "[::1]:7081": {"pass": "routes"},}, 1497 'listeners', 1498 ), 'source listeners configure' 1499 1500 def get_ipv6(): 1501 return self.get(sock_type='ipv6', port=7081) 1502 1503 self.route_match({"source": "127.0.0.1"}) 1504 assert self.get()['status'] == 200, 'exact' 1505 assert get_ipv6()['status'] == 404, 'exact ipv6' 1506 1507 self.route_match({"source": ["127.0.0.1"]}) 1508 assert self.get()['status'] == 200, 'exact 2' 1509 assert get_ipv6()['status'] == 404, 'exact 2 ipv6' 1510 1511 self.route_match({"source": "!127.0.0.1"}) 1512 assert self.get()['status'] == 404, 'exact neg' 1513 assert get_ipv6()['status'] == 200, 'exact neg ipv6' 1514 1515 self.route_match({"source": "127.0.0.2"}) 1516 assert self.get()['status'] == 404, 'exact 3' 1517 assert get_ipv6()['status'] == 404, 'exact 3 ipv6' 1518 1519 self.route_match({"source": "127.0.0.1-127.0.0.1"}) 1520 assert self.get()['status'] == 200, 'range single' 1521 assert get_ipv6()['status'] == 404, 'range single ipv6' 1522 1523 self.route_match({"source": "127.0.0.2-127.0.0.2"}) 1524 assert self.get()['status'] == 404, 'range single 2' 1525 assert get_ipv6()['status'] == 404, 'range single 2 ipv6' 1526 1527 self.route_match({"source": "127.0.0.2-127.0.0.3"}) 1528 assert self.get()['status'] == 404, 'range' 1529 assert get_ipv6()['status'] == 404, 'range ipv6' 1530 1531 self.route_match({"source": "127.0.0.1-127.0.0.2"}) 1532 assert self.get()['status'] == 200, 'range 2' 1533 assert get_ipv6()['status'] == 404, 'range 2 ipv6' 1534 1535 self.route_match({"source": "127.0.0.0-127.0.0.2"}) 1536 assert self.get()['status'] == 200, 'range 3' 1537 assert get_ipv6()['status'] == 404, 'range 3 ipv6' 1538 1539 self.route_match({"source": "127.0.0.0-127.0.0.1"}) 1540 assert self.get()['status'] == 200, 'range 4' 1541 assert get_ipv6()['status'] == 404, 'range 4 ipv6' 1542 1543 self.route_match({"source": "126.0.0.0-127.0.0.0"}) 1544 assert self.get()['status'] == 404, 'range 5' 1545 assert get_ipv6()['status'] == 404, 'range 5 ipv6' 1546 1547 self.route_match({"source": "126.126.126.126-127.0.0.2"}) 1548 assert self.get()['status'] == 200, 'range 6' 1549 assert get_ipv6()['status'] == 404, 'range 6 ipv6' 1550 1551 def test_routes_source_ipv6(self): 1552 assert 'success' in self.conf( 1553 { 1554 "[::1]:7080": {"pass": "routes"}, 1555 "127.0.0.1:7081": {"pass": "routes"}, 1556 }, 1557 'listeners', 1558 ), 'source listeners configure' 1559 1560 self.route_match({"source": "::1"}) 1561 assert self.get(sock_type='ipv6')['status'] == 200, 'exact' 1562 assert self.get(port=7081)['status'] == 404, 'exact ipv4' 1563 1564 self.route_match({"source": ["::1"]}) 1565 assert self.get(sock_type='ipv6')['status'] == 200, 'exact 2' 1566 assert self.get(port=7081)['status'] == 404, 'exact 2 ipv4' 1567 1568 self.route_match({"source": "!::1"}) 1569 assert self.get(sock_type='ipv6')['status'] == 404, 'exact neg' 1570 assert self.get(port=7081)['status'] == 200, 'exact neg ipv4' 1571 1572 self.route_match({"source": "::2"}) 1573 assert self.get(sock_type='ipv6')['status'] == 404, 'exact 3' 1574 assert self.get(port=7081)['status'] == 404, 'exact 3 ipv4' 1575 1576 self.route_match({"source": "::1-::1"}) 1577 assert self.get(sock_type='ipv6')['status'] == 200, 'range' 1578 assert self.get(port=7081)['status'] == 404, 'range ipv4' 1579 1580 self.route_match({"source": "::2-::2"}) 1581 assert self.get(sock_type='ipv6')['status'] == 404, 'range 2' 1582 assert self.get(port=7081)['status'] == 404, 'range 2 ipv4' 1583 1584 self.route_match({"source": "::2-::3"}) 1585 assert self.get(sock_type='ipv6')['status'] == 404, 'range 3' 1586 assert self.get(port=7081)['status'] == 404, 'range 3 ipv4' 1587 1588 self.route_match({"source": "::1-::2"}) 1589 assert self.get(sock_type='ipv6')['status'] == 200, 'range 4' 1590 assert self.get(port=7081)['status'] == 404, 'range 4 ipv4' 1591 1592 self.route_match({"source": "::0-::2"}) 1593 assert self.get(sock_type='ipv6')['status'] == 200, 'range 5' 1594 assert self.get(port=7081)['status'] == 404, 'range 5 ipv4' 1595 1596 self.route_match({"source": "::0-::1"}) 1597 assert self.get(sock_type='ipv6')['status'] == 200, 'range 6' 1598 assert self.get(port=7081)['status'] == 404, 'range 6 ipv4' 1599 1600 def test_routes_source_cidr(self): 1601 assert 'success' in self.conf( 1602 {"*:7080": {"pass": "routes"}, "[::1]:7081": {"pass": "routes"},}, 1603 'listeners', 1604 ), 'source listeners configure' 1605 1606 def get_ipv6(): 1607 return self.get(sock_type='ipv6', port=7081) 1608 1609 self.route_match({"source": "127.0.0.1/32"}) 1610 assert self.get()['status'] == 200, '32' 1611 assert get_ipv6()['status'] == 404, '32 ipv6' 1612 1613 self.route_match({"source": "127.0.0.0/32"}) 1614 assert self.get()['status'] == 404, '32 2' 1615 assert get_ipv6()['status'] == 404, '32 2 ipv6' 1616 1617 self.route_match({"source": "127.0.0.0/31"}) 1618 assert self.get()['status'] == 200, '31' 1619 assert get_ipv6()['status'] == 404, '31 ipv6' 1620 1621 self.route_match({"source": "0.0.0.0/1"}) 1622 assert self.get()['status'] == 200, '1' 1623 assert get_ipv6()['status'] == 404, '1 ipv6' 1624 1625 self.route_match({"source": "0.0.0.0/0"}) 1626 assert self.get()['status'] == 200, '0' 1627 assert get_ipv6()['status'] == 404, '0 ipv6' 1628 1629 def test_routes_source_cidr_ipv6(self): 1630 assert 'success' in self.conf( 1631 { 1632 "[::1]:7080": {"pass": "routes"}, 1633 "127.0.0.1:7081": {"pass": "routes"}, 1634 }, 1635 'listeners', 1636 ), 'source listeners configure' 1637 1638 self.route_match({"source": "::1/128"}) 1639 assert self.get(sock_type='ipv6')['status'] == 200, '128' 1640 assert self.get(port=7081)['status'] == 404, '128 ipv4' 1641 1642 self.route_match({"source": "::0/128"}) 1643 assert self.get(sock_type='ipv6')['status'] == 404, '128 2' 1644 assert self.get(port=7081)['status'] == 404, '128 ipv4' 1645 1646 self.route_match({"source": "::0/127"}) 1647 assert self.get(sock_type='ipv6')['status'] == 200, '127' 1648 assert self.get(port=7081)['status'] == 404, '127 ipv4' 1649 1650 self.route_match({"source": "::0/32"}) 1651 assert self.get(sock_type='ipv6')['status'] == 200, '32' 1652 assert self.get(port=7081)['status'] == 404, '32 ipv4' 1653 1654 self.route_match({"source": "::0/1"}) 1655 assert self.get(sock_type='ipv6')['status'] == 200, '1' 1656 assert self.get(port=7081)['status'] == 404, '1 ipv4' 1657 1658 self.route_match({"source": "::/0"}) 1659 assert self.get(sock_type='ipv6')['status'] == 200, '0' 1660 assert self.get(port=7081)['status'] == 404, '0 ipv4' 1661 1662 def test_routes_source_unix(self, temp_dir): 1663 addr = temp_dir + '/sock' 1664 1665 assert 'success' in self.conf( 1666 {"unix:" + addr: {"pass": "routes"}}, 'listeners' 1667 ), 'source listeners configure' 1668 1669 self.route_match({"source": "!0.0.0.0/0"}) 1670 assert ( 1671 self.get(sock_type='unix', addr=addr)['status'] == 200 1672 ), 'unix ipv4' 1673 1674 self.route_match({"source": "!::/0"}) 1675 assert ( 1676 self.get(sock_type='unix', addr=addr)['status'] == 200 1677 ), 'unix ipv6' 1678 1679 def test_routes_match_source(self): 1680 self.route_match({"source": "::"}) 1681 self.route_match( 1682 { 1683 "source": [ 1684 "127.0.0.1", 1685 "192.168.0.10:8080", 1686 "192.168.0.11:8080-8090", 1687 ] 1688 } 1689 ) 1690 self.route_match( 1691 { 1692 "source": [ 1693 "10.0.0.0/8", 1694 "10.0.0.0/7:1000", 1695 "10.0.0.0/32:8080-8090", 1696 ] 1697 } 1698 ) 1699 self.route_match( 1700 { 1701 "source": [ 1702 "10.0.0.0-10.0.0.1", 1703 "10.0.0.0-11.0.0.0:1000", 1704 "127.0.0.0-127.0.0.255:8080-8090", 1705 ] 1706 } 1707 ) 1708 self.route_match( 1709 {"source": ["2001::", "[2002::]:8000", "[2003::]:8080-8090"]} 1710 ) 1711 self.route_match( 1712 { 1713 "source": [ 1714 "2001::-200f:ffff:ffff:ffff:ffff:ffff:ffff:ffff", 1715 "[fe08::-feff::]:8000", 1716 "[fff0::-fff0::10]:8080-8090", 1717 ] 1718 } 1719 ) 1720 self.route_match( 1721 { 1722 "source": [ 1723 "2001::/16", 1724 "[0ff::/64]:8000", 1725 "[fff0:abcd:ffff:ffff:ffff::/128]:8080-8090", 1726 ] 1727 } 1728 ) 1729 self.route_match({"source": "*:0-65535"}) 1730 assert self.get()['status'] == 200, 'source any' 1731 1732 def test_routes_match_source_invalid(self): 1733 self.route_match_invalid({"source": "127"}) 1734 self.route_match_invalid({"source": "256.0.0.1"}) 1735 self.route_match_invalid({"source": "127.0.0."}) 1736 self.route_match_invalid({"source": " 127.0.0.1"}) 1737 self.route_match_invalid({"source": "127.0.0.1:"}) 1738 self.route_match_invalid({"source": "127.0.0.1/"}) 1739 self.route_match_invalid({"source": "11.0.0.0/33"}) 1740 self.route_match_invalid({"source": "11.0.0.0/65536"}) 1741 self.route_match_invalid({"source": "11.0.0.0-10.0.0.0"}) 1742 self.route_match_invalid({"source": "11.0.0.0:3000-2000"}) 1743 self.route_match_invalid({"source": ["11.0.0.0:3000-2000"]}) 1744 self.route_match_invalid({"source": "[2001::]:3000-2000"}) 1745 self.route_match_invalid({"source": "2001::-2000::"}) 1746 self.route_match_invalid({"source": "2001::/129"}) 1747 self.route_match_invalid({"source": "::FFFFF"}) 1748 self.route_match_invalid({"source": "[::1]:"}) 1749 self.route_match_invalid({"source": "[:::]:7080"}) 1750 self.route_match_invalid({"source": "*:"}) 1751 self.route_match_invalid({"source": "*:1-a"}) 1752 self.route_match_invalid({"source": "*:65536"}) 1753
| 1# -*- coding: utf-8 -*- 2import pytest 3 4from unit.applications.proto import TestApplicationProto 5from unit.option import option 6 7 8class TestRouting(TestApplicationProto): 9 prerequisites = {'modules': {'python': 'any'}} 10 11 def setup_method(self): 12 assert 'success' in self.conf( 13 { 14 "listeners": {"*:7080": {"pass": "routes"}}, 15 "routes": [ 16 {"match": {"method": "GET"}, "action": {"return": 200},} 17 ], 18 "applications": {}, 19 } 20 ), 'routing configure' 21 22 def route(self, route): 23 return self.conf([route], 'routes') 24 25 def route_match(self, match): 26 assert 'success' in self.route( 27 {"match": match, "action": {"return": 200}} 28 ), 'route match configure' 29 30 def route_match_invalid(self, match): 31 assert 'error' in self.route( 32 {"match": match, "action": {"return": 200}} 33 ), 'route match configure invalid' 34 35 def host(self, host, status): 36 assert ( 37 self.get(headers={'Host': host, 'Connection': 'close'})['status'] 38 == status 39 ), 'match host' 40 41 def cookie(self, cookie, status): 42 assert ( 43 self.get( 44 headers={ 45 'Host': 'localhost', 46 'Cookie': cookie, 47 'Connection': 'close', 48 }, 49 )['status'] 50 == status 51 ), 'match cookie' 52 53 def test_routes_match_method_positive(self): 54 assert self.get()['status'] == 200, 'GET' 55 assert self.post()['status'] == 404, 'POST' 56 57 def test_routes_match_method_positive_many(self): 58 self.route_match({"method": ["GET", "POST"]}) 59 60 assert self.get()['status'] == 200, 'GET' 61 assert self.post()['status'] == 200, 'POST' 62 assert self.delete()['status'] == 404, 'DELETE' 63 64 def test_routes_match_method_negative(self): 65 self.route_match({"method": "!GET"}) 66 67 assert self.get()['status'] == 404, 'GET' 68 assert self.post()['status'] == 200, 'POST' 69 70 def test_routes_match_method_negative_many(self): 71 self.route_match({"method": ["!GET", "!POST"]}) 72 73 assert self.get()['status'] == 404, 'GET' 74 assert self.post()['status'] == 404, 'POST' 75 assert self.delete()['status'] == 200, 'DELETE' 76 77 def test_routes_match_method_wildcard_left(self): 78 self.route_match({"method": "*ET"}) 79 80 assert self.get()['status'] == 200, 'GET' 81 assert self.post()['status'] == 404, 'POST' 82 83 def test_routes_match_method_wildcard_right(self): 84 self.route_match({"method": "GE*"}) 85 86 assert self.get()['status'] == 200, 'GET' 87 assert self.post()['status'] == 404, 'POST' 88 89 def test_routes_match_method_wildcard_left_right(self): 90 self.route_match({"method": "*GET*"}) 91 92 assert self.get()['status'] == 200, 'GET' 93 assert self.post()['status'] == 404, 'POST' 94 95 def test_routes_match_method_wildcard(self): 96 self.route_match({"method": "*"}) 97 98 assert self.get()['status'] == 200, 'GET' 99 100 def test_routes_match_invalid(self): 101 self.route_match_invalid({"method": "**"}) 102 103 def test_routes_match_valid(self): 104 self.route_match({"method": "blah*"}) 105 self.route_match({"host": "*blah*blah"}) 106 self.route_match({"host": "blah*blah*blah"}) 107 self.route_match({"host": "blah*blah*"}) 108 109 def test_routes_match_empty_exact(self): 110 self.route_match({"uri": ""}) 111 assert self.get()['status'] == 404 112 113 self.route_match({"uri": "/"}) 114 assert self.get()['status'] == 200 115 assert self.get(url='/blah')['status'] == 404 116 117 def test_routes_match_negative(self): 118 self.route_match({"uri": "!"}) 119 assert self.get()['status'] == 200 120 121 self.route_match({"uri": "!*"}) 122 assert self.get()['status'] == 404 123 124 self.route_match({"uri": "!/"}) 125 assert self.get()['status'] == 404 126 assert self.get(url='/blah')['status'] == 200 127 128 self.route_match({"uri": "!*blah"}) 129 assert self.get()['status'] == 200 130 assert self.get(url='/bla')['status'] == 200 131 assert self.get(url='/blah')['status'] == 404 132 assert self.get(url='/blah1')['status'] == 200 133 134 self.route_match({"uri": "!/blah*1*"}) 135 assert self.get()['status'] == 200 136 assert self.get(url='/blah')['status'] == 200 137 assert self.get(url='/blah1')['status'] == 404 138 assert self.get(url='/blah12')['status'] == 404 139 assert self.get(url='/blah2')['status'] == 200 140 141 def test_routes_match_wildcard_middle(self): 142 self.route_match({"host": "ex*le"}) 143 144 self.host('example', 200) 145 self.host('www.example', 404) 146 self.host('example.com', 404) 147 self.host('exampl', 404) 148 149 def test_routes_match_method_case_insensitive(self): 150 self.route_match({"method": "get"}) 151 152 assert self.get()['status'] == 200, 'GET' 153 154 def test_routes_match_wildcard_left_case_insensitive(self): 155 self.route_match({"method": "*get"}) 156 assert self.get()['status'] == 200, 'GET' 157 158 self.route_match({"method": "*et"}) 159 assert self.get()['status'] == 200, 'GET' 160 161 def test_routes_match_wildcard_middle_case_insensitive(self): 162 self.route_match({"method": "g*t"}) 163 164 assert self.get()['status'] == 200, 'GET' 165 166 def test_routes_match_wildcard_right_case_insensitive(self): 167 self.route_match({"method": "get*"}) 168 assert self.get()['status'] == 200, 'GET' 169 170 self.route_match({"method": "ge*"}) 171 assert self.get()['status'] == 200, 'GET' 172 173 def test_routes_match_wildcard_substring_case_insensitive(self): 174 self.route_match({"method": "*et*"}) 175 176 assert self.get()['status'] == 200, 'GET' 177 178 def test_routes_match_wildcard_left_case_sensitive(self): 179 self.route_match({"uri": "*blah"}) 180 181 assert self.get(url='/blah')['status'] == 200, '/blah' 182 assert self.get(url='/BLAH')['status'] == 404, '/BLAH' 183 184 def test_routes_match_wildcard_middle_case_sensitive(self): 185 self.route_match({"uri": "/b*h"}) 186 187 assert self.get(url='/blah')['status'] == 200, '/blah' 188 assert self.get(url='/BLAH')['status'] == 404, '/BLAH' 189 190 def test_route_match_wildcards_ordered(self): 191 self.route_match({"uri": "/a*x*y*"}) 192 193 assert self.get(url='/axy')['status'] == 200, '/axy' 194 assert self.get(url='/ayx')['status'] == 404, '/ayx' 195 196 def test_route_match_wildcards_adjust_start(self): 197 self.route_match({"uri": "/bla*bla*"}) 198 199 assert self.get(url='/bla_foo')['status'] == 404, '/bla_foo' 200 201 def test_route_match_wildcards_adjust_start_substr(self): 202 self.route_match({"uri": "*bla*bla*"}) 203 204 assert self.get(url='/bla_foo')['status'] == 404, '/bla_foo' 205 206 def test_route_match_wildcards_adjust_end(self): 207 self.route_match({"uri": "/bla*bla"}) 208 209 assert self.get(url='/foo_bla')['status'] == 404, '/foo_bla' 210 211 def test_routes_match_wildcard_right_case_sensitive(self): 212 self.route_match({"uri": "/bla*"}) 213 214 assert self.get(url='/blah')['status'] == 200, '/blah' 215 assert self.get(url='/BLAH')['status'] == 404, '/BLAH' 216 217 def test_routes_match_wildcard_substring_case_sensitive(self): 218 self.route_match({"uri": "*bla*"}) 219 220 assert self.get(url='/blah')['status'] == 200, '/blah' 221 assert self.get(url='/BLAH')['status'] == 404, '/BLAH' 222 223 def test_routes_match_many_wildcard_substrings_case_sensitive(self): 224 self.route_match({"uri": "*a*B*c*"}) 225 226 assert self.get(url='/blah-a-B-c-blah')['status'] == 200 227 assert self.get(url='/a-B-c')['status'] == 200 228 assert self.get(url='/aBc')['status'] == 200 229 assert self.get(url='/aBCaBbc')['status'] == 200 230 assert self.get(url='/ABc')['status'] == 404 231 232 def test_routes_empty_regex(self): 233 if not option.available['modules']['regex']: 234 pytest.skip('requires regex') 235 236 self.route_match({"uri": "~"}) 237 assert self.get(url='/')['status'] == 200, 'empty regexp' 238 assert self.get(url='/anything')['status'] == 200, '/anything' 239 240 self.route_match({"uri": "!~"}) 241 assert self.get(url='/')['status'] == 404, 'empty regexp 2' 242 assert self.get(url='/nothing')['status'] == 404, '/nothing' 243 244 def test_routes_bad_regex(self): 245 if not option.available['modules']['regex']: 246 pytest.skip('requires regex') 247 248 assert 'error' in self.route( 249 {"match": {"uri": "~/bl[ah"}, "action": {"return": 200}} 250 ), 'bad regex' 251 252 status = self.route( 253 {"match": {"uri": "~(?R)?z"}, "action": {"return": 200}} 254 ) 255 if 'error' not in status: 256 assert self.get(url='/nothing_z')['status'] == 500, '/nothing_z' 257 258 status = self.route( 259 {"match": {"uri": "~((?1)?z)"}, "action": {"return": 200}} 260 ) 261 if 'error' not in status: 262 assert self.get(url='/nothing_z')['status'] == 500, '/nothing_z' 263 264 def test_routes_match_regex_case_sensitive(self): 265 if not option.available['modules']['regex']: 266 pytest.skip('requires regex') 267 268 self.route_match({"uri": "~/bl[ah]"}) 269 270 assert self.get(url='/rlah')['status'] == 404, '/rlah' 271 assert self.get(url='/blah')['status'] == 200, '/blah' 272 assert self.get(url='/blh')['status'] == 200, '/blh' 273 assert self.get(url='/BLAH')['status'] == 404, '/BLAH' 274 275 def test_routes_match_regex_negative_case_sensitive(self): 276 if not option.available['modules']['regex']: 277 pytest.skip('requires regex') 278 279 self.route_match({"uri": "!~/bl[ah]"}) 280 281 assert self.get(url='/rlah')['status'] == 200, '/rlah' 282 assert self.get(url='/blah')['status'] == 404, '/blah' 283 assert self.get(url='/blh')['status'] == 404, '/blh' 284 assert self.get(url='/BLAH')['status'] == 200, '/BLAH' 285 286 def test_routes_pass_encode(self): 287 def check_pass(path, name): 288 assert 'success' in self.conf( 289 { 290 "listeners": {"*:7080": {"pass": "applications/" + path}}, 291 "applications": { 292 name: { 293 "type": "python", 294 "processes": {"spare": 0}, 295 "path": option.test_dir + '/python/empty', 296 "working_directory": option.test_dir 297 + '/python/empty', 298 "module": "wsgi", 299 } 300 }, 301 } 302 ) 303 304 assert self.get()['status'] == 200 305 306 check_pass("%25", "%") 307 check_pass("blah%2Fblah", "blah/blah") 308 check_pass("%2Fblah%2F%2Fblah%2F", "/blah//blah/") 309 check_pass("%20blah%252Fblah%7E", " blah%2Fblah~") 310 311 def check_pass_error(path, name): 312 assert 'error' in self.conf( 313 { 314 "listeners": {"*:7080": {"pass": "applications/" + path}}, 315 "applications": { 316 name: { 317 "type": "python", 318 "processes": {"spare": 0}, 319 "path": option.test_dir + '/python/empty', 320 "working_directory": option.test_dir 321 + '/python/empty', 322 "module": "wsgi", 323 } 324 }, 325 } 326 ) 327 328 check_pass_error("%", "%") 329 check_pass_error("%1", "%1") 330 331 def test_routes_absent(self): 332 assert 'success' in self.conf( 333 { 334 "listeners": {"*:7081": {"pass": "applications/empty"}}, 335 "applications": { 336 "empty": { 337 "type": "python", 338 "processes": {"spare": 0}, 339 "path": option.test_dir + '/python/empty', 340 "working_directory": option.test_dir + '/python/empty', 341 "module": "wsgi", 342 } 343 }, 344 } 345 ) 346 347 assert self.get(port=7081)['status'] == 200, 'routes absent' 348 349 def test_routes_pass_invalid(self): 350 assert 'error' in self.conf( 351 {"pass": "routes/blah"}, 'listeners/*:7080' 352 ), 'routes invalid' 353 354 def test_route_empty(self): 355 assert 'success' in self.conf( 356 { 357 "listeners": {"*:7080": {"pass": "routes/main"}}, 358 "routes": {"main": []}, 359 "applications": {}, 360 } 361 ), 'route empty configure' 362 363 assert self.get()['status'] == 404, 'route empty' 364 365 def test_routes_route_empty(self): 366 assert 'success' in self.conf( 367 {}, 'listeners' 368 ), 'routes empty listeners configure' 369 370 assert 'success' in self.conf({}, 'routes'), 'routes empty configure' 371 372 def test_routes_route_match_absent(self): 373 assert 'success' in self.conf( 374 [{"action": {"return": 200}}], 'routes' 375 ), 'route match absent configure' 376 377 assert self.get()['status'] == 200, 'route match absent' 378 379 def test_routes_route_action_absent(self, skip_alert): 380 skip_alert(r'failed to apply new conf') 381 382 assert 'error' in self.conf( 383 [{"match": {"method": "GET"}}], 'routes' 384 ), 'route pass absent configure' 385 386 def test_routes_route_pass(self): 387 assert 'success' in self.conf( 388 { 389 "applications": { 390 "app": { 391 "type": "python", 392 "processes": {"spare": 0}, 393 "path": "/app", 394 "module": "wsgi", 395 } 396 }, 397 "upstreams": { 398 "one": { 399 "servers": { 400 "127.0.0.1:7081": {}, 401 "127.0.0.1:7082": {}, 402 }, 403 }, 404 "two": { 405 "servers": { 406 "127.0.0.1:7081": {}, 407 "127.0.0.1:7082": {}, 408 }, 409 }, 410 }, 411 } 412 ) 413 414 assert 'success' in self.conf( 415 [{"action": {"pass": "routes"}}], 'routes' 416 ) 417 assert 'success' in self.conf( 418 [{"action": {"pass": "applications/app"}}], 'routes' 419 ) 420 assert 'success' in self.conf( 421 [{"action": {"pass": "upstreams/one"}}], 'routes' 422 ) 423 424 def test_routes_route_pass_absent(self): 425 assert 'error' in self.conf( 426 [{"match": {"method": "GET"}, "action": {}}], 'routes' 427 ), 'route pass absent configure' 428 429 def test_routes_route_pass_invalid(self): 430 assert 'success' in self.conf( 431 { 432 "applications": { 433 "app": { 434 "type": "python", 435 "processes": {"spare": 0}, 436 "path": "/app", 437 "module": "wsgi", 438 } 439 }, 440 "upstreams": { 441 "one": { 442 "servers": { 443 "127.0.0.1:7081": {}, 444 "127.0.0.1:7082": {}, 445 }, 446 }, 447 "two": { 448 "servers": { 449 "127.0.0.1:7081": {}, 450 "127.0.0.1:7082": {}, 451 }, 452 }, 453 }, 454 } 455 ) 456 457 assert 'error' in self.conf( 458 [{"action": {"pass": "blah"}}], 'routes' 459 ), 'route pass invalid' 460 assert 'error' in self.conf( 461 [{"action": {"pass": "routes/blah"}}], 'routes' 462 ), 'route pass routes invalid' 463 assert 'error' in self.conf( 464 [{"action": {"pass": "applications/blah"}}], 'routes' 465 ), 'route pass applications invalid' 466 assert 'error' in self.conf( 467 [{"action": {"pass": "upstreams/blah"}}], 'routes' 468 ), 'route pass upstreams invalid' 469 470 def test_routes_action_unique(self, temp_dir): 471 assert 'success' in self.conf( 472 { 473 "listeners": { 474 "*:7080": {"pass": "routes"}, 475 "*:7081": {"pass": "applications/app"}, 476 }, 477 "routes": [{"action": {"proxy": "http://127.0.0.1:7081"}}], 478 "applications": { 479 "app": { 480 "type": "python", 481 "processes": {"spare": 0}, 482 "path": "/app", 483 "module": "wsgi", 484 } 485 }, 486 } 487 ) 488 489 assert 'error' in self.conf( 490 {"proxy": "http://127.0.0.1:7081", "share": temp_dir}, 491 'routes/0/action', 492 ), 'proxy share' 493 assert 'error' in self.conf( 494 {"proxy": "http://127.0.0.1:7081", "pass": "applications/app",}, 495 'routes/0/action', 496 ), 'proxy pass' 497 assert 'error' in self.conf( 498 {"share": temp_dir, "pass": "applications/app"}, 'routes/0/action', 499 ), 'share pass' 500 501 def test_routes_rules_two(self): 502 assert 'success' in self.conf( 503 [ 504 {"match": {"method": "GET"}, "action": {"return": 200}}, 505 {"match": {"method": "POST"}, "action": {"return": 201}}, 506 ], 507 'routes', 508 ), 'rules two configure' 509 510 assert self.get()['status'] == 200, 'rules two match first' 511 assert self.post()['status'] == 201, 'rules two match second' 512 513 def test_routes_two(self): 514 assert 'success' in self.conf( 515 { 516 "listeners": {"*:7080": {"pass": "routes/first"}}, 517 "routes": { 518 "first": [ 519 { 520 "match": {"method": "GET"}, 521 "action": {"pass": "routes/second"}, 522 } 523 ], 524 "second": [ 525 { 526 "match": {"host": "localhost"}, 527 "action": {"return": 200}, 528 } 529 ], 530 }, 531 "applications": {}, 532 } 533 ), 'routes two configure' 534 535 assert self.get()['status'] == 200, 'routes two' 536 537 def test_routes_match_host_positive(self): 538 self.route_match({"host": "localhost"}) 539 540 assert self.get()['status'] == 200, 'localhost' 541 self.host('localhost.', 200) 542 self.host('localhost.', 200) 543 self.host('.localhost', 404) 544 self.host('www.localhost', 404) 545 self.host('localhost1', 404) 546 547 @pytest.mark.skip('not yet') 548 def test_routes_match_host_absent(self): 549 self.route_match({"host": "localhost"}) 550 551 assert ( 552 self.get(headers={'Connection': 'close'})['status'] == 400 553 ), 'match host absent' 554 555 def test_routes_match_host_ipv4(self): 556 self.route_match({"host": "127.0.0.1"}) 557 558 self.host('127.0.0.1', 200) 559 self.host('127.0.0.1:7080', 200) 560 561 def test_routes_match_host_ipv6(self): 562 self.route_match({"host": "[::1]"}) 563 564 self.host('[::1]', 200) 565 self.host('[::1]:7080', 200) 566 567 def test_routes_match_host_positive_many(self): 568 self.route_match({"host": ["localhost", "example.com"]}) 569 570 assert self.get()['status'] == 200, 'localhost' 571 self.host('example.com', 200) 572 573 def test_routes_match_host_positive_and_negative(self): 574 self.route_match({"host": ["*example.com", "!www.example.com"]}) 575 576 assert self.get()['status'] == 404, 'localhost' 577 self.host('example.com', 200) 578 self.host('www.example.com', 404) 579 self.host('!www.example.com', 200) 580 581 def test_routes_match_host_positive_and_negative_wildcard(self): 582 self.route_match({"host": ["*example*", "!www.example*"]}) 583 584 self.host('example.com', 200) 585 self.host('www.example.com', 404) 586 587 def test_routes_match_host_case_insensitive(self): 588 self.route_match({"host": "Example.com"}) 589 590 self.host('example.com', 200) 591 self.host('EXAMPLE.COM', 200) 592 593 def test_routes_match_host_port(self): 594 self.route_match({"host": "example.com"}) 595 596 self.host('example.com:7080', 200) 597 598 def test_routes_match_host_empty(self): 599 self.route_match({"host": ""}) 600 601 self.host('', 200) 602 assert ( 603 self.get(http_10=True, headers={})['status'] == 200 604 ), 'match host empty 2' 605 assert self.get()['status'] == 404, 'match host empty 3' 606 607 def test_routes_match_uri_positive(self): 608 self.route_match({"uri": ["/blah", "/slash/"]}) 609 610 assert self.get()['status'] == 404, '/' 611 assert self.get(url='/blah')['status'] == 200, '/blah' 612 assert self.get(url='/blah#foo')['status'] == 200, '/blah#foo' 613 assert self.get(url='/blah?var')['status'] == 200, '/blah?var' 614 assert self.get(url='//blah')['status'] == 200, '//blah' 615 assert self.get(url='/slash/foo/../')['status'] == 200, 'relative' 616 assert self.get(url='/slash/./')['status'] == 200, '/slash/./' 617 assert self.get(url='/slash//.//')['status'] == 200, 'adjacent slashes' 618 assert self.get(url='/%')['status'] == 400, 'percent' 619 assert self.get(url='/%1')['status'] == 400, 'percent digit' 620 assert self.get(url='/%A')['status'] == 400, 'percent letter' 621 assert self.get(url='/slash/.?args')['status'] == 200, 'dot args' 622 assert self.get(url='/slash/.#frag')['status'] == 200, 'dot frag' 623 assert ( 624 self.get(url='/slash/foo/..?args')['status'] == 200 625 ), 'dot dot args' 626 assert ( 627 self.get(url='/slash/foo/..#frag')['status'] == 200 628 ), 'dot dot frag' 629 assert self.get(url='/slash/.')['status'] == 200, 'trailing dot' 630 assert ( 631 self.get(url='/slash/foo/..')['status'] == 200 632 ), 'trailing dot dot' 633 634 def test_routes_match_uri_case_sensitive(self): 635 self.route_match({"uri": "/BLAH"}) 636 637 assert self.get(url='/blah')['status'] == 404, '/blah' 638 assert self.get(url='/BlaH')['status'] == 404, '/BlaH' 639 assert self.get(url='/BLAH')['status'] == 200, '/BLAH' 640 641 def test_routes_match_uri_normalize(self): 642 self.route_match({"uri": "/blah"}) 643 644 assert self.get(url='/%62%6c%61%68')['status'] == 200, 'normalize' 645 646 def test_routes_match_empty_array(self): 647 self.route_match({"uri": []}) 648 649 assert self.get(url='/blah')['status'] == 200, 'empty array' 650 651 def test_routes_reconfigure(self): 652 assert 'success' in self.conf([], 'routes'), 'redefine' 653 assert self.get()['status'] == 404, 'redefine request' 654 655 assert 'success' in self.conf( 656 [{"action": {"return": 200}}], 'routes' 657 ), 'redefine 2' 658 assert self.get()['status'] == 200, 'redefine request 2' 659 660 assert 'success' in self.conf([], 'routes'), 'redefine 3' 661 assert self.get()['status'] == 404, 'redefine request 3' 662 663 assert 'success' in self.conf( 664 { 665 "listeners": {"*:7080": {"pass": "routes/main"}}, 666 "routes": {"main": [{"action": {"return": 200}}]}, 667 "applications": {}, 668 } 669 ), 'redefine 4' 670 assert self.get()['status'] == 200, 'redefine request 4' 671 672 assert 'success' in self.conf_delete('routes/main/0'), 'redefine 5' 673 assert self.get()['status'] == 404, 'redefine request 5' 674 675 assert 'success' in self.conf_post( 676 {"action": {"return": 200}}, 'routes/main' 677 ), 'redefine 6' 678 assert self.get()['status'] == 200, 'redefine request 6' 679 680 assert 'error' in self.conf( 681 {"action": {"return": 200}}, 'routes/main/2' 682 ), 'redefine 7' 683 assert 'success' in self.conf( 684 {"action": {"return": 201}}, 'routes/main/1' 685 ), 'redefine 8' 686 687 assert len(self.conf_get('routes/main')) == 2, 'redefine conf 8' 688 assert self.get()['status'] == 200, 'redefine request 8' 689 690 def test_routes_edit(self): 691 self.route_match({"method": "GET"}) 692 693 assert self.get()['status'] == 200, 'routes edit GET' 694 assert self.post()['status'] == 404, 'routes edit POST' 695 696 assert 'success' in self.conf_post( 697 {"match": {"method": "POST"}, "action": {"return": 200}}, 'routes', 698 ), 'routes edit configure 2' 699 assert 'GET' == self.conf_get( 700 'routes/0/match/method' 701 ), 'routes edit configure 2 check' 702 assert 'POST' == self.conf_get( 703 'routes/1/match/method' 704 ), 'routes edit configure 2 check 2' 705 706 assert self.get()['status'] == 200, 'routes edit GET 2' 707 assert self.post()['status'] == 200, 'routes edit POST 2' 708 709 assert 'success' in self.conf_delete( 710 'routes/0' 711 ), 'routes edit configure 3' 712 713 assert self.get()['status'] == 404, 'routes edit GET 3' 714 assert self.post()['status'] == 200, 'routes edit POST 3' 715 716 assert 'error' in self.conf_delete( 717 'routes/1' 718 ), 'routes edit configure invalid' 719 assert 'error' in self.conf_delete( 720 'routes/-1' 721 ), 'routes edit configure invalid 2' 722 assert 'error' in self.conf_delete( 723 'routes/blah' 724 ), 'routes edit configure invalid 3' 725 726 assert self.get()['status'] == 404, 'routes edit GET 4' 727 assert self.post()['status'] == 200, 'routes edit POST 4' 728 729 assert 'success' in self.conf_delete( 730 'routes/0' 731 ), 'routes edit configure 5' 732 733 assert self.get()['status'] == 404, 'routes edit GET 5' 734 assert self.post()['status'] == 404, 'routes edit POST 5' 735 736 assert 'success' in self.conf_post( 737 {"match": {"method": "POST"}, "action": {"return": 200}}, 'routes', 738 ), 'routes edit configure 6' 739 740 assert self.get()['status'] == 404, 'routes edit GET 6' 741 assert self.post()['status'] == 200, 'routes edit POST 6' 742 743 assert 'success' in self.conf( 744 { 745 "listeners": {"*:7080": {"pass": "routes/main"}}, 746 "routes": {"main": [{"action": {"return": 200}}]}, 747 "applications": {}, 748 } 749 ), 'route edit configure 7' 750 751 assert 'error' in self.conf_delete( 752 'routes/0' 753 ), 'routes edit configure invalid 4' 754 assert 'error' in self.conf_delete( 755 'routes/main' 756 ), 'routes edit configure invalid 5' 757 758 assert self.get()['status'] == 200, 'routes edit GET 7' 759 760 assert 'success' in self.conf_delete( 761 'listeners/*:7080' 762 ), 'route edit configure 8' 763 assert 'success' in self.conf_delete( 764 'routes/main' 765 ), 'route edit configure 9' 766 767 def test_match_edit(self, skip_alert): 768 skip_alert(r'failed to apply new conf') 769 770 self.route_match({"method": ["GET", "POST"]}) 771 772 assert self.get()['status'] == 200, 'match edit GET' 773 assert self.post()['status'] == 200, 'match edit POST' 774 assert self.put()['status'] == 404, 'match edit PUT' 775 776 assert 'success' in self.conf_post( 777 '\"PUT\"', 'routes/0/match/method' 778 ), 'match edit configure 2' 779 assert ['GET', 'POST', 'PUT'] == self.conf_get( 780 'routes/0/match/method' 781 ), 'match edit configure 2 check' 782 783 assert self.get()['status'] == 200, 'match edit GET 2' 784 assert self.post()['status'] == 200, 'match edit POST 2' 785 assert self.put()['status'] == 200, 'match edit PUT 2' 786 787 assert 'success' in self.conf_delete( 788 'routes/0/match/method/1' 789 ), 'match edit configure 3' 790 assert ['GET', 'PUT'] == self.conf_get( 791 'routes/0/match/method' 792 ), 'match edit configure 3 check' 793 794 assert self.get()['status'] == 200, 'match edit GET 3' 795 assert self.post()['status'] == 404, 'match edit POST 3' 796 assert self.put()['status'] == 200, 'match edit PUT 3' 797 798 assert 'success' in self.conf_delete( 799 'routes/0/match/method/1' 800 ), 'match edit configure 4' 801 assert ['GET'] == self.conf_get( 802 'routes/0/match/method' 803 ), 'match edit configure 4 check' 804 805 assert self.get()['status'] == 200, 'match edit GET 4' 806 assert self.post()['status'] == 404, 'match edit POST 4' 807 assert self.put()['status'] == 404, 'match edit PUT 4' 808 809 assert 'error' in self.conf_delete( 810 'routes/0/match/method/1' 811 ), 'match edit configure invalid' 812 assert 'error' in self.conf_delete( 813 'routes/0/match/method/-1' 814 ), 'match edit configure invalid 2' 815 assert 'error' in self.conf_delete( 816 'routes/0/match/method/blah' 817 ), 'match edit configure invalid 3' 818 assert ['GET'] == self.conf_get( 819 'routes/0/match/method' 820 ), 'match edit configure 5 check' 821 822 assert self.get()['status'] == 200, 'match edit GET 5' 823 assert self.post()['status'] == 404, 'match edit POST 5' 824 assert self.put()['status'] == 404, 'match edit PUT 5' 825 826 assert 'success' in self.conf_delete( 827 'routes/0/match/method/0' 828 ), 'match edit configure 6' 829 assert [] == self.conf_get( 830 'routes/0/match/method' 831 ), 'match edit configure 6 check' 832 833 assert self.get()['status'] == 200, 'match edit GET 6' 834 assert self.post()['status'] == 200, 'match edit POST 6' 835 assert self.put()['status'] == 200, 'match edit PUT 6' 836 837 assert 'success' in self.conf( 838 '"GET"', 'routes/0/match/method' 839 ), 'match edit configure 7' 840 841 assert self.get()['status'] == 200, 'match edit GET 7' 842 assert self.post()['status'] == 404, 'match edit POST 7' 843 assert self.put()['status'] == 404, 'match edit PUT 7' 844 845 assert 'error' in self.conf_delete( 846 'routes/0/match/method/0' 847 ), 'match edit configure invalid 5' 848 assert 'error' in self.conf( 849 {}, 'routes/0/action' 850 ), 'match edit configure invalid 6' 851 852 assert 'success' in self.conf( 853 {}, 'routes/0/match' 854 ), 'match edit configure 8' 855 856 assert self.get()['status'] == 200, 'match edit GET 8' 857 858 def test_routes_match_rules(self): 859 self.route_match({"method": "GET", "host": "localhost", "uri": "/"}) 860 861 assert self.get()['status'] == 200, 'routes match rules' 862 863 def test_routes_loop(self): 864 assert 'success' in self.route( 865 {"match": {"uri": "/"}, "action": {"pass": "routes"}} 866 ), 'routes loop configure' 867 868 assert self.get()['status'] == 500, 'routes loop' 869 870 def test_routes_match_headers(self): 871 self.route_match({"headers": {"host": "localhost"}}) 872 873 assert self.get()['status'] == 200, 'match headers' 874 self.host('Localhost', 200) 875 self.host('localhost.com', 404) 876 self.host('llocalhost', 404) 877 self.host('host', 404) 878 879 def test_routes_match_headers_multiple(self): 880 self.route_match({"headers": {"host": "localhost", "x-blah": "test"}}) 881 882 assert self.get()['status'] == 404, 'match headers multiple' 883 assert ( 884 self.get( 885 headers={ 886 "Host": "localhost", 887 "X-blah": "test", 888 "Connection": "close", 889 } 890 )['status'] 891 == 200 892 ), 'match headers multiple 2' 893 894 assert ( 895 self.get( 896 headers={ 897 "Host": "localhost", 898 "X-blah": "", 899 "Connection": "close", 900 } 901 )['status'] 902 == 404 903 ), 'match headers multiple 3' 904 905 def test_routes_match_headers_multiple_values(self): 906 self.route_match({"headers": {"x-blah": "test"}}) 907 908 assert ( 909 self.get( 910 headers={ 911 "Host": "localhost", 912 "X-blah": ["test", "test", "test"], 913 "Connection": "close", 914 } 915 )['status'] 916 == 200 917 ), 'match headers multiple values' 918 assert ( 919 self.get( 920 headers={ 921 "Host": "localhost", 922 "X-blah": ["test", "blah", "test"], 923 "Connection": "close", 924 } 925 )['status'] 926 == 404 927 ), 'match headers multiple values 2' 928 assert ( 929 self.get( 930 headers={ 931 "Host": "localhost", 932 "X-blah": ["test", "", "test"], 933 "Connection": "close", 934 } 935 )['status'] 936 == 404 937 ), 'match headers multiple values 3' 938 939 def test_routes_match_headers_multiple_rules(self): 940 self.route_match({"headers": {"x-blah": ["test", "blah"]}}) 941 942 assert self.get()['status'] == 404, 'match headers multiple rules' 943 assert ( 944 self.get( 945 headers={ 946 "Host": "localhost", 947 "X-blah": "test", 948 "Connection": "close", 949 } 950 )['status'] 951 == 200 952 ), 'match headers multiple rules 2' 953 assert ( 954 self.get( 955 headers={ 956 "Host": "localhost", 957 "X-blah": "blah", 958 "Connection": "close", 959 } 960 )['status'] 961 == 200 962 ), 'match headers multiple rules 3' 963 assert ( 964 self.get( 965 headers={ 966 "Host": "localhost", 967 "X-blah": ["test", "blah", "test"], 968 "Connection": "close", 969 } 970 )['status'] 971 == 200 972 ), 'match headers multiple rules 4' 973 974 assert ( 975 self.get( 976 headers={ 977 "Host": "localhost", 978 "X-blah": ["blah", ""], 979 "Connection": "close", 980 } 981 )['status'] 982 == 404 983 ), 'match headers multiple rules 5' 984 985 def test_routes_match_headers_case_insensitive(self): 986 self.route_match({"headers": {"X-BLAH": "TEST"}}) 987 988 assert ( 989 self.get( 990 headers={ 991 "Host": "localhost", 992 "x-blah": "test", 993 "Connection": "close", 994 } 995 )['status'] 996 == 200 997 ), 'match headers case insensitive' 998 999 def test_routes_match_headers_invalid(self): 1000 self.route_match_invalid({"headers": ["blah"]}) 1001 self.route_match_invalid({"headers": {"foo": ["bar", {}]}}) 1002 self.route_match_invalid({"headers": {"": "blah"}}) 1003 1004 def test_routes_match_headers_empty_rule(self): 1005 self.route_match({"headers": {"host": ""}}) 1006 1007 assert self.get()['status'] == 404, 'localhost' 1008 self.host('', 200) 1009 1010 def test_routes_match_headers_empty(self): 1011 self.route_match({"headers": {}}) 1012 assert self.get()['status'] == 200, 'empty' 1013 1014 self.route_match({"headers": []}) 1015 assert self.get()['status'] == 200, 'empty 2' 1016 1017 def test_routes_match_headers_rule_array_empty(self): 1018 self.route_match({"headers": {"blah": []}}) 1019 1020 assert self.get()['status'] == 404, 'array empty' 1021 assert ( 1022 self.get( 1023 headers={ 1024 "Host": "localhost", 1025 "blah": "foo", 1026 "Connection": "close", 1027 } 1028 )['status'] 1029 == 200 1030 ), 'match headers rule array empty 2' 1031 1032 def test_routes_match_headers_array(self): 1033 self.route_match( 1034 { 1035 "headers": [ 1036 {"x-header1": "foo*"}, 1037 {"x-header2": "bar"}, 1038 {"x-header3": ["foo", "bar"]}, 1039 {"x-header1": "bar", "x-header4": "foo"}, 1040 ] 1041 } 1042 ) 1043 1044 def check_headers(hds): 1045 hds = dict({"Host": "localhost", "Connection": "close"}, **hds) 1046 assert ( 1047 self.get(headers=hds)['status'] == 200 1048 ), 'headers array match' 1049 1050 def check_headers_404(hds): 1051 hds = dict({"Host": "localhost", "Connection": "close"}, **hds) 1052 assert ( 1053 self.get(headers=hds)['status'] == 404 1054 ), 'headers array no match' 1055 1056 assert self.get()['status'] == 404, 'match headers array' 1057 check_headers({"x-header1": "foo123"}) 1058 check_headers({"x-header2": "bar"}) 1059 check_headers({"x-header3": "bar"}) 1060 check_headers_404({"x-header1": "bar"}) 1061 check_headers({"x-header1": "bar", "x-header4": "foo"}) 1062 1063 assert 'success' in self.conf_delete( 1064 'routes/0/match/headers/1' 1065 ), 'match headers array configure 2' 1066 1067 check_headers_404({"x-header2": "bar"}) 1068 check_headers({"x-header3": "foo"}) 1069 1070 def test_routes_match_arguments(self): 1071 self.route_match({"arguments": {"foo": "bar"}}) 1072 1073 assert self.get()['status'] == 404, 'args' 1074 assert self.get(url='/?foo=bar')['status'] == 200, 'args 2' 1075 assert self.get(url='/?foo=bar1')['status'] == 404, 'args 3' 1076 assert self.get(url='/?1foo=bar')['status'] == 404, 'args 4' 1077 assert self.get(url='/?Foo=bar')['status'] == 404, 'case' 1078 assert self.get(url='/?foo=Bar')['status'] == 404, 'case 2' 1079 1080 def test_routes_match_arguments_chars(self): 1081 chars = ( 1082 " !\"%23$%25%26'()*%2B,-./0123456789:;<%3D>?@" 1083 "ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~" 1084 ) 1085 1086 chars_enc = "" 1087 for h1 in ["2", "3", "4", "5", "6", "7"]: 1088 for h2 in [ 1089 "0", 1090 "1", 1091 "2", 1092 "3", 1093 "4", 1094 "5", 1095 "6", 1096 "7", 1097 "8", 1098 "9", 1099 "A", 1100 "B", 1101 "C", 1102 "D", 1103 "E", 1104 "F", 1105 ]: 1106 chars_enc += "%" + h1 + h2 1107 chars_enc = chars_enc[:-3] 1108 1109 def check_args(args, query): 1110 self.route_match({"arguments": args}) 1111 assert self.get(url='/?' + query)['status'] == 200 1112 1113 check_args({chars: chars}, chars + '=' + chars) 1114 check_args({chars: chars}, chars + '=' + chars_enc) 1115 check_args({chars: chars}, chars_enc + '=' + chars) 1116 check_args({chars: chars}, chars_enc + '=' + chars_enc) 1117 check_args({chars_enc: chars_enc}, chars + '=' + chars) 1118 check_args({chars_enc: chars_enc}, chars + '=' + chars_enc) 1119 check_args({chars_enc: chars_enc}, chars_enc + '=' + chars) 1120 check_args({chars_enc: chars_enc}, chars_enc + '=' + chars_enc) 1121 1122 def test_routes_match_arguments_empty(self): 1123 self.route_match({"arguments": {}}) 1124 assert self.get()['status'] == 200, 'arguments empty' 1125 1126 self.route_match({"arguments": []}) 1127 assert self.get()['status'] == 200, 'arguments empty 2' 1128 1129 def test_routes_match_arguments_space(self): 1130 self.route_match({"arguments": {"+fo o%20": "%20b+a r"}}) 1131 assert self.get(url='/? fo o = b a r&')['status'] == 200 1132 assert self.get(url='/?+fo+o+=+b+a+r&')['status'] == 200 1133 assert self.get(url='/?%20fo%20o%20=%20b%20a%20r&')['status'] == 200 1134 1135 self.route_match({"arguments": {"%20foo": " bar"}}) 1136 assert self.get(url='/? foo= bar')['status'] == 200 1137 assert self.get(url='/?+foo=+bar')['status'] == 200 1138 assert self.get(url='/?%20foo=%20bar')['status'] == 200 1139 assert self.get(url='/?+foo= bar')['status'] == 200 1140 assert self.get(url='/?%20foo=+bar')['status'] == 200 1141 1142 def test_routes_match_arguments_equal(self): 1143 self.route_match({"arguments": {"=": "="}}) 1144 assert self.get(url='/?%3D=%3D')['status'] == 200 1145 assert self.get(url='/?%3D==')['status'] == 200 1146 assert self.get(url='/?===')['status'] == 404 1147 assert self.get(url='/?%3D%3D%3D')['status'] == 404 1148 assert self.get(url='/?==%3D')['status'] == 404 1149 1150 def test_routes_match_arguments_enc(self): 1151 self.route_match({"arguments": {"Ю": "н"}}) 1152 assert self.get(url='/?%D0%AE=%D0%BD')['status'] == 200 1153 assert self.get(url='/?%d0%ae=%d0%Bd')['status'] == 200 1154 1155 def test_routes_match_arguments_hash(self): 1156 self.route_match({"arguments": {"#": "#"}}) 1157 assert self.get(url='/?%23=%23')['status'] == 200 1158 assert self.get(url='/?%23=%23#')['status'] == 200 1159 assert self.get(url='/?#=#')['status'] == 404 1160 assert self.get(url='/?%23=#')['status'] == 404 1161 1162 def test_routes_match_arguments_wildcard(self): 1163 self.route_match({"arguments": {"foo": "*"}}) 1164 assert self.get(url='/?foo')['status'] == 200 1165 assert self.get(url='/?foo=')['status'] == 200 1166 assert self.get(url='/?foo=blah')['status'] == 200 1167 assert self.get(url='/?blah=foo')['status'] == 404 1168 1169 self.route_match({"arguments": {"foo": "%25*"}}) 1170 assert self.get(url='/?foo=%xx')['status'] == 200 1171 1172 self.route_match({"arguments": {"foo": "%2A*"}}) 1173 assert self.get(url='/?foo=*xx')['status'] == 200 1174 assert self.get(url='/?foo=xx')['status'] == 404 1175 1176 self.route_match({"arguments": {"foo": "*%2A"}}) 1177 assert self.get(url='/?foo=xx*')['status'] == 200 1178 assert self.get(url='/?foo=xx*x')['status'] == 404 1179 1180 self.route_match({"arguments": {"foo": "1*2"}}) 1181 assert self.get(url='/?foo=12')['status'] == 200 1182 assert self.get(url='/?foo=1blah2')['status'] == 200 1183 assert self.get(url='/?foo=1%2A2')['status'] == 200 1184 assert self.get(url='/?foo=x12')['status'] == 404 1185 1186 self.route_match({"arguments": {"foo": "bar*", "%25": "%25"}}) 1187 assert self.get(url='/?foo=barxx&%=%')['status'] == 200 1188 assert self.get(url='/?foo=barxx&x%=%')['status'] == 404 1189 1190 def test_routes_match_arguments_negative(self): 1191 self.route_match({"arguments": {"foo": "!"}}) 1192 assert self.get(url='/?bar')['status'] == 404 1193 assert self.get(url='/?foo')['status'] == 404 1194 assert self.get(url='/?foo=')['status'] == 404 1195 assert self.get(url='/?foo=%25')['status'] == 200 1196 1197 self.route_match({"arguments": {"foo": "!*"}}) 1198 assert self.get(url='/?bar')['status'] == 404 1199 assert self.get(url='/?foo')['status'] == 404 1200 assert self.get(url='/?foo=')['status'] == 404 1201 assert self.get(url='/?foo=blah')['status'] == 404 1202 1203 self.route_match({"arguments": {"foo": "!%25"}}) 1204 assert self.get(url='/?foo=blah')['status'] == 200 1205 assert self.get(url='/?foo=%')['status'] == 404 1206 1207 self.route_match({"arguments": {"foo": "%21blah"}}) 1208 assert self.get(url='/?foo=%21blah')['status'] == 200 1209 assert self.get(url='/?foo=!blah')['status'] == 200 1210 assert self.get(url='/?foo=bar')['status'] == 404 1211 1212 self.route_match({"arguments": {"foo": "!!%21*a"}}) 1213 assert self.get(url='/?foo=blah')['status'] == 200 1214 assert self.get(url='/?foo=!blah')['status'] == 200 1215 assert self.get(url='/?foo=!!a')['status'] == 404 1216 assert self.get(url='/?foo=!!bla')['status'] == 404 1217 1218 def test_routes_match_arguments_percent(self): 1219 self.route_match({"arguments": {"%25": "%25"}}) 1220 assert self.get(url='/?%=%')['status'] == 200 1221 assert self.get(url='/?%25=%25')['status'] == 200 1222 assert self.get(url='/?%25=%')['status'] == 200 1223 1224 self.route_match({"arguments": {"%251": "%252"}}) 1225 assert self.get(url='/?%1=%2')['status'] == 200 1226 assert self.get(url='/?%251=%252')['status'] == 200 1227 assert self.get(url='/?%251=%2')['status'] == 200 1228 1229 self.route_match({"arguments": {"%25%21%251": "%25%24%252"}}) 1230 assert self.get(url='/?%!%1=%$%2')['status'] == 200 1231 assert self.get(url='/?%25!%251=%25$%252')['status'] == 200 1232 assert self.get(url='/?%25!%1=%$%2')['status'] == 200 1233 1234 def test_routes_match_arguments_ampersand(self): 1235 self.route_match({"arguments": {"foo": "&"}}) 1236 assert self.get(url='/?foo=%26')['status'] == 200 1237 assert self.get(url='/?foo=%26&')['status'] == 200 1238 assert self.get(url='/?foo=%26%26')['status'] == 404 1239 assert self.get(url='/?foo=&')['status'] == 404 1240 1241 self.route_match({"arguments": {"&": ""}}) 1242 assert self.get(url='/?%26=')['status'] == 200 1243 assert self.get(url='/?%26=&')['status'] == 200 1244 assert self.get(url='/?%26=%26')['status'] == 404 1245 assert self.get(url='/?&=')['status'] == 404 1246 1247 def test_routes_match_arguments_complex(self): 1248 self.route_match({"arguments": {"foo": ""}}) 1249 1250 assert self.get(url='/?foo')['status'] == 200, 'complex' 1251 assert self.get(url='/?blah=blah&foo=')['status'] == 200, 'complex 2' 1252 assert self.get(url='/?&&&foo&&&')['status'] == 200, 'complex 3' 1253 assert self.get(url='/?foo&foo=bar&foo')['status'] == 404, 'complex 4' 1254 assert self.get(url='/?foo=&foo')['status'] == 200, 'complex 5' 1255 assert self.get(url='/?&=&foo&==&')['status'] == 200, 'complex 6' 1256 assert self.get(url='/?&=&bar&==&')['status'] == 404, 'complex 7' 1257 1258 def test_routes_match_arguments_multiple(self): 1259 self.route_match({"arguments": {"foo": "bar", "blah": "test"}}) 1260 1261 assert self.get()['status'] == 404, 'multiple' 1262 assert ( 1263 self.get(url='/?foo=bar&blah=test')['status'] == 200 1264 ), 'multiple 2' 1265 assert self.get(url='/?foo=bar&blah')['status'] == 404, 'multiple 3' 1266 assert ( 1267 self.get(url='/?foo=bar&blah=tes')['status'] == 404 1268 ), 'multiple 4' 1269 assert ( 1270 self.get(url='/?foo=b%61r&bl%61h=t%65st')['status'] == 200 1271 ), 'multiple 5' 1272 1273 def test_routes_match_arguments_multiple_rules(self): 1274 self.route_match({"arguments": {"foo": ["bar", "blah"]}}) 1275 1276 assert self.get()['status'] == 404, 'rules' 1277 assert self.get(url='/?foo=bar')['status'] == 200, 'rules 2' 1278 assert self.get(url='/?foo=blah')['status'] == 200, 'rules 3' 1279 assert ( 1280 self.get(url='/?foo=blah&foo=bar&foo=blah')['status'] == 200 1281 ), 'rules 4' 1282 assert ( 1283 self.get(url='/?foo=blah&foo=bar&foo=')['status'] == 404 1284 ), 'rules 5' 1285 1286 def test_routes_match_arguments_array(self): 1287 self.route_match( 1288 { 1289 "arguments": [ 1290 {"var1": "val1*"}, 1291 {"var2": "val2"}, 1292 {"var3": ["foo", "bar"]}, 1293 {"var1": "bar", "var4": "foo"}, 1294 ] 1295 } 1296 ) 1297 1298 assert self.get()['status'] == 404, 'arr' 1299 assert self.get(url='/?var1=val123')['status'] == 200, 'arr 2' 1300 assert self.get(url='/?var2=val2')['status'] == 200, 'arr 3' 1301 assert self.get(url='/?var3=bar')['status'] == 200, 'arr 4' 1302 assert self.get(url='/?var1=bar')['status'] == 404, 'arr 5' 1303 assert self.get(url='/?var1=bar&var4=foo')['status'] == 200, 'arr 6' 1304 1305 assert 'success' in self.conf_delete( 1306 'routes/0/match/arguments/1' 1307 ), 'match arguments array configure 2' 1308 1309 assert self.get(url='/?var2=val2')['status'] == 404, 'arr 7' 1310 assert self.get(url='/?var3=foo')['status'] == 200, 'arr 8' 1311 1312 def test_routes_match_arguments_invalid(self): 1313 self.route_match_invalid({"arguments": ["var"]}) 1314 self.route_match_invalid({"arguments": [{"var1": {}}]}) 1315 self.route_match_invalid({"arguments": {"": "bar"}}) 1316 self.route_match_invalid({"arguments": {"foo": "%"}}) 1317 self.route_match_invalid({"arguments": {"foo": "%1G"}}) 1318 self.route_match_invalid({"arguments": {"%": "bar"}}) 1319 self.route_match_invalid({"arguments": {"foo": "%0"}}) 1320 self.route_match_invalid({"arguments": {"foo": "%%1F"}}) 1321 self.route_match_invalid({"arguments": {"%%1F": ""}}) 1322 self.route_match_invalid({"arguments": {"%7%F": ""}}) 1323 1324 def test_routes_match_cookies(self): 1325 self.route_match({"cookies": {"foO": "bar"}}) 1326 1327 assert self.get()['status'] == 404, 'cookie' 1328 self.cookie('foO=bar', 200) 1329 self.cookie('foO=bar;1', 200) 1330 self.cookie(['foO=bar', 'blah=blah'], 200) 1331 self.cookie('foO=bar; blah=blah', 200) 1332 self.cookie('Foo=bar', 404) 1333 self.cookie('foO=Bar', 404) 1334 self.cookie('foO=bar1', 404) 1335 self.cookie('1foO=bar;', 404) 1336 1337 def test_routes_match_cookies_empty(self): 1338 self.route_match({"cookies": {}}) 1339 assert self.get()['status'] == 200, 'cookies empty' 1340 1341 self.route_match({"cookies": []}) 1342 assert self.get()['status'] == 200, 'cookies empty 2' 1343 1344 def test_routes_match_cookies_invalid(self): 1345 self.route_match_invalid({"cookies": ["var"]}) 1346 self.route_match_invalid({"cookies": [{"foo": {}}]}) 1347 1348 def test_routes_match_cookies_multiple(self): 1349 self.route_match({"cookies": {"foo": "bar", "blah": "blah"}}) 1350 1351 assert self.get()['status'] == 404, 'multiple' 1352 self.cookie('foo=bar; blah=blah', 200) 1353 self.cookie(['foo=bar', 'blah=blah'], 200) 1354 self.cookie(['foo=bar; blah', 'blah'], 404) 1355 self.cookie(['foo=bar; blah=test', 'blah=blah'], 404) 1356 1357 def test_routes_match_cookies_multiple_values(self): 1358 self.route_match({"cookies": {"blah": "blah"}}) 1359 1360 self.cookie(['blah=blah', 'blah=blah', 'blah=blah'], 200) 1361 self.cookie(['blah=blah', 'blah=test', 'blah=blah'], 404) 1362 self.cookie(['blah=blah; blah=', 'blah=blah'], 404) 1363 1364 def test_routes_match_cookies_multiple_rules(self): 1365 self.route_match({"cookies": {"blah": ["test", "blah"]}}) 1366 1367 assert self.get()['status'] == 404, 'multiple rules' 1368 self.cookie('blah=test', 200) 1369 self.cookie('blah=blah', 200) 1370 self.cookie(['blah=blah', 'blah=test', 'blah=blah'], 200) 1371 self.cookie(['blah=blah; blah=test', 'blah=blah'], 200) 1372 self.cookie(['blah=blah', 'blah'], 200) # invalid cookie 1373 1374 def test_routes_match_cookies_array(self): 1375 self.route_match( 1376 { 1377 "cookies": [ 1378 {"var1": "val1*"}, 1379 {"var2": "val2"}, 1380 {"var3": ["foo", "bar"]}, 1381 {"var1": "bar", "var4": "foo"}, 1382 ] 1383 } 1384 ) 1385 1386 assert self.get()['status'] == 404, 'cookies array' 1387 self.cookie('var1=val123', 200) 1388 self.cookie('var2=val2', 200) 1389 self.cookie(' var2=val2 ', 200) 1390 self.cookie('var3=bar', 200) 1391 self.cookie('var3=bar;', 200) 1392 self.cookie('var1=bar', 404) 1393 self.cookie('var1=bar; var4=foo;', 200) 1394 self.cookie(['var1=bar', 'var4=foo'], 200) 1395 1396 assert 'success' in self.conf_delete( 1397 'routes/0/match/cookies/1' 1398 ), 'match cookies array configure 2' 1399 1400 self.cookie('var2=val2', 404) 1401 self.cookie('var3=foo', 200) 1402 1403 def test_routes_match_scheme(self): 1404 self.route_match({"scheme": "http"}) 1405 self.route_match({"scheme": "https"}) 1406 self.route_match({"scheme": "HtTp"}) 1407 self.route_match({"scheme": "HtTpS"}) 1408 1409 def test_routes_match_scheme_invalid(self): 1410 self.route_match_invalid({"scheme": ["http"]}) 1411 self.route_match_invalid({"scheme": "ftp"}) 1412 self.route_match_invalid({"scheme": "ws"}) 1413 self.route_match_invalid({"scheme": "*"}) 1414 self.route_match_invalid({"scheme": ""}) 1415 1416 def test_routes_source_port(self): 1417 def sock_port(): 1418 _, sock = self.http(b'', start=True, raw=True, no_recv=True) 1419 port = sock.getsockname()[1] 1420 return (sock, port) 1421 1422 sock, port = sock_port() 1423 sock2, port2 = sock_port() 1424 1425 self.route_match({"source": "127.0.0.1:" + str(port)}) 1426 assert self.get(sock=sock)['status'] == 200, 'exact' 1427 assert self.get(sock=sock2)['status'] == 404, 'exact 2' 1428 1429 sock, port = sock_port() 1430 sock2, port2 = sock_port() 1431 1432 self.route_match({"source": "!127.0.0.1:" + str(port)}) 1433 assert self.get(sock=sock)['status'] == 404, 'negative' 1434 assert self.get(sock=sock2)['status'] == 200, 'negative 2' 1435 1436 sock, port = sock_port() 1437 sock2, port2 = sock_port() 1438 1439 self.route_match({"source": ["*:" + str(port), "!127.0.0.1"]}) 1440 assert self.get(sock=sock)['status'] == 404, 'negative 3' 1441 assert self.get(sock=sock2)['status'] == 404, 'negative 4' 1442 1443 sock, port = sock_port() 1444 sock2, port2 = sock_port() 1445 1446 self.route_match( 1447 {"source": "127.0.0.1:" + str(port) + "-" + str(port)} 1448 ) 1449 assert self.get(sock=sock)['status'] == 200, 'range single' 1450 assert self.get(sock=sock2)['status'] == 404, 'range single 2' 1451 1452 socks = [ 1453 sock_port(), 1454 sock_port(), 1455 sock_port(), 1456 sock_port(), 1457 sock_port(), 1458 ] 1459 socks.sort(key=lambda sock: sock[1]) 1460 1461 self.route_match( 1462 { 1463 "source": "127.0.0.1:" 1464 + str(socks[1][1]) # second port number 1465 + "-" 1466 + str(socks[3][1]) # fourth port number 1467 } 1468 ) 1469 assert self.get(sock=socks[0][0])['status'] == 404, 'range' 1470 assert self.get(sock=socks[1][0])['status'] == 200, 'range 2' 1471 assert self.get(sock=socks[2][0])['status'] == 200, 'range 3' 1472 assert self.get(sock=socks[3][0])['status'] == 200, 'range 4' 1473 assert self.get(sock=socks[4][0])['status'] == 404, 'range 5' 1474 1475 socks = [ 1476 sock_port(), 1477 sock_port(), 1478 sock_port(), 1479 ] 1480 socks.sort(key=lambda sock: sock[1]) 1481 1482 self.route_match( 1483 { 1484 "source": [ 1485 "127.0.0.1:" + str(socks[0][1]), 1486 "127.0.0.1:" + str(socks[2][1]), 1487 ] 1488 } 1489 ) 1490 assert self.get(sock=socks[0][0])['status'] == 200, 'array' 1491 assert self.get(sock=socks[1][0])['status'] == 404, 'array 2' 1492 assert self.get(sock=socks[2][0])['status'] == 200, 'array 3' 1493 1494 def test_routes_source_addr(self): 1495 assert 'success' in self.conf( 1496 {"*:7080": {"pass": "routes"}, "[::1]:7081": {"pass": "routes"},}, 1497 'listeners', 1498 ), 'source listeners configure' 1499 1500 def get_ipv6(): 1501 return self.get(sock_type='ipv6', port=7081) 1502 1503 self.route_match({"source": "127.0.0.1"}) 1504 assert self.get()['status'] == 200, 'exact' 1505 assert get_ipv6()['status'] == 404, 'exact ipv6' 1506 1507 self.route_match({"source": ["127.0.0.1"]}) 1508 assert self.get()['status'] == 200, 'exact 2' 1509 assert get_ipv6()['status'] == 404, 'exact 2 ipv6' 1510 1511 self.route_match({"source": "!127.0.0.1"}) 1512 assert self.get()['status'] == 404, 'exact neg' 1513 assert get_ipv6()['status'] == 200, 'exact neg ipv6' 1514 1515 self.route_match({"source": "127.0.0.2"}) 1516 assert self.get()['status'] == 404, 'exact 3' 1517 assert get_ipv6()['status'] == 404, 'exact 3 ipv6' 1518 1519 self.route_match({"source": "127.0.0.1-127.0.0.1"}) 1520 assert self.get()['status'] == 200, 'range single' 1521 assert get_ipv6()['status'] == 404, 'range single ipv6' 1522 1523 self.route_match({"source": "127.0.0.2-127.0.0.2"}) 1524 assert self.get()['status'] == 404, 'range single 2' 1525 assert get_ipv6()['status'] == 404, 'range single 2 ipv6' 1526 1527 self.route_match({"source": "127.0.0.2-127.0.0.3"}) 1528 assert self.get()['status'] == 404, 'range' 1529 assert get_ipv6()['status'] == 404, 'range ipv6' 1530 1531 self.route_match({"source": "127.0.0.1-127.0.0.2"}) 1532 assert self.get()['status'] == 200, 'range 2' 1533 assert get_ipv6()['status'] == 404, 'range 2 ipv6' 1534 1535 self.route_match({"source": "127.0.0.0-127.0.0.2"}) 1536 assert self.get()['status'] == 200, 'range 3' 1537 assert get_ipv6()['status'] == 404, 'range 3 ipv6' 1538 1539 self.route_match({"source": "127.0.0.0-127.0.0.1"}) 1540 assert self.get()['status'] == 200, 'range 4' 1541 assert get_ipv6()['status'] == 404, 'range 4 ipv6' 1542 1543 self.route_match({"source": "126.0.0.0-127.0.0.0"}) 1544 assert self.get()['status'] == 404, 'range 5' 1545 assert get_ipv6()['status'] == 404, 'range 5 ipv6' 1546 1547 self.route_match({"source": "126.126.126.126-127.0.0.2"}) 1548 assert self.get()['status'] == 200, 'range 6' 1549 assert get_ipv6()['status'] == 404, 'range 6 ipv6' 1550 1551 def test_routes_source_ipv6(self): 1552 assert 'success' in self.conf( 1553 { 1554 "[::1]:7080": {"pass": "routes"}, 1555 "127.0.0.1:7081": {"pass": "routes"}, 1556 }, 1557 'listeners', 1558 ), 'source listeners configure' 1559 1560 self.route_match({"source": "::1"}) 1561 assert self.get(sock_type='ipv6')['status'] == 200, 'exact' 1562 assert self.get(port=7081)['status'] == 404, 'exact ipv4' 1563 1564 self.route_match({"source": ["::1"]}) 1565 assert self.get(sock_type='ipv6')['status'] == 200, 'exact 2' 1566 assert self.get(port=7081)['status'] == 404, 'exact 2 ipv4' 1567 1568 self.route_match({"source": "!::1"}) 1569 assert self.get(sock_type='ipv6')['status'] == 404, 'exact neg' 1570 assert self.get(port=7081)['status'] == 200, 'exact neg ipv4' 1571 1572 self.route_match({"source": "::2"}) 1573 assert self.get(sock_type='ipv6')['status'] == 404, 'exact 3' 1574 assert self.get(port=7081)['status'] == 404, 'exact 3 ipv4' 1575 1576 self.route_match({"source": "::1-::1"}) 1577 assert self.get(sock_type='ipv6')['status'] == 200, 'range' 1578 assert self.get(port=7081)['status'] == 404, 'range ipv4' 1579 1580 self.route_match({"source": "::2-::2"}) 1581 assert self.get(sock_type='ipv6')['status'] == 404, 'range 2' 1582 assert self.get(port=7081)['status'] == 404, 'range 2 ipv4' 1583 1584 self.route_match({"source": "::2-::3"}) 1585 assert self.get(sock_type='ipv6')['status'] == 404, 'range 3' 1586 assert self.get(port=7081)['status'] == 404, 'range 3 ipv4' 1587 1588 self.route_match({"source": "::1-::2"}) 1589 assert self.get(sock_type='ipv6')['status'] == 200, 'range 4' 1590 assert self.get(port=7081)['status'] == 404, 'range 4 ipv4' 1591 1592 self.route_match({"source": "::0-::2"}) 1593 assert self.get(sock_type='ipv6')['status'] == 200, 'range 5' 1594 assert self.get(port=7081)['status'] == 404, 'range 5 ipv4' 1595 1596 self.route_match({"source": "::0-::1"}) 1597 assert self.get(sock_type='ipv6')['status'] == 200, 'range 6' 1598 assert self.get(port=7081)['status'] == 404, 'range 6 ipv4' 1599 1600 def test_routes_source_cidr(self): 1601 assert 'success' in self.conf( 1602 {"*:7080": {"pass": "routes"}, "[::1]:7081": {"pass": "routes"},}, 1603 'listeners', 1604 ), 'source listeners configure' 1605 1606 def get_ipv6(): 1607 return self.get(sock_type='ipv6', port=7081) 1608 1609 self.route_match({"source": "127.0.0.1/32"}) 1610 assert self.get()['status'] == 200, '32' 1611 assert get_ipv6()['status'] == 404, '32 ipv6' 1612 1613 self.route_match({"source": "127.0.0.0/32"}) 1614 assert self.get()['status'] == 404, '32 2' 1615 assert get_ipv6()['status'] == 404, '32 2 ipv6' 1616 1617 self.route_match({"source": "127.0.0.0/31"}) 1618 assert self.get()['status'] == 200, '31' 1619 assert get_ipv6()['status'] == 404, '31 ipv6' 1620 1621 self.route_match({"source": "0.0.0.0/1"}) 1622 assert self.get()['status'] == 200, '1' 1623 assert get_ipv6()['status'] == 404, '1 ipv6' 1624 1625 self.route_match({"source": "0.0.0.0/0"}) 1626 assert self.get()['status'] == 200, '0' 1627 assert get_ipv6()['status'] == 404, '0 ipv6' 1628 1629 def test_routes_source_cidr_ipv6(self): 1630 assert 'success' in self.conf( 1631 { 1632 "[::1]:7080": {"pass": "routes"}, 1633 "127.0.0.1:7081": {"pass": "routes"}, 1634 }, 1635 'listeners', 1636 ), 'source listeners configure' 1637 1638 self.route_match({"source": "::1/128"}) 1639 assert self.get(sock_type='ipv6')['status'] == 200, '128' 1640 assert self.get(port=7081)['status'] == 404, '128 ipv4' 1641 1642 self.route_match({"source": "::0/128"}) 1643 assert self.get(sock_type='ipv6')['status'] == 404, '128 2' 1644 assert self.get(port=7081)['status'] == 404, '128 ipv4' 1645 1646 self.route_match({"source": "::0/127"}) 1647 assert self.get(sock_type='ipv6')['status'] == 200, '127' 1648 assert self.get(port=7081)['status'] == 404, '127 ipv4' 1649 1650 self.route_match({"source": "::0/32"}) 1651 assert self.get(sock_type='ipv6')['status'] == 200, '32' 1652 assert self.get(port=7081)['status'] == 404, '32 ipv4' 1653 1654 self.route_match({"source": "::0/1"}) 1655 assert self.get(sock_type='ipv6')['status'] == 200, '1' 1656 assert self.get(port=7081)['status'] == 404, '1 ipv4' 1657 1658 self.route_match({"source": "::/0"}) 1659 assert self.get(sock_type='ipv6')['status'] == 200, '0' 1660 assert self.get(port=7081)['status'] == 404, '0 ipv4' 1661 1662 def test_routes_source_unix(self, temp_dir): 1663 addr = temp_dir + '/sock' 1664 1665 assert 'success' in self.conf( 1666 {"unix:" + addr: {"pass": "routes"}}, 'listeners' 1667 ), 'source listeners configure' 1668 1669 self.route_match({"source": "!0.0.0.0/0"}) 1670 assert ( 1671 self.get(sock_type='unix', addr=addr)['status'] == 200 1672 ), 'unix ipv4' 1673 1674 self.route_match({"source": "!::/0"}) 1675 assert ( 1676 self.get(sock_type='unix', addr=addr)['status'] == 200 1677 ), 'unix ipv6' 1678 1679 def test_routes_match_source(self): 1680 self.route_match({"source": "::"}) 1681 self.route_match( 1682 { 1683 "source": [ 1684 "127.0.0.1", 1685 "192.168.0.10:8080", 1686 "192.168.0.11:8080-8090", 1687 ] 1688 } 1689 ) 1690 self.route_match( 1691 { 1692 "source": [ 1693 "10.0.0.0/8", 1694 "10.0.0.0/7:1000", 1695 "10.0.0.0/32:8080-8090", 1696 ] 1697 } 1698 ) 1699 self.route_match( 1700 { 1701 "source": [ 1702 "10.0.0.0-10.0.0.1", 1703 "10.0.0.0-11.0.0.0:1000", 1704 "127.0.0.0-127.0.0.255:8080-8090", 1705 ] 1706 } 1707 ) 1708 self.route_match( 1709 {"source": ["2001::", "[2002::]:8000", "[2003::]:8080-8090"]} 1710 ) 1711 self.route_match( 1712 { 1713 "source": [ 1714 "2001::-200f:ffff:ffff:ffff:ffff:ffff:ffff:ffff", 1715 "[fe08::-feff::]:8000", 1716 "[fff0::-fff0::10]:8080-8090", 1717 ] 1718 } 1719 ) 1720 self.route_match( 1721 { 1722 "source": [ 1723 "2001::/16", 1724 "[0ff::/64]:8000", 1725 "[fff0:abcd:ffff:ffff:ffff::/128]:8080-8090", 1726 ] 1727 } 1728 ) 1729 self.route_match({"source": "*:0-65535"}) 1730 assert self.get()['status'] == 200, 'source any' 1731 1732 def test_routes_match_source_invalid(self): 1733 self.route_match_invalid({"source": "127"}) 1734 self.route_match_invalid({"source": "256.0.0.1"}) 1735 self.route_match_invalid({"source": "127.0.0."}) 1736 self.route_match_invalid({"source": " 127.0.0.1"}) 1737 self.route_match_invalid({"source": "127.0.0.1:"}) 1738 self.route_match_invalid({"source": "127.0.0.1/"}) 1739 self.route_match_invalid({"source": "11.0.0.0/33"}) 1740 self.route_match_invalid({"source": "11.0.0.0/65536"}) 1741 self.route_match_invalid({"source": "11.0.0.0-10.0.0.0"}) 1742 self.route_match_invalid({"source": "11.0.0.0:3000-2000"}) 1743 self.route_match_invalid({"source": ["11.0.0.0:3000-2000"]}) 1744 self.route_match_invalid({"source": "[2001::]:3000-2000"}) 1745 self.route_match_invalid({"source": "2001::-2000::"}) 1746 self.route_match_invalid({"source": "2001::/129"}) 1747 self.route_match_invalid({"source": "::FFFFF"}) 1748 self.route_match_invalid({"source": "[::1]:"}) 1749 self.route_match_invalid({"source": "[:::]:7080"}) 1750 self.route_match_invalid({"source": "*:"}) 1751 self.route_match_invalid({"source": "*:1-a"}) 1752 self.route_match_invalid({"source": "*:65536"}) 1753
|