#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 */ }; |