Maybe a bug: SSI echo with encoding

洪亮 hongliang.sjtu at
Sun Mar 8 21:37:10 MSK 2009

Hello Everyone,

I found something unusual while using SSI echo command.

Let's say a ssi html file like this:

<!--#set var="x" value="%20" -->
<!--#echo var="x" encoding="url" -->
<!--#echo var="x" encoding="url" -->
<!--#echo var="x" encoding="url" -->

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

        len = 2 * ngx_escape_uri(NULL, value->data, value->len,
        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,
            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) {
            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":

<!--#set var="foo" value="a%20b" -->
<!--#echo var="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.
        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
       //...there're also some changes in this part, but here I didn't post

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

<!--#set var="foo" value="<b>a%20b</b>" -->
<!--#echo var="foo" encoding="none"-->
<!--#echo var="foo" encoding="entity"-->
<!--#echo var="foo" encoding="cookie"-->
<!--#echo var="foo" encoding="url"-->
<!--#echo var="foo" encoding="url"-->
<!--#echo var="foo" encoding="url"-->

The new compiled Nginx outputs:

&lt;b&gt;a%20b&lt;/b&gt;     ("entity", In browser, it's "a%20b" in bold
&lt;b&gt;a b&lt;/b&gt;           ("cookie", In browser, it's "a b" in bold
...                (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. :-)

Wish you all best,
goudou @ Shanghai, China
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <>

More information about the nginx mailing list