diff options
Diffstat (limited to 'src/core/ngx_string.c')
-rw-r--r-- | src/core/ngx_string.c | 108 |
1 files changed, 108 insertions, 0 deletions
diff --git a/src/core/ngx_string.c b/src/core/ngx_string.c index a236654d7..fc3738234 100644 --- a/src/core/ngx_string.c +++ b/src/core/ngx_string.c @@ -928,3 +928,111 @@ ngx_escape_uri(u_char *dst, u_char *src, size_t size, ngx_uint_t type) return (uintptr_t) dst; } + + +void +ngx_unescape_uri(u_char **dst, u_char **src, size_t size) +{ + u_char *d, *s, ch, c, decoded; + enum { + sw_usual = 0, + sw_quoted, + sw_quoted_second + } state; + + d = *dst; + s = *src; + + state = 0; + decoded = 0; + + while (size--) { + + ch = *s++; + + switch (state) { + case sw_usual: + if (ch == '?') { + *d++ = ch; + goto done; + } + + if (ch == '%') { + state = sw_quoted; + break; + } + + *d++ = ch; + break; + + case sw_quoted: + + if (ch >= '0' && ch <= '9') { + decoded = (u_char) (ch - '0'); + state = sw_quoted_second; + break; + } + + c = (u_char) (ch | 0x20); + if (c >= 'a' && c <= 'f') { + decoded = (u_char) (c - 'a' + 10); + state = sw_quoted_second; + break; + } + + /* skip the invalid quoted character */ + + s++; + size--; + + break; + + case sw_quoted_second: + + if (ch >= '0' && ch <= '9') { + ch = (u_char) ((decoded << 4) + ch - '0'); + + state = sw_usual; + + if (ch > '%' && ch < 0x7f) { + *d++ = ch; + break; + } + + *d++ = '%'; *d++ = *(s - 2); *d++ = *(s - 1); + + break; + } + + c = (u_char) (ch | 0x20); + if (c >= 'a' && c <= 'f') { + ch = (u_char) ((decoded << 4) + c - 'a' + 10); + + if (ch == '?') { + *d++ = ch; + goto done; + } + + state = sw_usual; + + if (ch > '%' && ch < 0x7f) { + *d++ = ch; + break; + } + + *d++ = '%'; *d++ = *(s - 2); *d++ = *(s - 1); + + break; + } + + /* skip the invalid quoted character */ + + break; + } + } + +done: + + *dst = d; + *src = s; +} |