Apache HTTPD
mod_ext_filter.c
Go to the documentation of this file.
1/* Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17/*
18 * mod_ext_filter allows Unix-style filters to filter http content.
19 */
20
21#include "httpd.h"
22#include "http_config.h"
23#include "http_log.h"
24#include "http_protocol.h"
25
26#include "http_core.h"
27#include "apr_buckets.h"
28#include "util_filter.h"
29#include "util_script.h"
30#include "util_time.h"
31#include "apr_strings.h"
32#include "apr_hash.h"
33#include "apr_lib.h"
34#include "apr_poll.h"
35#define APR_WANT_STRFUNC
36#include "apr_want.h"
37
42
43typedef struct ef_filter_t {
44 const char *name;
47 const char *command;
48 const char *enable_env;
49 const char *disable_env;
50 char **args;
51 const char *intype; /* list of IMTs we process (well, just one for now) */
52#define INTYPE_ALL (char *)1
53 const char *outtype; /* IMT of filtered output */
54#define OUTTYPE_UNCHANGED (char *)1
57
58typedef struct ef_dir_t {
60 int onfail;
62
74
75module AP_MODULE_DECLARE_DATA ext_filter_module;
76static const server_rec *main_server;
77
81 apr_off_t);
82
83#define ERRFN_USERDATA_KEY "EXTFILTCHILDERRFN"
84
85static void *create_ef_dir_conf(apr_pool_t *p, char *dummy)
86{
87 ef_dir_t *dc = (ef_dir_t *)apr_pcalloc(p, sizeof(ef_dir_t));
88
89 dc->log_stderr = -1;
90 dc->onfail = -1;
91
92 return dc;
93}
94
96{
97 ef_server_t *conf;
98
99 conf = (ef_server_t *)apr_pcalloc(p, sizeof(ef_server_t));
100 conf->p = p;
101 conf->h = apr_hash_make(conf->p);
102 return conf;
103}
104
105static void *merge_ef_dir_conf(apr_pool_t *p, void *basev, void *overridesv)
106{
107 ef_dir_t *a = (ef_dir_t *)apr_pcalloc (p, sizeof(ef_dir_t));
109
110 if (over->log_stderr != -1) { /* if admin coded something... */
111 a->log_stderr = over->log_stderr;
112 }
113 else {
114 a->log_stderr = base->log_stderr;
115 }
116
117 if (over->onfail != -1) { /* if admin coded something... */
118 a->onfail = over->onfail;
119 }
120 else {
121 a->onfail = base->onfail;
122 }
123
124 return a;
125}
126
127static const char *add_options(cmd_parms *cmd, void *in_dc,
128 const char *arg)
129{
130 ef_dir_t *dc = in_dc;
131
132 if (!strcasecmp(arg, "LogStderr")) {
133 dc->log_stderr = 1;
134 }
135 else if (!strcasecmp(arg, "NoLogStderr")) {
136 dc->log_stderr = 0;
137 }
138 else if (!strcasecmp(arg, "Onfail=remove")) {
139 dc->onfail = 1;
140 }
141 else if (!strcasecmp(arg, "Onfail=abort")) {
142 dc->onfail = 0;
143 }
144 else {
145 return apr_pstrcat(cmd->temp_pool,
146 "Invalid ExtFilterOptions option: ",
147 arg,
148 NULL);
149 }
150
151 return NULL;
152}
153
154static const char *parse_cmd(apr_pool_t *p, const char **args, ef_filter_t *filter)
155{
156 if (**args == '"') {
157 const char *start = *args + 1;
158 char *parms;
159 int escaping = 0;
160 apr_status_t rv;
161
162 ++*args; /* move past leading " */
163 /* find true end of args string (accounting for escaped quotes) */
164 while (**args && (**args != '"' || (**args == '"' && escaping))) {
165 if (escaping) {
166 escaping = 0;
167 }
168 else if (**args == '\\') {
169 escaping = 1;
170 }
171 ++*args;
172 }
173 if (**args != '"') {
174 return "Expected cmd= delimiter";
175 }
176 /* copy *just* the arg string for parsing, */
178 ++*args; /* move past trailing " */
179
180 /* parse and tokenize the args. */
181 rv = apr_tokenize_to_argv(parms, &(filter->args), p);
182 if (rv != APR_SUCCESS) {
183 return "cmd= parse error";
184 }
185 }
186 else
187 {
188 /* simple path */
189 /* Allocate space for two argv pointers and parse the args. */
190 filter->args = (char **)apr_palloc(p, 2 * sizeof(char *));
191 filter->args[0] = ap_getword_white(p, args);
192 filter->args[1] = NULL; /* end of args */
193 }
194 if (!filter->args[0]) {
195 return "Invalid cmd= parameter";
196 }
197 filter->command = filter->args[0];
198
199 return NULL;
200}
201
202static const char *define_filter(cmd_parms *cmd, void *dummy, const char *args)
203{
204 ef_server_t *conf = ap_get_module_config(cmd->server->module_config,
205 &ext_filter_module);
206 const char *token;
207 const char *name;
208 char *normalized_name;
209 ef_filter_t *filter;
210
211 name = ap_getword_white(cmd->pool, &args);
212 if (!name) {
213 return "Filter name not found";
214 }
215
216 /* During request processing, we find information about the filter
217 * by looking up the filter name provided by core server in our
218 * hash table. But the core server has normalized the filter
219 * name by converting it to lower case. Thus, when adding the
220 * filter to our hash table we have to use lower case as well.
221 */
224
226 return apr_psprintf(cmd->pool, "ExtFilter %s is already defined",
227 name);
228 }
229
230 filter = (ef_filter_t *)apr_pcalloc(conf->p, sizeof(ef_filter_t));
231 filter->name = name;
232 filter->mode = OUTPUT_FILTER;
233 filter->ftype = AP_FTYPE_RESOURCE;
235
236 while (*args) {
237 while (apr_isspace(*args)) {
238 ++args;
239 }
240
241 /* Nasty parsing... I wish I could simply use ap_getword_white()
242 * here and then look at the token, but ap_getword_white() doesn't
243 * do the right thing when we have cmd="word word word"
244 */
245 if (!strncasecmp(args, "preservescontentlength", 22)) {
246 token = ap_getword_white(cmd->pool, &args);
247 if (!strcasecmp(token, "preservescontentlength")) {
248 filter->preserves_content_length = 1;
249 }
250 else {
251 return apr_psprintf(cmd->pool,
252 "mangled argument `%s'",
253 token);
254 }
255 continue;
256 }
257
258 if (!strncasecmp(args, "mode=", 5)) {
259 args += 5;
260 token = ap_getword_white(cmd->pool, &args);
261 if (!strcasecmp(token, "output")) {
262 filter->mode = OUTPUT_FILTER;
263 }
264 else if (!strcasecmp(token, "input")) {
265 filter->mode = INPUT_FILTER;
266 }
267 else {
268 return apr_psprintf(cmd->pool, "Invalid mode: `%s'",
269 token);
270 }
271 continue;
272 }
273
274 if (!strncasecmp(args, "ftype=", 6)) {
275 args += 6;
276 token = ap_getword_white(cmd->pool, &args);
277 filter->ftype = atoi(token);
278 continue;
279 }
280
281 if (!strncasecmp(args, "enableenv=", 10)) {
282 args += 10;
283 token = ap_getword_white(cmd->pool, &args);
284 filter->enable_env = token;
285 continue;
286 }
287
288 if (!strncasecmp(args, "disableenv=", 11)) {
289 args += 11;
290 token = ap_getword_white(cmd->pool, &args);
291 filter->disable_env = token;
292 continue;
293 }
294
295 if (!strncasecmp(args, "intype=", 7)) {
296 args += 7;
297 filter->intype = ap_getword_white(cmd->pool, &args);
298 continue;
299 }
300
301 if (!strncasecmp(args, "outtype=", 8)) {
302 args += 8;
303 filter->outtype = ap_getword_white(cmd->pool, &args);
304 continue;
305 }
306
307 if (!strncasecmp(args, "cmd=", 4)) {
308 args += 4;
309 if ((token = parse_cmd(cmd->pool, &args, filter))) {
310 return token;
311 }
312 continue;
313 }
314
315 return apr_psprintf(cmd->pool, "Unexpected parameter: `%s'",
316 args);
317 }
318
319 /* parsing is done... register the filter
320 */
321 if (filter->mode == OUTPUT_FILTER) {
322 /* XXX need a way to ensure uniqueness among all filters */
324 }
325 else if (filter->mode == INPUT_FILTER) {
326 /* XXX need a way to ensure uniqueness among all filters */
328 }
329 else {
330 ap_assert(1 != 1); /* we set the field wrong somehow */
331 }
332
333 return NULL;
334}
335
336static const command_rec cmds[] =
337{
338 AP_INIT_ITERATE("ExtFilterOptions",
340 NULL,
341 ACCESS_CONF, /* same as SetInputFilter/SetOutputFilter */
342 "valid options: LogStderr, NoLogStderr"),
343 AP_INIT_RAW_ARGS("ExtFilterDefine",
345 NULL,
346 RSRC_CONF,
347 "Define an external filter"),
348 {NULL}
349};
350
352{
354 return OK;
355}
356
361
363 apr_procattr_t *procattr)
364{
365#if defined(RLIMIT_CPU) || defined(RLIMIT_NPROC) || \
366 defined(RLIMIT_DATA) || defined(RLIMIT_VMEM) || defined (RLIMIT_AS)
367 core_dir_config *conf =
369 apr_status_t rv;
370
371#ifdef RLIMIT_CPU
372 rv = apr_procattr_limit_set(procattr, APR_LIMIT_CPU, conf->limit_cpu);
373 ap_assert(rv == APR_SUCCESS); /* otherwise, we're out of sync with APR */
374#endif
375#if defined(RLIMIT_DATA) || defined(RLIMIT_VMEM) || defined(RLIMIT_AS)
376 rv = apr_procattr_limit_set(procattr, APR_LIMIT_MEM, conf->limit_mem);
377 ap_assert(rv == APR_SUCCESS); /* otherwise, we're out of sync with APR */
378#endif
379#ifdef RLIMIT_NPROC
380 rv = apr_procattr_limit_set(procattr, APR_LIMIT_NPROC, conf->limit_nproc);
381 ap_assert(rv == APR_SUCCESS); /* otherwise, we're out of sync with APR */
382#endif
383
384#endif /* if at least one limit defined */
385
386 return APR_SUCCESS;
387}
388
390{
391 return apr_file_close(vfile);
392}
393
394static void child_errfn(apr_pool_t *pool, apr_status_t err, const char *description)
395{
396 request_rec *r;
397 void *vr;
399 char time_str[APR_CTIME_LEN];
400
402 r = vr;
404 ap_recent_ctime(time_str, apr_time_now());
406 "[%s] [client %s] mod_ext_filter (%d)%pm: %s\n",
407 time_str,
409 err,
410 &err,
411 description);
412}
413
414/* init_ext_filter_process: get the external filter process going
415 * This is per-filter-instance (i.e., per-request) initialization.
416 */
418{
419 ef_ctx_t *ctx = f->ctx;
421 ef_dir_t *dc = ctx->dc;
422 const char * const *env;
423
424 ctx->proc = apr_pcalloc(ctx->p, sizeof(*ctx->proc));
425
426 rc = apr_procattr_create(&ctx->procattr, ctx->p);
428
429 rc = apr_procattr_io_set(ctx->procattr,
434
435 rc = set_resource_limits(f->r, ctx->procattr);
437
438 if (dc->log_stderr > 0) {
440 f->r->server->error_log, /* stderr in child */
441 NULL);
443 }
444
448
449 rc = apr_procattr_error_check_set(ctx->procattr, 1);
450 if (rc != APR_SUCCESS) {
451 return rc;
452 }
453
454 /* add standard CGI variables as well as DOCUMENT_URI, DOCUMENT_PATH_INFO,
455 * and QUERY_STRING_UNESCAPED
456 */
457 ap_add_cgi_vars(f->r);
459 apr_table_setn(f->r->subprocess_env, "DOCUMENT_URI", f->r->uri);
460 apr_table_setn(f->r->subprocess_env, "DOCUMENT_PATH_INFO", f->r->path_info);
461 if (f->r->args) {
462 /* QUERY_STRING is added by ap_add_cgi_vars */
463 char *arg_copy = apr_pstrdup(f->r->pool, f->r->args);
465 apr_table_setn(f->r->subprocess_env, "QUERY_STRING_UNESCAPED",
467 }
468
469 env = (const char * const *) ap_create_environment(ctx->p,
470 f->r->subprocess_env);
471
472 rc = apr_proc_create(ctx->proc,
473 ctx->filter->command,
474 (const char * const *)ctx->filter->args,
475 env, /* environment */
476 ctx->procattr,
477 ctx->p);
478 if (rc != APR_SUCCESS) {
480 "couldn't create child process to run `%s'",
481 ctx->filter->command);
482 return rc;
483 }
484
486
487 /* We don't want the handle to the child's stdin inherited by any
488 * other processes created by httpd. Otherwise, when we close our
489 * handle, the child won't see EOF because another handle will still
490 * be open.
491 */
492
493 apr_pool_cleanup_register(ctx->p, ctx->proc->in,
494 apr_pool_cleanup_null, /* other mechanism */
496
497#if APR_FILES_AS_SOCKETS
498 {
499 apr_pollfd_t pfd = { 0 };
500
501 rc = apr_pollset_create(&ctx->pollset, 2, ctx->p, 0);
503
504 pfd.p = ctx->p;
507 pfd.desc.f = ctx->proc->in;
508 rc = apr_pollset_add(ctx->pollset, &pfd);
510
511 pfd.reqevents = APR_POLLIN;
512 pfd.desc.f = ctx->proc->out;
513 rc = apr_pollset_add(ctx->pollset, &pfd);
515 }
516#endif
517
518 return APR_SUCCESS;
519}
520
521static const char *get_cfg_string(ef_dir_t *dc, ef_filter_t *filter, apr_pool_t *p)
522{
523 const char *log_stderr_str = dc->log_stderr < 1 ?
524 "NoLogStderr" : "LogStderr";
526 "PreservesContentLength" : "!PreserveContentLength";
527 const char *intype_str = !filter->intype ?
528 "*/*" : filter->intype;
529 const char *outtype_str = !filter->outtype ?
530 "(unchanged)" : filter->outtype;
531
532 return apr_psprintf(p,
533 "ExtFilterOptions %s %s ExtFilterInType %s "
534 "ExtFilterOuttype %s",
537}
538
539static ef_filter_t *find_filter_def(const server_rec *s, const char *fname)
540{
541 ef_server_t *sc;
542 ef_filter_t *f;
543
544 sc = ap_get_module_config(s->module_config, &ext_filter_module);
546 if (!f && s != main_server) {
547 s = main_server;
548 sc = ap_get_module_config(s->module_config, &ext_filter_module);
550 }
551 return f;
552}
553
555{
556 ef_ctx_t *ctx;
557 ef_dir_t *dc;
558 apr_status_t rv;
559
560 f->ctx = ctx = apr_pcalloc(f->r->pool, sizeof(ef_ctx_t));
561 dc = ap_get_module_config(f->r->per_dir_config,
562 &ext_filter_module);
563 ctx->dc = dc;
564 /* look for the user-defined filter */
565 ctx->filter = find_filter_def(f->r->server, f->frec->name);
566 if (!ctx->filter) {
568 "couldn't find definition of filter '%s'",
569 f->frec->name);
570 return APR_EINVAL;
571 }
572 ctx->p = f->r->pool;
573 if (ctx->filter->intype &&
574 ctx->filter->intype != INTYPE_ALL) {
575 const char *ctypes;
576
577 if (ctx->filter->mode == INPUT_FILTER) {
578 ctypes = apr_table_get(f->r->headers_in, "Content-Type");
579 }
580 else {
581 ctypes = f->r->content_type;
582 }
583
584 if (ctypes) {
585 const char *ctype = ap_getword(f->r->pool, &ctypes, ';');
586
587 if (strcasecmp(ctx->filter->intype, ctype)) {
588 /* wrong IMT for us; don't mess with the output */
589 ctx->noop = 1;
590 }
591 }
592 else {
593 ctx->noop = 1;
594 }
595 }
596 if (ctx->filter->enable_env &&
597 !apr_table_get(f->r->subprocess_env, ctx->filter->enable_env)) {
598 /* an environment variable that enables the filter isn't set; bail */
599 ctx->noop = 1;
600 }
601 if (ctx->filter->disable_env &&
602 apr_table_get(f->r->subprocess_env, ctx->filter->disable_env)) {
603 /* an environment variable that disables the filter is set; bail */
604 ctx->noop = 1;
605 }
606 if (!ctx->noop) {
608 if (rv != APR_SUCCESS) {
609 return rv;
610 }
611 if (ctx->filter->outtype &&
612 ctx->filter->outtype != OUTTYPE_UNCHANGED) {
613 ap_set_content_type(f->r, ctx->filter->outtype);
614 }
615 if (ctx->filter->preserves_content_length != 1) {
616 /* nasty, but needed to avoid confusing the browser
617 */
618 apr_table_unset(f->r->headers_out, "Content-Length");
619 }
620 }
621
622 if (APLOGrtrace1(f->r)) {
624 "%sfiltering `%s' of type `%s' through `%s', cfg %s",
625 ctx->noop ? "NOT " : "",
626 f->r->uri ? f->r->uri : f->r->filename,
627 f->r->content_type ? f->r->content_type : "(unspecified)",
628 ctx->filter->command,
629 get_cfg_string(dc, ctx->filter, f->r->pool));
630 }
631
632 return APR_SUCCESS;
633}
634
635/* drain_available_output():
636 *
637 * if any data is available from the filter, read it and append it
638 * to the bucket brigade
639 */
642{
643 request_rec *r = f->r;
645 ef_ctx_t *ctx = f->ctx;
647 char buf[4096];
648 apr_status_t rv;
649 apr_bucket *b;
650
651 while (1) {
652 int lvl = APLOG_TRACE5;
653 len = sizeof(buf);
654 rv = apr_file_read(ctx->proc->out, buf, &len);
655 if (rv && !APR_STATUS_IS_EAGAIN(rv))
657 ap_log_rerror(APLOG_MARK, lvl, rv, r, APLOGNO(01460)
658 "apr_file_read(child output), len %" APR_SIZE_T_FMT, len);
659 if (rv != APR_SUCCESS) {
660 return rv;
661 }
662 b = apr_bucket_heap_create(buf, len, NULL, c->bucket_alloc);
664 return APR_SUCCESS;
665 }
666 /* we should never get here; if we do, a bogus error message would be
667 * the least of our problems
668 */
669 return APR_ANONYMOUS;
670}
671
674{
675 ef_ctx_t *ctx = f->ctx;
676 apr_status_t rv;
679
680 do {
682 rv = apr_file_write_full(ctx->proc->in,
683 (const char *)data + bytes_written,
684 tmplen, &tmplen);
686 if (rv != APR_SUCCESS && !APR_STATUS_IS_EAGAIN(rv)) {
688 "apr_file_write(child input), len %" APR_SIZE_T_FMT,
689 tmplen);
690 return rv;
691 }
692 if (APR_STATUS_IS_EAGAIN(rv)) {
693 /* XXX handle blocking conditions here... if we block, we need
694 * to read data from the child process and pass it down to the
695 * next filter!
696 */
697 rv = drain_available_output(f, bb);
698 if (APR_STATUS_IS_EAGAIN(rv)) {
699#if APR_FILES_AS_SOCKETS
700 int num_events;
701 const apr_pollfd_t *pdesc;
702
703 rv = apr_pollset_poll(ctx->pollset, f->r->server->timeout,
704 &num_events, &pdesc);
705 if (rv != APR_SUCCESS && !APR_STATUS_IS_EINTR(rv)) {
707 "apr_pollset_poll()");
708 /* some error such as APR_TIMEUP */
709 return rv;
710 }
712 "apr_pollset_poll()");
713#else /* APR_FILES_AS_SOCKETS */
714 /* Yuck... I'd really like to wait until I can read
715 * or write, but instead I have to sleep and try again
716 */
718 ap_log_rerror(APLOG_MARK, APLOG_TRACE6, 0, f->r, "apr_sleep()");
719#endif /* APR_FILES_AS_SOCKETS */
720 }
721 else if (rv != APR_SUCCESS) {
722 return rv;
723 }
724 }
725 } while (bytes_written < len);
726 return rv;
727}
728
729/* ef_unified_filter:
730 *
731 * runs the bucket brigade bb through the filter and puts the result into
732 * bb, dropping the previous content of bb (the input)
733 */
734
736{
737 request_rec *r = f->r;
739 ef_ctx_t *ctx = f->ctx;
740 apr_bucket *b;
742 const char *data;
743 apr_status_t rv;
744 char buf[4096];
747
748 bb_tmp = apr_brigade_create(r->pool, c->bucket_alloc);
749
750 for (b = APR_BRIGADE_FIRST(bb);
751 b != APR_BRIGADE_SENTINEL(bb);
753 {
754 if (APR_BUCKET_IS_EOS(b)) {
755 eos = b;
756 break;
757 }
758
759 if (AP_BUCKET_IS_ERROR(b)) {
763 break;
764 }
765
767 if (rv != APR_SUCCESS) {
768 ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, APLOGNO(01463) "apr_bucket_read()");
769 return rv;
770 }
771
772 /* Good cast, we just tested len isn't negative */
773 if (len > 0 &&
775 != APR_SUCCESS) {
776 return rv;
777 }
778 }
779
783
784 if (eos) {
785 /* close the child's stdin to signal that no more data is coming;
786 * that will cause the child to finish generating output
787 */
788 if ((rv = apr_file_close(ctx->proc->in)) != APR_SUCCESS) {
790 "apr_file_close(child input)");
791 return rv;
792 }
793 /* since we've seen eos and closed the child's stdin, set the proper pipe
794 * timeout; we don't care if we don't return from apr_file_read() for a while...
795 */
796 rv = apr_file_pipe_timeout_set(ctx->proc->out,
797 r->server->timeout);
798 if (rv) {
800 "apr_file_pipe_timeout_set(child output)");
801 return rv;
802 }
803 }
804
805 do {
806 int lvl = APLOG_TRACE6;
807 len = sizeof(buf);
808 rv = apr_file_read(ctx->proc->out, buf, &len);
809 if (rv && !APR_STATUS_IS_EOF(rv) && !APR_STATUS_IS_EAGAIN(rv))
810 lvl = APLOG_ERR;
811 ap_log_rerror(APLOG_MARK, lvl, rv, r, APLOGNO(01466)
812 "apr_file_read(child output), len %" APR_SIZE_T_FMT, len);
813 if (APR_STATUS_IS_EAGAIN(rv)) {
814 if (eos) {
815 /* should not occur, because we have an APR timeout in place */
816 AP_DEBUG_ASSERT(1 != 1);
817 }
818 return APR_SUCCESS;
819 }
820
821 if (rv == APR_SUCCESS) {
822 b = apr_bucket_heap_create(buf, len, NULL, c->bucket_alloc);
824 }
825 } while (rv == APR_SUCCESS);
826
827 if (!APR_STATUS_IS_EOF(rv)) {
828 return rv;
829 }
830
831 if (eos) {
832 b = apr_bucket_eos_create(c->bucket_alloc);
834 ctx->hit_eos = 1;
835 }
836
837 return APR_SUCCESS;
838}
839
841{
842 request_rec *r = f->r;
843 ef_ctx_t *ctx = f->ctx;
844 apr_status_t rv;
845
846 if (!ctx) {
847 if ((rv = init_filter_instance(f)) != APR_SUCCESS) {
848 ctx = f->ctx;
850 "can't initialise output filter %s: %s",
851 f->frec->name,
852 (ctx->dc->onfail == 1) ? "removing" : "aborting");
854 if (ctx->dc->onfail == 1) {
855 return ap_pass_brigade(f->next, bb);
856 }
857 else {
858 apr_bucket *e;
859 f->r->status_line = "500 Internal Server Error";
860
863 NULL, r->pool,
864 f->c->bucket_alloc);
866 e = apr_bucket_eos_create(f->c->bucket_alloc);
868 ap_pass_brigade(f->next, bb);
869 return AP_FILTER_ERROR;
870 }
871 }
872 ctx = f->ctx;
873 }
874 if (ctx->noop) {
876 return ap_pass_brigade(f->next, bb);
877 }
878
879 rv = ef_unified_filter(f, bb);
880 if (rv != APR_SUCCESS) {
882 "ef_unified_filter() failed");
883 }
884
885 if ((rv = ap_pass_brigade(f->next, bb)) != APR_SUCCESS) {
887 "ap_pass_brigade() failed");
888 }
889 return rv;
890}
891
895{
896 ef_ctx_t *ctx = f->ctx;
897 apr_status_t rv;
898
899 /* just get out of the way of things we don't want. */
900 if (mode != AP_MODE_READBYTES) {
901 return ap_get_brigade(f->next, bb, mode, block, readbytes);
902 }
903
904 if (!ctx) {
905 if ((rv = init_filter_instance(f)) != APR_SUCCESS) {
906 ctx = f->ctx;
908 "can't initialise input filter %s: %s",
909 f->frec->name,
910 (ctx->dc->onfail == 1) ? "removing" : "aborting");
912 if (ctx->dc->onfail == 1) {
913 return ap_get_brigade(f->next, bb, mode, block, readbytes);
914 }
915 else {
916 f->r->status = HTTP_INTERNAL_SERVER_ERROR;
918 }
919 }
920 ctx = f->ctx;
921 }
922
923 if (ctx->hit_eos) {
924 /* Match behaviour of HTTP_IN if filter is re-invoked after
925 * hitting EOS: give back another EOS. */
926 apr_bucket *e = apr_bucket_eos_create(f->c->bucket_alloc);
928 return APR_SUCCESS;
929 }
930
931 if (ctx->noop) {
933 return ap_get_brigade(f->next, bb, mode, block, readbytes);
934 }
935
936 rv = ap_get_brigade(f->next, bb, mode, block, readbytes);
937 if (rv != APR_SUCCESS) {
938 return rv;
939 }
940
941 rv = ef_unified_filter(f, bb);
942 return rv;
943}
944
946{
951 NULL,
952 cmds,
954};
const char apr_size_t len
Definition ap_regex.h:187
APR-UTIL Buckets/Bucket Brigades.
APR Hash Tables.
APR general purpose library routines.
APR Poll interface.
APR Strings library.
APR Standard Headers Support.
#define ap_get_module_config(v, m)
void ap_hook_post_config(ap_HOOK_post_config_t *pf, const char *const *aszPre, const char *const *aszSucc, int nOrder)
Definition config.c:105
#define AP_DECLARE_MODULE(foo)
ap_conf_vector_t * base
#define AP_INIT_ITERATE(directive, func, mconfig, where, help)
#define AP_INIT_RAW_ARGS(directive, func, mconfig, where, help)
request_rec * r
#define AP_FILTER_ERROR
Definition httpd.h:473
#define OK
Definition httpd.h:456
void ap_remove_input_filter(ap_filter_t *f)
ap_filter_type
apr_status_t ap_pass_brigade(ap_filter_t *filter, apr_bucket_brigade *bucket)
ap_filter_rec_t * ap_register_output_filter(const char *name, ap_out_filter_func filter_func, ap_init_filter_func filter_init, ap_filter_type ftype)
apr_status_t ap_filter_rec_t * ap_register_input_filter(const char *name, ap_in_filter_func filter_func, ap_init_filter_func filter_init, ap_filter_type ftype)
apr_status_t ap_get_brigade(ap_filter_t *filter, apr_bucket_brigade *bucket, ap_input_mode_t mode, apr_read_type_e block, apr_off_t readbytes)
void ap_remove_output_filter(ap_filter_t *f)
@ AP_FTYPE_RESOURCE
#define ap_get_core_module_config(v)
Definition http_core.h:383
#define APLOGNO(n)
Definition http_log.h:117
#define ap_log_rerror
Definition http_log.h:454
#define APLOG_ERR
Definition http_log.h:67
#define APLOG_MARK
Definition http_log.h:283
#define APLOGrtrace1(r)
Definition http_log.h:246
#define APLOG_WARNING
Definition http_log.h:68
#define APLOG_TRACE1
Definition http_log.h:72
#define APLOG_TRACE5
Definition http_log.h:76
#define APLOG_TRACE6
Definition http_log.h:77
#define APLOG_DEBUG
Definition http_log.h:71
const unsigned char * buf
Definition util_md5.h:50
void ap_set_content_type(request_rec *r, const char *ct)
#define AP_BUCKET_IS_ERROR(e)
apr_bucket * ap_bucket_error_create(int error, const char *buf, apr_pool_t *p, apr_bucket_alloc_t *list)
void ap_add_common_vars(request_rec *r)
char ** ap_create_environment(apr_pool_t *p, apr_table_t *t)
void ap_add_cgi_vars(request_rec *r)
apr_status_t ap_recent_ctime(char *date_str, apr_time_t t)
Definition util_time.c:158
void * dummy
Definition http_vhost.h:62
void const char * arg
Definition http_vhost.h:63
#define APR_ANONYMOUS
Definition apr_errno.h:468
#define APR_EINVAL
Definition apr_errno.h:711
#define APR_STATUS_IS_EINTR(s)
Definition apr_errno.h:1281
#define APR_STATUS_IS_EAGAIN(s)
Definition apr_errno.h:1272
#define APR_STATUS_IS_EOF(s)
Definition apr_errno.h:567
apr_file_t * f
#define APR_BRIGADE_INSERT_TAIL(b, e)
apr_file_t apr_off_t start
#define APR_BUCKET_NEXT(e)
apr_read_type_e
Definition apr_buckets.h:57
apr_bucket * e
#define APR_BRIGADE_CONCAT(a, b)
#define APR_BRIGADE_SENTINEL(b)
#define APR_BUCKET_IS_EOS(e)
apr_brigade_flush void * ctx
#define apr_bucket_copy(e, c)
apr_bucket apr_bucket_brigade * a
#define APR_BRIGADE_FIRST(b)
#define apr_bucket_read(e, str, len, block)
@ APR_BLOCK_READ
Definition apr_buckets.h:58
apr_dbd_transaction_t int mode
Definition apr_dbd.h:261
#define APR_HOOK_MIDDLE
Definition apr_hooks.h:303
apr_redis_t * rc
Definition apr_redis.h:173
#define ACCESS_CONF
#define RSRC_CONF
#define HTTP_INTERNAL_SERVER_ERROR
Definition httpd.h:535
#define STANDARD20_MODULE_STUFF
char * ap_getword_white(apr_pool_t *p, const char **line)
Definition util.c:751
char * ap_getword(apr_pool_t *p, const char **line, char stop)
Definition util.c:723
char * ap_escape_shell_cmd(apr_pool_t *p, const char *s)
Definition util.c:1812
#define AP_DEBUG_ASSERT(exp)
Definition httpd.h:2283
void ap_str_tolower(char *s)
Definition util.c:2410
#define ap_assert(exp)
Definition httpd.h:2271
int ap_unescape_url(char *url)
Definition util.c:1939
apr_size_t size
const char int apr_pool_t * pool
Definition apr_cstr.h:84
#define apr_isspace(c)
Definition apr_lib.h:225
#define APR_SUCCESS
Definition apr_errno.h:225
int apr_status_t
Definition apr_errno.h:44
void * data
const void apr_size_t apr_size_t * bytes_written
const char * fname
int strcasecmp(const char *a, const char *b)
int strncasecmp(const char *a, const char *b, size_t n)
#define APR_HASH_KEY_STRING
Definition apr_hash.h:47
apr_vformatter_buff_t * c
Definition apr_lib.h:175
char const *const char const *const ** env
@ APR_POLL_FILE
Definition apr_poll.h:94
apr_pool_t * b
Definition apr_pools.h:529
#define apr_pcalloc(p, size)
Definition apr_pools.h:465
const char * s
Definition apr_strings.h:95
apr_int32_t apr_int32_t apr_int32_t err
#define APR_LIMIT_MEM
#define APR_LIMIT_NPROC
apr_cmdtype_e cmd
#define APR_LIMIT_CPU
const char const char *const * args
#define APR_CHILD_BLOCK
@ APR_KILL_AFTER_TIMEOUT
#define APR_CTIME_LEN
Definition apr_time.h:198
#define apr_time_from_msec(msec)
Definition apr_time.h:75
#define APR_POLLOUT
Definition apr_poll.h:51
#define APR_POLLIN
Definition apr_poll.h:49
Apache Configuration.
CORE HTTP Daemon.
Apache Logging library.
HTTP protocol handling.
HTTP Daemon routines.
static apr_file_t * stderr_log
Definition log.c:170
apr_pool_t * p
Definition md_event.c:32
static const server_rec * main_server
#define ERRFN_USERDATA_KEY
static const char * parse_cmd(apr_pool_t *p, const char **args, ef_filter_t *filter)
static apr_status_t set_resource_limits(request_rec *r, apr_procattr_t *procattr)
static void * merge_ef_dir_conf(apr_pool_t *p, void *basev, void *overridesv)
static const char * add_options(cmd_parms *cmd, void *in_dc, const char *arg)
static apr_status_t init_ext_filter_process(ap_filter_t *f)
static const char * define_filter(cmd_parms *cmd, void *dummy, const char *args)
#define INTYPE_ALL
static void * create_ef_dir_conf(apr_pool_t *p, char *dummy)
static ef_filter_t * find_filter_def(const server_rec *s, const char *fname)
static apr_status_t ef_input_filter(ap_filter_t *, apr_bucket_brigade *, ap_input_mode_t, apr_read_type_e, apr_off_t)
static void register_hooks(apr_pool_t *p)
static int ef_unified_filter(ap_filter_t *f, apr_bucket_brigade *bb)
static void child_errfn(apr_pool_t *pool, apr_status_t err, const char *description)
static apr_status_t ef_close_file(void *vfile)
static apr_status_t ef_output_filter(ap_filter_t *, apr_bucket_brigade *)
#define OUTTYPE_UNCHANGED
static apr_status_t drain_available_output(ap_filter_t *f, apr_bucket_brigade *bb)
static void * create_ef_server_conf(apr_pool_t *p, server_rec *s)
static const command_rec cmds[]
static apr_status_t pass_data_to_filter(ap_filter_t *f, const char *data, apr_size_t len, apr_bucket_brigade *bb)
static const char * get_cfg_string(ef_dir_t *dc, ef_filter_t *filter, apr_pool_t *p)
static apr_status_t init_filter_instance(ap_filter_t *f)
static int ef_init(apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp, server_rec *main_s)
return NULL
Definition mod_so.c:359
char * name
The representation of a filter chain.
apr_interval_time_t timeout
apr_pool_t * pool
apr_int16_t reqevents
Definition apr_poll.h:111
apr_datatype_e desc_type
Definition apr_poll.h:110
apr_descriptor desc
Definition apr_poll.h:113
apr_pool_t * p
Definition apr_poll.h:109
Structure to store things which are per connection.
Definition httpd.h:1152
Per-directory configuration.
Definition http_core.h:527
ef_filter_t * filter
ef_dir_t * dc
apr_procattr_t * procattr
apr_proc_t * proc
apr_pool_t * p
int preserves_content_length
const char * command
const char * name
enum ef_filter_t::@15 mode
ap_filter_type ftype
const char * intype
const char * enable_env
const char * outtype
const char * disable_env
apr_pool_t * p
apr_hash_t * h
A structure that represents the current request.
Definition httpd.h:845
char * useragent_ip
Definition httpd.h:1101
apr_pool_t * pool
Definition httpd.h:847
conn_rec * connection
Definition httpd.h:849
server_rec * server
Definition httpd.h:851
struct ap_conf_vector_t * per_dir_config
Definition httpd.h:1047
A structure to store information for each virtual server.
Definition httpd.h:1322
apr_interval_time_t timeout
Definition httpd.h:1372
static apr_pollset_t * pollset
Definition testpoll.c:41
apr_file_t * f
Definition apr_poll.h:100
Apache filter library.
ap_input_mode_t
input filtering modes
Definition util_filter.h:41
@ AP_MODE_READBYTES
Definition util_filter.h:43
Apache script tools.
Apache date-time handling functions.