mod_ext_filter.c revision aa9b03a5f32732c0caaef03a7ed78ffb290e29e4
acc9093ae1f3c97acc635bd5b2c7c0969da21183trawick/* ====================================================================
acc9093ae1f3c97acc635bd5b2c7c0969da21183trawick * The Apache Software License, Version 1.1
33bdcae1f7a1a65e351dda2a766a0cf28b1e695dnd * Copyright (c) 2000-2003 The Apache Software Foundation. All rights
acc9093ae1f3c97acc635bd5b2c7c0969da21183trawick * reserved.
acc9093ae1f3c97acc635bd5b2c7c0969da21183trawick * Redistribution and use in source and binary forms, with or without
acc9093ae1f3c97acc635bd5b2c7c0969da21183trawick * modification, are permitted provided that the following conditions
acc9093ae1f3c97acc635bd5b2c7c0969da21183trawick * 1. Redistributions of source code must retain the above copyright
acc9093ae1f3c97acc635bd5b2c7c0969da21183trawick * notice, this list of conditions and the following disclaimer.
acc9093ae1f3c97acc635bd5b2c7c0969da21183trawick * 2. Redistributions in binary form must reproduce the above copyright
acc9093ae1f3c97acc635bd5b2c7c0969da21183trawick * notice, this list of conditions and the following disclaimer in
acc9093ae1f3c97acc635bd5b2c7c0969da21183trawick * the documentation and/or other materials provided with the
acc9093ae1f3c97acc635bd5b2c7c0969da21183trawick * distribution.
acc9093ae1f3c97acc635bd5b2c7c0969da21183trawick * 3. The end-user documentation included with the redistribution,
acc9093ae1f3c97acc635bd5b2c7c0969da21183trawick * if any, must include the following acknowledgment:
acc9093ae1f3c97acc635bd5b2c7c0969da21183trawick * "This product includes software developed by the
acc9093ae1f3c97acc635bd5b2c7c0969da21183trawick * Apache Software Foundation (http://www.apache.org/)."
acc9093ae1f3c97acc635bd5b2c7c0969da21183trawick * Alternately, this acknowledgment may appear in the software itself,
acc9093ae1f3c97acc635bd5b2c7c0969da21183trawick * if and wherever such third-party acknowledgments normally appear.
acc9093ae1f3c97acc635bd5b2c7c0969da21183trawick * 4. The names "Apache" and "Apache Software Foundation" must
acc9093ae1f3c97acc635bd5b2c7c0969da21183trawick * not be used to endorse or promote products derived from this
acc9093ae1f3c97acc635bd5b2c7c0969da21183trawick * software without prior written permission. For written
acc9093ae1f3c97acc635bd5b2c7c0969da21183trawick * permission, please contact apache@apache.org.
acc9093ae1f3c97acc635bd5b2c7c0969da21183trawick * 5. Products derived from this software may not be called "Apache",
acc9093ae1f3c97acc635bd5b2c7c0969da21183trawick * nor may "Apache" appear in their name, without prior written
acc9093ae1f3c97acc635bd5b2c7c0969da21183trawick * permission of the Apache Software Foundation.
acc9093ae1f3c97acc635bd5b2c7c0969da21183trawick * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
acc9093ae1f3c97acc635bd5b2c7c0969da21183trawick * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
acc9093ae1f3c97acc635bd5b2c7c0969da21183trawick * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
acc9093ae1f3c97acc635bd5b2c7c0969da21183trawick * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
acc9093ae1f3c97acc635bd5b2c7c0969da21183trawick * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
acc9093ae1f3c97acc635bd5b2c7c0969da21183trawick * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
acc9093ae1f3c97acc635bd5b2c7c0969da21183trawick * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
acc9093ae1f3c97acc635bd5b2c7c0969da21183trawick * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
acc9093ae1f3c97acc635bd5b2c7c0969da21183trawick * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
acc9093ae1f3c97acc635bd5b2c7c0969da21183trawick * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
acc9093ae1f3c97acc635bd5b2c7c0969da21183trawick * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
acc9093ae1f3c97acc635bd5b2c7c0969da21183trawick * SUCH DAMAGE.
acc9093ae1f3c97acc635bd5b2c7c0969da21183trawick * ====================================================================
acc9093ae1f3c97acc635bd5b2c7c0969da21183trawick * This software consists of voluntary contributions made by many
acc9093ae1f3c97acc635bd5b2c7c0969da21183trawick * individuals on behalf of the Apache Software Foundation. For more
acc9093ae1f3c97acc635bd5b2c7c0969da21183trawick * information on the Apache Software Foundation, please see
acc9093ae1f3c97acc635bd5b2c7c0969da21183trawick * Portions of this software are based upon public domain software
acc9093ae1f3c97acc635bd5b2c7c0969da21183trawick * originally written at the National Center for Supercomputing Applications,
acc9093ae1f3c97acc635bd5b2c7c0969da21183trawick * University of Illinois, Urbana-Champaign.
acc9093ae1f3c97acc635bd5b2c7c0969da21183trawick * mod_ext_filter allows Unix-style filters to filter http content.
acc9093ae1f3c97acc635bd5b2c7c0969da21183trawicktypedef struct ef_server_t {
acc9093ae1f3c97acc635bd5b2c7c0969da21183trawicktypedef struct ef_filter_t {
acc9093ae1f3c97acc635bd5b2c7c0969da21183trawick const char *name;
acc9093ae1f3c97acc635bd5b2c7c0969da21183trawick const char *command;
acc9093ae1f3c97acc635bd5b2c7c0969da21183trawick const char *intype; /* list of IMTs we process (well, just one for now) */
acc9093ae1f3c97acc635bd5b2c7c0969da21183trawicktypedef struct ef_dir_t {
acc9093ae1f3c97acc635bd5b2c7c0969da21183trawicktypedef struct ef_ctx_t {
acc9093ae1f3c97acc635bd5b2c7c0969da21183trawickstatic apr_status_t ef_output_filter(ap_filter_t *, apr_bucket_brigade *);
aa9b03a5f32732c0caaef03a7ed78ffb290e29e4trawickstatic apr_status_t ef_input_filter(ap_filter_t *, apr_bucket_brigade *,
acc9093ae1f3c97acc635bd5b2c7c0969da21183trawickstatic void *create_ef_dir_conf(apr_pool_t *p, char *dummy)
acc9093ae1f3c97acc635bd5b2c7c0969da21183trawick ef_dir_t *dc = (ef_dir_t *)apr_pcalloc(p, sizeof(ef_dir_t));
acc9093ae1f3c97acc635bd5b2c7c0969da21183trawickstatic void *create_ef_server_conf(apr_pool_t *p, server_rec *s)
acc9093ae1f3c97acc635bd5b2c7c0969da21183trawick conf = (ef_server_t *)apr_pcalloc(p, sizeof(ef_server_t));
acc9093ae1f3c97acc635bd5b2c7c0969da21183trawickstatic void *merge_ef_dir_conf(apr_pool_t *p, void *basev, void *overridesv)
acc9093ae1f3c97acc635bd5b2c7c0969da21183trawick ef_dir_t *a = (ef_dir_t *)apr_pcalloc (p, sizeof(ef_dir_t));
acc9093ae1f3c97acc635bd5b2c7c0969da21183trawick ef_dir_t *base = (ef_dir_t *)basev, *over = (ef_dir_t *)overridesv;
acc9093ae1f3c97acc635bd5b2c7c0969da21183trawick if (over->debug != -1) { /* if admin coded something... */
acc9093ae1f3c97acc635bd5b2c7c0969da21183trawick if (over->log_stderr != -1) { /* if admin coded something... */
acc9093ae1f3c97acc635bd5b2c7c0969da21183trawickstatic const char *add_options(cmd_parms *cmd, void *in_dc,
acc9093ae1f3c97acc635bd5b2c7c0969da21183trawick const char *arg)
acc9093ae1f3c97acc635bd5b2c7c0969da21183trawick "Invalid ExtFilterOptions option: ",
acc9093ae1f3c97acc635bd5b2c7c0969da21183trawickstatic const char *parse_cmd(apr_pool_t *p, const char **args, ef_filter_t *filter)
acc9093ae1f3c97acc635bd5b2c7c0969da21183trawick /* find true end of args string (accounting for escaped quotes) */
acc9093ae1f3c97acc635bd5b2c7c0969da21183trawick while (**args && (**args != '"' || (**args == '"' && escaping))) {
acc9093ae1f3c97acc635bd5b2c7c0969da21183trawick return "Expected cmd= delimiter";
acc9093ae1f3c97acc635bd5b2c7c0969da21183trawick /* copy *just* the arg string for parsing, */
acc9093ae1f3c97acc635bd5b2c7c0969da21183trawick /* parse and tokenize the args. */
acc9093ae1f3c97acc635bd5b2c7c0969da21183trawick rv = apr_tokenize_to_argv(parms, &(filter->args), p);
acc9093ae1f3c97acc635bd5b2c7c0969da21183trawick return "cmd= parse error";
acc9093ae1f3c97acc635bd5b2c7c0969da21183trawick /* simple path */
6e128d9c91437b22850d19fc166a6165e3c4831ctrawick /* Allocate space for two argv pointers and parse the args. */
6e128d9c91437b22850d19fc166a6165e3c4831ctrawick filter->args = (char **)apr_palloc(p, 2 * sizeof(char *));
acc9093ae1f3c97acc635bd5b2c7c0969da21183trawick return "Invalid cmd= parameter";
acc9093ae1f3c97acc635bd5b2c7c0969da21183trawickstatic const char *define_filter(cmd_parms *cmd, void *dummy, const char *args)
acc9093ae1f3c97acc635bd5b2c7c0969da21183trawick ef_server_t *conf = ap_get_module_config(cmd->server->module_config,
acc9093ae1f3c97acc635bd5b2c7c0969da21183trawick const char *token;
acc9093ae1f3c97acc635bd5b2c7c0969da21183trawick const char *name;
acc9093ae1f3c97acc635bd5b2c7c0969da21183trawick return "Filter name not found";
acc9093ae1f3c97acc635bd5b2c7c0969da21183trawick if (apr_hash_get(conf->h, name, APR_HASH_KEY_STRING)) {
acc9093ae1f3c97acc635bd5b2c7c0969da21183trawick return apr_psprintf(cmd->pool, "ExtFilter %s is already defined",
acc9093ae1f3c97acc635bd5b2c7c0969da21183trawick filter = (ef_filter_t *)apr_pcalloc(conf->p, sizeof(ef_filter_t));
acc9093ae1f3c97acc635bd5b2c7c0969da21183trawick apr_hash_set(conf->h, name, APR_HASH_KEY_STRING, filter);
acc9093ae1f3c97acc635bd5b2c7c0969da21183trawick /* Nasty parsing... I wish I could simply use ap_getword_white()
acc9093ae1f3c97acc635bd5b2c7c0969da21183trawick * here and then look at the token, but ap_getword_white() doesn't
acc9093ae1f3c97acc635bd5b2c7c0969da21183trawick * do the right thing when we have cmd="word word word"
acc9093ae1f3c97acc635bd5b2c7c0969da21183trawick if (!strncasecmp(args, "preservescontentlength", 22)) {
acc9093ae1f3c97acc635bd5b2c7c0969da21183trawick "mangled argument `%s'",
acc9093ae1f3c97acc635bd5b2c7c0969da21183trawick return apr_psprintf(cmd->pool, "Invalid mode: `%s'",
acc9093ae1f3c97acc635bd5b2c7c0969da21183trawick filter->intype = ap_getword_white(cmd->pool, &args);
acc9093ae1f3c97acc635bd5b2c7c0969da21183trawick filter->outtype = ap_getword_white(cmd->pool, &args);
acc9093ae1f3c97acc635bd5b2c7c0969da21183trawick if ((token = parse_cmd(cmd->pool, &args, filter))) {
acc9093ae1f3c97acc635bd5b2c7c0969da21183trawick return apr_psprintf(cmd->pool, "Unexpected parameter: `%s'",
acc9093ae1f3c97acc635bd5b2c7c0969da21183trawick /* parsing is done... register the filter
acc9093ae1f3c97acc635bd5b2c7c0969da21183trawick /* XXX need a way to ensure uniqueness among all filters */
acc9093ae1f3c97acc635bd5b2c7c0969da21183trawick ap_register_output_filter(filter->name, ef_output_filter, NULL, filter->ftype);
acc9093ae1f3c97acc635bd5b2c7c0969da21183trawick /* XXX need a way to ensure uniqueness among all filters */
aa9b03a5f32732c0caaef03a7ed78ffb290e29e4trawick ap_register_input_filter(filter->name, ef_input_filter, NULL, filter->ftype);
acc9093ae1f3c97acc635bd5b2c7c0969da21183trawick ap_assert(1 != 1); /* we set the field wrong somehow */
acc9093ae1f3c97acc635bd5b2c7c0969da21183trawick ACCESS_CONF, /* same as SetInputFilter/SetOutputFilter */
acc9093ae1f3c97acc635bd5b2c7c0969da21183trawick "valid options: DebugLevel=n, LogStderr, NoLogStderr"),
acc9093ae1f3c97acc635bd5b2c7c0969da21183trawick "Define an external filter"),
acc9093ae1f3c97acc635bd5b2c7c0969da21183trawickstatic int ef_init(apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp, server_rec *main_s)
acc9093ae1f3c97acc635bd5b2c7c0969da21183trawick ap_hook_post_config(ef_init, NULL, NULL, APR_HOOK_MIDDLE);
acc9093ae1f3c97acc635bd5b2c7c0969da21183trawickstatic apr_status_t set_resource_limits(request_rec *r,
acc9093ae1f3c97acc635bd5b2c7c0969da21183trawick#if defined(RLIMIT_CPU) || defined(RLIMIT_NPROC) || \
acc9093ae1f3c97acc635bd5b2c7c0969da21183trawick defined(RLIMIT_DATA) || defined(RLIMIT_VMEM) || defined (RLIMIT_AS)
acc9093ae1f3c97acc635bd5b2c7c0969da21183trawick (core_dir_config *)ap_get_module_config(r->per_dir_config,
acc9093ae1f3c97acc635bd5b2c7c0969da21183trawick rv = apr_procattr_limit_set(procattr, APR_LIMIT_CPU, conf->limit_cpu);
acc9093ae1f3c97acc635bd5b2c7c0969da21183trawick ap_assert(rv == APR_SUCCESS); /* otherwise, we're out of sync with APR */
acc9093ae1f3c97acc635bd5b2c7c0969da21183trawick#if defined(RLIMIT_DATA) || defined(RLIMIT_VMEM) || defined(RLIMIT_AS)
acc9093ae1f3c97acc635bd5b2c7c0969da21183trawick rv = apr_procattr_limit_set(procattr, APR_LIMIT_MEM, conf->limit_mem);
acc9093ae1f3c97acc635bd5b2c7c0969da21183trawick ap_assert(rv == APR_SUCCESS); /* otherwise, we're out of sync with APR */
acc9093ae1f3c97acc635bd5b2c7c0969da21183trawick rv = apr_procattr_limit_set(procattr, APR_LIMIT_NPROC, conf->limit_nproc);
acc9093ae1f3c97acc635bd5b2c7c0969da21183trawick ap_assert(rv == APR_SUCCESS); /* otherwise, we're out of sync with APR */
acc9093ae1f3c97acc635bd5b2c7c0969da21183trawick#endif /* if at least one limit defined */
9efe68be3c81ee85225972195fb725dbfc2e8b24trawickstatic void child_errfn(apr_pool_t *pool, apr_status_t err, const char *description)
9efe68be3c81ee85225972195fb725dbfc2e8b24trawick apr_pool_userdata_get(&vr, ERRFN_USERDATA_KEY, pool);
9efe68be3c81ee85225972195fb725dbfc2e8b24trawick "[%s] [client %s] mod_ext_filter (%d)%s: %s\n",
acc9093ae1f3c97acc635bd5b2c7c0969da21183trawick/* init_ext_filter_process: get the external filter process going
acc9093ae1f3c97acc635bd5b2c7c0969da21183trawick * This is per-filter-instance (i.e., per-request) initialization.
acc9093ae1f3c97acc635bd5b2c7c0969da21183trawickstatic apr_status_t init_ext_filter_process(ap_filter_t *f)
acc9093ae1f3c97acc635bd5b2c7c0969da21183trawick const char * const *env;
acc9093ae1f3c97acc635bd5b2c7c0969da21183trawick ctx->proc = apr_pcalloc(ctx->p, sizeof(*ctx->proc));
1d509de8742bc4904aad80d982650393cd5bc1f3trawick rc = apr_procattr_child_errfn_set(ctx->procattr, child_errfn);
1d509de8742bc4904aad80d982650393cd5bc1f3trawick apr_pool_userdata_set(f->r, ERRFN_USERDATA_KEY, apr_pool_cleanup_null, ctx->p);
1d509de8742bc4904aad80d982650393cd5bc1f3trawick rc = apr_procattr_error_check_set(ctx->procattr, 1);
acc9093ae1f3c97acc635bd5b2c7c0969da21183trawick /* add standard CGI variables as well as DOCUMENT_URI, DOCUMENT_PATH_INFO,
acc9093ae1f3c97acc635bd5b2c7c0969da21183trawick * and QUERY_STRING_UNESCAPED
acc9093ae1f3c97acc635bd5b2c7c0969da21183trawick apr_table_setn(f->r->subprocess_env, "DOCUMENT_URI", f->r->uri);
acc9093ae1f3c97acc635bd5b2c7c0969da21183trawick apr_table_setn(f->r->subprocess_env, "DOCUMENT_PATH_INFO", f->r->path_info);
acc9093ae1f3c97acc635bd5b2c7c0969da21183trawick if (f->r->args) {
acc9093ae1f3c97acc635bd5b2c7c0969da21183trawick /* QUERY_STRING is added by ap_add_cgi_vars */
acc9093ae1f3c97acc635bd5b2c7c0969da21183trawick char *arg_copy = apr_pstrdup(f->r->pool, f->r->args);
acc9093ae1f3c97acc635bd5b2c7c0969da21183trawick apr_table_setn(f->r->subprocess_env, "QUERY_STRING_UNESCAPED",
acc9093ae1f3c97acc635bd5b2c7c0969da21183trawick env = (const char * const *) ap_create_environment(ctx->p,
acc9093ae1f3c97acc635bd5b2c7c0969da21183trawick "couldn't create child process to run `%s'",
acc9093ae1f3c97acc635bd5b2c7c0969da21183trawick apr_pool_note_subprocess(ctx->p, ctx->proc, APR_KILL_AFTER_TIMEOUT);
acc9093ae1f3c97acc635bd5b2c7c0969da21183trawick /* We don't want the handle to the child's stdin inherited by any
acc9093ae1f3c97acc635bd5b2c7c0969da21183trawick * other processes created by httpd. Otherwise, when we close our
acc9093ae1f3c97acc635bd5b2c7c0969da21183trawick * handle, the child won't see EOF because another handle will still
acc9093ae1f3c97acc635bd5b2c7c0969da21183trawick rc = apr_poll_socket_add(ctx->pollset, newsock, APR_POLLOUT);
acc9093ae1f3c97acc635bd5b2c7c0969da21183trawick rc = apr_socket_from_file(&newsock, ctx->proc->out);
acc9093ae1f3c97acc635bd5b2c7c0969da21183trawick rc = apr_poll_socket_add(ctx->pollset, newsock, APR_POLLIN);
acc9093ae1f3c97acc635bd5b2c7c0969da21183trawickstatic const char *get_cfg_string(ef_dir_t *dc, ef_filter_t *filter, apr_pool_t *p)
acc9093ae1f3c97acc635bd5b2c7c0969da21183trawick "DebugLevel=0" : apr_psprintf(p, "DebugLevel=%d", dc->debug);
acc9093ae1f3c97acc635bd5b2c7c0969da21183trawick const char *preserve_content_length_str = filter->preserves_content_length ?
acc9093ae1f3c97acc635bd5b2c7c0969da21183trawick "PreservesContentLength" : "!PreserveContentLength";
acc9093ae1f3c97acc635bd5b2c7c0969da21183trawick "ExtFilterOptions %s %s %s ExtFilterInType %s "
acc9093ae1f3c97acc635bd5b2c7c0969da21183trawick "ExtFilterOuttype %s",
acc9093ae1f3c97acc635bd5b2c7c0969da21183trawick debug_str, log_stderr_str, preserve_content_length_str,
acc9093ae1f3c97acc635bd5b2c7c0969da21183trawickstatic ef_filter_t *find_filter_def(const server_rec *s, const char *fname)
acc9093ae1f3c97acc635bd5b2c7c0969da21183trawick sc = ap_get_module_config(s->module_config, &ext_filter_module);
acc9093ae1f3c97acc635bd5b2c7c0969da21183trawick f = apr_hash_get(sc->h, fname, APR_HASH_KEY_STRING);
acc9093ae1f3c97acc635bd5b2c7c0969da21183trawick if (!f && s != main_server) {
acc9093ae1f3c97acc635bd5b2c7c0969da21183trawick sc = ap_get_module_config(s->module_config, &ext_filter_module);
acc9093ae1f3c97acc635bd5b2c7c0969da21183trawick f = apr_hash_get(sc->h, fname, APR_HASH_KEY_STRING);
acc9093ae1f3c97acc635bd5b2c7c0969da21183trawickstatic apr_status_t init_filter_instance(ap_filter_t *f)
acc9093ae1f3c97acc635bd5b2c7c0969da21183trawick f->ctx = ctx = apr_pcalloc(f->r->pool, sizeof(ef_ctx_t));
acc9093ae1f3c97acc635bd5b2c7c0969da21183trawick /* look for the user-defined filter */
acc9093ae1f3c97acc635bd5b2c7c0969da21183trawick ctx->filter = find_filter_def(f->r->server, f->frec->name);
acc9093ae1f3c97acc635bd5b2c7c0969da21183trawick "couldn't find definition of filter '%s'",
aa9b03a5f32732c0caaef03a7ed78ffb290e29e4trawick const char *ctypes;
aa9b03a5f32732c0caaef03a7ed78ffb290e29e4trawick ctypes = apr_table_get(f->r->headers_in, "Content-Type");
acc9093ae1f3c97acc635bd5b2c7c0969da21183trawick const char *ctype = ap_getword(f->r->pool, &ctypes, ';');
acc9093ae1f3c97acc635bd5b2c7c0969da21183trawick /* wrong IMT for us; don't mess with the output */
acc9093ae1f3c97acc635bd5b2c7c0969da21183trawick !apr_table_get(f->r->subprocess_env, ctx->filter->enable_env)) {
acc9093ae1f3c97acc635bd5b2c7c0969da21183trawick /* an environment variable that enables the filter isn't set; bail */
acc9093ae1f3c97acc635bd5b2c7c0969da21183trawick apr_table_get(f->r->subprocess_env, ctx->filter->disable_env)) {
acc9093ae1f3c97acc635bd5b2c7c0969da21183trawick /* an environment variable that disables the filter is set; bail */
acc9093ae1f3c97acc635bd5b2c7c0969da21183trawick /* nasty, but needed to avoid confusing the browser
acc9093ae1f3c97acc635bd5b2c7c0969da21183trawick apr_table_unset(f->r->headers_out, "Content-Length");
acc9093ae1f3c97acc635bd5b2c7c0969da21183trawick "%sfiltering `%s' of type `%s' through `%s', cfg %s",
acc9093ae1f3c97acc635bd5b2c7c0969da21183trawick f->r->content_type ? f->r->content_type : "(unspecified)",
acc9093ae1f3c97acc635bd5b2c7c0969da21183trawick/* drain_available_output():
aa9b03a5f32732c0caaef03a7ed78ffb290e29e4trawick * if any data is available from the filter, read it and append it
aa9b03a5f32732c0caaef03a7ed78ffb290e29e4trawick * to the the bucket brigade
aa9b03a5f32732c0caaef03a7ed78ffb290e29e4trawickstatic apr_status_t drain_available_output(ap_filter_t *f,
acc9093ae1f3c97acc635bd5b2c7c0969da21183trawick while (1) {
acc9093ae1f3c97acc635bd5b2c7c0969da21183trawick "apr_file_read(child output), len %" APR_SIZE_T_FMT,
aa9b03a5f32732c0caaef03a7ed78ffb290e29e4trawick b = apr_bucket_heap_create(buf, len, NULL, c->bucket_alloc);
acc9093ae1f3c97acc635bd5b2c7c0969da21183trawick /* we should never get here; if we do, a bogus error message would be
acc9093ae1f3c97acc635bd5b2c7c0969da21183trawick * the least of our problems
acc9093ae1f3c97acc635bd5b2c7c0969da21183trawickstatic apr_status_t pass_data_to_filter(ap_filter_t *f, const char *data,
acc9093ae1f3c97acc635bd5b2c7c0969da21183trawick if (rv != APR_SUCCESS && !APR_STATUS_IS_EAGAIN(rv)) {
acc9093ae1f3c97acc635bd5b2c7c0969da21183trawick "apr_file_write(child input), len %" APR_SIZE_T_FMT,
acc9093ae1f3c97acc635bd5b2c7c0969da21183trawick /* XXX handle blocking conditions here... if we block, we need
acc9093ae1f3c97acc635bd5b2c7c0969da21183trawick * to read data from the child process and pass it down to the
acc9093ae1f3c97acc635bd5b2c7c0969da21183trawick * next filter!
acc9093ae1f3c97acc635bd5b2c7c0969da21183trawick if (rv != APR_SUCCESS && !APR_STATUS_IS_EINTR(rv)) {
acc9093ae1f3c97acc635bd5b2c7c0969da21183trawick /* some error such as APR_TIMEUP */
acc9093ae1f3c97acc635bd5b2c7c0969da21183trawick#else /* APR_FILES_AS_SOCKETS */
acc9093ae1f3c97acc635bd5b2c7c0969da21183trawick /* Yuck... I'd really like to wait until I can read
acc9093ae1f3c97acc635bd5b2c7c0969da21183trawick * or write, but instead I have to sleep and try again
acc9093ae1f3c97acc635bd5b2c7c0969da21183trawick 0, f->r, "apr_sleep()");
acc9093ae1f3c97acc635bd5b2c7c0969da21183trawick#endif /* APR_FILES_AS_SOCKETS */
aa9b03a5f32732c0caaef03a7ed78ffb290e29e4trawick/* ef_unified_filter:
aa9b03a5f32732c0caaef03a7ed78ffb290e29e4trawick * runs the bucket brigade bb through the filter and puts the result into
aa9b03a5f32732c0caaef03a7ed78ffb290e29e4trawick * bb, dropping the previous content of bb (the input)
aa9b03a5f32732c0caaef03a7ed78ffb290e29e4trawickstatic int ef_unified_filter(ap_filter_t *f, apr_bucket_brigade *bb)
acc9093ae1f3c97acc635bd5b2c7c0969da21183trawick const char *data;
aa9b03a5f32732c0caaef03a7ed78ffb290e29e4trawick bb_tmp = apr_brigade_create(r->pool, c->bucket_alloc);
acc9093ae1f3c97acc635bd5b2c7c0969da21183trawick rv = apr_bucket_read(b, &data, &len, APR_BLOCK_READ);
acc9093ae1f3c97acc635bd5b2c7c0969da21183trawick ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, "apr_bucket_read()");
acc9093ae1f3c97acc635bd5b2c7c0969da21183trawick /* Good cast, we just tested len isn't negative */
aa9b03a5f32732c0caaef03a7ed78ffb290e29e4trawick (rv = pass_data_to_filter(f, data, (apr_size_t)len, bb_tmp))
acc9093ae1f3c97acc635bd5b2c7c0969da21183trawick /* close the child's stdin to signal that no more data is coming;
acc9093ae1f3c97acc635bd5b2c7c0969da21183trawick * that will cause the child to finish generating output
acc9093ae1f3c97acc635bd5b2c7c0969da21183trawick if ((rv = apr_file_close(ctx->proc->in)) != APR_SUCCESS) {
acc9093ae1f3c97acc635bd5b2c7c0969da21183trawick "apr_file_close(child input)");
acc9093ae1f3c97acc635bd5b2c7c0969da21183trawick /* since we've seen eos and closed the child's stdin, set the proper pipe
acc9093ae1f3c97acc635bd5b2c7c0969da21183trawick * timeout; we don't care if we don't return from apr_file_read() for a while...
acc9093ae1f3c97acc635bd5b2c7c0969da21183trawick "apr_file_pipe_timeout_set(child output)");
acc9093ae1f3c97acc635bd5b2c7c0969da21183trawick if ((rv && !APR_STATUS_IS_EOF(rv) && !APR_STATUS_IS_EAGAIN(rv)) ||
acc9093ae1f3c97acc635bd5b2c7c0969da21183trawick "apr_file_read(child output), len %" APR_SIZE_T_FMT,
acc9093ae1f3c97acc635bd5b2c7c0969da21183trawick /* should not occur, because we have an APR timeout in place */
aa9b03a5f32732c0caaef03a7ed78ffb290e29e4trawick b = apr_bucket_heap_create(buf, len, NULL, c->bucket_alloc);
aa9b03a5f32732c0caaef03a7ed78ffb290e29e4trawickstatic apr_status_t ef_output_filter(ap_filter_t *f, apr_bucket_brigade *bb)
aa9b03a5f32732c0caaef03a7ed78ffb290e29e4trawick if ((rv = init_filter_instance(f)) != APR_SUCCESS) {
aa9b03a5f32732c0caaef03a7ed78ffb290e29e4trawick "ef_unified_filter() failed");
aa9b03a5f32732c0caaef03a7ed78ffb290e29e4trawick if ((rv = ap_pass_brigade(f->next, bb)) != APR_SUCCESS) {
aa9b03a5f32732c0caaef03a7ed78ffb290e29e4trawick "ap_pass_brigade() failed");
acc9093ae1f3c97acc635bd5b2c7c0969da21183trawickstatic int ef_input_filter(ap_filter_t *f, apr_bucket_brigade *bb,
aa9b03a5f32732c0caaef03a7ed78ffb290e29e4trawick if ((rv = init_filter_instance(f)) != APR_SUCCESS) {
aa9b03a5f32732c0caaef03a7ed78ffb290e29e4trawick return ap_get_brigade(f->next, bb, mode, block, readbytes);