Ejemplo n.º 1
0
RegexSearch::RegexSearch(const std::string& regex,
                         Report* report,
                         const std::wstring& file_path)
    : regex_(regex),
      report_(report),
      file_path_(file_path),
      block_offset_(0),
      match_offset_(0),
      sre_pool_(nullptr),
      sre_ctx_(nullptr) {
  sre_pool_ = sre_create_pool(4096);
  assert(sre_pool_);
  sre_uint_t ncaps;
  sre_int_t err_offset;
  sre_regex_t* sre_regex = sre_regex_parse(
      sre_pool_,
      const_cast<sre_char*>(reinterpret_cast<const sre_char*>(regex_.c_str())),
      &ncaps, 0, &err_offset);
  assert(sre_regex);
  sre_program_t* sre_program = sre_regex_compile(sre_pool_, sre_regex);
  assert(sre_program);
  matches_.resize(2 * (ncaps + 1));
  sre_ctx_ = sre_vm_pike_create_ctx(sre_pool_, sre_program, matches_.data(),
                                    matches_.size() * sizeof(sre_int_t));
  assert(sre_ctx_);
}
static char *
ngx_http_replace_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
{
    u_char         **value;
    sre_int_t        err_offset, err_regex_id;
    ngx_str_t        prefix, suffix;
    sre_pool_t      *ppool; /* parser pool */
    sre_regex_t     *re;
    sre_program_t   *prog;

    ngx_http_replace_main_conf_t    *rmcf;

    ngx_http_replace_loc_conf_t *prev = parent;
    ngx_http_replace_loc_conf_t *conf = child;

    ngx_conf_merge_size_value(conf->max_buffered_size,
                              prev->max_buffered_size,
                              8192);

    ngx_conf_merge_uint_value(conf->last_modified,
                              prev->last_modified,
                              NGX_HTTP_REPLACE_CLEAR_LAST_MODIFIED);

    if (ngx_http_merge_types(cf, &conf->types_keys, &conf->types,
                             &prev->types_keys, &prev->types,
                             ngx_http_html_default_types)
        != NGX_OK)
    {
        return NGX_CONF_ERROR;
    }

    if (conf->skip == NULL) {
        conf->skip = prev->skip;
    }

    if (conf->regexes.nelts > 0 && conf->program == NULL) {

        dd("parsing and compiling %d regexes", (int) conf->regexes.nelts);

        ppool = sre_create_pool(1024);
        if (ppool == NULL) {
            return NGX_CONF_ERROR;
        }

        value = conf->regexes.elts;

        re = sre_regex_parse_multi(ppool, value, conf->regexes.nelts,
                                   &conf->ncaps, conf->multi_flags.elts,
                                   &err_offset, &err_regex_id);

        if (re == NULL) {

            if (err_offset >= 0) {
                prefix.data = value[err_regex_id];
                prefix.len = err_offset;

                suffix.data = value[err_regex_id] + err_offset;
                suffix.len = ngx_strlen(value[err_regex_id]) - err_offset;

                ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                                   "failed to parse regex at offset %i: "
                                   "syntax error; marked by <-- HERE in "
                                   "\"%V <-- HERE %V\"",
                                   (ngx_int_t) err_offset, &prefix, &suffix);

            } else {

                if (err_regex_id >= 0) {
                    ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                                       "failed to parse regex \"%s\"",
                                       value[err_regex_id]);

                } else {
                    ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                                       "failed to parse regex \"%s\" "
                                       "and its siblings",
                                       value[0]);
                }
            }

            sre_destroy_pool(ppool);
            return NGX_CONF_ERROR;
        }

        rmcf = ngx_http_conf_get_module_main_conf(cf,
                                              ngx_http_replace_filter_module);

        prog = sre_regex_compile(rmcf->compiler_pool, re);

        sre_destroy_pool(ppool);

        if (prog == NULL) {
            ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                               "failed to compile regex \"%s\" and its "
                               "siblings", value[0]);

            return NGX_CONF_ERROR;
        }

        conf->program = prog;
        conf->ovecsize = 2 * (conf->ncaps + 1) * sizeof(sre_int_t);

    } else {

        conf->regexes       = prev->regexes;
        conf->multi_once    = prev->multi_once;
        conf->multi_flags   = prev->multi_flags;
        conf->multi_replace = prev->multi_replace;
        conf->parse_buf     = prev->parse_buf;
        conf->verbatim      = prev->verbatim;
        conf->program       = prev->program;
        conf->ncaps         = prev->ncaps;
        conf->ovecsize      = prev->ovecsize;
        conf->seen_once     = prev->seen_once;
        conf->seen_global   = prev->seen_global;
    }

    return NGX_CONF_OK;
}
static char *
ngx_http_replace_filter(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
    ngx_http_replace_loc_conf_t     *rlcf = conf;
    ngx_http_replace_main_conf_t    *rmcf;

    int             *flags;
    u_char          *p, **re;
    ngx_str_t       *value;
    ngx_uint_t       i;
    uint8_t         *once;

    ngx_pool_cleanup_t                          *cln;
    ngx_http_replace_complex_value_t            *cv;
    ngx_http_replace_compile_complex_value_t     ccv;

    value = cf->args->elts;

    re = ngx_array_push(&rlcf->regexes);
    if (re == NULL) {
        return NGX_CONF_ERROR;
    }

    *re = value[1].data;

    cv = ngx_array_push(&rlcf->multi_replace);
    if (cv == NULL) {
        return NGX_CONF_ERROR;
    }

    ngx_memzero(cv, sizeof(ngx_http_replace_complex_value_t));
    ngx_memzero(&ccv, sizeof(ngx_http_replace_compile_complex_value_t));

    ccv.cf = cf;
    ccv.value = &value[2];
    ccv.complex_value = cv;

    if (ngx_http_replace_compile_complex_value(&ccv) != NGX_OK) {
        return NGX_CONF_ERROR;
    }

    /* check variable usage in the "replace" argument */

    if (cv->capture_variables) {
        rlcf->parse_buf = ngx_http_replace_capturing_parse;

    } else if (rlcf->parse_buf == NULL) {
        rlcf->parse_buf = ngx_http_replace_non_capturing_parse;
    }

#if 0
    rlcf->parse_buf = ngx_http_replace_capturing_parse;
#endif

    flags = ngx_array_push(&rlcf->multi_flags);
    if (flags == NULL) {
        return NGX_CONF_ERROR;
    }
    *flags = 0;

    once = ngx_array_push(&rlcf->multi_once);
    if (once == NULL) {
        return NGX_CONF_ERROR;
    }
    *once = 1;  /* default to once */

    if (cf->args->nelts == 4) {
        /* 3 user args */

        p = value[3].data;

        for (i = 0; i < value[3].len; i++) {
            switch (p[i]) {
            case 'i':
                *flags |= SRE_REGEX_CASELESS;
                break;

            case 'g':
                *once = 0;
                break;

            default:
                return "specifies an unrecognized regex flag";
            }
        }
    }

    if (*once) {
        rlcf->seen_once = 1;

    } else {
        rlcf->seen_global = 1;
    }

    if (rlcf->seen_once && rlcf->regexes.nelts > 1) {
        rlcf->parse_buf = ngx_http_replace_capturing_parse;

        if (rlcf->verbatim.value.data == NULL) {
            ngx_str_t           v = ngx_string("$&");

            ngx_memzero(&ccv, sizeof(ngx_http_replace_compile_complex_value_t));

            ccv.cf = cf;
            ccv.value = &v;
            ccv.complex_value = &rlcf->verbatim;

            if (ngx_http_replace_compile_complex_value(&ccv) != NGX_OK) {
                return NGX_CONF_ERROR;
            }
        }
    }

    rmcf =
        ngx_http_conf_get_module_main_conf(cf, ngx_http_replace_filter_module);

    if (rmcf->compiler_pool == NULL) {
        rmcf->compiler_pool = sre_create_pool(SREGEX_COMPILER_POOL_SIZE);
        if (rmcf->compiler_pool == NULL) {
            return NGX_CONF_ERROR;
        }

        cln = ngx_pool_cleanup_add(cf->pool, 0);
        if (cln == NULL) {
            sre_destroy_pool(rmcf->compiler_pool);
            rmcf->compiler_pool = NULL;
            return NGX_CONF_ERROR;
        }

        cln->data = rmcf->compiler_pool;
        cln->handler = ngx_http_replace_cleanup_pool;
    }

    return NGX_CONF_OK;
}
static ngx_int_t
ngx_http_replace_header_filter(ngx_http_request_t *r)
{
    size_t                         size;
    ngx_str_t                      skip;
    ngx_pool_cleanup_t            *cln;
    ngx_http_replace_ctx_t        *ctx;
    ngx_http_replace_loc_conf_t  *rlcf;

    rlcf = ngx_http_get_module_loc_conf(r, ngx_http_replace_filter_module);

    dd("replace header filter");

    if (rlcf->regexes.nelts == 0
        || r->headers_out.content_length_n == 0
        || (r->headers_out.content_encoding
            && r->headers_out.content_encoding->value.len)
        || ngx_http_test_content_type(r, &rlcf->types) == NULL)
    {
        return ngx_http_next_header_filter(r);
    }

    dd("skip: %p", rlcf->skip);

    if (rlcf->skip != NULL) {
        if (ngx_http_complex_value(r, rlcf->skip, &skip) != NGX_OK) {
            return NGX_ERROR;
        }

        if (skip.len && (skip.len != 1 || skip.data[0] != '0')) {
            return ngx_http_next_header_filter(r);
        }
    }

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

    ctx->last_special = &ctx->special;
    ctx->last_pending = &ctx->pending;
    ctx->last_pending2 = &ctx->pending2;
    ctx->last_captured = &ctx->captured;

    ctx->sub = ngx_pcalloc(r->pool,
                           rlcf->multi_replace.nelts * sizeof(ngx_str_t));
    if (ctx->sub == NULL) {
        return NGX_ERROR;
    }

    ctx->ovector = ngx_palloc(r->pool, rlcf->ovecsize);
    if (ctx->ovector == NULL) {
        return NGX_ERROR;
    }

    size = ngx_align(rlcf->regexes.nelts, 8) / 8;
    ctx->disabled = ngx_pcalloc(r->pool, size);
    if (ctx->disabled == NULL) {
        return NGX_ERROR;
    }

    ctx->vm_pool = sre_create_pool(1024);
    if (ctx->vm_pool == NULL) {
        return NGX_ERROR;
    }

    dd("created vm pool %p", ctx->vm_pool);

    cln = ngx_pool_cleanup_add(r->pool, 0);
    if (cln == NULL) {
        sre_destroy_pool(ctx->vm_pool);
        return NGX_ERROR;
    }

    cln->data = ctx->vm_pool;
    cln->handler = ngx_http_replace_cleanup_pool;

    ctx->vm_ctx = sre_vm_pike_create_ctx(ctx->vm_pool, rlcf->program,
                                         ctx->ovector, rlcf->ovecsize);
    if (ctx->vm_ctx == NULL) {
        return NGX_ERROR;
    }

    ngx_http_set_ctx(r, ctx, ngx_http_replace_filter_module);

    ctx->last_out = &ctx->out;

    r->filter_need_in_memory = 1;

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

        if (rlcf->last_modified == NGX_HTTP_REPLACE_CLEAR_LAST_MODIFIED) {
            ngx_http_clear_last_modified(r);
        }
    }

    return ngx_http_next_header_filter(r);
}