#i nclude "httpd.h"
#i nclude "util_filter.h"
#i nclude "http_config.h"
#i nclude "http_log.h"
/* The string which is to be replaced by the time stamp */
static char TIME_COOKIE[] = "***TIME-COOKIE***";
/* Declare the module name */
module AP_MODULE_DECLARE_DATA time_cookie;
typedef struct tc_context_ {
apr_bucket_brigade *bb;
apr_time_t timestamp;
} tc_context;
/*
This function passes in the system filter information (f)
and the bucket brigade representing content to be filtered (bb)
*/
static int time_cookie_filter(ap_filter_t *f, apr_bucket_brigade *bb)
{
tc_context *ctx = f->ctx; /* The filter context */
apr_bucket *curr_bucket;
apr_pool_t *pool = f->r->pool; /* The pool for all memory requests */
/* The buffer where we shall place the time stamp string.
APR_RFC822_DATE_LEN the fixed length of such strings */
char time_str[APR_RFC822_DATE_LEN+1];
apr_time_t timestamp;
if (ctx == NULL) {
/* The first time this filter has been invoked for this transaction */
f->ctx = ctx = apr_pcalloc(f->r->pool, sizeof(*ctx));
ctx->bb = apr_brigade_create(f->r->pool, f->c->bucket_alloc);
timestamp = apr_time_now();
ctx->timestamp = timestamp;
}
else {
/* Get the time stamp we've already set */
timestamp = ctx->timestamp;
}
/* Render the time into a string in RFC822 format */
apr_rfc822_date(time_str, timestamp);
/*
Iterate over each bucket in the brigade.
Find each "cookie" in the "kitchen" and replace with the time stamp
*/
APR_BRIGADE_FOREACH(curr_bucket, bb) {
const char *kitchen, *cookie;
apr_size_t len;
if (APR_BUCKET_IS_EOS(curr_bucket) || APR_BUCKET_IS_FLUSH(curr_bucket)) {
APR_BUCKET_REMOVE(curr_bucket);
APR_BRIGADE_INSERT_TAIL(ctx->bb, curr_bucket);
ap_pass_brigade(f->next, ctx->bb);
return APR_SUCCESS;
}
apr_bucket_read(curr_bucket, &kitchen, &len, APR_NONBLOCK_READ);
while (kitchen && strcmp(kitchen, "")) {
/* Return a poiner to the next occurrence of the cookie */
cookie = ap_strstr(kitchen, TIME_COOKIE);
if (cookie) {
/* Write the text up to the cookie, then the cookie
to the next filter in the chain
*/
ap_fwrite(f->next, ctx->bb, kitchen, cookie-kitchen);
ap_fputs(f->next, ctx->bb, time_str);
kitchen = cookie + sizeof(TIME_COOKIE) - 1;
/*
The following is an example of writing to the error log.
The message is actually not really appropriate for the error log,
but it serves as example.
*/
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, f->r,
"Replacing cookie with /"%s/"", time_str);
} else {
/* No more cookies found, so just write the rest of the
string and flag that we're done
*/
ap_fputs(f->next, ctx->bb, kitchen);
kitchen = "";
}
}
}
return APR_SUCCESS;
}
/* Register the filter function as a filter for modifying the HTTP body (content) */
static void time_cookie_register_hook(apr_pool_t *pool)
{
ap_register_output_filter("TIMECOOKIE", time_cookie_filter,NULL,
AP_FTYPE_CONTENT_SET);
}
/* Define the module data */
module AP_MODULE_DECLARE_DATA time_cookie =
{
STANDARD20_MODULE_STUFF,
NULL, /* dir config creater */
NULL, /* dir merger --- default is to override */
NULL, /* server config */
NULL, /* merge server config */
NULL, /* command apr_table_t */
time_cookie_register_hook /* register hook */
}; |