diff options
author | hongbotian <hongbo.tianhongbo@huawei.com> | 2015-11-30 03:10:21 -0500 |
---|---|---|
committer | hongbotian <hongbo.tianhongbo@huawei.com> | 2015-11-30 03:10:21 -0500 |
commit | c0b7206652b2852bc574694e7ba07ba1c2acdc00 (patch) | |
tree | 5cb95cb0e19e03610525903df46279df2c3b7eb1 /rubbos/app/httpd-2.0.64/modules/filters/mod_ext_filter.c | |
parent | b6d3d6e668b793220f2d3af1bc3e828553dc3fe6 (diff) |
delete app
Change-Id: Id4c572809969ebe89e946e88063eaed262cff3f2
Signed-off-by: hongbotian <hongbo.tianhongbo@huawei.com>
Diffstat (limited to 'rubbos/app/httpd-2.0.64/modules/filters/mod_ext_filter.c')
-rw-r--r-- | rubbos/app/httpd-2.0.64/modules/filters/mod_ext_filter.c | 890 |
1 files changed, 0 insertions, 890 deletions
diff --git a/rubbos/app/httpd-2.0.64/modules/filters/mod_ext_filter.c b/rubbos/app/httpd-2.0.64/modules/filters/mod_ext_filter.c deleted file mode 100644 index cc77b40a..00000000 --- a/rubbos/app/httpd-2.0.64/modules/filters/mod_ext_filter.c +++ /dev/null @@ -1,890 +0,0 @@ -/* Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* - * mod_ext_filter allows Unix-style filters to filter http content. - */ - -#include "httpd.h" -#include "http_config.h" -#include "http_log.h" -#include "http_protocol.h" -#define CORE_PRIVATE -#include "http_core.h" -#include "apr_buckets.h" -#include "util_filter.h" -#include "util_script.h" -#include "util_time.h" -#include "apr_strings.h" -#include "apr_hash.h" -#include "apr_lib.h" -#include "apr_poll.h" -#define APR_WANT_STRFUNC -#include "apr_want.h" - -typedef struct ef_server_t { - apr_pool_t *p; - apr_hash_t *h; -} ef_server_t; - -typedef struct ef_filter_t { - const char *name; - enum {INPUT_FILTER=1, OUTPUT_FILTER} mode; - ap_filter_type ftype; - const char *command; - const char *enable_env; - const char *disable_env; - char **args; - const char *intype; /* list of IMTs we process (well, just one for now) */ -#define INTYPE_ALL (char *)1 - const char *outtype; /* IMT of filtered output */ -#define OUTTYPE_UNCHANGED (char *)1 - int preserves_content_length; -} ef_filter_t; - -typedef struct ef_dir_t { - int debug; - int log_stderr; -} ef_dir_t; - -typedef struct ef_ctx_t { - apr_pool_t *p; - apr_proc_t *proc; - apr_procattr_t *procattr; - ef_dir_t *dc; - ef_filter_t *filter; - int noop; -#if APR_FILES_AS_SOCKETS - apr_pollfd_t *pollset; -#endif -} ef_ctx_t; - -module AP_MODULE_DECLARE_DATA ext_filter_module; -static const server_rec *main_server; - -static apr_status_t ef_output_filter(ap_filter_t *, apr_bucket_brigade *); - -#define DBGLVL_SHOWOPTIONS 1 -#define DBGLVL_ERRORCHECK 2 -#define DBGLVL_GORY 9 - -#define ERRFN_USERDATA_KEY "EXTFILTCHILDERRFN" - -static void *create_ef_dir_conf(apr_pool_t *p, char *dummy) -{ - ef_dir_t *dc = (ef_dir_t *)apr_pcalloc(p, sizeof(ef_dir_t)); - - dc->debug = -1; - dc->log_stderr = -1; - - return dc; -} - -static void *create_ef_server_conf(apr_pool_t *p, server_rec *s) -{ - ef_server_t *conf; - - conf = (ef_server_t *)apr_pcalloc(p, sizeof(ef_server_t)); - conf->p = p; - conf->h = apr_hash_make(conf->p); - return conf; -} - -static void *merge_ef_dir_conf(apr_pool_t *p, void *basev, void *overridesv) -{ - ef_dir_t *a = (ef_dir_t *)apr_pcalloc (p, sizeof(ef_dir_t)); - ef_dir_t *base = (ef_dir_t *)basev, *over = (ef_dir_t *)overridesv; - - if (over->debug != -1) { /* if admin coded something... */ - a->debug = over->debug; - } - else { - a->debug = base->debug; - } - - if (over->log_stderr != -1) { /* if admin coded something... */ - a->log_stderr = over->log_stderr; - } - else { - a->log_stderr = base->log_stderr; - } - - return a; -} - -static const char *add_options(cmd_parms *cmd, void *in_dc, - const char *arg) -{ - ef_dir_t *dc = in_dc; - - if (!strncasecmp(arg, "DebugLevel=", 11)) { - dc->debug = atoi(arg + 11); - } - else if (!strcasecmp(arg, "LogStderr")) { - dc->log_stderr = 1; - } - else if (!strcasecmp(arg, "NoLogStderr")) { - dc->log_stderr = 0; - } - else { - return apr_pstrcat(cmd->temp_pool, - "Invalid ExtFilterOptions option: ", - arg, - NULL); - } - - return NULL; -} - -static const char *parse_cmd(apr_pool_t *p, const char **args, ef_filter_t *filter) -{ - if (**args == '"') { - const char *start = *args + 1; - char *parms; - int escaping = 0; - apr_status_t rv; - - ++*args; /* move past leading " */ - /* find true end of args string (accounting for escaped quotes) */ - while (**args && (**args != '"' || (**args == '"' && escaping))) { - if (escaping) { - escaping = 0; - } - else if (**args == '\\') { - escaping = 1; - } - ++*args; - } - if (**args != '"') { - return "Expected cmd= delimiter"; - } - /* copy *just* the arg string for parsing, */ - parms = apr_pstrndup(p, start, *args - start); - ++*args; /* move past trailing " */ - - /* parse and tokenize the args. */ - rv = apr_tokenize_to_argv(parms, &(filter->args), p); - if (rv != APR_SUCCESS) { - return "cmd= parse error"; - } - } - else - { - /* simple path */ - /* Allocate space for two argv pointers and parse the args. */ - filter->args = (char **)apr_palloc(p, 2 * sizeof(char *)); - filter->args[0] = ap_getword_white(p, args); - filter->args[1] = NULL; /* end of args */ - } - if (!filter->args[0]) { - return "Invalid cmd= parameter"; - } - filter->command = filter->args[0]; - - return NULL; -} - -static const char *define_filter(cmd_parms *cmd, void *dummy, const char *args) -{ - ef_server_t *conf = ap_get_module_config(cmd->server->module_config, - &ext_filter_module); - const char *token; - const char *name; - ef_filter_t *filter; - - name = ap_getword_white(cmd->pool, &args); - if (!name) { - return "Filter name not found"; - } - - if (apr_hash_get(conf->h, name, APR_HASH_KEY_STRING)) { - return apr_psprintf(cmd->pool, "ExtFilter %s is already defined", - name); - } - - filter = (ef_filter_t *)apr_pcalloc(conf->p, sizeof(ef_filter_t)); - filter->name = name; - filter->mode = OUTPUT_FILTER; - filter->ftype = AP_FTYPE_RESOURCE; - apr_hash_set(conf->h, name, APR_HASH_KEY_STRING, filter); - - while (*args) { - while (apr_isspace(*args)) { - ++args; - } - - /* Nasty parsing... I wish I could simply use ap_getword_white() - * here and then look at the token, but ap_getword_white() doesn't - * do the right thing when we have cmd="word word word" - */ - if (!strncasecmp(args, "preservescontentlength", 22)) { - token = ap_getword_white(cmd->pool, &args); - if (!strcasecmp(token, "preservescontentlength")) { - filter->preserves_content_length = 1; - } - else { - return apr_psprintf(cmd->pool, - "mangled argument `%s'", - token); - } - continue; - } - - if (!strncasecmp(args, "mode=", 5)) { - args += 5; - token = ap_getword_white(cmd->pool, &args); - if (!strcasecmp(token, "output")) { - filter->mode = OUTPUT_FILTER; - } - else if (!strcasecmp(token, "input")) { - filter->mode = INPUT_FILTER; - } - else { - return apr_psprintf(cmd->pool, "Invalid mode: `%s'", - token); - } - continue; - } - - if (!strncasecmp(args, "ftype=", 6)) { - args += 6; - token = ap_getword_white(cmd->pool, &args); - filter->ftype = atoi(token); - continue; - } - - if (!strncasecmp(args, "enableenv=", 10)) { - args += 10; - token = ap_getword_white(cmd->pool, &args); - filter->enable_env = token; - continue; - } - - if (!strncasecmp(args, "disableenv=", 11)) { - args += 11; - token = ap_getword_white(cmd->pool, &args); - filter->disable_env = token; - continue; - } - - if (!strncasecmp(args, "intype=", 7)) { - args += 7; - filter->intype = ap_getword_white(cmd->pool, &args); - continue; - } - - if (!strncasecmp(args, "outtype=", 8)) { - args += 8; - filter->outtype = ap_getword_white(cmd->pool, &args); - continue; - } - - if (!strncasecmp(args, "cmd=", 4)) { - args += 4; - if ((token = parse_cmd(cmd->pool, &args, filter))) { - return token; - } - continue; - } - - return apr_psprintf(cmd->pool, "Unexpected parameter: `%s'", - args); - } - - /* parsing is done... register the filter - */ - if (filter->mode == OUTPUT_FILTER) { - /* XXX need a way to ensure uniqueness among all filters */ - ap_register_output_filter(filter->name, ef_output_filter, NULL, filter->ftype); - } -#if 0 /* no input filters yet */ - else if (filter->mode == INPUT_FILTER) { - /* XXX need a way to ensure uniqueness among all filters */ - ap_register_input_filter(filter->name, ef_input_filter, NULL, AP_FTYPE_RESOURCE); - } -#endif - else { - ap_assert(1 != 1); /* we set the field wrong somehow */ - } - - return NULL; -} - -static const command_rec cmds[] = -{ - AP_INIT_ITERATE("ExtFilterOptions", - add_options, - NULL, - ACCESS_CONF, /* same as SetInputFilter/SetOutputFilter */ - "valid options: DebugLevel=n, LogStderr, NoLogStderr"), - AP_INIT_RAW_ARGS("ExtFilterDefine", - define_filter, - NULL, - RSRC_CONF, - "Define an external filter"), - {NULL} -}; - -static int ef_init(apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp, server_rec *main_s) -{ - main_server = main_s; - return OK; -} - -static void register_hooks(apr_pool_t *p) -{ - ap_hook_post_config(ef_init, NULL, NULL, APR_HOOK_MIDDLE); -} - -static apr_status_t set_resource_limits(request_rec *r, - apr_procattr_t *procattr) -{ -#if defined(RLIMIT_CPU) || defined(RLIMIT_NPROC) || \ - defined(RLIMIT_DATA) || defined(RLIMIT_VMEM) || defined (RLIMIT_AS) - core_dir_config *conf = - (core_dir_config *)ap_get_module_config(r->per_dir_config, - &core_module); - apr_status_t rv; - -#ifdef RLIMIT_CPU - rv = apr_procattr_limit_set(procattr, APR_LIMIT_CPU, conf->limit_cpu); - ap_assert(rv == APR_SUCCESS); /* otherwise, we're out of sync with APR */ -#endif -#if defined(RLIMIT_DATA) || defined(RLIMIT_VMEM) || defined(RLIMIT_AS) - rv = apr_procattr_limit_set(procattr, APR_LIMIT_MEM, conf->limit_mem); - ap_assert(rv == APR_SUCCESS); /* otherwise, we're out of sync with APR */ -#endif -#ifdef RLIMIT_NPROC - rv = apr_procattr_limit_set(procattr, APR_LIMIT_NPROC, conf->limit_nproc); - ap_assert(rv == APR_SUCCESS); /* otherwise, we're out of sync with APR */ -#endif - -#endif /* if at least one limit defined */ - - return APR_SUCCESS; -} - -static apr_status_t ef_close_file(void *vfile) -{ - return apr_file_close(vfile); -} - -static void child_errfn(apr_pool_t *pool, apr_status_t err, const char *description) -{ - request_rec *r; - void *vr; - apr_file_t *stderr_log; - char errbuf[200]; - char time_str[APR_CTIME_LEN]; - - apr_pool_userdata_get(&vr, ERRFN_USERDATA_KEY, pool); - r = vr; - apr_file_open_stderr(&stderr_log, pool); - ap_recent_ctime(time_str, apr_time_now()); - apr_file_printf(stderr_log, - "[%s] [client %s] mod_ext_filter (%d)%s: %s\n", - time_str, - r->connection->remote_ip, - err, - apr_strerror(err, errbuf, sizeof(errbuf)), - description); -} - -/* init_ext_filter_process: get the external filter process going - * This is per-filter-instance (i.e., per-request) initialization. - */ -static apr_status_t init_ext_filter_process(ap_filter_t *f) -{ - ef_ctx_t *ctx = f->ctx; - apr_status_t rc; - ef_dir_t *dc = ctx->dc; - const char * const *env; - - ctx->proc = apr_pcalloc(ctx->p, sizeof(*ctx->proc)); - - rc = apr_procattr_create(&ctx->procattr, ctx->p); - ap_assert(rc == APR_SUCCESS); - - rc = apr_procattr_io_set(ctx->procattr, - APR_CHILD_BLOCK, - APR_CHILD_BLOCK, - APR_CHILD_BLOCK); - ap_assert(rc == APR_SUCCESS); - - rc = set_resource_limits(f->r, ctx->procattr); - ap_assert(rc == APR_SUCCESS); - - if (dc->log_stderr > 0) { - rc = apr_procattr_child_err_set(ctx->procattr, - f->r->server->error_log, /* stderr in child */ - NULL); - ap_assert(rc == APR_SUCCESS); - } - - rc = apr_procattr_child_errfn_set(ctx->procattr, child_errfn); - ap_assert(rc == APR_SUCCESS); - apr_pool_userdata_set(f->r, ERRFN_USERDATA_KEY, apr_pool_cleanup_null, ctx->p); - - if (dc->debug >= DBGLVL_ERRORCHECK) { - rc = apr_procattr_error_check_set(ctx->procattr, 1); - ap_assert(rc == APR_SUCCESS); - } - - /* add standard CGI variables as well as DOCUMENT_URI, DOCUMENT_PATH_INFO, - * 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 0 -static 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; -} -#endif - -module 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 -}; |