PatchPath attempts to patch a request path based on an interpretation of the standards RFC 2616 and RFC 3986 where the reserved characters should not be unescaped. Currently the Go stdlib does unescape these characters (v1.12.5). It expects the parsed path as found in http.Request.URL.Path and the
(parsed, raw string)
| 64 | // - https://tools.ietf.org/html/rfc2616#section-3.2.3 and |
| 65 | // - https://tools.ietf.org/html/rfc3986#section-2.2 |
| 66 | func PatchPath(parsed, raw string) string { |
| 67 | p, r := []byte(parsed), []byte(raw) |
| 68 | patched := make([]byte, 0, len(r)) |
| 69 | var ( |
| 70 | escape bool |
| 71 | seq []byte |
| 72 | unescaped byte |
| 73 | handled bool |
| 74 | doPatch bool |
| 75 | modified bool |
| 76 | pi int |
| 77 | ) |
| 78 | |
| 79 | for i := 0; i < len(r); i++ { |
| 80 | c := r[i] |
| 81 | escape = c == '%' |
| 82 | modified = pi >= len(p) || !escape && p[pi] != c |
| 83 | if modified { |
| 84 | doPatch = false |
| 85 | break |
| 86 | } |
| 87 | |
| 88 | if !escape { |
| 89 | patched = append(patched, p[pi]) |
| 90 | pi++ |
| 91 | continue |
| 92 | } |
| 93 | |
| 94 | if len(r) < i+escapeLength { |
| 95 | doPatch = false |
| 96 | break |
| 97 | } |
| 98 | |
| 99 | seq = r[i : i+escapeLength] |
| 100 | i += escapeLength - 1 |
| 101 | unescaped, handled = unescape(seq) |
| 102 | if !handled { |
| 103 | patched = append(patched, p[pi]) |
| 104 | pi++ |
| 105 | continue |
| 106 | } |
| 107 | |
| 108 | modified = p[pi] != unescaped |
| 109 | if modified { |
| 110 | doPatch = false |
| 111 | break |
| 112 | } |
| 113 | |
| 114 | patched = append(patched, seq...) |
| 115 | doPatch = true |
| 116 | pi++ |
| 117 | } |
| 118 | |
| 119 | if !doPatch { |
| 120 | return parsed |
| 121 | } |
| 122 | |
| 123 | modified = pi < len(p) |