static ngx_int_t
ngx_http_ssi_body_filter(ngx_http_request_t *r, ngx_chain_t *in)
{
    size_t                     len;
    ngx_int_t                  rc;
    ngx_buf_t                 *b;
    ngx_uint_t                 i, index;
    ngx_chain_t               *cl, **ll;
    ngx_table_elt_t           *param;
    ngx_http_ssi_ctx_t        *ctx, *mctx;
    ngx_http_ssi_block_t      *bl;
    ngx_http_ssi_param_t      *prm;
    ngx_http_ssi_command_t    *cmd;
    ngx_http_ssi_loc_conf_t   *slcf;
    ngx_http_ssi_main_conf_t  *smcf;
    ngx_str_t                 *params[NGX_HTTP_SSI_MAX_PARAMS + 1];
    ctx = ngx_http_get_module_ctx(r, ngx_http_ssi_filter_module);
    if (ctx == NULL
        || (in == NULL
            && ctx->buf == NULL
            && ctx->in == NULL
            && ctx->busy == NULL))
    {
        return ngx_http_next_body_filter(r, in);
    }
    if (in) {
        if (ngx_chain_add_copy(r->pool, &ctx->in, in) != NGX_OK) {
            return NGX_ERROR;
        }
    }
    ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                   "http ssi filter \"%V?%V\"", &r->uri, &r->args);
    if (ctx->wait) {
        if (r != r->connection->data) {
            ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                           "http ssi filter wait \"%V?%V\" non-active",
                           &ctx->wait->uri, &ctx->wait->args);
            return NGX_AGAIN;
        }
        if (ctx->wait->done) {
            ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                           "http ssi filter wait \"%V?%V\" done",
                           &ctx->wait->uri, &ctx->wait->args);
            ctx->wait = NULL;
        } else {
            ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                           "http ssi filter wait \"%V?%V\"",
                           &ctx->wait->uri, &ctx->wait->args);
            return ngx_http_next_body_filter(r, NULL);
        }
    }
    slcf = ngx_http_get_module_loc_conf(r, ngx_http_ssi_filter_module);
    while (ctx->in || ctx->buf) {
        if (ctx->buf == NULL) {
            ctx->buf = ctx->in->buf;
            ctx->in = ctx->in->next;
            ctx->pos = ctx->buf->pos;
        }
        if (ctx->state == ssi_start_state) {
            ctx->copy_start = ctx->pos;
            ctx->copy_end = ctx->pos;
        }
        b = NULL;
        while (ctx->pos < ctx->buf->last) {
            ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                           "saved: %uz state: %ui", ctx->saved, ctx->state);
            rc = ngx_http_ssi_parse(r, ctx);
            ngx_log_debug4(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                           "parse: %i, looked: %uz %p-%p",
                           rc, ctx->looked, ctx->copy_start, ctx->copy_end);
            if (rc == NGX_ERROR) {
                return rc;
            }
            if (ctx->copy_start != ctx->copy_end) {
                if (ctx->output) {
                    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                                   "saved: %uz", ctx->saved);
                    if (ctx->saved) {
                        if (ctx->free) {
                            cl = ctx->free;
                            ctx->free = ctx->free->next;
                            b = cl->buf;
                            ngx_memzero(b, sizeof(ngx_buf_t));
                        } else {
                            b = ngx_calloc_buf(r->pool);
                            if (b == NULL) {
                                return NGX_ERROR;
                            }
                            cl = ngx_alloc_chain_link(r->pool);
                            if (cl == NULL) {
                                return NGX_ERROR;
                            }
                            cl->buf = b;
                        }
                        b->memory = 1;
                        b->pos = ngx_http_ssi_string;
                        b->last = ngx_http_ssi_string + ctx->saved;
                        *ctx->last_out = cl;
                        ctx->last_out = &cl->next;
                        ctx->saved = 0;
                    }
                    if (ctx->free) {
                        cl = ctx->free;
                        ctx->free = ctx->free->next;
                        b = cl->buf;
                    } else {
                        b = ngx_alloc_buf(r->pool);
                        if (b == NULL) {
                            return NGX_ERROR;
                        }
                        cl = ngx_alloc_chain_link(r->pool);
                        if (cl == NULL) {
                            return NGX_ERROR;
                        }
                        cl->buf = b;
                    }
                    ngx_memcpy(b, ctx->buf, sizeof(ngx_buf_t));
                    b->pos = ctx->copy_start;
                    b->last = ctx->copy_end;
                    b->shadow = NULL;
                    b->last_buf = 0;
                    b->recycled = 0;
                    if (b->in_file) {
                        if (slcf->min_file_chunk < (size_t) (b->last - b->pos))
                        {
                            b->file_last = b->file_pos
                                                   + (b->last - ctx->buf->pos);
                            b->file_pos += b->pos - ctx->buf->pos;
                        } else {
                            b->in_file = 0;
                        }
                    }
                    cl->next = NULL;
                    *ctx->last_out = cl;
                    ctx->last_out = &cl->next;
                } else {
                    if (ctx->block
                        && ctx->saved + (ctx->copy_end - ctx->copy_start))
                    {
                        b = ngx_create_temp_buf(r->pool,
                               ctx->saved + (ctx->copy_end - ctx->copy_start));
                        if (b == NULL) {
                            return NGX_ERROR;
                        }
                        if (ctx->saved) {
                            b->last = ngx_cpymem(b->pos, ngx_http_ssi_string,
                                                 ctx->saved);
                        }
                        b->last = ngx_cpymem(b->last, ctx->copy_start,
                                             ctx->copy_end - ctx->copy_start);
                        cl = ngx_alloc_chain_link(r->pool);
                        if (cl == NULL) {
                            return NGX_ERROR;
                        }
                        cl->buf = b;
                        cl->next = NULL;
                        b = NULL;
                        mctx = ngx_http_get_module_ctx(r->main,
                                                   ngx_http_ssi_filter_module);
                        bl = mctx->blocks->elts;
                        for (ll = &bl[mctx->blocks->nelts - 1].bufs;
                             *ll;
                             ll = &(*ll)->next)
                        {
                        }
                        *ll = cl;
                    }
                    ctx->saved = 0;
                }
            }
            if (ctx->state == ssi_start_state) {
                ctx->copy_start = ctx->pos;
                ctx->copy_end = ctx->pos;
            } else {
                ctx->copy_start = NULL;
                ctx->copy_end = NULL;
            }
            if (rc == NGX_AGAIN) {
                continue;
            }
            b = NULL;
            if (rc == NGX_OK) {
                smcf = ngx_http_get_module_main_conf(r,
                                                   ngx_http_ssi_filter_module);
                cmd = ngx_hash_find(&smcf->hash, ctx->key, ctx->command.data,
                                    ctx->command.len);
                if (cmd == NULL) {
                    if (ctx->output) {
                        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
                                      "invalid SSI command: \"%V\"",
                                      &ctx->command);
                        goto ssi_error;
                    }
                    continue;
                }
                if (!ctx->output && !cmd->block) {
                    if (ctx->block) {
                        len = 5 + ctx->command.len + 4;
                        param = ctx->params.elts;
                        for (i = 0; i < ctx->params.nelts; i++) {
                            len += 1 + param[i].key.len + 2
                                + param[i].value.len + 1;
                        }
                        b = ngx_create_temp_buf(r->pool, len);
                        if (b == NULL) {
                            return NGX_ERROR;
                        }
                        cl = ngx_alloc_chain_link(r->pool);
                        if (cl == NULL) {
                            return NGX_ERROR;
                        }
                        cl->buf = b;
                        cl->next = NULL;
                        *b->last++ = '<';
                        *b->last++ = '!';
                        *b->last++ = '-';
                        *b->last++ = '-';
                        *b->last++ = '#';
                        b->last = ngx_cpymem(b->last, ctx->command.data,
                                             ctx->command.len);
                        for (i = 0; i < ctx->params.nelts; i++) {
                            *b->last++ = ' ';
                            b->last = ngx_cpymem(b->last, param[i].key.data,
                                                 param[i].key.len);
                            *b->last++ = '=';
                            *b->last++ = '"';
                            b->last = ngx_cpymem(b->last, param[i].value.data,
                                                 param[i].value.len);
                            *b->last++ = '"';
                        }
                        *b->last++ = ' ';
                        *b->last++ = '-';
                        *b->last++ = '-';
                        *b->last++ = '>';
                        mctx = ngx_http_get_module_ctx(r->main,
                                                   ngx_http_ssi_filter_module);
                        bl = mctx->blocks->elts;
                        for (ll = &bl[mctx->blocks->nelts - 1].bufs;
                             *ll;
                             ll = &(*ll)->next)
                        {
                        }
                        *ll = cl;
                        b = NULL;
                        continue;
                    }
                    if (cmd->conditional == 0) {
                        continue;
                    }
                }
                if (cmd->conditional
                    && (ctx->conditional == 0
                        || ctx->conditional > cmd->conditional))
                {
                    ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
                                  "invalid context of SSI command: \"%V\"",
                                  &ctx->command);
                    goto ssi_error;
                }
                if (ctx->params.nelts > NGX_HTTP_SSI_MAX_PARAMS) {
                    ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
                                  "too many SSI command parameters: \"%V\"",
                                  &ctx->command);
                    goto ssi_error;
                }
                ngx_memzero(params,
                           (NGX_HTTP_SSI_MAX_PARAMS + 1) * sizeof(ngx_str_t *));
                param = ctx->params.elts;
                for (i = 0; i < ctx->params.nelts; i++) {
                    for (prm = cmd->params; prm->name.len; prm++) {
                        if (param[i].key.len != prm->name.len
                            || ngx_strncmp(param[i].key.data, prm->name.data,
                                           prm->name.len) != 0)
                        {
                            continue;
                        }
                        if (!prm->multiple) {
                            if (params[prm->index]) {
                                ngx_log_error(NGX_LOG_ERR,
                                              r->connection->log, 0,
                                              "duplicate \"%V\" parameter "
                                              "in \"%V\" SSI command",
                                              &param[i].key, &ctx->command);
                                goto ssi_error;
                            }
                            params[prm->index] = &param[i].value;
                            break;
                        }
                        for (index = prm->index; params[index]; index++) {
                        }
                        params[index] = &param[i].value;
                        break;
                    }
                    if (prm->name.len == 0) {
                        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
                                      "invalid parameter name: \"%V\" "
                                      "in \"%V\" SSI command",
                                      &param[i].key, &ctx->command);
                        goto ssi_error;
                    }
                }
                for (prm = cmd->params; prm->name.len; prm++) {
                    if (prm->mandatory && params[prm->index] == 0) {
                        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
                                      "mandatory \"%V\" parameter is absent "
                                      "in \"%V\" SSI command",
                                      &prm->name, &ctx->command);
                        goto ssi_error;
                    }
                }
                if (cmd->flush && ctx->out) {
                    ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                                   "ssi flush");
                    if (ngx_http_ssi_output(r, ctx) == NGX_ERROR) {
                        return NGX_ERROR;
                    }
                }
                rc = cmd->handler(r, ctx, params);
                if (rc == NGX_OK) {
                    continue;
                }
                if (rc == NGX_DONE || rc == NGX_AGAIN || rc == NGX_ERROR) {
                    ngx_http_ssi_buffered(r, ctx);
                    return rc;
                }
            }
    ssi_error:
            if (slcf->silent_errors) {
                continue;
            }
            if (ctx->free) {
                cl = ctx->free;
                ctx->free = ctx->free->next;
                b = cl->buf;
                ngx_memzero(b, sizeof(ngx_buf_t));
            } else {
                b = ngx_calloc_buf(r->pool);
                if (b == NULL) {
                    return NGX_ERROR;
                }
                cl = ngx_alloc_chain_link(r->pool);
                if (cl == NULL) {
                    return NGX_ERROR;
                }
                cl->buf = b;
            }
            b->memory = 1;
            b->pos = ctx->errmsg.data;
            b->last = ctx->errmsg.data + ctx->errmsg.len;
            cl->next = NULL;
            *ctx->last_out = cl;
            ctx->last_out = &cl->next;
            continue;
        }
        if (ctx->buf->last_buf || ngx_buf_in_memory(ctx->buf)) {
            if (b == NULL) {
                if (ctx->free) {
                    cl = ctx->free;
                    ctx->free = ctx->free->next;
                    b = cl->buf;
                    ngx_memzero(b, sizeof(ngx_buf_t));
                } else {
                    b = ngx_calloc_buf(r->pool);
                    if (b == NULL) {
                        return NGX_ERROR;
                    }
                    cl = ngx_alloc_chain_link(r->pool);
                    if (cl == NULL) {
                        return NGX_ERROR;
                    }
                    cl->buf = b;
                }
                b->sync = 1;
                cl->next = NULL;
                *ctx->last_out = cl;
                ctx->last_out = &cl->next;
            }
            b->last_buf = ctx->buf->last_buf;
            b->shadow = ctx->buf;
            if (slcf->ignore_recycled_buffers == 0)  {
                b->recycled = ctx->buf->recycled;
            }
        }
        ctx->buf = NULL;
        ctx->saved = ctx->looked;
    }
    if (ctx->out == NULL && ctx->busy == NULL) {
        return NGX_OK;
    }
    return ngx_http_ssi_output(r, ctx);
}
['static ngx_int_t\nngx_http_ssi_body_filter(ngx_http_request_t *r, ngx_chain_t *in)\n{\n    size_t                     len;\n    ngx_int_t                  rc;\n    ngx_buf_t                 *b;\n    ngx_uint_t                 i, index;\n    ngx_chain_t               *cl, **ll;\n    ngx_table_elt_t           *param;\n    ngx_http_ssi_ctx_t        *ctx, *mctx;\n    ngx_http_ssi_block_t      *bl;\n    ngx_http_ssi_param_t      *prm;\n    ngx_http_ssi_command_t    *cmd;\n    ngx_http_ssi_loc_conf_t   *slcf;\n    ngx_http_ssi_main_conf_t  *smcf;\n    ngx_str_t                 *params[NGX_HTTP_SSI_MAX_PARAMS + 1];\n    ctx = ngx_http_get_module_ctx(r, ngx_http_ssi_filter_module);\n    if (ctx == NULL\n        || (in == NULL\n            && ctx->buf == NULL\n            && ctx->in == NULL\n            && ctx->busy == NULL))\n    {\n        return ngx_http_next_body_filter(r, in);\n    }\n    if (in) {\n        if (ngx_chain_add_copy(r->pool, &ctx->in, in) != NGX_OK) {\n            return NGX_ERROR;\n        }\n    }\n    ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,\n                   "http ssi filter \\"%V?%V\\"", &r->uri, &r->args);\n    if (ctx->wait) {\n        if (r != r->connection->data) {\n            ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,\n                           "http ssi filter wait \\"%V?%V\\" non-active",\n                           &ctx->wait->uri, &ctx->wait->args);\n            return NGX_AGAIN;\n        }\n        if (ctx->wait->done) {\n            ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,\n                           "http ssi filter wait \\"%V?%V\\" done",\n                           &ctx->wait->uri, &ctx->wait->args);\n            ctx->wait = NULL;\n        } else {\n            ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,\n                           "http ssi filter wait \\"%V?%V\\"",\n                           &ctx->wait->uri, &ctx->wait->args);\n            return ngx_http_next_body_filter(r, NULL);\n        }\n    }\n    slcf = ngx_http_get_module_loc_conf(r, ngx_http_ssi_filter_module);\n    while (ctx->in || ctx->buf) {\n        if (ctx->buf == NULL) {\n            ctx->buf = ctx->in->buf;\n            ctx->in = ctx->in->next;\n            ctx->pos = ctx->buf->pos;\n        }\n        if (ctx->state == ssi_start_state) {\n            ctx->copy_start = ctx->pos;\n            ctx->copy_end = ctx->pos;\n        }\n        b = NULL;\n        while (ctx->pos < ctx->buf->last) {\n            ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,\n                           "saved: %uz state: %ui", ctx->saved, ctx->state);\n            rc = ngx_http_ssi_parse(r, ctx);\n            ngx_log_debug4(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,\n                           "parse: %i, looked: %uz %p-%p",\n                           rc, ctx->looked, ctx->copy_start, ctx->copy_end);\n            if (rc == NGX_ERROR) {\n                return rc;\n            }\n            if (ctx->copy_start != ctx->copy_end) {\n                if (ctx->output) {\n                    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,\n                                   "saved: %uz", ctx->saved);\n                    if (ctx->saved) {\n                        if (ctx->free) {\n                            cl = ctx->free;\n                            ctx->free = ctx->free->next;\n                            b = cl->buf;\n                            ngx_memzero(b, sizeof(ngx_buf_t));\n                        } else {\n                            b = ngx_calloc_buf(r->pool);\n                            if (b == NULL) {\n                                return NGX_ERROR;\n                            }\n                            cl = ngx_alloc_chain_link(r->pool);\n                            if (cl == NULL) {\n                                return NGX_ERROR;\n                            }\n                            cl->buf = b;\n                        }\n                        b->memory = 1;\n                        b->pos = ngx_http_ssi_string;\n                        b->last = ngx_http_ssi_string + ctx->saved;\n                        *ctx->last_out = cl;\n                        ctx->last_out = &cl->next;\n                        ctx->saved = 0;\n                    }\n                    if (ctx->free) {\n                        cl = ctx->free;\n                        ctx->free = ctx->free->next;\n                        b = cl->buf;\n                    } else {\n                        b = ngx_alloc_buf(r->pool);\n                        if (b == NULL) {\n                            return NGX_ERROR;\n                        }\n                        cl = ngx_alloc_chain_link(r->pool);\n                        if (cl == NULL) {\n                            return NGX_ERROR;\n                        }\n                        cl->buf = b;\n                    }\n                    ngx_memcpy(b, ctx->buf, sizeof(ngx_buf_t));\n                    b->pos = ctx->copy_start;\n                    b->last = ctx->copy_end;\n                    b->shadow = NULL;\n                    b->last_buf = 0;\n                    b->recycled = 0;\n                    if (b->in_file) {\n                        if (slcf->min_file_chunk < (size_t) (b->last - b->pos))\n                        {\n                            b->file_last = b->file_pos\n                                                   + (b->last - ctx->buf->pos);\n                            b->file_pos += b->pos - ctx->buf->pos;\n                        } else {\n                            b->in_file = 0;\n                        }\n                    }\n                    cl->next = NULL;\n                    *ctx->last_out = cl;\n                    ctx->last_out = &cl->next;\n                } else {\n                    if (ctx->block\n                        && ctx->saved + (ctx->copy_end - ctx->copy_start))\n                    {\n                        b = ngx_create_temp_buf(r->pool,\n                               ctx->saved + (ctx->copy_end - ctx->copy_start));\n                        if (b == NULL) {\n                            return NGX_ERROR;\n                        }\n                        if (ctx->saved) {\n                            b->last = ngx_cpymem(b->pos, ngx_http_ssi_string,\n                                                 ctx->saved);\n                        }\n                        b->last = ngx_cpymem(b->last, ctx->copy_start,\n                                             ctx->copy_end - ctx->copy_start);\n                        cl = ngx_alloc_chain_link(r->pool);\n                        if (cl == NULL) {\n                            return NGX_ERROR;\n                        }\n                        cl->buf = b;\n                        cl->next = NULL;\n                        b = NULL;\n                        mctx = ngx_http_get_module_ctx(r->main,\n                                                   ngx_http_ssi_filter_module);\n                        bl = mctx->blocks->elts;\n                        for (ll = &bl[mctx->blocks->nelts - 1].bufs;\n                             *ll;\n                             ll = &(*ll)->next)\n                        {\n                        }\n                        *ll = cl;\n                    }\n                    ctx->saved = 0;\n                }\n            }\n            if (ctx->state == ssi_start_state) {\n                ctx->copy_start = ctx->pos;\n                ctx->copy_end = ctx->pos;\n            } else {\n                ctx->copy_start = NULL;\n                ctx->copy_end = NULL;\n            }\n            if (rc == NGX_AGAIN) {\n                continue;\n            }\n            b = NULL;\n            if (rc == NGX_OK) {\n                smcf = ngx_http_get_module_main_conf(r,\n                                                   ngx_http_ssi_filter_module);\n                cmd = ngx_hash_find(&smcf->hash, ctx->key, ctx->command.data,\n                                    ctx->command.len);\n                if (cmd == NULL) {\n                    if (ctx->output) {\n                        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,\n                                      "invalid SSI command: \\"%V\\"",\n                                      &ctx->command);\n                        goto ssi_error;\n                    }\n                    continue;\n                }\n                if (!ctx->output && !cmd->block) {\n                    if (ctx->block) {\n                        len = 5 + ctx->command.len + 4;\n                        param = ctx->params.elts;\n                        for (i = 0; i < ctx->params.nelts; i++) {\n                            len += 1 + param[i].key.len + 2\n                                + param[i].value.len + 1;\n                        }\n                        b = ngx_create_temp_buf(r->pool, len);\n                        if (b == NULL) {\n                            return NGX_ERROR;\n                        }\n                        cl = ngx_alloc_chain_link(r->pool);\n                        if (cl == NULL) {\n                            return NGX_ERROR;\n                        }\n                        cl->buf = b;\n                        cl->next = NULL;\n                        *b->last++ = \'<\';\n                        *b->last++ = \'!\';\n                        *b->last++ = \'-\';\n                        *b->last++ = \'-\';\n                        *b->last++ = \'#\';\n                        b->last = ngx_cpymem(b->last, ctx->command.data,\n                                             ctx->command.len);\n                        for (i = 0; i < ctx->params.nelts; i++) {\n                            *b->last++ = \' \';\n                            b->last = ngx_cpymem(b->last, param[i].key.data,\n                                                 param[i].key.len);\n                            *b->last++ = \'=\';\n                            *b->last++ = \'"\';\n                            b->last = ngx_cpymem(b->last, param[i].value.data,\n                                                 param[i].value.len);\n                            *b->last++ = \'"\';\n                        }\n                        *b->last++ = \' \';\n                        *b->last++ = \'-\';\n                        *b->last++ = \'-\';\n                        *b->last++ = \'>\';\n                        mctx = ngx_http_get_module_ctx(r->main,\n                                                   ngx_http_ssi_filter_module);\n                        bl = mctx->blocks->elts;\n                        for (ll = &bl[mctx->blocks->nelts - 1].bufs;\n                             *ll;\n                             ll = &(*ll)->next)\n                        {\n                        }\n                        *ll = cl;\n                        b = NULL;\n                        continue;\n                    }\n                    if (cmd->conditional == 0) {\n                        continue;\n                    }\n                }\n                if (cmd->conditional\n                    && (ctx->conditional == 0\n                        || ctx->conditional > cmd->conditional))\n                {\n                    ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,\n                                  "invalid context of SSI command: \\"%V\\"",\n                                  &ctx->command);\n                    goto ssi_error;\n                }\n                if (ctx->params.nelts > NGX_HTTP_SSI_MAX_PARAMS) {\n                    ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,\n                                  "too many SSI command parameters: \\"%V\\"",\n                                  &ctx->command);\n                    goto ssi_error;\n                }\n                ngx_memzero(params,\n                           (NGX_HTTP_SSI_MAX_PARAMS + 1) * sizeof(ngx_str_t *));\n                param = ctx->params.elts;\n                for (i = 0; i < ctx->params.nelts; i++) {\n                    for (prm = cmd->params; prm->name.len; prm++) {\n                        if (param[i].key.len != prm->name.len\n                            || ngx_strncmp(param[i].key.data, prm->name.data,\n                                           prm->name.len) != 0)\n                        {\n                            continue;\n                        }\n                        if (!prm->multiple) {\n                            if (params[prm->index]) {\n                                ngx_log_error(NGX_LOG_ERR,\n                                              r->connection->log, 0,\n                                              "duplicate \\"%V\\" parameter "\n                                              "in \\"%V\\" SSI command",\n                                              &param[i].key, &ctx->command);\n                                goto ssi_error;\n                            }\n                            params[prm->index] = &param[i].value;\n                            break;\n                        }\n                        for (index = prm->index; params[index]; index++) {\n                        }\n                        params[index] = &param[i].value;\n                        break;\n                    }\n                    if (prm->name.len == 0) {\n                        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,\n                                      "invalid parameter name: \\"%V\\" "\n                                      "in \\"%V\\" SSI command",\n                                      &param[i].key, &ctx->command);\n                        goto ssi_error;\n                    }\n                }\n                for (prm = cmd->params; prm->name.len; prm++) {\n                    if (prm->mandatory && params[prm->index] == 0) {\n                        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,\n                                      "mandatory \\"%V\\" parameter is absent "\n                                      "in \\"%V\\" SSI command",\n                                      &prm->name, &ctx->command);\n                        goto ssi_error;\n                    }\n                }\n                if (cmd->flush && ctx->out) {\n                    ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,\n                                   "ssi flush");\n                    if (ngx_http_ssi_output(r, ctx) == NGX_ERROR) {\n                        return NGX_ERROR;\n                    }\n                }\n                rc = cmd->handler(r, ctx, params);\n                if (rc == NGX_OK) {\n                    continue;\n                }\n                if (rc == NGX_DONE || rc == NGX_AGAIN || rc == NGX_ERROR) {\n                    ngx_http_ssi_buffered(r, ctx);\n                    return rc;\n                }\n            }\n    ssi_error:\n            if (slcf->silent_errors) {\n                continue;\n            }\n            if (ctx->free) {\n                cl = ctx->free;\n                ctx->free = ctx->free->next;\n                b = cl->buf;\n                ngx_memzero(b, sizeof(ngx_buf_t));\n            } else {\n                b = ngx_calloc_buf(r->pool);\n                if (b == NULL) {\n                    return NGX_ERROR;\n                }\n                cl = ngx_alloc_chain_link(r->pool);\n                if (cl == NULL) {\n                    return NGX_ERROR;\n                }\n                cl->buf = b;\n            }\n            b->memory = 1;\n            b->pos = ctx->errmsg.data;\n            b->last = ctx->errmsg.data + ctx->errmsg.len;\n            cl->next = NULL;\n            *ctx->last_out = cl;\n            ctx->last_out = &cl->next;\n            continue;\n        }\n        if (ctx->buf->last_buf || ngx_buf_in_memory(ctx->buf)) {\n            if (b == NULL) {\n                if (ctx->free) {\n                    cl = ctx->free;\n                    ctx->free = ctx->free->next;\n                    b = cl->buf;\n                    ngx_memzero(b, sizeof(ngx_buf_t));\n                } else {\n                    b = ngx_calloc_buf(r->pool);\n                    if (b == NULL) {\n                        return NGX_ERROR;\n                    }\n                    cl = ngx_alloc_chain_link(r->pool);\n                    if (cl == NULL) {\n                        return NGX_ERROR;\n                    }\n                    cl->buf = b;\n                }\n                b->sync = 1;\n                cl->next = NULL;\n                *ctx->last_out = cl;\n                ctx->last_out = &cl->next;\n            }\n            b->last_buf = ctx->buf->last_buf;\n            b->shadow = ctx->buf;\n            if (slcf->ignore_recycled_buffers == 0)  {\n                b->recycled = ctx->buf->recycled;\n            }\n        }\n        ctx->buf = NULL;\n        ctx->saved = ctx->looked;\n    }\n    if (ctx->out == NULL && ctx->busy == NULL) {\n        return NGX_OK;\n    }\n    return ngx_http_ssi_output(r, ctx);\n}', 'static ngx_int_t\nngx_http_ssi_parse(ngx_http_request_t *r, ngx_http_ssi_ctx_t *ctx)\n{\n    u_char                *p, *value, *last, *copy_end, ch;\n    size_t                 looked;\n    ngx_http_ssi_state_e   state;\n    state = ctx->state;\n    looked = ctx->looked;\n    last = ctx->buf->last;\n    copy_end = ctx->copy_end;\n    for (p = ctx->pos; p < last; p++) {\n        ch = *p;\n        if (state == ssi_start_state) {\n            for ( ;; ) {\n                if (ch == \'<\') {\n                    copy_end = p;\n                    looked = 1;\n                    state = ssi_tag_state;\n                    goto tag_started;\n                }\n                if (++p == last) {\n                    break;\n                }\n                ch = *p;\n            }\n            ctx->state = state;\n            ctx->pos = p;\n            ctx->looked = looked;\n            ctx->copy_end = p;\n            if (ctx->copy_start == NULL) {\n                ctx->copy_start = ctx->buf->pos;\n            }\n            return NGX_AGAIN;\n        tag_started:\n            continue;\n        }\n        switch (state) {\n        case ssi_start_state:\n            break;\n        case ssi_tag_state:\n            switch (ch) {\n            case \'!\':\n                looked = 2;\n                state = ssi_comment0_state;\n                break;\n            case \'<\':\n                copy_end = p;\n                break;\n            default:\n                copy_end = p;\n                looked = 0;\n                state = ssi_start_state;\n                break;\n            }\n            break;\n        case ssi_comment0_state:\n            switch (ch) {\n            case \'-\':\n                looked = 3;\n                state = ssi_comment1_state;\n                break;\n            case \'<\':\n                copy_end = p;\n                looked = 1;\n                state = ssi_tag_state;\n                break;\n            default:\n                copy_end = p;\n                looked = 0;\n                state = ssi_start_state;\n                break;\n            }\n            break;\n        case ssi_comment1_state:\n            switch (ch) {\n            case \'-\':\n                looked = 4;\n                state = ssi_sharp_state;\n                break;\n            case \'<\':\n                copy_end = p;\n                looked = 1;\n                state = ssi_tag_state;\n                break;\n            default:\n                copy_end = p;\n                looked = 0;\n                state = ssi_start_state;\n                break;\n            }\n            break;\n        case ssi_sharp_state:\n            switch (ch) {\n            case \'#\':\n                if (p - ctx->pos < 4) {\n                    ctx->saved = 0;\n                }\n                looked = 0;\n                state = ssi_precommand_state;\n                break;\n            case \'<\':\n                copy_end = p;\n                looked = 1;\n                state = ssi_tag_state;\n                break;\n            default:\n                copy_end = p;\n                looked = 0;\n                state = ssi_start_state;\n                break;\n            }\n            break;\n        case ssi_precommand_state:\n            switch (ch) {\n            case \' \':\n            case CR:\n            case LF:\n            case \'\\t\':\n                break;\n            default:\n                ctx->command.len = 1;\n                ctx->command.data = ngx_pnalloc(r->pool,\n                                                NGX_HTTP_SSI_COMMAND_LEN);\n                if (ctx->command.data == NULL) {\n                    return NGX_ERROR;\n                }\n                ctx->command.data[0] = ch;\n                ctx->key = 0;\n                ctx->key = ngx_hash(ctx->key, ch);\n                ctx->params.nelts = 0;\n                state = ssi_command_state;\n                break;\n            }\n            break;\n        case ssi_command_state:\n            switch (ch) {\n            case \' \':\n            case CR:\n            case LF:\n            case \'\\t\':\n                state = ssi_preparam_state;\n                break;\n            case \'-\':\n                state = ssi_comment_end0_state;\n                break;\n            default:\n                if (ctx->command.len == NGX_HTTP_SSI_COMMAND_LEN) {\n                    ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,\n                                  "the \\"%V%c...\\" SSI command is too long",\n                                  &ctx->command, ch);\n                    state = ssi_error_state;\n                    break;\n                }\n                ctx->command.data[ctx->command.len++] = ch;\n                ctx->key = ngx_hash(ctx->key, ch);\n            }\n            break;\n        case ssi_preparam_state:\n            switch (ch) {\n            case \' \':\n            case CR:\n            case LF:\n            case \'\\t\':\n                break;\n            case \'-\':\n                state = ssi_comment_end0_state;\n                break;\n            default:\n                ctx->param = ngx_array_push(&ctx->params);\n                if (ctx->param == NULL) {\n                    return NGX_ERROR;\n                }\n                ctx->param->key.len = 1;\n                ctx->param->key.data = ngx_pnalloc(r->pool,\n                                                   NGX_HTTP_SSI_PARAM_LEN);\n                if (ctx->param->key.data == NULL) {\n                    return NGX_ERROR;\n                }\n                ctx->param->key.data[0] = ch;\n                ctx->param->value.len = 0;\n                if (ctx->value_buf == NULL) {\n                    ctx->param->value.data = ngx_pnalloc(r->pool,\n                                                         ctx->value_len + 1);\n                    if (ctx->param->value.data == NULL) {\n                        return NGX_ERROR;\n                    }\n                } else {\n                    ctx->param->value.data = ctx->value_buf;\n                }\n                state = ssi_param_state;\n                break;\n            }\n            break;\n        case ssi_param_state:\n            switch (ch) {\n            case \' \':\n            case CR:\n            case LF:\n            case \'\\t\':\n                state = ssi_preequal_state;\n                break;\n            case \'=\':\n                state = ssi_prevalue_state;\n                break;\n            case \'-\':\n                state = ssi_error_end0_state;\n                ctx->param->key.data[ctx->param->key.len++] = ch;\n                ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,\n                              "invalid \\"%V\\" parameter in \\"%V\\" SSI command",\n                              &ctx->param->key, &ctx->command);\n                break;\n            default:\n                if (ctx->param->key.len == NGX_HTTP_SSI_PARAM_LEN) {\n                    state = ssi_error_state;\n                    ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,\n                                  "too long \\"%V%c...\\" parameter in "\n                                  "\\"%V\\" SSI command",\n                                  &ctx->param->key, ch, &ctx->command);\n                    break;\n                }\n                ctx->param->key.data[ctx->param->key.len++] = ch;\n            }\n            break;\n        case ssi_preequal_state:\n            switch (ch) {\n            case \' \':\n            case CR:\n            case LF:\n            case \'\\t\':\n                break;\n            case \'=\':\n                state = ssi_prevalue_state;\n                break;\n            default:\n                if (ch == \'-\') {\n                    state = ssi_error_end0_state;\n                } else {\n                    state = ssi_error_state;\n                }\n                ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,\n                              "unexpected \\"%c\\" symbol after \\"%V\\" "\n                              "parameter in \\"%V\\" SSI command",\n                              ch, &ctx->param->key, &ctx->command);\n                break;\n            }\n            break;\n        case ssi_prevalue_state:\n            switch (ch) {\n            case \' \':\n            case CR:\n            case LF:\n            case \'\\t\':\n                break;\n            case \'"\':\n                state = ssi_double_quoted_value_state;\n                break;\n            case \'\\\'\':\n                state = ssi_quoted_value_state;\n                break;\n            default:\n                if (ch == \'-\') {\n                    state = ssi_error_end0_state;\n                } else {\n                    state = ssi_error_state;\n                }\n                ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,\n                              "unexpected \\"%c\\" symbol before value of "\n                              "\\"%V\\" parameter in \\"%V\\" SSI command",\n                              ch, &ctx->param->key, &ctx->command);\n                break;\n            }\n            break;\n        case ssi_double_quoted_value_state:\n            switch (ch) {\n            case \'"\':\n                state = ssi_postparam_state;\n                break;\n            case \'\\\\\':\n                ctx->saved_state = ssi_double_quoted_value_state;\n                state = ssi_quoted_symbol_state;\n            default:\n                if (ctx->param->value.len == ctx->value_len) {\n                    ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,\n                                  "too long \\"%V%c...\\" value of \\"%V\\" "\n                                  "parameter in \\"%V\\" SSI command",\n                                  &ctx->param->value, ch, &ctx->param->key,\n                                  &ctx->command);\n                    state = ssi_error_state;\n                    break;\n                }\n                ctx->param->value.data[ctx->param->value.len++] = ch;\n            }\n            break;\n        case ssi_quoted_value_state:\n            switch (ch) {\n            case \'\\\'\':\n                state = ssi_postparam_state;\n                break;\n            case \'\\\\\':\n                ctx->saved_state = ssi_quoted_value_state;\n                state = ssi_quoted_symbol_state;\n            default:\n                if (ctx->param->value.len == ctx->value_len) {\n                    ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,\n                                  "too long \\"%V%c...\\" value of \\"%V\\" "\n                                  "parameter in \\"%V\\" SSI command",\n                                  &ctx->param->value, ch, &ctx->param->key,\n                                  &ctx->command);\n                    state = ssi_error_state;\n                    break;\n                }\n                ctx->param->value.data[ctx->param->value.len++] = ch;\n            }\n            break;\n        case ssi_quoted_symbol_state:\n            state = ctx->saved_state;\n            if (ctx->param->value.len == ctx->value_len) {\n                ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,\n                              "too long \\"%V%c...\\" value of \\"%V\\" "\n                              "parameter in \\"%V\\" SSI command",\n                              &ctx->param->value, ch, &ctx->param->key,\n                              &ctx->command);\n                state = ssi_error_state;\n                break;\n            }\n            ctx->param->value.data[ctx->param->value.len++] = ch;\n            break;\n        case ssi_postparam_state:\n            if (ctx->param->value.len + 1 < ctx->value_len / 2) {\n                value = ngx_pnalloc(r->pool, ctx->param->value.len + 1);\n                if (value == NULL) {\n                    return NGX_ERROR;\n                }\n                ngx_memcpy(value, ctx->param->value.data,\n                           ctx->param->value.len);\n                ctx->value_buf = ctx->param->value.data;\n                ctx->param->value.data = value;\n            } else {\n                ctx->value_buf = NULL;\n            }\n            switch (ch) {\n            case \' \':\n            case CR:\n            case LF:\n            case \'\\t\':\n                state = ssi_preparam_state;\n                break;\n            case \'-\':\n                state = ssi_comment_end0_state;\n                break;\n            default:\n                ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,\n                              "unexpected \\"%c\\" symbol after \\"%V\\" value "\n                              "of \\"%V\\" parameter in \\"%V\\" SSI command",\n                              ch, &ctx->param->value, &ctx->param->key,\n                              &ctx->command);\n                state = ssi_error_state;\n                break;\n            }\n            break;\n        case ssi_comment_end0_state:\n            switch (ch) {\n            case \'-\':\n                state = ssi_comment_end1_state;\n                break;\n            default:\n                ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,\n                              "unexpected \\"%c\\" symbol in \\"%V\\" SSI command",\n                              ch, &ctx->command);\n                state = ssi_error_state;\n                break;\n            }\n            break;\n        case ssi_comment_end1_state:\n            switch (ch) {\n            case \'>\':\n                ctx->state = ssi_start_state;\n                ctx->pos = p + 1;\n                ctx->looked = looked;\n                ctx->copy_end = copy_end;\n                if (ctx->copy_start == NULL && copy_end) {\n                    ctx->copy_start = ctx->buf->pos;\n                }\n                return NGX_OK;\n            default:\n                ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,\n                              "unexpected \\"%c\\" symbol in \\"%V\\" SSI command",\n                              ch, &ctx->command);\n                state = ssi_error_state;\n                break;\n            }\n            break;\n        case ssi_error_state:\n            switch (ch) {\n            case \'-\':\n                state = ssi_error_end0_state;\n                break;\n            default:\n                break;\n            }\n            break;\n        case ssi_error_end0_state:\n            switch (ch) {\n            case \'-\':\n                state = ssi_error_end1_state;\n                break;\n            default:\n                state = ssi_error_state;\n                break;\n            }\n            break;\n        case ssi_error_end1_state:\n            switch (ch) {\n            case \'>\':\n                ctx->state = ssi_start_state;\n                ctx->pos = p + 1;\n                ctx->looked = looked;\n                ctx->copy_end = copy_end;\n                if (ctx->copy_start == NULL && copy_end) {\n                    ctx->copy_start = ctx->buf->pos;\n                }\n                return NGX_HTTP_SSI_ERROR;\n            default:\n                state = ssi_error_state;\n                break;\n            }\n            break;\n        }\n    }\n    ctx->state = state;\n    ctx->pos = p;\n    ctx->looked = looked;\n    ctx->copy_end = (state == ssi_start_state) ? p : copy_end;\n    if (ctx->copy_start == NULL && ctx->copy_end) {\n        ctx->copy_start = ctx->buf->pos;\n    }\n    return NGX_AGAIN;\n}']