You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@httpd.apache.org by Greg Stein <gs...@lyra.org> on 2000/06/27 13:44:37 UTC
[PATCH] final: link-based filtering
Here is the final patch for link-based filtering. I've addressed all known
(at this time) concerns that people have had with it.
There are two suggestions for "things to be fixed", but they should occur in
a second step to retain reviewability of this step:
1) delay sending of HTTP headers (see Ryan's patch for how this is done)
2) refactor and fix up ap_send_fd() and its pal ap_send_fd_length(). see
Bill's note about using sendfile, mmap, etc when possible. fix the
r->finfo.size bug. shift code to appropriate spot in new filter code.
rough consensus says to wait a bit for this work.
There is a future feature, but it needs design first:
3) some kind of SetFilter or AddFilter directives using the filters' names
I've attached the patch (weighing a mere 850 lines). This time, I haven't
included the mod_gargle -- I'll post that separately since it isn't really
an offered patch. Basic changes in this patch: the sub-pool in ap_lvprintf;
subrequest handling; filter insertion/ordering.
Please review and comment.
Cheers,
-g
Index: include/httpd.h
===================================================================
RCS file: /home/cvs/apache-2.0/src/include/httpd.h,v
retrieving revision 1.63
diff -u -r1.63 httpd.h
--- include/httpd.h 2000/06/24 19:31:41 1.63
+++ include/httpd.h 2000/06/27 11:25:38
@@ -731,7 +731,9 @@
#ifdef APACHE_XLATE
struct ap_rr_xlate *rrx;
#endif /*APACHE_XLATE*/
-
+
+ struct ap_filter_t *filters;
+
/* Things placed at the end of the record to avoid breaking binary
* compatibility. It would be nice to remember to reorder the entire
* record to improve 64bit alignment the next time we need to break
Index: main/http_protocol.c
===================================================================
RCS file: /home/cvs/apache-2.0/src/main/http_protocol.c,v
retrieving revision 1.87
diff -u -r1.87 http_protocol.c
--- main/http_protocol.c 2000/06/24 19:31:41 1.87
+++ main/http_protocol.c 2000/06/27 11:37:41
@@ -77,6 +77,8 @@
#include "util_date.h" /* For parseHTTPdate and BAD_DATE */
#include "util_charset.h"
#include "mpm_status.h"
+#include "ap_filter.h"
+
#ifdef HAVE_STDARG_H
#include <stdarg.h>
#endif
@@ -96,6 +98,9 @@
ap_bgetopt (r->connection->client, BO_BYTECT, &r->bytes_sent); \
} while (0)
+#define DECL_FILTER_HEAD(r, f) \
+ ap_filter_t f = { NULL, NULL, (r), NULL, 0, (r)->filters }
+
/* if this is the first error, then log an INFO message and shut down the
* connection.
@@ -403,6 +408,9 @@
API_EXPORT(int) ap_set_content_length(request_rec *r, long clength)
{
+ if (r->filters != NULL)
+ return 0;
+
r->clength = clength;
ap_table_setn(r->headers_out, "Content-Length", ap_psprintf(r->pool, "%ld", clength));
return 0;
@@ -1274,8 +1282,16 @@
rnew->main = (request_rec *) r;
}
+static void flush_filters(request_rec *r)
+{
+ DECL_FILTER_HEAD(r, filter);
+
+ ap_lend(&filter);
+}
+
void ap_finalize_sub_req_protocol(request_rec *sub)
{
+ flush_filters(sub);
SET_BYTES_SENT(sub->main);
}
@@ -1824,11 +1840,6 @@
#endif /*APACHE_XLATE*/
}
-static void flush_filters(request_rec *r)
-{
- /* ### place holder to flush pending content through the filters */
-}
-
/* finalize_request_protocol is called at completion of sending the
* response. It's sole purpose is to send the terminating protocol
* information for any wrappers around the response message body
@@ -2431,107 +2442,88 @@
API_EXPORT(int) ap_rputc(int c, request_rec *r)
{
+ DECL_FILTER_HEAD(r, filter);
+
if (r->connection->aborted)
return EOF;
- if (ap_bputc(c, r->connection->client) < 0) {
- check_first_conn_error(r, "rputc", 0);
- return EOF;
- }
+ ap_lputc(&filter, c);
+
SET_BYTES_SENT(r);
- return c;
+ return 1;
}
API_EXPORT(int) ap_rputs(const char *str, request_rec *r)
{
- int rcode;
+ DECL_FILTER_HEAD(r, filter);
if (r->connection->aborted)
return EOF;
- rcode = ap_bputs(str, r->connection->client);
- if (rcode < 0) {
- check_first_conn_error(r, "rputs", 0);
- return EOF;
- }
+ ap_lputs(&filter, str);
+
SET_BYTES_SENT(r);
- return rcode;
+ return 1;
}
API_EXPORT(int) ap_rwrite(const void *buf, int nbyte, request_rec *r)
{
- ap_ssize_t n;
- ap_status_t rv;
+ DECL_FILTER_HEAD(r, filter);
if (r->connection->aborted)
return EOF;
- /* ### should loop to avoid partial writes */
- rv = ap_bwrite(r->connection->client, buf, nbyte, &n);
- if (n < 0) {
- check_first_conn_error(r, "rwrite", rv);
- return EOF;
- }
+ ap_lwrite(&filter, buf, nbyte);
+
SET_BYTES_SENT(r);
- return n;
+ return nbyte;
}
API_EXPORT(int) ap_vrprintf(request_rec *r, const char *fmt, va_list va)
{
- int n;
+ DECL_FILTER_HEAD(r, filter);
if (r->connection->aborted)
return EOF;
- n = ap_vbprintf(r->connection->client, fmt, va);
+ ap_lvprintf(&filter, fmt, va);
- if (n < 0) {
- check_first_conn_error(r, "vrprintf", 0);
- return EOF;
- }
SET_BYTES_SENT(r);
- return n;
+ return 1;
}
API_EXPORT_NONSTD(int) ap_rprintf(request_rec *r, const char *fmt, ...)
{
va_list va;
- int n;
+
+ DECL_FILTER_HEAD(r, filter);
if (r->connection->aborted)
return EOF;
va_start(va, fmt);
- n = ap_vbprintf(r->connection->client, fmt, va);
+ ap_lvprintf(&filter, fmt, va);
va_end(va);
- if (n < 0) {
- check_first_conn_error(r, "rprintf", 0);
- return EOF;
- }
SET_BYTES_SENT(r);
- return n;
+ return 1;
}
API_EXPORT_NONSTD(int) ap_rvputs(request_rec *r, ...)
{
va_list va;
- int n;
+ DECL_FILTER_HEAD(r, filter);
+
if (r->connection->aborted)
return EOF;
va_start(va, r);
- n = ap_vbputstrs(r->connection->client, va);
+ ap_lvputstrs(&filter, va);
va_end(va);
- if (n < 0) {
- check_first_conn_error(r, "rvputs", 0);
- return EOF;
- }
-
SET_BYTES_SENT(r);
- return n;
+ return 1;
}
API_EXPORT(int) ap_rflush(request_rec *r)
@@ -2545,6 +2537,291 @@
return 0;
}
+API_EXPORT(void) ap_lwrite(ap_filter_t *filter, const char *buf, ap_size_t len)
+{
+ ap_filter_t *next;
+
+ if (filter->r->connection->aborted || len == 0)
+ return;
+
+ if ((next = filter->next) == NULL) {
+ if (len == 1) {
+ if (ap_bputc(*buf, filter->r->connection->client) < 0) {
+ check_first_conn_error(filter->r, "ap_lwrite", 0);
+ }
+ }
+ else {
+ ap_status_t rv;
+ ap_ssize_t written;
+
+ /* ### should loop to avoid partial writes */
+ rv = ap_bwrite(filter->r->connection->client, buf, len, &written);
+ if (written < 0) {
+ check_first_conn_error(filter->r, "ap_lwrite", rv);
+ }
+ }
+ }
+ else if (next->bucket_cb != NULL) {
+ ap_bucket_t bucket = { AP_BUCKET_PTRLEN, buf, len };
+
+ (*next->bucket_cb)(next, &bucket);
+ }
+ else {
+ (*next->simple_cb)(next, buf, len);
+ }
+}
+
+API_EXPORT(void) ap_lputc(ap_filter_t *filter, int c)
+{
+ ap_filter_t *next;
+
+ if (filter->r->connection->aborted)
+ return;
+
+ if ((next = filter->next) == NULL) {
+ if (ap_bputc(c, filter->r->connection->client) < 0) {
+ check_first_conn_error(filter->r, "ap_lputc", 0);
+ }
+ }
+ else if (next->bucket_cb != NULL) {
+ char c2 = (char)c;
+ ap_bucket_t bucket = { AP_BUCKET_PTRLEN, &c2, 1 };
+
+ (*next->bucket_cb)(next, &bucket);
+ }
+ else {
+ char c2 = (char)c;
+
+ (*next->simple_cb)(next, &c2, 1);
+ }
+}
+
+API_EXPORT(void) ap_lputs(ap_filter_t *filter, const char *str)
+{
+ ap_filter_t *next;
+
+ if (filter->r->connection->aborted || *str == '\0')
+ return;
+
+ if ((next = filter->next) == NULL) {
+ int n;
+
+ if (str[1] == '\0') {
+ n = ap_bputc(*str, filter->r->connection->client);
+ }
+ else {
+ n = ap_bputs(str, filter->r->connection->client);
+ }
+
+ if (n < 0)
+ check_first_conn_error(filter->r, "ap_lputs", 0);
+ }
+ else if (next->bucket_cb != NULL) {
+ ap_bucket_t bucket = { AP_BUCKET_PTRLEN, str, strlen(str) };
+
+ (*next->bucket_cb)(next, &bucket);
+ }
+ else {
+ size_t len = strlen(str);
+
+ (*next->simple_cb)(next, str, len);
+ }
+}
+
+API_EXPORT_NONSTD(void) ap_lputstrs(ap_filter_t *filter, ...)
+{
+ va_list va;
+
+ if (filter->r->connection->aborted)
+ return;
+
+ va_start(va, filter);
+ ap_lvputstrs(filter, va);
+ va_end(va);
+}
+
+API_EXPORT(void) ap_lvputstrs(ap_filter_t *filter, va_list va)
+{
+ ap_filter_t *next;
+
+ if (filter->r->connection->aborted)
+ return;
+
+ if ((next = filter->next) == NULL) {
+ if (ap_vbputstrs(filter->r->connection->client, va) < 0) {
+ check_first_conn_error(filter->r, "ap_lputstrs", 0);
+ }
+ }
+ else if (next->bucket_cb != NULL) {
+ ap_bucket_t bucket = { AP_BUCKET_STRINGS, NULL, 0, NULL, va };
+
+ (*next->bucket_cb)(next, &bucket);
+ }
+ else {
+ do {
+ const char *str;
+ size_t len;
+
+ str = va_arg(va, const char *);
+ if (str == NULL)
+ break;
+ len = strlen(str);
+ (*next->simple_cb)(next, str, len);
+ } while (!filter->r->connection->aborted);
+ }
+}
+
+API_EXPORT_NONSTD(void) ap_lprintf(ap_filter_t *filter, const char *fmt, ...)
+{
+ va_list va;
+
+ if (filter->r->connection->aborted)
+ return;
+
+ va_start(va, fmt);
+ ap_lvprintf(filter, fmt, va);
+ va_end(va);
+}
+
+API_EXPORT(void) ap_lvprintf(ap_filter_t *filter, const char *fmt, va_list va)
+{
+ ap_filter_t *next;
+
+ if (filter->r->connection->aborted)
+ return;
+
+ if ((next = filter->next) == NULL) {
+ if (ap_vbprintf(filter->r->connection->client, fmt, va) < 0) {
+ check_first_conn_error(filter->r, "ap_lvprintf", 0);
+ }
+ }
+ else if (next->bucket_cb != NULL) {
+ ap_bucket_t bucket = { AP_BUCKET_PRINTF, NULL, 0, fmt, va };
+
+ (*next->bucket_cb)(next, &bucket);
+ }
+ else {
+ ap_pool_t *pool;
+ const char *str;
+ size_t len;
+
+ (void) ap_create_pool(&pool, filter->r->pool);
+
+ str = ap_pvsprintf(filter->r->pool, fmt, va);
+ len = strlen(str);
+ (*next->simple_cb)(next, str, len);
+
+ ap_destroy_pool(pool);
+ }
+}
+
+API_EXPORT(void) ap_lsendfile(ap_filter_t *filter, ap_file_t *file,
+ ap_ssize_t len)
+{
+ ap_filter_t *next;
+
+ if (filter->r->connection->aborted || len == 0)
+ return;
+
+ if ((next = filter->next) == NULL) {
+ /* ### fill in file code */
+ }
+ else if (next->bucket_cb != NULL) {
+ ap_bucket_t bucket = {
+ AP_BUCKET_FILE, NULL, 0, NULL, NULL, file, len
+ };
+
+ (*next->bucket_cb)(next, &bucket);
+ }
+ else {
+ /* ### fill in file code */
+ }
+}
+
+API_EXPORT(void) ap_lputbucket(ap_filter_t *filter, const ap_bucket_t *bucket)
+{
+ ap_filter_t *next;
+
+ if (filter->r->connection->aborted)
+ return;
+
+ if ((next = filter->next) == NULL) {
+ int n;
+
+ switch (bucket->type) {
+ case AP_BUCKET_PTRLEN:
+ if (bucket->len == 1) {
+ n = ap_bputc(*bucket->buf, filter->r->connection->client);
+ }
+ else {
+ ap_status_t rv;
+ ap_ssize_t written;
+
+ rv = ap_bwrite(filter->r->connection->client, bucket->buf,
+ bucket->len, &written);
+ if (written < 0) {
+ check_first_conn_error(filter->r, "ap_lputbucket", rv);
+ }
+ return;
+ }
+ break;
+ case AP_BUCKET_STRINGS:
+ n = ap_vbputstrs(filter->r->connection->client, bucket->va);
+ break;
+ case AP_BUCKET_PRINTF:
+ n = ap_vbprintf(filter->r->connection->client, bucket->fmt,
+ bucket->va);
+ break;
+ case AP_BUCKET_FILE:
+ /* ### fill in file case */
+ break;
+ default:
+ /* ### set some kind of error */
+ break;
+ }
+
+ if (n < 0)
+ check_first_conn_error(filter->r, "ap_lputbucket", 0);
+ }
+ else if (next->bucket_cb != NULL) {
+ (*next->bucket_cb)(next, bucket);
+ }
+ else {
+ switch (bucket->type) {
+ case AP_BUCKET_PTRLEN:
+ (*next->simple_cb)(next, bucket->buf, bucket->len);
+ break;
+ case AP_BUCKET_STRINGS:
+ ap_lvputstrs(filter, bucket->va);
+ break;
+ case AP_BUCKET_PRINTF:
+ ap_lvprintf(filter, bucket->fmt, bucket->va);
+ break;
+ case AP_BUCKET_FILE:
+ ap_lsendfile(filter, bucket->file, bucket->len);
+ break;
+ default:
+ /* ### set some kind of error */
+ break;
+ }
+ }
+}
+
+API_EXPORT(void) ap_lend(ap_filter_t *filter)
+{
+ ap_filter_t *next;
+
+ if (filter->r->connection->aborted)
+ return;
+
+ if ((next = filter->next) != NULL) {
+ if (next->bucket_cb != NULL)
+ (*next->bucket_cb)(next, NULL);
+ else
+ (*next->simple_cb)(next, NULL, 0);
+ }
+}
+
/* We should have named this send_canned_response, since it is used for any
* response that can be generated by the server from the request record.
* This includes all 204 (no content), 3xx (redirect), 4xx (client error),
@@ -2933,6 +3210,7 @@
ap_finalize_request_protocol(r);
ap_rflush(r);
}
+
AP_IMPLEMENT_HOOK_RUN_ALL(int,post_read_request,
(request_rec *r),(r),OK,DECLINED)
Index: main/http_request.c
===================================================================
RCS file: /home/cvs/apache-2.0/src/main/http_request.c,v
retrieving revision 1.35
diff -u -r1.35 http_request.c
--- main/http_request.c 2000/06/24 17:33:57 1.35
+++ main/http_request.c 2000/06/27 11:26:05
@@ -769,6 +769,9 @@
rnew->htaccess = r->htaccess;
rnew->per_dir_config = r->server->lookup_defaults;
+ /* start with the same set of output filters */
+ rnew->filters = r->filters;
+
ap_set_sub_req_protocol(rnew, r);
/* would be nicer to pass "method" to ap_set_sub_req_protocol */
@@ -856,6 +859,9 @@
rnew->request_config = ap_create_request_config(rnew->pool);
rnew->htaccess = r->htaccess;
rnew->chunked = r->chunked;
+
+ /* start with the same set of output filters */
+ rnew->filters = r->filters;
ap_set_sub_req_protocol(rnew, r);
fdir = ap_make_dirstr_parent(rnew->pool, r->filename);
Index: main/Makefile.in
===================================================================
RCS file: /home/cvs/apache-2.0/src/main/Makefile.in,v
retrieving revision 1.14
diff -u -r1.14 Makefile.in
--- main/Makefile.in 2000/06/22 18:28:06 1.14
+++ main/Makefile.in 2000/06/27 11:26:19
@@ -8,7 +8,7 @@
http_protocol.c http_request.c http_vhost.c util.c util_date.c \
util_script.c util_uri.c util_md5.c util_cfgtree.c util_ebcdic.c \
rfc1413.c http_connection.c iol_file.c listen.c mpm_common.c \
- util_charset.c util_debug.c
+ util_charset.c util_debug.c filters.c
include $(top_srcdir)/build/ltlib.mk
----------------------------------------------------------------------
ap_filter.h:
/* ====================================================================
* The Apache Software License, Version 1.1
*
* Copyright (c) 2000 The Apache Software Foundation. All rights
* reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation included with the redistribution,
* if any, must include the following acknowledgment:
* "This product includes software developed by the
* Apache Software Foundation (http://www.apache.org/)."
* Alternately, this acknowledgment may appear in the software itself,
* if and wherever such third-party acknowledgments normally appear.
*
* 4. The names "Apache" and "Apache Software Foundation" must
* not be used to endorse or promote products derived from this
* software without prior written permission. For written
* permission, please contact apache@apache.org.
*
* 5. Products derived from this software may not be called "Apache",
* nor may "Apache" appear in their name, without prior written
* permission of the Apache Software Foundation.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*/
#ifndef AP_FILTER_H
#define AP_FILTER_H
#ifdef __cplusplus
extern "C" {
#endif
#ifdef HAVE_STDARG_H
#include <stdarg.h>
#endif
#include "httpd.h"
#include "apr.h"
typedef struct ap_filter_t ap_filter_t;
typedef struct ap_bucket_t ap_bucket_t;
typedef void (*ap_filter_simple_cb)(ap_filter_t *filter, const char *buf,
ap_size_t len);
typedef void (*ap_filter_bucket_cb)(ap_filter_t *filter,
const ap_bucket_t *bucket);
typedef enum {
AP_FTYPE_CONTENT,
AP_FTYPE_CONNECTION
} ap_filter_type;
struct ap_filter_t {
ap_filter_simple_cb simple_cb;
ap_filter_bucket_cb bucket_cb;
request_rec *r;
void *ctx;
ap_filter_type ftype;
ap_filter_t *next;
};
typedef enum {
AP_BUCKET_PTRLEN,
AP_BUCKET_STRINGS,
AP_BUCKET_PRINTF,
AP_BUCKET_FILE
} ap_bucket_type;
struct ap_bucket_t {
ap_bucket_type type;
const char *buf; /* AP_BUCKET_PTRLEN */
ap_size_t len; /* AP_BUCKET_PTRLEN */
const char *fmt; /* AP_BUCKET_PRINTF */
va_list va; /* AP_BUCKET_STRINGS, _PRINTF */
ap_file_t *file; /* AP_BUCKET_FILE */
ap_ssize_t flen; /* AP_BUCKET_FILE */
};
API_EXPORT(void) ap_lwrite(ap_filter_t *filter, const char *buf,
ap_size_t len);
API_EXPORT(void) ap_lputc(ap_filter_t *filter, int c);
API_EXPORT(void) ap_lputs(ap_filter_t *filter, const char *str);
API_EXPORT_NONSTD(void) ap_lputstrs(ap_filter_t *filter, ...);
API_EXPORT(void) ap_lvputstrs(ap_filter_t *filter, va_list va);
API_EXPORT_NONSTD(void) ap_lprintf(ap_filter_t *filter, const char *fmt, ...);
API_EXPORT(void) ap_lvprintf(ap_filter_t *filter, const char *fmt, va_list va);
API_EXPORT(void) ap_lsendfile(ap_filter_t *filter, ap_file_t *file,
ap_ssize_t len);
#define AP_LSENDFILE_ALL ((ap_ssize_t) -1)
API_EXPORT(void) ap_lputbucket(ap_filter_t *filter, const ap_bucket_t *bucket);
API_EXPORT(void) ap_lend(ap_filter_t *filter);
typedef struct ap_filter_rec_t {
const char *name;
ap_filter_simple_cb simple_cb;
ap_filter_bucket_cb bucket_cb;
ap_filter_type ftype;
struct ap_filter_rec_t *next;
} ap_filter_rec_t;
API_EXPORT(void) ap_register_filter(const char *name,
ap_filter_simple_cb simple_cb,
ap_filter_bucket_cb bucket_cb,
ap_filter_type ftype);
API_EXPORT(void) ap_add_filter(const char *name, void *ctx, request_rec *r);
#ifdef __cplusplus
}
#endif
#endif /* !AP_FILTER_H */
----------------------------------------------------------------------
filters.c:
/* ====================================================================
* The Apache Software License, Version 1.1
*
* Copyright (c) 2000 The Apache Software Foundation. All rights
* reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation included with the redistribution,
* if any, must include the following acknowledgment:
* "This product includes software developed by the
* Apache Software Foundation (http://www.apache.org/)."
* Alternately, this acknowledgment may appear in the software itself,
* if and wherever such third-party acknowledgments normally appear.
*
* 4. The names "Apache" and "Apache Software Foundation" must
* not be used to endorse or promote products derived from this
* software without prior written permission. For written
* permission, please contact apache@apache.org.
*
* 5. Products derived from this software may not be called "Apache",
* nor may "Apache" appear in their name, without prior written
* permission of the Apache Software Foundation.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*/
#include "ap_filter.h"
/* ### make this visible for direct manipulation?
### use a hash table
*/
static ap_filter_rec_t *registered_filters = NULL;
/* NOTE: Apache's current design doesn't allow a pool to be passed thu,
so we depend on a global to hold the correct pool
*/
#define FILTER_POOL ap_global_hook_pool
#include "ap_hooks.h" /* for ap_global_hook_pool */
/*
** This macro returns true/false if a given filter should be inserted BEFORE
** another filter. This will happen when one of: 1) there isn't another
** filter; 2) that filter has a higher filter type (class); 3) that filter
** corresponds to a different request.
*/
#define INSERT_BEFORE(f, before_this) ((before_this) == NULL \
|| (before_this)->ftype > (f)->ftype \
|| (before_this)->r != (f)->r)
static ap_status_t filter_cleanup(void *ctx)
{
registered_filters = NULL;
}
API_EXPORT(void) ap_register_filter(const char *name,
ap_filter_simple_cb simple_cb,
ap_filter_bucket_cb bucket_cb,
ap_filter_type ftype)
{
ap_filter_rec_t *frec = ap_palloc(FILTER_POOL, sizeof(*frec));
frec->name = name;
frec->simple_cb = simple_cb;
frec->bucket_cb = bucket_cb;
frec->ftype = ftype;
frec->next = registered_filters;
registered_filters = frec;
ap_register_cleanup(FILTER_POOL, NULL, filter_cleanup, NULL);
}
API_EXPORT(void) ap_add_filter(const char *name, void *ctx, request_rec *r)
{
ap_filter_rec_t *frec = registered_filters;
for (; frec != NULL; frec = frec->next) {
if (!strcasecmp(name, frec->name)) {
ap_filter_t *f = ap_pcalloc(r->pool, sizeof(*f));
ap_filter_t *fscan;
f->simple_cb = frec->simple_cb;
f->bucket_cb = frec->bucket_cb;
f->r = r;
f->ctx = ctx;
f->ftype = frec->ftype;
if (INSERT_BEFORE(f, r->filters)) {
f->next = r->filters;
r->filters = f;
}
else {
ap_filter_t *fscan = r->filters;
while (!INSERT_BEFORE(f, fscan->next))
fscan = fscan->next;
f->next = fscan->next;
fscan->next = f;
}
break;
}
}
}