ПРОЕКТЫ 


  АРХИВ 


Apache-Talk @lexa.ru 

Inet-Admins @info.east.ru 

Filmscanners @halftone.co.uk 

Security-alerts @yandex-team.ru 

nginx-ru @sysoev.ru 


  СТАТЬИ 


  ПЕРСОНАЛЬНОЕ 


  ПРОГРАММЫ 



ПИШИТЕ
ПИСЬМА












     АРХИВ :: nginx-ru
Nginx-ru mailing list archive (nginx-ru@sysoev.ru)

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Разработка модуля


  • To: nginx-ru@xxxxxxxxx
  • Subject: Разработка модуля
  • From: "Alexander Dolgarev" <a.dolgarev@xxxxxxxxx>
  • Date: Wed, 12 Mar 2008 02:32:55 +0200
  • Dkim-signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=gamma; h=domainkey-signature:received:received:message-id:date:from:to:subject:mime-version:content-type; bh=oL7VQYjB0Qq6sAHp68zWkoqJdDLrVBSe1iAD6T1AEyQ=; b=tmQXkCDkfR11wTc3LsgWFR//A0JQZ4LLDCgbSCyb0ZkZj1Axbea2LjT7o69If4xEc4G+To7rBta5jQa0npla8l1v+3aGEGesHP6wdC8y6VlWXYOvR+FkGvcDVGq4UPX5zv0vo2aISUYy070g8MQBkKAwxHnAV5SNHChCin6VjF0=
  • Domainkey-signature: a=rsa-sha1; c=nofws; d=gmail.com; s=gamma; h=message-id:date:from:to:subject:mime-version:content-type; b=Psm8RRRSaPrsjVHOMsw3fX1lynreHz2wvaUoieyhkTej/1APo8Y92a/Yihz4LYjQt6TnsalivakmWjy4XmuKo/qiGWzVlM23N+NszIYixrHePaw4hotMn2Jv3uSVe15SDzx4Avlwr/2T5oHMoWQ7vg4g+A4Tdu9gAkBGS5yrywA=

Наткнулся на простую проблему, не могу понять в чем дело. Надо было
слегка расширить модуль sub_filter, скопировал
ngx_http_sub_filter_module.c в ngx_http_substitute_filter_module.c,
заменил соответственно везде sub_ на substitute_ (в
ngx_http_substitute_filter_commands тоже), написал config и собрал
./configure --prefix=/usr/local/nginx --add-module=../substitute
--with-http_sub_module

При этом
        location /test/ {
            sub_filter </body> '!!!</body>';
            sub_filter_once on;

        }
работает, а
        location /test/ {
            substitute_filter </body> '!!!</body>';
            substitute_filter_once on;

        }
работать отказывается, причем ошибок никаких не выдает,
ngx_http_substitute_filter_init вызывается, а
ngx_http_substitute_header_filter и ngx_http_substitute_body_filter -
нет.
В чем может быть проблема (исходники в аттачменте)?

Еще момент, для отладки использую daemon off, удобно, но все же, куда
попадает вывод функций ngx_log_debugX()? Логично предположить, что в
error_log с уровнем debug, но там нет тех сообщений, что выводились с
помощью ngx_log_debugX().

Заранее спасибо.
#include <ngx_config.h>
#include <ngx_core.h>
#include <ngx_http.h>


typedef struct {
    ngx_str_t      match;
    ngx_str_t      sub;

    ngx_array_t   *types;     /* array of ngx_str_t */

    ngx_array_t   *substitute_lengths;
    ngx_array_t   *substitute_values;

    ngx_flag_t     once;
} ngx_http_substitute_loc_conf_t;


typedef enum {
    substitute_start_state = 0,
    substitute_match_state,
} ngx_http_substitute_state_e;


typedef struct {
    ngx_str_t      match;

    ngx_uint_t     once;   /* unsigned  once:1 */

    ngx_buf_t     *buf;

    u_char        *pos;
    u_char        *copy_start;
    u_char        *copy_end;

    ngx_chain_t   *in;
    ngx_chain_t   *out;
    ngx_chain_t  **last_out;
    ngx_chain_t   *busy;
    ngx_chain_t   *free;

    ngx_str_t      sub;

    ngx_uint_t     state;
    size_t         saved;
    size_t         looked;
} ngx_http_substitute_ctx_t;


static ngx_int_t ngx_http_substitute_output(ngx_http_request_t *r,
    ngx_http_substitute_ctx_t *ctx);
static ngx_int_t ngx_http_substitute_parse(ngx_http_request_t *r,
    ngx_http_substitute_ctx_t *ctx);

static char * ngx_http_substitute_filter(ngx_conf_t *cf, ngx_command_t *cmd,
    void *conf);
static char *ngx_http_substitute_types(ngx_conf_t *cf, ngx_command_t *cmd, void 
*conf);
static void *ngx_http_substitute_create_conf(ngx_conf_t *cf);
static char *ngx_http_substitute_merge_conf(ngx_conf_t *cf,
    void *parent, void *child);
static ngx_int_t ngx_http_substitute_filter_init(ngx_conf_t *cf);


static ngx_command_t  ngx_http_substitute_filter_commands[] = {

    { ngx_string("substitute_filter"),
      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE2,
      ngx_http_substitute_filter,
      NGX_HTTP_LOC_CONF_OFFSET,
      0,
      NULL },

    { ngx_string("substitute_filter_types"),
      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
      ngx_http_substitute_types,
      NGX_HTTP_LOC_CONF_OFFSET,
      0,
      NULL },

    { ngx_string("substitute_filter_once"),
      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
      ngx_conf_set_flag_slot,
      NGX_HTTP_LOC_CONF_OFFSET,
      offsetof(ngx_http_substitute_loc_conf_t, once),
      NULL },

      ngx_null_command
};


static ngx_http_module_t  ngx_http_substitute_filter_module_ctx = {
    NULL,                                  /* preconfiguration */
    ngx_http_substitute_filter_init,              /* postconfiguration */

    NULL,                                  /* create main configuration */
    NULL,                                  /* init main configuration */

    NULL,                                  /* create server configuration */
    NULL,                                  /* merge server configuration */

    ngx_http_substitute_create_conf,              /* create location 
configuration */
    ngx_http_substitute_merge_conf                /* merge location 
configuration */
};


ngx_module_t  ngx_http_substitute_filter_module = {
    NGX_MODULE_V1,
    &ngx_http_substitute_filter_module_ctx,       /* module context */
    ngx_http_substitute_filter_commands,          /* module directives */
    NGX_HTTP_MODULE,                       /* module type */
    NULL,                                  /* init master */
    NULL,                                  /* init module */
    NULL,                                  /* init process */
    NULL,                                  /* init thread */
    NULL,                                  /* exit thread */
    NULL,                                  /* exit process */
    NULL,                                  /* exit master */
    NGX_MODULE_V1_PADDING
};


static ngx_http_output_header_filter_pt  ngx_http_next_header_filter;
static ngx_http_output_body_filter_pt    ngx_http_next_body_filter;


static ngx_int_t
ngx_http_substitute_header_filter(ngx_http_request_t *r)
{
    ngx_str_t                *type;
    ngx_uint_t                i;
    ngx_http_substitute_ctx_t        *ctx;
    ngx_http_substitute_loc_conf_t  *slcf;

    slcf = ngx_http_get_module_loc_conf(r, ngx_http_substitute_filter_module);

    if (slcf->match.len == 0
        || r->headers_out.content_type.len == 0
        || r->headers_out.content_length_n == 0)
    {
        return ngx_http_next_header_filter(r);
    }

    type = slcf->types->elts;
    for (i = 0; i < slcf->types->nelts; i++) {
        if (r->headers_out.content_type.len >= type[i].len
            && ngx_strncasecmp(r->headers_out.content_type.data,
                               type[i].data, type[i].len) == 0)
        {
            goto found;
        }
    }

    return ngx_http_next_header_filter(r);

found:

    ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_substitute_ctx_t));
    if (ctx == NULL) {
        return NGX_ERROR;
    }

    ngx_http_set_ctx(r, ctx, ngx_http_substitute_filter_module);

    ctx->match = slcf->match;
    ctx->last_out = &ctx->out;
    ctx->sub = slcf->sub;

    r->filter_need_in_memory = 1;

    if (r == r->main) {
        ngx_http_clear_content_length(r);
        ngx_http_clear_last_modified(r);
    }

    return ngx_http_next_header_filter(r);
}


static ngx_int_t
ngx_http_substitute_body_filter(ngx_http_request_t *r, ngx_chain_t *in)
{
    ngx_int_t                  rc;
    ngx_buf_t                 *b;
    ngx_chain_t               *cl;
    ngx_http_substitute_ctx_t        *ctx;
    ngx_http_substitute_loc_conf_t   *slcf;

    ctx = ngx_http_get_module_ctx(r, ngx_http_substitute_filter_module);

    if (ctx == NULL) {
        return ngx_http_next_body_filter(r, in);
    }

    if ((in == NULL
         && ctx->buf == NULL
         && ctx->in == NULL
         && ctx->busy == NULL))
    {
        return ngx_http_next_body_filter(r, in);
    }

    if (ctx->once && (ctx->buf == NULL || ctx->in == NULL)) {

        if (ctx->busy) {
            if (ngx_http_substitute_output(r, ctx) == NGX_ERROR) {
                return NGX_ERROR;
            }
        }

        return ngx_http_next_body_filter(r, in);
    }

    /* add the incoming chain to the chain ctx->in */

    if (in) {
        if (ngx_chain_add_copy(r->pool, &ctx->in, in) == NGX_ERROR) {
            return NGX_ERROR;
        }
    }

    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                   "http sub filter \"%V\"", &r->uri);

    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 == substitute_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: %d state: %d", ctx->saved, ctx->state);

            rc = ngx_http_substitute_parse(r, ctx);

            ngx_log_debug4(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                           "parse: %d, looked: %d %p-%p",
                           rc, ctx->looked, ctx->copy_start, ctx->copy_end);

            if (rc == NGX_ERROR) {
                return rc;
            }

            if (ctx->copy_start != ctx->copy_end) {

                ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                               "saved: %d", 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 = ctx->match.data;
                    b->last = ctx->match.data + 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) {
                    b->file_last = b->file_pos + (b->last - b->start);
                    b->file_pos += b->pos - b->start;
                }

                cl->next = NULL;
                *ctx->last_out = cl;
                ctx->last_out = &cl->next;
            }

            if (ctx->state == substitute_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;
            }


            /* rc == NGX_OK */

            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;
            }

            slcf = ngx_http_get_module_loc_conf(r, 
ngx_http_substitute_filter_module);

            if (ctx->sub.data == NULL) {

                if (ngx_http_script_run(r, &ctx->sub, 
slcf->substitute_lengths->elts,
                                        0, slcf->substitute_values->elts)
                    == NULL)
                {
                    return NGX_ERROR;
                }
            }

            if (ctx->sub.len) {
                b->memory = 1;
                b->pos = ctx->sub.data;
                b->last = ctx->sub.data + ctx->sub.len;

            } else {
                b->sync = 1;
            }

            cl->buf = b;
            cl->next = NULL;
            *ctx->last_out = cl;
            ctx->last_out = &cl->next;

            ctx->once = slcf->once;

            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;

            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_substitute_output(r, ctx);
}


static ngx_int_t
ngx_http_substitute_output(ngx_http_request_t *r, ngx_http_substitute_ctx_t 
*ctx)
{
    ngx_int_t     rc;
    ngx_buf_t    *b;
    ngx_chain_t  *cl;

#if 1
    b = NULL;
    for (cl = ctx->out; cl; cl = cl->next) {
        ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                       "sub out: %p %p", cl->buf, cl->buf->pos);
        if (cl->buf == b) {
            ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0,
                          "the same buf was used in sub");
            ngx_debug_point();
            return NGX_ERROR;
        }
        b = cl->buf;
    }
#endif

    rc = ngx_http_next_body_filter(r, ctx->out);

    if (ctx->busy == NULL) {
        ctx->busy = ctx->out;

    } else {
        for (cl = ctx->busy; cl->next; cl = cl->next) { /* void */ }
        cl->next = ctx->out;
    }

    ctx->out = NULL;
    ctx->last_out = &ctx->out;

    while (ctx->busy) {

        cl = ctx->busy;
        b = cl->buf;

        if (ngx_buf_size(b) != 0) {
            break;
        }

#if (NGX_HAVE_WRITE_ZEROCOPY)
        if (b->zerocopy_busy) {
            break;
        }
#endif

        if (b->shadow) {
            b->shadow->pos = b->shadow->last;
        }

        ctx->busy = cl->next;

        if (ngx_buf_in_memory(b) || b->in_file) {
            /* add data bufs only to the free buf chain */

            cl->next = ctx->free;
            ctx->free = cl;
        }
    }

    if (ctx->in || ctx->buf) {
        r->buffered |= NGX_HTTP_SUB_BUFFERED;

    } else {
        r->buffered &= ~NGX_HTTP_SUB_BUFFERED;
    }

    return rc;
}


static ngx_int_t
ngx_http_substitute_parse(ngx_http_request_t *r, ngx_http_substitute_ctx_t *ctx)
{
    u_char                *p, *last, *copy_end, ch, match;
    size_t                 looked;
    ngx_http_substitute_state_e   state;

    if (ctx->once) {
        ctx->copy_start = ctx->pos;
        ctx->copy_end = ctx->buf->last;
        ctx->pos = ctx->buf->last;
        ctx->looked = 0;

        ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "once");

        return NGX_AGAIN;
    }

    state = ctx->state;
    looked = ctx->looked;
    last = ctx->buf->last;
    copy_end = ctx->copy_end;

    for (p = ctx->pos; p < last; p++) {

        ch = *p;
        ch = ngx_tolower(ch);

        if (state == substitute_start_state) {

            /* the tight loop */

            match = ctx->match.data[0];

            for ( ;; ) {
                if (ch == match) {
                    copy_end = p;
                    looked = 1;
                    state = substitute_match_state;

                    goto match_started;
                }

                if (++p == last) {
                    break;
                }

                ch = *p;
                ch = ngx_tolower(ch);
            }

            ctx->state = state;
            ctx->pos = p;
            ctx->looked = looked;
            ctx->copy_end = p;

            if (ctx->copy_start == NULL) {
                ctx->copy_start = ctx->buf->pos;
            }

            return NGX_AGAIN;

        match_started:

            continue;
        }

        /* state == substitute_match_state */

        if (ch == ctx->match.data[looked]) {
            looked++;

            if (looked == ctx->match.len) {
                if ((size_t) (p - ctx->pos) < looked) {
                    ctx->saved = 0;
                }

                ctx->state = substitute_start_state;
                ctx->pos = p + 1;
                ctx->looked = looked;
                ctx->copy_end = copy_end;

                if (ctx->copy_start == NULL && copy_end) {
                    ctx->copy_start = ctx->buf->pos;
                }

                return NGX_OK;
            }

        } else if (ch == ctx->match.data[0]) {
            copy_end = p;
            looked = 1;

        } else {
            copy_end = p;
            looked = 0;
            state = substitute_start_state;
        }
    }

    ctx->state = state;
    ctx->pos = p;
    ctx->looked = looked;

    ctx->copy_end = (state == substitute_start_state) ? p : copy_end;

    if (ctx->copy_start == NULL && ctx->copy_end) {
        ctx->copy_start = ctx->buf->pos;
    }

    return NGX_AGAIN;
}


static char *
ngx_http_substitute_filter(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
    ngx_http_substitute_loc_conf_t *slcf = conf;

    ngx_str_t                  *value;
    ngx_int_t                   n;
    ngx_uint_t                  i;
    ngx_http_script_compile_t   sc;

    if (slcf->match.len) {
        return "is duplicate";
    }

    value = cf->args->elts;

    slcf->match = value[1];

    for (i = 0; i < value[1].len; i++) {
        value[1].data[i] = ngx_tolower(value[1].data[i]);
    }

    n = ngx_http_script_variables_count(&value[2]);

    if (n == 0) {
        slcf->sub = value[2];
        return NGX_CONF_OK;
    }

    ngx_memzero(&sc, sizeof(ngx_http_script_compile_t));

    sc.cf = cf;
    sc.source = &value[2];
    sc.lengths = &slcf->substitute_lengths;
    sc.values = &slcf->substitute_values;
    sc.variables = n;
    sc.complete_lengths = 1;
    sc.complete_values = 1;

    if (ngx_http_script_compile(&sc) != NGX_OK) {
        return NGX_CONF_ERROR;
    }

    return NGX_CONF_OK;
}


static char *
ngx_http_substitute_types(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
    ngx_http_substitute_loc_conf_t *slcf = conf;

    ngx_str_t   *value, *type;
    ngx_uint_t   i;

    if (slcf->types == NULL) {
        slcf->types = ngx_array_create(cf->pool, 4, sizeof(ngx_str_t));
        if (slcf->types == NULL) {
            return NGX_CONF_ERROR;
        }

        type = ngx_array_push(slcf->types);
        if (type == NULL) {
            return NGX_CONF_ERROR;
        }

        type->len = sizeof("text/html") - 1;
        type->data = (u_char *) "text/html";
    }

    value = cf->args->elts;

    for (i = 1; i < cf->args->nelts; i++) {

        if (ngx_strcmp(value[i].data, "text/html") == 0) {
            continue;
        }

        type = ngx_array_push(slcf->types);
        if (type == NULL) {
            return NGX_CONF_ERROR;
        }

        type->len = value[i].len;

        type->data = ngx_palloc(cf->pool, type->len + 1);
        if (type->data == NULL) {
            return NGX_CONF_ERROR;
        }

        ngx_cpystrn(type->data, value[i].data, type->len + 1);
    }

    return NGX_CONF_OK;
}


static void *
ngx_http_substitute_create_conf(ngx_conf_t *cf)
{
    ngx_http_substitute_loc_conf_t  *slcf;

    slcf = ngx_pcalloc(cf->pool, sizeof(ngx_http_substitute_loc_conf_t));
    if (slcf == NULL) {
        return NGX_CONF_ERROR;
    }

    /*
     * set by ngx_pcalloc():
     *
     *     conf->match.len = 0;
     *     conf->match.data = NULL;
     *     conf->sub.len = 0;
     *     conf->sub.data = NULL;
     *     conf->substitute_lengths = NULL;
     *     conf->substitute_values = NULL;
     *     conf->types = NULL;
     */

    slcf->once = NGX_CONF_UNSET;

    return slcf;
}


static char *
ngx_http_substitute_merge_conf(ngx_conf_t *cf, void *parent, void *child)
{
    ngx_http_substitute_loc_conf_t *prev = parent;
    ngx_http_substitute_loc_conf_t *conf = child;

    ngx_str_t  *type;

    ngx_conf_merge_value(conf->once, prev->once, 1);
    ngx_conf_merge_str_value(conf->match, prev->match, "");

    if (conf->sub.data == NULL && conf->substitute_lengths == NULL) {
        conf->sub = prev->sub;
        conf->substitute_lengths = prev->substitute_lengths;
        conf->substitute_values = prev->substitute_values;
    }

    if (conf->types == NULL) {
        if (prev->types == NULL) {
            conf->types = ngx_array_create(cf->pool, 1, sizeof(ngx_str_t));
            if (conf->types == NULL) {
                return NGX_CONF_ERROR;
            }

            type = ngx_array_push(conf->types);
            if (type == NULL) {
                return NGX_CONF_ERROR;
            }

            type->len = sizeof("text/html") - 1;
            type->data = (u_char *) "text/html";

        } else {
            conf->types = prev->types;
        }
    }

    return NGX_CONF_OK;
}


static ngx_int_t
ngx_http_substitute_filter_init(ngx_conf_t *cf)
{
    ngx_http_next_header_filter = ngx_http_top_header_filter;
    ngx_http_top_header_filter = ngx_http_substitute_header_filter;

    ngx_http_next_body_filter = ngx_http_top_body_filter;
    ngx_http_top_body_filter = ngx_http_substitute_body_filter;

    return NGX_OK;
}

Attachment: config
Description: Binary data



 




Copyright © Lexa Software, 1996-2009.