trimPathPrefix is like strings.TrimPrefix, but customized for advanced URI path prefix matching. The string prefix will be trimmed from the beginning of escapedPath if escapedPath starts with prefix. Rather than a naive 1:1 comparison of each byte to determine if escapedPath starts with prefix, both
(escapedPath, prefix string)
| 406 | // same escape at that position. Otherwise, all character comparisons are |
| 407 | // performed in normalized/unescaped space. |
| 408 | func trimPathPrefix(escapedPath, prefix string) string { |
| 409 | var iPath, iPrefix int |
| 410 | for iPath < len(escapedPath) && iPrefix < len(prefix) { |
| 411 | prefixCh := prefix[iPrefix] |
| 412 | ch := string(escapedPath[iPath]) |
| 413 | |
| 414 | if ch == "%" && prefixCh != '%' && len(escapedPath) >= iPath+3 { |
| 415 | var err error |
| 416 | ch, err = url.PathUnescape(escapedPath[iPath : iPath+3]) |
| 417 | if err != nil { |
| 418 | // should be impossible unless EscapedPath() is returning invalid values! |
| 419 | return escapedPath |
| 420 | } |
| 421 | iPath += 2 |
| 422 | } |
| 423 | |
| 424 | // prefix comparisons are case-insensitive to consistency with |
| 425 | // path matcher, which is case-insensitive for good reasons |
| 426 | if !strings.EqualFold(ch, string(prefixCh)) { |
| 427 | return escapedPath |
| 428 | } |
| 429 | |
| 430 | iPath++ |
| 431 | iPrefix++ |
| 432 | } |
| 433 | |
| 434 | // if we iterated through the entire prefix, we found it, so trim it |
| 435 | if iPath >= len(prefix) { |
| 436 | return escapedPath[iPath:] |
| 437 | } |
| 438 | |
| 439 | // otherwise we did not find the prefix |
| 440 | return escapedPath |
| 441 | } |
| 442 | |
| 443 | func reverse(s string) string { |
| 444 | r := []rune(s) |