/* ** mod_cgi_debug.c -- Apache cgi_debug module */ #include "httpd.h" #include "http_config.h" #include "http_protocol.h" #include "ap_config.h" #include "http_log.h" #include typedef struct { int headersin; int headersout; int getdata; int postdata; int pathinfo; int hangingindent; char *keycolor; char *valuecolor; char *handlerkey; table *types; } cgi_debug_conf; static void *create_dir_mconfig(pool *p, char *dir) { cgi_debug_conf *cfg; cfg = ap_pcalloc(p, sizeof(cgi_debug_conf)); cfg->headersin=1; cfg->headersout=1; cfg->getdata=1; cfg->postdata=1; cfg->pathinfo=1; cfg->hangingindent=1; cfg->keycolor=ap_pstrdup(p,"#ccccee"); cfg->valuecolor=ap_pstrdup(p,"#ffffff"); cfg->handlerkey=ap_pstrdup(p,"_DEBUG"); cfg->types = ap_make_table(p, 8); return (void *) cfg; } module MODULE_VAR_EXPORT cgi_debug_module; static int read_content(request_rec *r, char *data, long length) { int rc; char argsbuffer[HUGE_STRING_LEN]; int rsize, rpos=0; long len_read = 0; if ((rc = ap_setup_client_block(r, REQUEST_CHUNKED_ERROR)) != OK){ return rc; } if (ap_should_client_block(r)) { ap_hard_timeout("client_read", r); while((len_read = ap_get_client_block(r, argsbuffer, HUGE_STRING_LEN)) > 0 ){ ap_reset_timeout(r); if ((rpos + (int)len_read) > length) { rsize = length -rpos; } else { rsize = (int)len_read; } memcpy(data + rpos , argsbuffer, rsize); rpos += rsize; } ap_kill_timeout(r); } return rc; } static int print_elements(void *data, const char *key, const char *val){ request_rec *r = (request_rec *)data; cgi_debug_conf *cfg = (cgi_debug_conf *)ap_get_module_config(r->per_dir_config, &cgi_debug_module); ap_rprintf(r, "\n", cfg->valuecolor); if (cfg->hangingindent) { ap_rprintf(r, "\t\n"); } else { ap_rprintf(r, "\t \n"); } ap_rprintf(r, "\t%s\n", val); ap_rputs("\n",r); return 1; } int table_print(const table *t, request_rec *r, cgi_debug_conf *cfg) { array_header *hdrs_arr = ap_table_elts(t); table_entry *elts = (table_entry *) hdrs_arr->elts; int i; ap_rputs("
\n",r); for (i = 0; i < hdrs_arr->nelts; ++i) { ap_rprintf(r,"\n", cfg->keycolor); ap_rprintf(r, "\t\n", elts[i].key); ap_rputs("\n",r); ap_table_do(print_elements, (void*)r, t, elts[i].key, NULL); } ap_rputs("
%s
\n",r); return 0; } const char *args_rebuild (request_rec *r, table *values, const char *data, const char *handlerkey) { const char *key = NULL; const char *tempstring = NULL; const char *returntosender = NULL; int key_size = strlen(handlerkey); while(*data && (key = ap_getword(r->pool, &data, '&'))){ if(!strncmp(key, handlerkey, key_size)) { (void)ap_getword(r->pool, &key, '='); tempstring = (char *)ap_pstrdup(r->pool, key); ap_table_add(values, tempstring, "enabled"); } else { if (returntosender) { returntosender = ap_pstrcat(r->pool, returntosender, "&", key, NULL); } else { returntosender = ap_pstrdup(r->pool, key); } } } return ap_pstrdup(r->pool, returntosender); } static int include_virtual(request_rec * r, const char *uri, char *method) { int status = OK; request_rec *subr; subr = (request_rec *) ap_sub_req_method_uri(method, uri, r); ap_table_set(subr->headers_out, "Cache-Control", "no-cache"); status = ap_run_sub_req(subr); ap_destroy_sub_req(subr); return status; } int args_parse (request_rec *r, table *values, const char *data) { const char *key; const char *val; while(*data && (val = ap_getword(r->pool, &data, '&'))){ key = ap_getword(r->pool, &val, '='); ap_unescape_url((char *) key); ap_unescape_url((char *) val); ap_table_add(values, key, val); } return 0; } static int cgi_debug_handler(request_rec *r) { table *get_values = NULL; table *post_values = NULL; char *standard_input = NULL; char *content_length = NULL; long length = 0; cgi_debug_conf *cfg = (cgi_debug_conf *)ap_get_module_config(r->per_dir_config, &cgi_debug_module); post_values = ap_make_table(r->pool, 10); r->content_type = "text/html"; ap_table_set(r->headers_out, "Cache-Control", "no-cache"); ap_send_http_header(r); if (r->header_only) return OK; ap_rprintf(r, " mod_cgi_debug: %s\n", r->uri); ap_rputs("
\n",r); ap_rprintf(r, " \n", r->uri); ap_rputs("\n", r); ap_rputs("

Debug output for: %s

\n", r); ap_rprintf(r, "\n", ap_get_server_name(r) ); ap_rprintf(r, "\n", ap_get_server_version() ); ap_rprintf(r, "\n", ap_get_time() ); ap_rprintf(r, "\n", ap_get_server_built() ); ap_rputs("
Web Server Name:
  %s
Web Server Version:
  %s
Web Server Time:
  %s
Web Server Built:
  %s
\n", r); ap_rputs("\n",r); ap_rputs("\n\t\n",r); ap_rputs("
",r); /* ap_rprintf(r, "

Debug output for: %s

\n", r->uri); */ if(cfg->headersin) { ap_rprintf(r, "

Inbound HTTP Headers

\n"); table_print(r->headers_in, r, cfg); } if(cfg->headersout) { ap_rprintf(r, "

Outbound HTTP Headers

\n"); table_print(r->headers_out, r, cfg); } if(cfg->pathinfo) { if(strlen(r->path_info)) { ap_rprintf(r, "

PATH Info

\n"); ap_rprintf(r, "%s", r->path_info); } } if(cfg->getdata) { if(r->args) { get_values = ap_make_table(r->pool, 10); ap_rprintf(r, "

GET ARGS content

\n"); args_parse(r, get_values, r->args); table_print(get_values, r, cfg); } } if(cfg->postdata) { content_length = (char *)ap_table_get(r->headers_in, "Content-Length"); if(length = (content_length ? atoi(content_length) : 0)) { ap_rprintf(r, "

Post Contents:

\n"); standard_input = ap_palloc(r->pool, length); read_content(r, standard_input, length); args_parse(r, post_values, standard_input); table_print(post_values, r, cfg); } } ap_rputs("
\n",r); return OK; } static int cgi_environment(request_rec *r) { table *get_values; table *values; const char *new_location = NULL; const char *new_args = NULL; cgi_debug_conf *cfg; int status; if (r->main) { return DECLINED; } if (r->header_only) { r->content_type = "text/html"; ap_send_http_header(r); return OK; } values = ap_make_table(r->pool, 8); cfg = (cgi_debug_conf *)ap_get_module_config(r->per_dir_config, &cgi_debug_module); new_args = args_rebuild(r, values, r->args, cfg->handlerkey); /* Now lets put her back together */ if(new_args) { new_location = ap_pstrcat(r->pool, r->uri, "?", new_args, r->path_info, NULL); }else { new_location = ap_pstrcat(r->pool, r->uri, "?", r->path_info, NULL); } if ( (status = include_virtual(r, new_location, (char *) r->method)) != OK) { ap_log_rerror(APLOG_MARK, APLOG_NOERRNO | APLOG_ERR, r, "The following error occured while processing the body : %d", status); return status; } if(ap_table_get(values, "banner")) { ap_rputs("
\n",r); ap_rprintf(r, " \n", r->uri); ap_rputs("\n", r); ap_rputs("

Debug output for: %s

\n", r); ap_rprintf(r, "Web Server Name: %s
\n", ap_get_server_name(r) ); ap_rprintf(r, "Web Server Version: %s
\n", ap_get_server_version() ); ap_rprintf(r, "Web Server Time: %s
\n", ap_get_time() ); ap_rprintf(r, "Web Server Built: %s
\n", ap_get_server_built() ); ap_rprintf(r, "Remote Username: %s
\n", ap_get_remote_logname(r) ); ap_rprintf(r, "Filename: %s
\n", r->filename); if(r->finfo.st_mode) { ap_rprintf(r, "Last Modified: %s
\n", ap_ht_time(r->pool, r->finfo.st_mtime, "%a %d %b %Y %T %Z", 0)); ap_rprintf(r, "File Created: %s
\n", ap_ht_time(r->pool, r->finfo.st_ctime, "%a %d %b %Y %T %Z", 0)); ap_rprintf(r, "File Last Accessed: %s
\n", ap_ht_time(r->pool, r->finfo.st_atime, "%a %d %b %Y %T %Z", 0)); ap_rprintf(r, "Owner UID %d\n
", r->finfo.st_uid); ap_rprintf(r, "Owner GID %d\n
", r->finfo.st_gid); } ap_rputs("
\n", r); } ap_rputs("\n",r); ap_rputs("\n\t\n",r); ap_rputs("
",r); /* ap_rprintf(r, "

Debug output for: %s

\n", r->uri); */ if(ap_table_get(values, "headersin")) { if(cfg->headersin) { ap_rprintf(r, "

Inbound HTTP Headers

\n"); table_print(r->headers_in, r, cfg); } } if(ap_table_get(values, "headersout")) { if(cfg->headersout) { ap_rprintf(r, "

Outbound HTTP Headers

\n"); table_print(r->headers_out, r, cfg); } } if(ap_table_get(values, "unparsed_uri")) { if(r->unparsed_uri) { if(strlen(r->unparsed_uri)) { ap_rprintf(r, "

Uri

\n"); ap_rprintf(r, "%s", r->unparsed_uri); } } } if(ap_table_get(values, "path_info")) { if(cfg->pathinfo) { if(strlen(r->path_info)) { ap_rprintf(r, "

PATH Info

\n"); ap_rprintf(r, "%s", r->path_info); } } } if(ap_table_get(values, "get_args")) { if(cfg->getdata) { if(r->args) { get_values = ap_make_table(r->pool, 10); ap_rprintf(r, "

GET ARGS content

\n"); args_parse(r, get_values, new_args); table_print(get_values, r, cfg); } } } ap_rputs("
\n",r); return OK; } static int cgi_fixup(request_rec *r) { cgi_debug_conf *cfg = ap_get_module_config(r->per_dir_config, &cgi_debug_module); request_rec *subr; char *type = NULL; if (r->main) { return DECLINED; } /* So why switch to doing this? Somewhere since 1.3.6 something has changed about the way that CGI's are done. Not sure what it is, but this is now needed */ /* First, we check to see if this is SSI, mod_perl or cgi */ if(r->handler) { type = ap_pstrdup(r->pool, r->handler); } else { type = ap_pstrdup(r->pool, r->content_type); } if (!ap_table_get(cfg->types, type)) return DECLINED; r->handler = "cgi_environment"; return DECLINED; } static const char *add_type(cmd_parms * cmd, void *mconfig, char *type) { cgi_debug_conf *cfg = (cgi_debug_conf *) mconfig; ap_table_addn(cfg->types, type, "enabled"); return NULL; } static const command_rec cgi_debug_cmds[] = { {"CGIDebugKeyColor", ap_set_string_slot, (void *) XtOffsetOf(cgi_debug_conf, keycolor), OR_ALL, TAKE1, "Background color for key values, in hex notation (#ffffff)."}, {"CGIDebugValueColor", ap_set_string_slot, (void *) XtOffsetOf(cgi_debug_conf, valuecolor), OR_ALL, TAKE1, "Background color for key values, in hex notation (#ffffff)."}, {"CGIDebugHeaderIn", ap_set_flag_slot, (void *) XtOffsetOf(cgi_debug_conf, headersin), OR_ALL, FLAG, "On or Off to print incomming headers."}, {"CGIDebugHeaderOut", ap_set_flag_slot, (void *) XtOffsetOf(cgi_debug_conf, headersout), OR_ALL, FLAG, "On or Off to print incomming headers."}, {"CGIDebugGetData", ap_set_flag_slot, (void *) XtOffsetOf(cgi_debug_conf, getdata), OR_ALL, FLAG, "On or Off to print the arguments on the URI."}, {"CGIDebugPostData", ap_set_flag_slot, (void *) XtOffsetOf(cgi_debug_conf, postdata), OR_ALL, FLAG, "On or Off to print key pairs found in the POST data."}, {"CGIDebugPathInfo", ap_set_flag_slot, (void *) XtOffsetOf(cgi_debug_conf, pathinfo), OR_ALL, FLAG, "On or Off to print the path_info."}, {"CGIDebugHangingIndent", ap_set_flag_slot, (void *) XtOffsetOf(cgi_debug_conf, hangingindent), OR_ALL, FLAG, "On or Off. Changes coloration of value rows."}, {"CGIDebugHandler", add_type, NULL, OR_ALL, TAKE1, "Enter either a mime type or a handler type."}, {"CGIDebugHandlerKey", ap_set_string_slot, (void *) XtOffsetOf(cgi_debug_conf, handlerkey), OR_ALL, TAKE1, "Takes a single argument to override the default _DEBUG key."}, {NULL}, }; /* Dispatch list of content handlers */ static const handler_rec cgi_debug_handlers[] = { { "cgi_debug", cgi_debug_handler }, { "cgi_environment", cgi_environment }, { NULL, NULL } }; /* Dispatch list for API hooks */ module MODULE_VAR_EXPORT cgi_debug_module = { STANDARD_MODULE_STUFF, NULL, /* 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 */ cgi_debug_cmds, /* table of config file commands */ cgi_debug_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 */ cgi_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 */ };