(escapedPath, matchPath string)
| 543 | } |
| 544 | |
| 545 | func (MatchPath) matchPatternWithEscapeSequence(escapedPath, matchPath string) bool { |
| 546 | escapedPath = strings.ToLower(escapedPath) |
| 547 | // We would just compare the pattern against r.URL.Path, |
| 548 | // but the pattern contains %, indicating that we should |
| 549 | // compare at least some part of the path in raw/escaped |
| 550 | // space, not normalized space; so we build the string we |
| 551 | // will compare against by adding the normalized parts |
| 552 | // of the path, then switching to the escaped parts where |
| 553 | // the pattern hints to us wherever % is present. |
| 554 | var sb strings.Builder |
| 555 | |
| 556 | // iterate the pattern and escaped path in lock-step; |
| 557 | // increment iPattern every time we consume a char from the pattern, |
| 558 | // increment iPath every time we consume a char from the path; |
| 559 | // iPattern and iPath are our cursors/iterator positions for each string |
| 560 | var iPattern, iPath int |
| 561 | for { |
| 562 | if iPattern >= len(matchPath) || iPath >= len(escapedPath) { |
| 563 | break |
| 564 | } |
| 565 | // get the next character from the request path |
| 566 | |
| 567 | pathCh := string(escapedPath[iPath]) |
| 568 | var escapedPathCh string |
| 569 | |
| 570 | // normalize (decode) escape sequences |
| 571 | if pathCh == "%" && len(escapedPath) >= iPath+3 { |
| 572 | // hold onto this in case we find out the intent is to match in escaped space here; |
| 573 | // we lowercase it even though technically the spec says: "For consistency, URI |
| 574 | // producers and normalizers should use uppercase hexadecimal digits for all percent- |
| 575 | // encodings" (RFC 3986 section 2.1) - we lowercased the matcher pattern earlier in |
| 576 | // provisioning so we do the same here to gain case-insensitivity in equivalence; |
| 577 | // besides, this string is never shown visibly |
| 578 | escapedPathCh = strings.ToLower(escapedPath[iPath : iPath+3]) |
| 579 | |
| 580 | var err error |
| 581 | pathCh, err = url.PathUnescape(escapedPathCh) |
| 582 | if err != nil { |
| 583 | // should be impossible unless EscapedPath() is giving us an invalid sequence! |
| 584 | return false |
| 585 | } |
| 586 | iPath += 2 // escape sequence is 2 bytes longer than normal char |
| 587 | } |
| 588 | |
| 589 | // now get the next character from the pattern |
| 590 | |
| 591 | normalize := true |
| 592 | switch matchPath[iPattern] { |
| 593 | case '%': |
| 594 | // escape sequence |
| 595 | |
| 596 | // if not a wildcard ("%*"), compare literally; consume next two bytes of pattern |
| 597 | if len(matchPath) >= iPattern+3 && matchPath[iPattern+1] != '*' { |
| 598 | sb.WriteString(escapedPathCh) |
| 599 | iPath++ |
| 600 | iPattern += 2 |
| 601 | break |
| 602 | } |
no test coverage detected