* Inspired by mod_jk's jk_servlet_normalize(). */
| 487 | * Inspired by mod_jk's jk_servlet_normalize(). |
| 488 | */ |
| 489 | AP_DECLARE(int) ap_normalize_path(char *path, unsigned int flags) |
| 490 | { |
| 491 | int ret = 1; |
| 492 | apr_size_t l = 1, w = 1, n; |
| 493 | int decode_unreserved = (flags & AP_NORMALIZE_DECODE_UNRESERVED) != 0; |
| 494 | int merge_slashes = (flags & AP_NORMALIZE_MERGE_SLASHES) != 0; |
| 495 | |
| 496 | if (!AP_IS_SLASH(path[0])) { |
| 497 | /* Besides "OPTIONS *", a request-target should start with '/' |
| 498 | * per RFC 7230 section 5.3, so anything else is invalid. |
| 499 | */ |
| 500 | if (path[0] == '*' && path[1] == '\0') { |
| 501 | return 1; |
| 502 | } |
| 503 | /* However, AP_NORMALIZE_ALLOW_RELATIVE can be used to bypass |
| 504 | * this restriction (e.g. for subrequest file lookups). |
| 505 | */ |
| 506 | if (!(flags & AP_NORMALIZE_ALLOW_RELATIVE) || path[0] == '\0') { |
| 507 | return 0; |
| 508 | } |
| 509 | |
| 510 | l = w = 0; |
| 511 | } |
| 512 | |
| 513 | while (path[l] != '\0') { |
| 514 | /* RFC-3986 section 2.3: |
| 515 | * For consistency, percent-encoded octets in the ranges of |
| 516 | * ALPHA (%41-%5A and %61-%7A), DIGIT (%30-%39), hyphen (%2D), |
| 517 | * period (%2E), underscore (%5F), or tilde (%7E) should [...] |
| 518 | * be decoded to their corresponding unreserved characters by |
| 519 | * URI normalizers. |
| 520 | */ |
| 521 | if (decode_unreserved && path[l] == '%') { |
| 522 | if (apr_isxdigit(path[l + 1]) && apr_isxdigit(path[l + 2])) { |
| 523 | const char c = x2c(&path[l + 1]); |
| 524 | if (TEST_CHAR(c, T_URI_UNRESERVED)) { |
| 525 | /* Replace last char and fall through as the current |
| 526 | * read position */ |
| 527 | l += 2; |
| 528 | path[l] = c; |
| 529 | } |
| 530 | } |
| 531 | else { |
| 532 | /* Invalid encoding */ |
| 533 | ret = 0; |
| 534 | } |
| 535 | } |
| 536 | |
| 537 | if (w == 0 || AP_IS_SLASH(path[w - 1])) { |
| 538 | /* Collapse ///// sequences to / */ |
| 539 | if (merge_slashes && AP_IS_SLASH(path[l])) { |
| 540 | do { |
| 541 | l++; |
| 542 | } while (AP_IS_SLASH(path[l])); |
| 543 | continue; |
| 544 | } |
| 545 | |
| 546 | if (path[l] == '.') { |
no test coverage detected