"Fossies" - the Fresh Open Source Software Archive 
As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style:
standard) with prefixed line numbers and
code folding option.
Alternatively you can here
view or
download the uninterpreted source code file.
1 /*
2 ** mod_cgi_debug.c -- Apache cgi_debug module
3 */
4
5 #include "httpd.h"
6 #include "http_config.h"
7 #include "http_protocol.h"
8 #include "ap_config.h"
9 #include "http_log.h"
10 #include <sys/stat.h>
11
12
13 typedef struct {
14 int headersin;
15 int headersout;
16 int getdata;
17 int postdata;
18 int pathinfo;
19 int hangingindent;
20 char *keycolor;
21 char *valuecolor;
22 char *handlerkey;
23 table *types;
24 } cgi_debug_conf;
25
26 static void *create_dir_mconfig(pool *p, char *dir)
27 {
28 cgi_debug_conf *cfg;
29 cfg = ap_pcalloc(p, sizeof(cgi_debug_conf));
30 cfg->headersin=1;
31 cfg->headersout=1;
32 cfg->getdata=1;
33 cfg->postdata=1;
34 cfg->pathinfo=1;
35 cfg->hangingindent=1;
36 cfg->keycolor=ap_pstrdup(p,"#ccccee");
37 cfg->valuecolor=ap_pstrdup(p,"#ffffff");
38 cfg->handlerkey=ap_pstrdup(p,"_DEBUG");
39 cfg->types = ap_make_table(p, 8);
40
41 return (void *) cfg;
42 }
43
44
45 module MODULE_VAR_EXPORT cgi_debug_module;
46
47
48 static int read_content(request_rec *r, char *data, long length) {
49 int rc;
50 char argsbuffer[HUGE_STRING_LEN];
51 int rsize, rpos=0;
52 long len_read = 0;
53
54 if ((rc = ap_setup_client_block(r, REQUEST_CHUNKED_ERROR)) != OK){
55 return rc;
56 }
57
58 if (ap_should_client_block(r)) {
59 ap_hard_timeout("client_read", r);
60 while((len_read = ap_get_client_block(r, argsbuffer, HUGE_STRING_LEN)) > 0 ){
61 ap_reset_timeout(r);
62 if ((rpos + (int)len_read) > length) {
63 rsize = length -rpos;
64 } else {
65 rsize = (int)len_read;
66 }
67 memcpy(data + rpos , argsbuffer, rsize);
68 rpos += rsize;
69 }
70
71 ap_kill_timeout(r);
72 }
73
74 return rc;
75 }
76
77 static int print_elements(void *data, const char *key, const char *val){
78 request_rec *r = (request_rec *)data;
79 cgi_debug_conf *cfg = (cgi_debug_conf *)ap_get_module_config(r->per_dir_config, &cgi_debug_module);
80
81 ap_rprintf(r, "<TR bgcolor=\"%s\" VALIGN=\"TOP\">\n", cfg->valuecolor);
82 if (cfg->hangingindent) {
83 ap_rprintf(r, "\t<TD WIDTH=\"10%\"></TD>\n");
84 }
85 else {
86 ap_rprintf(r, "\t<TD WIDTH=\"10%\"> </TD>\n");
87 }
88 ap_rprintf(r, "\t<TD>%s</TD>\n", val);
89 ap_rputs("</TR>\n",r);
90
91 return 1;
92 }
93
94 int table_print(const table *t, request_rec *r, cgi_debug_conf *cfg)
95 {
96 array_header *hdrs_arr = ap_table_elts(t);
97 table_entry *elts = (table_entry *) hdrs_arr->elts;
98 int i;
99
100 ap_rputs("<CENTER><TABLE BORDER=\"0\" WIDTH=\"90%\" CELLSPACING=\"0\" CELLPADDING=\"0\">\n",r);
101 for (i = 0; i < hdrs_arr->nelts; ++i) {
102 ap_rprintf(r,"<TR bgcolor=\"%s\" VALIGN=\"TOP\">\n", cfg->keycolor);
103 ap_rprintf(r, "\t<TD COLSPAN=2><B>%s</B></TD>\n", elts[i].key);
104 ap_rputs("</TR>\n",r);
105 ap_table_do(print_elements, (void*)r, t, elts[i].key, NULL);
106 }
107 ap_rputs("</TABLE></CENTER>\n",r);
108
109 return 0;
110 }
111
112 const char *args_rebuild (request_rec *r, table *values, const char *data, const char *handlerkey) {
113 const char *key = NULL;
114 const char *tempstring = NULL;
115 const char *returntosender = NULL;
116 int key_size = strlen(handlerkey);
117
118 while(*data && (key = ap_getword(r->pool, &data, '&'))){
119 if(!strncmp(key, handlerkey, key_size)) {
120 (void)ap_getword(r->pool, &key, '=');
121 tempstring = (char *)ap_pstrdup(r->pool, key);
122 ap_table_add(values, tempstring, "enabled");
123 } else {
124 if (returntosender) {
125 returntosender = ap_pstrcat(r->pool, returntosender, "&", key, NULL);
126 } else {
127 returntosender = ap_pstrdup(r->pool, key);
128 }
129 }
130 }
131
132 return ap_pstrdup(r->pool, returntosender);
133 }
134
135 static int include_virtual(request_rec * r, const char *uri, char *method) {
136 int status = OK;
137 request_rec *subr;
138 subr = (request_rec *) ap_sub_req_method_uri(method, uri, r);
139 ap_table_set(subr->headers_out, "Cache-Control", "no-cache");
140 status = ap_run_sub_req(subr);
141 ap_destroy_sub_req(subr);
142
143 return status;
144 }
145
146 int args_parse (request_rec *r, table *values, const char *data) {
147 const char *key;
148 const char *val;
149
150 while(*data && (val = ap_getword(r->pool, &data, '&'))){
151 key = ap_getword(r->pool, &val, '=');
152 ap_unescape_url((char *) key);
153 ap_unescape_url((char *) val);
154 ap_table_add(values, key, val);
155 }
156
157 return 0;
158 }
159
160 static int cgi_debug_handler(request_rec *r)
161 {
162 table *get_values = NULL;
163 table *post_values = NULL;
164 char *standard_input = NULL;
165 char *content_length = NULL;
166 long length = 0;
167 cgi_debug_conf *cfg = (cgi_debug_conf *)ap_get_module_config(r->per_dir_config, &cgi_debug_module);
168
169
170 post_values = ap_make_table(r->pool, 10);
171
172 r->content_type = "text/html";
173 ap_table_set(r->headers_out, "Cache-Control", "no-cache");
174 ap_send_http_header(r);
175 if (r->header_only)
176 return OK;
177
178 ap_rprintf(r, "<html> <title>mod_cgi_debug: %s</title><body text=\"#000000\" bgcolor=\"#000000\">\n", r->uri);
179 ap_rputs("<CENTER><TABLE CELLPADDING=\"0\" bgcolor=\"#ffffff\" BORDER=\"0\" WIDTH=\"100\%\">\n",r);
180 ap_rprintf(r, "<TD><H1> Debug output for: %s </H1></TD> \n", r->uri);
181 ap_rputs("<TD><TABLE CELLPADDING=\"0\" CELLSPACING=\"0\">\n", r);
182 ap_rprintf(r, "<TR ALIGN=\"LEFT\"><TH COLSPAN=\"2\" >Web Server Name:</TH></TR><TR ALIGN=\"LEFT\"><TD WIDTH=\"10\%\"> </TD><TD><FONT SIZE=\"1\"> %s</FONT></TD>\n", ap_get_server_name(r) );
183 ap_rprintf(r, "<TR ALIGN=\"LEFT\"><TH COLSPAN=\"2\">Web Server Version:</TH></TR><TR ALIGN=\"LEFT\"><TD WIDTH=\"10\%\"> </TD><TD><FONT SIZE=\"1\"> %s</FONT></TD>\n", ap_get_server_version() );
184 ap_rprintf(r, "<TR ALIGN=\"LEFT\"><TH COLSPAN=\"2\">Web Server Time:</TH></TR><TR ALIGN=\"LEFT\"><TD WIDTH=\"10\%\"> </TD><TD><FONT SIZE=\"1\"> %s</FONT></TD>\n", ap_get_time() );
185 ap_rprintf(r, "<TR ALIGN=\"LEFT\"><TH COLSPAN=\"2\">Web Server Built:</TH></TR><TR ALIGN=\"LEFT\"><TD WIDTH=\"10\%\"> </TD><TD><FONT SIZE=\"1\"> %s</FONT></TD>\n", ap_get_server_built() );
186
187 ap_rputs("</TABLE></TD></TR>\n", r);
188 ap_rputs("</TABLE></CENTER>\n", r);
189
190 ap_rputs("<TABLE CELLPADDING=15 bgcolor=\"#ffffff\" BORDER=\"0\" WIDTH=\"100%\">\n",r);
191 ap_rputs("<TR>\n\t<TD>",r);
192 /* ap_rprintf(r, "<H1> Debug output for: %s </H1> \n", r->uri); */
193
194 if(cfg->headersin) {
195 ap_rprintf(r, "<H3>Inbound HTTP Headers</H3>\n");
196 table_print(r->headers_in, r, cfg);
197 }
198 if(cfg->headersout) {
199 ap_rprintf(r, "<H3>Outbound HTTP Headers</H3>\n");
200 table_print(r->headers_out, r, cfg);
201 }
202
203 if(cfg->pathinfo) {
204 if(strlen(r->path_info)) {
205 ap_rprintf(r, "<H3>PATH Info</H3>\n");
206 ap_rprintf(r, "%s", r->path_info);
207 }
208 }
209
210 if(cfg->getdata) {
211 if(r->args) {
212 get_values = ap_make_table(r->pool, 10);
213 ap_rprintf(r, "<H3>GET ARGS content</H3>\n");
214 args_parse(r, get_values, r->args);
215 table_print(get_values, r, cfg);
216 }
217 }
218
219 if(cfg->postdata) {
220 content_length = (char *)ap_table_get(r->headers_in, "Content-Length");
221 if(length = (content_length ? atoi(content_length) : 0)) {
222 ap_rprintf(r, "<H3>Post Contents:</H3>\n");
223 standard_input = ap_palloc(r->pool, length);
224 read_content(r, standard_input, length);
225 args_parse(r, post_values, standard_input);
226 table_print(post_values, r, cfg);
227 }
228 }
229 ap_rputs("</TD></TR>\n",r);
230 ap_rputs("</TABLE>\n",r);
231
232 return OK;
233 }
234
235 static int cgi_environment(request_rec *r)
236 {
237 table *get_values;
238 table *values;
239 const char *new_location = NULL;
240 const char *new_args = NULL;
241 cgi_debug_conf *cfg;
242 int status;
243
244
245 if (r->main) {
246 return DECLINED;
247 }
248
249 if (r->header_only) {
250 r->content_type = "text/html";
251 ap_send_http_header(r);
252 return OK;
253 }
254
255 values = ap_make_table(r->pool, 8);
256 cfg = (cgi_debug_conf *)ap_get_module_config(r->per_dir_config, &cgi_debug_module);
257
258 new_args = args_rebuild(r, values, r->args, cfg->handlerkey);
259
260 /* Now lets put her back together */
261 if(new_args) {
262 new_location = ap_pstrcat(r->pool, r->uri, "?", new_args, r->path_info, NULL);
263 }else {
264 new_location = ap_pstrcat(r->pool, r->uri, "?", r->path_info, NULL);
265 }
266
267 if ( (status = include_virtual(r, new_location, (char *) r->method)) != OK) {
268 ap_log_rerror(APLOG_MARK, APLOG_NOERRNO | APLOG_ERR, r,
269 "The following error occured while processing the body : %d",
270 status);
271
272 return status;
273 }
274
275
276 if(ap_table_get(values, "banner")) {
277 ap_rputs("<CENTER><TABLE CELLPADDING=15 bgcolor=\"#ffffff\" BORDER=\"0\" WIDTH=\"75%\">\n",r);
278 ap_rprintf(r, "<TD><H1> Debug output for: %s </H1></TD> \n", r->uri);
279 ap_rputs("<TD>\n", r);
280 ap_rprintf(r, "Web Server Name: %s<BR>\n", ap_get_server_name(r) );
281 ap_rprintf(r, "Web Server Version: %s<BR>\n", ap_get_server_version() );
282 ap_rprintf(r, "Web Server Time: %s<BR>\n", ap_get_time() );
283 ap_rprintf(r, "Web Server Built: %s<BR>\n", ap_get_server_built() );
284 ap_rprintf(r, "Remote Username: %s<BR>\n", ap_get_remote_logname(r) );
285 ap_rprintf(r, "Filename: %s<BR>\n", r->filename);
286
287 if(r->finfo.st_mode) {
288 ap_rprintf(r, "Last Modified: %s<BR>\n",
289 ap_ht_time(r->pool, r->finfo.st_mtime, "%a %d %b %Y %T %Z", 0));
290 ap_rprintf(r, "File Created: %s<BR>\n",
291 ap_ht_time(r->pool, r->finfo.st_ctime, "%a %d %b %Y %T %Z", 0));
292 ap_rprintf(r, "File Last Accessed: %s<BR>\n",
293 ap_ht_time(r->pool, r->finfo.st_atime, "%a %d %b %Y %T %Z", 0));
294 ap_rprintf(r, "Owner UID %d\n<BR>", r->finfo.st_uid);
295 ap_rprintf(r, "Owner GID %d\n<BR>", r->finfo.st_gid);
296 }
297
298 ap_rputs("</TD></TR>\n", r);
299 ap_rputs("</TABLE></CENTER>\n", r);
300 }
301
302 ap_rputs("<TABLE CELLPADDING=15 bgcolor=\"#ffffff\" BORDER=\"0\" WIDTH=\"100%\">\n",r);
303 ap_rputs("<TR>\n\t<TD>",r);
304 /* ap_rprintf(r, "<H1> Debug output for: %s </H1> \n", r->uri); */
305
306 if(ap_table_get(values, "headersin")) {
307 if(cfg->headersin) {
308 ap_rprintf(r, "<H3>Inbound HTTP Headers</H3>\n");
309 table_print(r->headers_in, r, cfg);
310 }
311 }
312
313 if(ap_table_get(values, "headersout")) {
314 if(cfg->headersout) {
315 ap_rprintf(r, "<H3>Outbound HTTP Headers</H3>\n");
316 table_print(r->headers_out, r, cfg);
317 }
318 }
319
320 if(ap_table_get(values, "unparsed_uri")) {
321 if(r->unparsed_uri) {
322 if(strlen(r->unparsed_uri)) {
323 ap_rprintf(r, "<H3>Uri</H3>\n");
324 ap_rprintf(r, "%s", r->unparsed_uri);
325 }
326 }
327 }
328
329 if(ap_table_get(values, "path_info")) {
330 if(cfg->pathinfo) {
331 if(strlen(r->path_info)) {
332 ap_rprintf(r, "<H3>PATH Info</H3>\n");
333 ap_rprintf(r, "%s", r->path_info);
334 }
335 }
336 }
337
338 if(ap_table_get(values, "get_args")) {
339 if(cfg->getdata) {
340 if(r->args) {
341 get_values = ap_make_table(r->pool, 10);
342 ap_rprintf(r, "<H3>GET ARGS content</H3>\n");
343 args_parse(r, get_values, new_args);
344 table_print(get_values, r, cfg);
345 }
346 }
347 }
348
349 ap_rputs("</TD></TR>\n",r);
350 ap_rputs("</TABLE>\n",r);
351
352 return OK;
353 }
354
355 static int cgi_fixup(request_rec *r)
356 {
357 cgi_debug_conf *cfg = ap_get_module_config(r->per_dir_config, &cgi_debug_module);
358 request_rec *subr;
359 char *type = NULL;
360
361 if (r->main) {
362 return DECLINED;
363 }
364
365 /* So why switch to doing this? Somewhere since 1.3.6 something
366 has changed about the way that CGI's are done. Not sure what
367 it is, but this is now needed */
368 /* First, we check to see if this is SSI, mod_perl or cgi */
369 if(r->handler) {
370 type = ap_pstrdup(r->pool, r->handler);
371 } else {
372 type = ap_pstrdup(r->pool, r->content_type);
373 }
374
375 if (!ap_table_get(cfg->types, type))
376 return DECLINED;
377
378 r->handler = "cgi_environment";
379
380 return DECLINED;
381 }
382
383 static const char *add_type(cmd_parms * cmd, void *mconfig, char *type)
384 {
385 cgi_debug_conf *cfg = (cgi_debug_conf *) mconfig;
386 ap_table_addn(cfg->types, type, "enabled");
387
388 return NULL;
389 }
390
391
392 static const command_rec cgi_debug_cmds[] = {
393 {"CGIDebugKeyColor", ap_set_string_slot, (void *) XtOffsetOf(cgi_debug_conf, keycolor), OR_ALL, TAKE1, "Background color for key values, in hex notation (#ffffff)."},
394 {"CGIDebugValueColor", ap_set_string_slot, (void *) XtOffsetOf(cgi_debug_conf, valuecolor), OR_ALL, TAKE1, "Background color for key values, in hex notation (#ffffff)."},
395 {"CGIDebugHeaderIn", ap_set_flag_slot, (void *) XtOffsetOf(cgi_debug_conf, headersin), OR_ALL, FLAG, "On or Off to print incomming headers."},
396 {"CGIDebugHeaderOut", ap_set_flag_slot, (void *) XtOffsetOf(cgi_debug_conf, headersout), OR_ALL, FLAG, "On or Off to print incomming headers."},
397 {"CGIDebugGetData", ap_set_flag_slot, (void *) XtOffsetOf(cgi_debug_conf, getdata), OR_ALL, FLAG, "On or Off to print the arguments on the URI."},
398 {"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."},
399 {"CGIDebugPathInfo", ap_set_flag_slot, (void *) XtOffsetOf(cgi_debug_conf, pathinfo), OR_ALL, FLAG, "On or Off to print the path_info."},
400 {"CGIDebugHangingIndent", ap_set_flag_slot, (void *) XtOffsetOf(cgi_debug_conf, hangingindent), OR_ALL, FLAG, "On or Off. Changes coloration of value rows."},
401 {"CGIDebugHandler", add_type, NULL, OR_ALL, TAKE1, "Enter either a mime type or a handler type."},
402 {"CGIDebugHandlerKey", ap_set_string_slot, (void *) XtOffsetOf(cgi_debug_conf, handlerkey), OR_ALL, TAKE1, "Takes a single argument to override the default _DEBUG key."},
403
404 {NULL},
405 };
406
407
408 /* Dispatch list of content handlers */
409 static const handler_rec cgi_debug_handlers[] = {
410 { "cgi_debug", cgi_debug_handler },
411 { "cgi_environment", cgi_environment },
412 { NULL, NULL }
413 };
414
415 /* Dispatch list for API hooks */
416 module MODULE_VAR_EXPORT cgi_debug_module = {
417 STANDARD_MODULE_STUFF,
418 NULL, /* module initializer */
419 create_dir_mconfig, /* create per-dir config structures */
420 NULL, /* merge per-dir config structures */
421 NULL, /* create per-server config structures */
422 NULL, /* merge per-server config structures */
423 cgi_debug_cmds, /* table of config file commands */
424 cgi_debug_handlers, /* [#8] MIME-typed-dispatched handlers */
425 NULL, /* [#1] URI to filename translation */
426 NULL, /* [#4] validate user id from request */
427 NULL, /* [#5] check if the user is ok _here_ */
428 NULL, /* [#3] check access by host address */
429 NULL, /* [#6] determine MIME type */
430 cgi_fixup, /* [#7] pre-run fixups */
431 NULL, /* [#9] log a transaction */
432 NULL, /* [#2] header parser */
433 NULL, /* child_init */
434 NULL, /* child_exit */
435 NULL /* [#0] post read-request */
436 };
437