Maybe a bug: SSI echo with encoding

Hello Everyone,

I found something unusual while using SSI echo command.

Let’s say a ssi html file like this:

nginx will output:
%20 %2520 %252520 %25252520

not what we expected:
%20 %2034 %2034 %2034

After digging into nginx’s source code, I realized that this is because
the
original value “x” was changed after the first ngx_escape_uri() call in
src/http/modules/ngx_http_ssi_filter_module.c: (version 0.6.35, around
line
2200)

case NGX_HTTP_SSI_URL_ENCODING:
    len = 2 * ngx_escape_uri(NULL, value->data, value->len,
                             NGX_ESCAPE_HTML);
    if (len) {
        p = ngx_palloc(r->pool, value->len + len);
        if (p == NULL) {
            return NGX_HTTP_SSI_ERROR;
        }
        (void) ngx_escape_uri(p, value->data, value->len,

NGX_ESCAPE_HTML);
value->len += len; //That’s it!
value->data = p;
}

I don’t think setting value->len and value->data is a right thing here.
People use SSI to echo some variables with encoding, but they don’t
expect
those original variables are changed after that.

This happens if encoding is set to “entity” as well. I think this is a
bug.
Although not too many people use SSI in such a way like me, it’s
dangerous
that seeing a value of variable keeps growing and growing.

Version 0.7.x has the same problem.

Here’s my bugfix:
key = 0; //not a good name, but can use it as a flag
switch(ctx->encoding) {
//…
case NGX_HTTP_SSI_URL_ENCODING:
//…
key = 1;
len += value->len;
}
//…
b->memory = 1;
if(key) {
b->pos = p;
b->last = p+len;
} else {
b->pos = value->data;
b->last = value->data + value->len;
}

That’s the main part of code change. After that, problem solved. Then
nginx
will output what we expected, however many times we do “echo”:

%20 %2520 %2520 %2520

And also I want to suggest another feature: add a new parameter value to
the
“encoding” parameter of SSI echo command, let’s say it “cookie”. For
example, some people may want to output a variable “foo”:

(
Setting variable “foo” is just for example. Actually, in production
envrionment “foo” might be from cookie. For example, in nginx.conf, we
can
set “foo” like this:

if ($http_cookie ~* “foo=([^;]+)(?:;|$)” ) {
set $foo $1;
}
)

The output is “a%20b”. But I want nginx to output “a b”, not “a%20b”.
Too
bad there’s no way of doing it. So I added those code to
ngx_http_ssi_filter_module.c, here’s main part of it:

//have to set ctx->encoding first
//NGX_HTTP_SSI_COOKIE_ENCODING defines somewhere else.
case NGX_HTTP_SSI_COOKIE_ENCODING:
    if(!value->len) break;

    p = ngx_palloc(r->pool, value->len);
    if (p == NULL) {
        return NGX_HTTP_SSI_ERROR;
    }

    dst = p;
    src = value->data;

    ngx_unescape_uri(&dst, &src, value->len, NGX_UNESCAPE_URI);

    len = (value->data + value->len) - src;
    if (len) {
        dst = ngx_copy(dst, src, len);
    }

    key = 1;
    len = dst - p;
    //fall through, let it "entity" encoding take effect

case NGX_HTTP_SSI_ENTITY_ENCODING:
//…there’re also some changes in this part, but here I didn’t
post
them

Then, nginx will output variable foo as “a b”. For example,

The new compiled Nginx outputs:

a%20b
<b>a%20b</b> (“entity”, In browser, it’s “a%20b” in bold
font)
<b>a b</b> (“cookie”, In browser, it’s “a b” in
bold
font)
a%2520b
a%2520b
a%2520b
… (because the bug I mentioned at the first of email
has
been fixed so after several times “url” encoding the output of variable
foo
won’t be “a%25%25%25…20b”)

I attached ngx_http_ssi_filter_module.c and ngx_http_ssi_filter_module.h
to
this email (If this maillist doesn’t support attachment, please let me
know). It’s the full source code that modified by me. It’s a little ugly
because I just wanted to get my idea work as soon as possible and didn’t
pay
much attention to code style and something else. If Igor or someone else
put
my bugfix to nginx’s code trunk I will be very happy to see a little
line
“Thanks to goudou” in CHANGELOG. :slight_smile:

Wish you all best,
goudou @ Shanghai, China

sorry I forgot to attach files. Here they are.