I'm Zuwen Shi from China,I find a unescape uri bug in your program.<br><div class="gmail_quote">The source code location is src\core\ngx_string.c->ngx_unescape_uri<br>If I put a string "%%s%elect",it convert the string to "%slect",and %% to %,%el to l,actually the right convert is "%%s%elect".<br>

So,I patch the ngx_unescape_uri like below,the red part is which I modified.<div>Nginx is a really nice project.</div><div><br><div>void</div><div>ngx_unescape_uri(u_char **dst, u_char **src, size_t size, ngx_uint_t type)</div>

<div>{</div><div>    u_char  *d, *s, ch, c, decoded;</div><div>    enum {</div><div>        sw_usual = 0,</div><div>        sw_quoted,</div><div>        sw_quoted_second</div><div>    } state;</div><div><br></div><div>    d = *dst;</div>

<div>    s = *src;</div><div><br></div><div>    state = 0;</div><div>    decoded = 0;</div><div><br></div><div>    while (size--) {</div><div><br></div><div>        ch = *s++;</div><div><br></div><div>        switch (state) {</div>

<div>        case sw_usual:</div><div>            if (ch == '?'</div><div>                && (type & (NGX_UNESCAPE_URI|NGX_UNESCAPE_REDIRECT)))</div><div>            {</div><div>                *d++ = ch;</div>

<div>                goto done;</div><div>            }</div><div><br></div><div><font color="#ff0000">            if (ch == '%'&&size>1) {</font></div><div><font color="#ff0000">                ch=*s;</font></div>

<div><font color="#ff0000">                c = (u_char) (ch | 0x20);</font></div><div><font color="#ff0000">                if ((ch >= '0' && ch <= '9')||(c >= 'a' && c <= 'f')) {</font></div>

<div><font color="#ff0000">                ch=*(s+1);</font></div><div><font color="#ff0000">                c = (u_char) (ch | 0x20);</font></div><div><font color="#ff0000">                if ((ch >= '0' && ch <= '9')||(c >= 'a' && c <= 'f')) {</font></div>

<div><font color="#ff0000">                state = sw_quoted;</font></div><div><font color="#ff0000">                break;</font></div><div><font color="#ff0000">                }</font></div>
<div><font color="#ff0000">                }</font></div><div><font color="#ff0000">                *d++ = '%';</font></div><div><font color="#ff0000">                break;</font></div>
<div><font color="#ff0000">            }</font></div><div><font color="#ff0000"><br></font></div><div><font color="#ff0000">            if (ch == '+') {</font></div>
<div><font color="#ff0000">            *d++ = ' ';</font></div><div><font color="#ff0000">            break;</font></div><div><font color="#ff0000">            }</font></div>
<div><br></div><div>            *d++ = ch;</div><div>            break;</div><div><br></div><div>        case sw_quoted:</div><div><br></div><div>            if (ch >= '0' && ch <= '9') {</div>

<div>                decoded = (u_char) (ch - '0');</div><div>                state = sw_quoted_second;</div><div>                break;</div><div>            }</div><div><br></div><div>            c = (u_char) (ch | 0x20);</div>

<div>            if (c >= 'a' && c <= 'f') {</div><div>                decoded = (u_char) (c - 'a' + 10);</div><div>                state = sw_quoted_second;</div><div>                break;</div>

<div>            }</div><div><br></div><div>            /* the invalid quoted character */</div><div><br></div><div>            state = sw_usual;</div><div><br></div><div>            *d++ = ch;</div><div><br></div><div>            break;</div>

<div><br></div><div>        case sw_quoted_second:</div><div><br></div><div>            state = sw_usual;</div><div><br></div><div>            if (ch >= '0' && ch <= '9') {</div><div>                ch = (u_char) ((decoded << 4) + ch - '0');</div>

<div><br></div><div>                if (type & NGX_UNESCAPE_REDIRECT) {</div><div>                    if (ch > '%' && ch < 0x7f) {</div><div>                        *d++ = ch;</div><div>                        break;</div>

<div>                    }</div><div><br></div><div>                    *d++ = '%'; *d++ = *(s - 2); *d++ = *(s - 1);</div><div><br></div><div>                    break;</div><div>                }</div><div><br>
</div>
<div>                *d++ = ch;</div><div><br></div><div>                break;</div><div>            }</div><div><br></div><div>            c = (u_char) (ch | 0x20);</div><div>            if (c >= 'a' && c <= 'f') {</div>

<div>                ch = (u_char) ((decoded << 4) + c - 'a' + 10);</div><div><br></div><div>                if (type & NGX_UNESCAPE_URI) {</div><div>                    if (ch == '?') {</div><div>

                        *d++ = ch;</div><div>                        goto done;</div><div>                    }</div><div><br></div><div>                    *d++ = ch;</div><div>                    break;</div><div>                }</div>

<div><br></div><div>                if (type & NGX_UNESCAPE_REDIRECT) {</div><div>                    if (ch == '?') {</div><div>                        *d++ = ch;</div><div>                        goto done;</div>

<div>                    }</div><div><br></div><div>                    if (ch > '%' && ch < 0x7f) {</div><div>                        *d++ = ch;</div><div>                        break;</div><div>                    }</div>

<div><br></div><div>                    *d++ = '%'; *d++ = *(s - 2); *d++ = *(s - 1);</div><div>                    break;</div><div>                }</div><div><br></div><div>                *d++ = ch;</div><div>

<br></div><div>                break;</div><div>            }</div><div><br></div><div>            /* the invalid quoted character */</div><div><br></div><div>            break;</div><div>        }</div><div>    }</div><div>

<br></div><div>done:</div><div><br></div><div>    *dst = d;</div><div>    *src = s;</div><div>}</div><div><br></div><div><br></div></div>
</div><br>