home *** CD-ROM | disk | FTP | other *** search
- /*
- * mod_trailer.c
- *
- * An Apache module that adds document trailer functionality.
- *
- * A document trailer is a text or HTML file that is appended to all
- * objects with a certain prefix in their URI. This module allows
- * you to assign a trailer file to a URI with the config file directive
- *
- * "Trailer <URI prefix> <trailer filename>"
- *
- * For example, to append a trailer with a filename of
- * "/usr/local/htdocs/trailer.html" to all objects with URIs beginning
- * with "/add/trailers/here/" you would place the following in your srm.conf:
- *
- * Trailer /add/trailers/here/ /usr/local/htdocs/trailer.html
- *
- *
- * This is only my second Apache module, and is much more complex than the
- * first one I wrote (which was a simple authentication module to
- * authenticate users from the unix password file). If you have any
- * comments or suggestions as to how this might be improved, please drop me
- * some email.
- *
- * If someone wanted some fancy trailers, it would be pretty simple to
- * have this append server-parsed-html trailers instead of just plain
- * text or html. Some other features that might be useful would be a
- * per directory default trailer (perhaps a .trailer file that gets appended
- * to all files in its directory) or a feature that appends a specified
- * trailer to all documents with a certain extension.
- *
- * Feel free to use this module however you like, and distribute it freely.
- * I only ask that you do not remove my name from the credits. If you
- * modify this code and distribute it, please include a list of revisions
- * in the history, along with your name. And if you find this module
- * useful, send me some email and let me know!
- *
- * Nathan W. Schrenk (nschrenk@neog.com) 11/10/95
- *
- * HISTORY:
- *
- * v 0.1 - 11/10/95 - mod_trailer.c created. This is probably full of bugs,
- * and perhaps can be done in a much better way. But hey, it
- * seems to work for me.
- *
- * v 0.2 - 11/11/95 - A bug that popped up with the POST request method was
- * fixed and now only the most specific URI prefix is matched.
- * You can now specify overlapping trailers, and the trailer
- * associated with the longest prefix will be used).
- */
-
- #include "httpd.h"
- #include "http_config.h"
- #include "http_log.h"
- #include "http_main.h"
- #include "http_protocol.h"
- #include "http_request.h"
-
- #define TRAILER_MAGIC_TYPE "text/x-trailer-appended-html"
- #define MAX_TRAILERS 20
-
- /* trailer_entry = a struct to hold trailer alias info */
-
- typedef struct {
- char *prefix; /* prefix in which to use trailer */
- char *t_file; /* filename of trailer to use */
- } trailer_entry;
-
-
- module trailer_module;
-
- /*
- * create_trailer_config() and merg_trailer_config() handle trailer
- * configuration stuff. Pretty self explanatory...
- */
-
- void *create_trailer_config(pool *p, server_rec *s)
- {
- array_header *t_cf = (array_header *) pcalloc(p,sizeof(array_header));
-
- t_cf = make_array(p,MAX_TRAILERS,sizeof(trailer_entry));
-
- return t_cf;
- }
-
- void *merge_trailer_config(pool *p, void *basev, void *overridesv)
- {
- array_header *t_cf = (array_header *) pcalloc(p,sizeof(array_header));
- array_header *base = (array_header *) basev,
- *overrides = (array_header *) overridesv;
-
- t_cf = append_arrays(p,overrides,base);
-
- return t_cf;
- }
-
-
- /*
- * add_trailer() adds trailer config file info into the server config
- */
-
- char *add_trailer(cmd_parms *cmd, void *dummy, char *p, char *f)
- {
- server_rec *s = cmd->server;
- array_header *trailer_conf =
- (array_header *) get_module_config(s->module_config,&trailer_module);
- trailer_entry *new_trailer = push_array(trailer_conf);
-
- new_trailer->prefix = p;
- new_trailer->t_file = f;
-
- return NULL;
- }
-
- command_rec trailer_cmds[] = {
- {"Trailer", add_trailer, NULL, RSRC_CONF, TAKE2,
- "A URI prefix and a trailer filename"},
- { NULL }
- };
-
- /*
- * find_trailer() returns the trailer filename for request r, or NULL
- * if the trailer cannot be determined. This has to give the trailer
- * of the most specific prefix, so we can't stop when we find the first
- * one that matches.
- */
-
- char *find_trailer(request_rec *r)
- {
- void *sconf = r->server->module_config;
- array_header *t_array =
- (array_header *) get_module_config(sconf,&trailer_module);
- trailer_entry *entries = (trailer_entry *) t_array->elts, *t;
- int i,l,longest = 0;
- char *trailer = NULL;
-
- for (i = 0; i < t_array->nelts; i++) {
- t = &entries[i];
- l = strlen(t->prefix);
- if (!strncmp(r->uri,t->prefix,l) && (l > longest)) {
- longest = l;
- trailer = t->t_file;
- }
- }
-
- return trailer;
- }
-
- /*
- * check_for_trailer() is run in the fixup stage to check
- * and see if the requested object has a trailer. If so, the request's
- * real content type is noted in r->notes, then is set to
- * TRAILER_MAGIC_TYPE.
- */
-
- int check_for_trailer(request_rec *r)
- {
- if (r->method_number == M_GET)
- if (find_trailer(r)) {
-
- /* check to see if this is already typed as a trailer to
- prevent recursively calling the trailer handler -- does this
- ever do anything? */
-
- if (!strcmp(r->content_type,TRAILER_MAGIC_TYPE))
- return DECLINED;
-
- /* make a note of the real content type for the trailer handler */
-
- table_set(r->notes,"pre-trailer-type",r->content_type);
- r->content_type = TRAILER_MAGIC_TYPE;
- return OK;
- }
-
- return DECLINED;
- }
-
- /*
- * trailer_handler() sends out the document requested and appends
- * the trailer file to it if the requested document's content type begins
- * with "text/"
- */
-
- int trailer_handler(request_rec *r)
- {
- int subr_status;
- char *t_file,*old_type,buf[MAX_STRING_LEN];
- FILE *tf;
- struct stat tf_stat;
- request_rec *subr = sub_req_lookup_uri(r->uri,r);
-
- /* set subr's content_type to the old content type */
- old_type = table_get(r->notes,"pre-trailer-type");
- if (old_type)
- subr->content_type = old_type;
-
- subr_status = run_sub_req(subr); /* run subrequest */
-
- if ((subr_status == OK) && !strncmp(subr->content_type,"text/",5)) {
- t_file = find_trailer(r);
- if (t_file && (stat(t_file,&tf_stat) || (!tf_stat.st_mode))) {
- sprintf(buf,"Trailer file %s does not exist",t_file);
- log_reason(buf,r->uri,r);
-
- return subr_status;
- }
-
- tf = pfopen(r->pool,t_file,"r");
- if (tf == NULL) {
- log_reason("file permissions deny server access to trailer file",
- t_file, r);
- return subr_status;
- }
-
- soft_timeout ("send", r);
- if (!r->header_only)
- send_fd (tf, r);
- pfclose (r->pool,tf);
-
- r->headers_out = subr->headers_out;
- r->err_headers_out = subr->headers_out;
-
- return OK;
- }
-
- /* copy headers out to handle redirect, etc */
-
- if (subr_status == REDIRECT) {
- r->headers_out = subr->headers_out;
- r->err_headers_out = subr->headers_out;
- }
-
- return subr_status;
- }
-
- handler_rec trailer_handlers[] = {
- { TRAILER_MAGIC_TYPE, trailer_handler },
- { NULL }
- };
-
- module trailer_module = {
- STANDARD_MODULE_STUFF,
- NULL, /* initializer */
- NULL, /* dir config creater */
- NULL, /* dir merger --- default is to override */
- create_trailer_config, /* server config */
- merge_trailer_config, /* merge server configs */
- trailer_cmds, /* command table */
- trailer_handlers, /* handlers */
- NULL, /* filename translation */
- NULL, /* check_user_id */
- NULL, /* check auth */
- NULL, /* check access */
- NULL, /* type_checker */
- check_for_trailer, /* fixups */
- NULL /* logger */
- };
-