⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 mod_ext_filter.c

📁 Apache HTTP Server 是一个功能强大的灵活的与HTTP/1.1相兼容的web服务器.这里给出的是Apache HTTP服务器的源码。
💻 C
📖 第 1 页 / 共 2 页
字号:
     * and QUERY_STRING_UNESCAPED     */    ap_add_cgi_vars(f->r);    ap_add_common_vars(f->r);    apr_table_setn(f->r->subprocess_env, "DOCUMENT_URI", f->r->uri);    apr_table_setn(f->r->subprocess_env, "DOCUMENT_PATH_INFO", f->r->path_info);    if (f->r->args) {            /* QUERY_STRING is added by ap_add_cgi_vars */        char *arg_copy = apr_pstrdup(f->r->pool, f->r->args);        ap_unescape_url(arg_copy);        apr_table_setn(f->r->subprocess_env, "QUERY_STRING_UNESCAPED",                       ap_escape_shell_cmd(f->r->pool, arg_copy));    }    env = (const char * const *) ap_create_environment(ctx->p,                                                       f->r->subprocess_env);    rc = apr_proc_create(ctx->proc,                             ctx->filter->command,                             (const char * const *)ctx->filter->args,                             env, /* environment */                            ctx->procattr,                             ctx->p);    if (rc != APR_SUCCESS) {        ap_log_rerror(APLOG_MARK, APLOG_ERR, rc, f->r,                      "couldn't create child process to run `%s'",                      ctx->filter->command);        return rc;    }    apr_pool_note_subprocess(ctx->p, ctx->proc, APR_KILL_AFTER_TIMEOUT);    /* We don't want the handle to the child's stdin inherited by any     * other processes created by httpd.  Otherwise, when we close our     * handle, the child won't see EOF because another handle will still     * be open.     */    apr_pool_cleanup_register(ctx->p, ctx->proc->in,                          apr_pool_cleanup_null, /* other mechanism */                         ef_close_file);#if APR_FILES_AS_SOCKETS    {        apr_socket_t *newsock;        rc = apr_poll_setup(&ctx->pollset, 2, ctx->p);        ap_assert(rc == APR_SUCCESS);        rc = apr_socket_from_file(&newsock, ctx->proc->in);        ap_assert(rc == APR_SUCCESS);        rc = apr_poll_socket_add(ctx->pollset, newsock, APR_POLLOUT);        ap_assert(rc == APR_SUCCESS);        rc = apr_socket_from_file(&newsock, ctx->proc->out);        ap_assert(rc == APR_SUCCESS);        rc = apr_poll_socket_add(ctx->pollset, newsock, APR_POLLIN);        ap_assert(rc == APR_SUCCESS);    }#endif    return APR_SUCCESS;}static const char *get_cfg_string(ef_dir_t *dc, ef_filter_t *filter, apr_pool_t *p){    const char *debug_str = dc->debug == -1 ?         "DebugLevel=0" : apr_psprintf(p, "DebugLevel=%d", dc->debug);    const char *log_stderr_str = dc->log_stderr < 1 ?        "NoLogStderr" : "LogStderr";    const char *preserve_content_length_str = filter->preserves_content_length ?        "PreservesContentLength" : "!PreserveContentLength";    const char *intype_str = !filter->intype ?        "*/*" : filter->intype;    const char *outtype_str = !filter->outtype ?        "(unchanged)" : filter->outtype;        return apr_psprintf(p,                        "ExtFilterOptions %s %s %s ExtFilterInType %s "                        "ExtFilterOuttype %s",                        debug_str, log_stderr_str, preserve_content_length_str,                        intype_str, outtype_str);}static ef_filter_t *find_filter_def(const server_rec *s, const char *fname){    ef_server_t *sc;    ef_filter_t *f;    sc = ap_get_module_config(s->module_config, &ext_filter_module);    f = apr_hash_get(sc->h, fname, APR_HASH_KEY_STRING);    if (!f && s != main_server) {        s = main_server;        sc = ap_get_module_config(s->module_config, &ext_filter_module);        f = apr_hash_get(sc->h, fname, APR_HASH_KEY_STRING);    }    return f;}static apr_status_t init_filter_instance(ap_filter_t *f){    ef_ctx_t *ctx;    ef_dir_t *dc;    apr_status_t rv;    f->ctx = ctx = apr_pcalloc(f->r->pool, sizeof(ef_ctx_t));    dc = ap_get_module_config(f->r->per_dir_config,                              &ext_filter_module);    ctx->dc = dc;    /* look for the user-defined filter */    ctx->filter = find_filter_def(f->r->server, f->frec->name);    if (!ctx->filter) {        ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, f->r,                      "couldn't find definition of filter '%s'",                      f->frec->name);        return APR_EINVAL;    }    ctx->p = f->r->pool;    if (ctx->filter->intype &&        ctx->filter->intype != INTYPE_ALL) {        if (!f->r->content_type) {            ctx->noop = 1;        }        else {            const char *ctypes = f->r->content_type;            const char *ctype = ap_getword(f->r->pool, &ctypes, ';');            if (strcasecmp(ctx->filter->intype, ctype)) {                /* wrong IMT for us; don't mess with the output */                ctx->noop = 1;            }        }    }    if (ctx->filter->enable_env &&        !apr_table_get(f->r->subprocess_env, ctx->filter->enable_env)) {        /* an environment variable that enables the filter isn't set; bail */        ctx->noop = 1;    }    if (ctx->filter->disable_env &&        apr_table_get(f->r->subprocess_env, ctx->filter->disable_env)) {        /* an environment variable that disables the filter is set; bail */        ctx->noop = 1;    }    if (!ctx->noop) {        rv = init_ext_filter_process(f);        if (rv != APR_SUCCESS) {            return rv;        }        if (ctx->filter->outtype &&            ctx->filter->outtype != OUTTYPE_UNCHANGED) {            ap_set_content_type(f->r, ctx->filter->outtype);        }        if (ctx->filter->preserves_content_length != 1) {            /* nasty, but needed to avoid confusing the browser              */            apr_table_unset(f->r->headers_out, "Content-Length");        }    }    if (dc->debug >= DBGLVL_SHOWOPTIONS) {        ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, f->r,                      "%sfiltering `%s' of type `%s' through `%s', cfg %s",                      ctx->noop ? "NOT " : "",                      f->r->uri ? f->r->uri : f->r->filename,                      f->r->content_type ? f->r->content_type : "(unspecified)",                      ctx->filter->command,                      get_cfg_string(dc, ctx->filter, f->r->pool));    }    return APR_SUCCESS;}/* drain_available_output():  * * if any data is available from the filter, read it and pass it * to the next filter */static apr_status_t drain_available_output(ap_filter_t *f){    request_rec *r = f->r;    conn_rec *c = r->connection;    ef_ctx_t *ctx = f->ctx;    ef_dir_t *dc = ctx->dc;    apr_size_t len;    char buf[4096];    apr_status_t rv;    apr_bucket_brigade *bb;    apr_bucket *b;    while (1) {        len = sizeof(buf);        rv = apr_file_read(ctx->proc->out,                      buf,                      &len);        if ((rv && !APR_STATUS_IS_EAGAIN(rv)) ||            dc->debug >= DBGLVL_GORY) {            ap_log_rerror(APLOG_MARK, APLOG_DEBUG, rv, r,                          "apr_file_read(child output), len %" APR_SIZE_T_FMT,                          !rv ? len : -1);        }        if (rv != APR_SUCCESS) {            return rv;        }        bb = apr_brigade_create(r->pool, c->bucket_alloc);        b = apr_bucket_transient_create(buf, len, c->bucket_alloc);        APR_BRIGADE_INSERT_TAIL(bb, b);        if ((rv = ap_pass_brigade(f->next, bb)) != APR_SUCCESS) {            ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r,                          "ap_pass_brigade()");            return rv;        }    }    /* we should never get here; if we do, a bogus error message would be     * the least of our problems      */    return APR_ANONYMOUS;}static apr_status_t pass_data_to_filter(ap_filter_t *f, const char *data,                                         apr_size_t len){    ef_ctx_t *ctx = f->ctx;    ef_dir_t *dc = ctx->dc;    apr_status_t rv;    apr_size_t bytes_written = 0;    apr_size_t tmplen;        do {        tmplen = len - bytes_written;        rv = apr_file_write(ctx->proc->in,                       (const char *)data + bytes_written,                       &tmplen);        bytes_written += tmplen;        if (rv != APR_SUCCESS && !APR_STATUS_IS_EAGAIN(rv)) {            ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, f->r,                          "apr_file_write(child input), len %" APR_SIZE_T_FMT,                          tmplen);            return rv;        }        if (APR_STATUS_IS_EAGAIN(rv)) {            /* XXX handle blocking conditions here...  if we block, we need              * to read data from the child process and pass it down to the             * next filter!             */            rv = drain_available_output(f);            if (APR_STATUS_IS_EAGAIN(rv)) {#if APR_FILES_AS_SOCKETS                int num_events;                                rv = apr_poll(ctx->pollset, 2,                              &num_events, f->r->server->timeout);                if (rv || dc->debug >= DBGLVL_GORY) {                    ap_log_rerror(APLOG_MARK, APLOG_DEBUG,                                  rv, f->r, "apr_poll()");                }                if (rv != APR_SUCCESS && !APR_STATUS_IS_EINTR(rv)) {                     /* some error such as APR_TIMEUP */                    return rv;                }#else /* APR_FILES_AS_SOCKETS */                /* Yuck... I'd really like to wait until I can read                 * or write, but instead I have to sleep and try again                  */                apr_sleep(100000); /* 100 milliseconds */                if (dc->debug >= DBGLVL_GORY) {                    ap_log_rerror(APLOG_MARK, APLOG_DEBUG,                                   0, f->r, "apr_sleep()");                }#endif /* APR_FILES_AS_SOCKETS */            }            else if (rv != APR_SUCCESS) {                return rv;            }        }    } while (bytes_written < len);    return rv;}static apr_status_t ef_output_filter(ap_filter_t *f, apr_bucket_brigade *bb){    request_rec *r = f->r;    conn_rec *c = r->connection;    ef_ctx_t *ctx = f->ctx;    apr_bucket *b;    ef_dir_t *dc;    apr_size_t len;    const char *data;    apr_status_t rv;    char buf[4096];    apr_bucket *eos = NULL;    if (!ctx) {        if ((rv = init_filter_instance(f)) != APR_SUCCESS) {            return rv;        }        ctx = f->ctx;    }    if (ctx->noop) {        ap_remove_output_filter(f);        return ap_pass_brigade(f->next, bb);    }    dc = ctx->dc;    APR_BRIGADE_FOREACH(b, bb) {        if (APR_BUCKET_IS_EOS(b)) {            eos = b;            break;        }        rv = apr_bucket_read(b, &data, &len, APR_BLOCK_READ);        if (rv != APR_SUCCESS) {            ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, "apr_bucket_read()");            return rv;        }        /* Good cast, we just tested len isn't negative */        if (len > 0 &&            (rv = pass_data_to_filter(f, data, (apr_size_t)len))                 != APR_SUCCESS) {            return rv;        }    }    apr_brigade_destroy(bb);    /* XXX What we *really* need to do once we've hit eos is create a pipe bucket     * from the child output pipe and pass down the pipe bucket + eos.     */    if (eos) {        /* close the child's stdin to signal that no more data is coming;         * that will cause the child to finish generating output         */        if ((rv = apr_file_close(ctx->proc->in)) != APR_SUCCESS) {            ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r,                          "apr_file_close(child input)");            return rv;        }        /* since we've seen eos and closed the child's stdin, set the proper pipe          * timeout; we don't care if we don't return from apr_file_read() for a while...          */        rv = apr_file_pipe_timeout_set(ctx->proc->out,                                        r->server->timeout);        if (rv) {            ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r,                          "apr_file_pipe_timeout_set(child output)");            return rv;        }    }    do {        len = sizeof(buf);        rv = apr_file_read(ctx->proc->out,                      buf,                      &len);        if ((rv && !APR_STATUS_IS_EOF(rv) && !APR_STATUS_IS_EAGAIN(rv)) ||            dc->debug >= DBGLVL_GORY) {            ap_log_rerror(APLOG_MARK, APLOG_DEBUG, rv, r,                          "apr_file_read(child output), len %" APR_SIZE_T_FMT,                          !rv ? len : -1);        }        if (APR_STATUS_IS_EAGAIN(rv)) {            if (eos) {                /* should not occur, because we have an APR timeout in place */                AP_DEBUG_ASSERT(1 != 1);            }            return APR_SUCCESS;        }                if (rv == APR_SUCCESS) {            bb = apr_brigade_create(r->pool, c->bucket_alloc);            b = apr_bucket_transient_create(buf, len, c->bucket_alloc);            APR_BRIGADE_INSERT_TAIL(bb, b);            if ((rv = ap_pass_brigade(f->next, bb)) != APR_SUCCESS) {                ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r,                              "ap_pass_brigade(filtered buffer) failed");                return rv;            }        }    } while (rv == APR_SUCCESS);    if (!APR_STATUS_IS_EOF(rv)) {        return rv;    }    if (eos) {        /* pass down eos */        bb = apr_brigade_create(r->pool, c->bucket_alloc);        b = apr_bucket_eos_create(c->bucket_alloc);        APR_BRIGADE_INSERT_TAIL(bb, b);        if ((rv = ap_pass_brigade(f->next, bb)) != APR_SUCCESS) {            ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r,                          "ap_pass_brigade(eos) failed");            return rv;        }    }    return APR_SUCCESS;}#if 0static int ef_input_filter(ap_filter_t *f, apr_bucket_brigade *bb,                            ap_input_mode_t mode, apr_read_type_e block,                           apr_off_t readbytes){    apr_status_t rv;    apr_bucket *b;    char *buf;    apr_ssize_t len;    char *zero;    rv = ap_get_brigade(f->next, bb, mode, block, readbytes);    if (rv != APR_SUCCESS) {        return rv;    }    APR_BRIGADE_FOREACH(b, bb) {        if (!APR_BUCKET_IS_EOS(b)) {            if ((rv = apr_bucket_read(b, (const char **)&buf, &len, APR_BLOCK_READ)) != APR_SUCCESS) {                ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, f->r, "apr_bucket_read() failed");                return rv;            }            ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, "apr_bucket_read -> %d bytes",                         len);            while ((zero = memchr(buf, '0', len))) {                *zero = 'a';            }        }        else            ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, "got eos bucket");    }    return rv;}#endifmodule AP_MODULE_DECLARE_DATA ext_filter_module ={    STANDARD20_MODULE_STUFF,    create_ef_dir_conf,    merge_ef_dir_conf,    create_ef_server_conf,    NULL,    cmds,    register_hooks};

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -