# Ngx unescape uri bug

**URL:** <https://www.ruby-forum.com/t/ngx-unescape-uri-bug/227689>\
**Category:** NGINX\
**Created:** [March 25, 2013, 8:11am UTC](https://www.ruby-forum.com/t/ngx-unescape-uri-bug/227689 "2013-03-25T08:11:33Z")\
**Posts on this page:** 2\
**Page:** 1

<div class="post-metadata">

**Author:** ![David\_Shee](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/d/35a633/32.png) [@David\_Shee](https://www.ruby-forum.com/u/David_Shee)\
**Post date:** [March 25, 2013, 8:11am UTC](https://www.ruby-forum.com/t/ngx-unescape-uri-bug/227689/1 "2013-03-25T08:11:33Z")

</div>

I’m Zuwen Shi from China,I find a unescape uri bug in your program.  
The source code location is src\core\ngx\_string.c-\>ngx\_unescape\_uri  
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”.  
So,I patch the ngx\_unescape\_uri like below,the red part is which I  
modified.  
Nginx is a really nice project.

void  
ngx\_unescape\_uri(u\_char \*\*dst, u\_char \*\*src, size\_t size, ngx\_uint\_t  
type)  
{  
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 == '?'
            && (type & (NGX_UNESCAPE_URI|NGX_UNESCAPE_REDIRECT)))
        {
            *d++ = ch;
            goto done;
        }

        if (ch == '%'&&size>1) {
            ch=*s;
            c = (u_char) (ch | 0x20);
            if ((ch >= '0' && ch <= '9')||(c >= 'a' && c <= 'f')) {
            ch=*(s+1);
            c = (u_char) (ch | 0x20);
            if ((ch >= '0' && ch <= '9')||(c >= 'a' && c <= 'f')) {
            state = sw_quoted;
            break;
            }
            }
            *d++ = '%';
            break;
        }

        if (ch == '+') {
        *d++ = ' ';
        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;
        }

        /* the invalid quoted character */

        state = sw_usual;

        *d++ = ch;

        break;

    case sw_quoted_second:

        state = sw_usual;

        if (ch >= '0' && ch <= '9') {
            ch = (u_char) ((decoded << 4) + ch - '0');

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

                *d++ = '%'; *d++ = *(s - 2); *d++ = *(s - 1);

                break;
            }

            *d++ = ch;

            break;
        }

        c = (u_char) (ch | 0x20);
        if (c >= 'a' && c <= 'f') {
            ch = (u_char) ((decoded << 4) + c - 'a' + 10);

            if (type & NGX_UNESCAPE_URI) {
                if (ch == '?') {
                    *d++ = ch;
                    goto done;
                }

                *d++ = ch;
                break;
            }

            if (type & NGX_UNESCAPE_REDIRECT) {
                if (ch == '?') {
                    *d++ = ch;
                    goto done;
                }

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

                *d++ = '%'; *d++ = *(s - 2); *d++ = *(s - 1);
                break;
            }

            *d++ = ch;

            break;
        }

        /* the invalid quoted character */

        break;
    }
}

```

done:

```
*dst = d;
*src = s;

```

}

---

<div class="post-metadata">

**Author:** ![David\_Shee](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/d/35a633/32.png) [@David\_Shee](https://www.ruby-forum.com/u/David_Shee)\
**Post date:** [March 25, 2013, 12:47pm UTC](https://www.ruby-forum.com/t/ngx-unescape-uri-bug/227689/2 "2013-03-25T12:47:19Z")

</div>

Hello!

On Mon, Mar 25, 2013 at 03:11:10PM +0800, David Shee wrote:

> I’m Zuwen Shi from China,I find a unescape uri bug in your program.  
> The source code location is src\core\ngx\_string.c-\>ngx\_unescape\_uri  
> 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”.

I would rather say that behaviour is undefined in case of  
incorrect input, and both results are correct.

> So,I patch the ngx\_unescape\_uri like below,the red part is which I modified.

You may want to post unified diff into nginx-devel@ mailing list.  
And please don’t use html. Thank you.

–  
Maxim D.

> **[nginx: donation](http://nginx.org/en/donation.html)**
