/* ** mod_layout.c -- Apache layout module ** $Revision: 1.10 $ */ #include "httpd.h" #include "http_config.h" #include "http_protocol.h" #include "ap_config.h" #include "http_log.h" typedef struct { int enabled; int proxy; int headertype; int footertype; char *header; char *footer; table *types; } layout_conf; module MODULE_VAR_EXPORT layout_module; static void *create_dir_mconfig(pool *p, char *dir) { layout_conf *cfg; cfg = ap_pcalloc(p, sizeof(layout_conf)); cfg->enabled = 0; cfg->proxy = 0; cfg->types = ap_make_table(p, 4); ap_table_set(cfg->types, INCLUDES_MAGIC_TYPE, "enabled"); ap_table_set(cfg->types, INCLUDES_MAGIC_TYPE3, "enabled"); ap_table_set(cfg->types, "server-parsed", "enabled"); ap_table_set(cfg->types, "text/html", "enabled"); ap_table_set(cfg->types, "text/plain", "enabled"); ap_table_set(cfg->types, "perl-script", "enabled"); ap_table_set(cfg->types, "cgi-script", "enabled"); ap_table_set(cfg->types, "application/x-httpd-cgi", "enabled"); return (void *)cfg; } static int include_virtual(request_rec *r, char *uri, char *method) { int status = OK; request_rec *subr; subr = (request_rec *) ap_sub_req_method_uri(method, uri, r); status = ap_run_sub_req(subr); ap_destroy_sub_req(subr); return status; } static int include_virtual_container(request_rec *r, char *uri) { int status = OK; request_rec *subr; subr = (request_rec *) ap_sub_req_method_uri("GET", uri, r); ap_table_set(subr->subprocess_env, "LAYOUT_SCRIPT_NAME", r->uri); ap_table_set(subr->subprocess_env, "LAYOUT_PATH_INFO", r->path_info); ap_table_set(subr->subprocess_env, "LAYOUT_QUERY_STRING", r->args); status = ap_run_sub_req(subr); ap_destroy_sub_req(subr); return status; } static int layout_handler(request_rec *r) { int status; request_rec *subr; layout_conf *cfg = ap_get_module_config(r->per_dir_config, &layout_module); const char *content_length; if (r->main) { return DECLINED; } if ((r->finfo.st_mode == 0) && (r->proxyreq == 0)) { ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, r, "File not found: %s", (r->path_info ? ap_pstrcat(r->pool, r->filename, r->path_info, NULL) : r->filename)); return HTTP_NOT_FOUND; } r->content_type = "text/html"; ap_update_mtime(r, r->finfo.st_mtime); ap_set_last_modified(r); /* ap_set_etag(r); */ ap_send_http_header(r); if (r->header_only) { return OK; } /* So you are asking, what is up with Content-Length? Well to make CGI's work we have to spoof it a bit. Namely, if Content-Length is set when mod_cgi runs, mod_cgi will try to read the request. Now if your CGI gets it contents through a POST method this of course is a no go since all of the contents will have already been read (and Apache will deadlock trying to read from a stream with no data in it. To get around this we spoof the content length till the original request runs */ content_length = ap_pstrdup(r->pool, ap_table_get(r->headers_in, "Content-Length")); if (cfg->header) { if(cfg->headertype) { ap_rputs(cfg->header, r); } else { ap_table_set(r->headers_in, "Content-Length", "0"); (void)include_virtual_container(r,cfg->header); } } /* Now we handle the orignal request. */ ap_table_set(r->headers_in, "Content-Length", content_length); (void)include_virtual(r,r->unparsed_uri,(char *)r->method); if (cfg->footer) { if(cfg->footertype) { ap_rputs(cfg->footer, r); } else { /* Just to be paranoid */ ap_table_set(r->headers_in, "Content-Length", "0"); (void)include_virtual_container(r,cfg->footer); } } return OK; } static int layout_fixup(request_rec *r) { layout_conf *cfg = ap_get_module_config(r->per_dir_config, &layout_module); request_rec *subr; const char *type; if (!cfg->enabled) { return DECLINED; } if (r->main) { return DECLINED; } if(cfg->proxy && r->proxyreq) { /* Damn! Ok, here is the problem. If the request is for something which is and index how do we determine its mime type? Currently we just assume that it is a NULL and wrap it. This is far from perfect and is still pretty much a shot in the dark. More research needed. */ subr = (request_rec *) ap_sub_req_lookup_file(r->uri, r); type = subr->content_type; ap_destroy_sub_req(subr); if (ap_table_get(cfg->types, r->content_type) || r->content_type == NULL) { r->handler = "layout"; return DECLINED; } } if (!ap_table_get(cfg->types, r->content_type) ) { return DECLINED; } r->handler = "layout"; return DECLINED; } /* Dispatch list of content handlers */ static const handler_rec layout_handlers[] = { { "layout", layout_handler }, { NULL } }; static const char * add_header (cmd_parms *cmd, void *mconfig, char *uri) { layout_conf *cfg = (layout_conf *) mconfig; cfg->header = ap_pstrdup(cmd->pool, uri); cfg->enabled = 1; return NULL; } static const char * add_footer (cmd_parms *cmd, void *mconfig, char *uri) { layout_conf *cfg; char *trash; cfg = (layout_conf *) mconfig; cfg->enabled = 1; cfg->footer = ap_pstrdup(cmd->pool, uri); return NULL; } static const char * add_header_txt (cmd_parms *cmd, void *mconfig, char *uri) { layout_conf *cfg = (layout_conf *) mconfig; cfg->header = ap_pstrdup(cmd->pool, uri); cfg->headertype = 1; cfg->enabled = 1; return NULL; } static const char * add_footer_txt (cmd_parms *cmd, void *mconfig, char *uri) { layout_conf *cfg; cfg = (layout_conf *) mconfig; cfg->footer = ap_pstrdup(cmd->pool, uri); cfg->footertype = 1; cfg->enabled = 1; return NULL; } static const char * add_type (cmd_parms *cmd, void *mconfig, char *type) { layout_conf *cfg; cfg = (layout_conf *) mconfig; ap_table_addn(cfg->types, type, "enabled"); return NULL; } static const char * layout_proxy (cmd_parms *cmd, void *mconfig, int flag) { layout_conf *cfg; cfg = (layout_conf *) mconfig; cfg->proxy = flag; return NULL; } static const char * remove_default_types (cmd_parms *cmd, void *mconfig, int flag) { layout_conf *cfg; if (flag) { return NULL; } cfg = (layout_conf *) mconfig; ap_table_unset(cfg->types, INCLUDES_MAGIC_TYPE); ap_table_unset(cfg->types, INCLUDES_MAGIC_TYPE3); ap_table_unset(cfg->types, "server-parsed"); ap_table_unset(cfg->types, "text/html"); ap_table_unset(cfg->types, "text/plain"); ap_table_unset(cfg->types, "perl-script"); ap_table_unset(cfg->types, "cgi-script"); ap_table_unset(cfg->types, "application/x-httpd-cgi"); return NULL; } static const command_rec layout_cmds[] = { { "Header", add_header, NULL, OR_ALL, TAKE1, "A filename with the footer contents." }, { "HeaderTXT", add_header_txt, NULL, OR_ALL, TAKE1, "Double Quoted text" }, { "Footer", add_footer, NULL, OR_ALL, TAKE1, "A filename with the footer contents." }, { "FooterTXT", add_footer_txt, NULL, OR_ALL, TAKE1, "Double Quoted text" }, { "LayoutHandler", add_type, NULL, OR_ALL, TAKE1, "Enter either a mime type or a handler type." }, { "LayoutProxy", layout_proxy, NULL, OR_ALL, FLAG, "This can either be On or Off (default it Off)." }, { "LayoutDefaultHandlers", remove_default_types, NULL, OR_ALL, FLAG, "Turns On (default) or Off a list of standard types to handle." }, { NULL }, }; static void layout_init(server_rec *s, pool *p) { /* Tell apache we're here */ ap_add_version_component("mod_layout/1.0"); } /* Dispatch list for API hooks */ module MODULE_VAR_EXPORT layout_module = { STANDARD_MODULE_STUFF, layout_init, /* module initializer */ create_dir_mconfig, /* create per-dir config structures */ NULL, /* merge per-dir config structures */ NULL, /* create per-server config structures */ NULL, /* merge per-server config structures */ layout_cmds, /* table of config file commands */ layout_handlers, /* [#8] MIME-typed-dispatched handlers */ NULL, /* [#1] URI to filename translation */ NULL, /* [#4] validate user id from request */ NULL, /* [#5] check if the user is ok _here_ */ NULL, /* [#3] check access by host address */ NULL, /* [#6] determine MIME type */ layout_fixup, /* [#7] pre-run fixups */ NULL, /* [#9] log a transaction */ NULL, /* [#2] header parser */ NULL, /* child_init */ NULL, /* child_exit */ NULL /* [#0] post read-request */ };