1 const char cgisimple_rcs[] = "$Id: cgisimple.c,v 1.106 2011/02/14 16:07:52 fabiankeil Exp $";
2 /*********************************************************************
4 * File : $Source: /cvsroot/ijbswa/current/cgisimple.c,v $
6 * Purpose : Simple CGIs to get information about Privoxy's
9 * Functions declared include:
12 * Copyright : Written by and Copyright (C) 2001-2011 the
13 * Privoxy team. http://www.privoxy.org/
15 * Based on the Internet Junkbuster originally written
16 * by and Copyright (C) 1997 Anonymous Coders and
17 * Junkbusters Corporation. http://www.junkbusters.com
19 * This program is free software; you can redistribute it
20 * and/or modify it under the terms of the GNU General
21 * Public License as published by the Free Software
22 * Foundation; either version 2 of the License, or (at
23 * your option) any later version.
25 * This program is distributed in the hope that it will
26 * be useful, but WITHOUT ANY WARRANTY; without even the
27 * implied warranty of MERCHANTABILITY or FITNESS FOR A
28 * PARTICULAR PURPOSE. See the GNU General Public
29 * License for more details.
31 * The GNU General Public License should be included with
32 * this file. If not, you can view it at
33 * http://www.gnu.org/copyleft/gpl.html
34 * or write to the Free Software Foundation, Inc., 59
35 * Temple Place - Suite 330, Boston, MA 02111-1307, USA.
37 **********************************************************************/
43 #include <sys/types.h>
51 #endif /* def HAVE_ACCESS */
55 #include "cgisimple.h"
67 const char cgisimple_h_rcs[] = CGISIMPLE_H_VERSION;
69 static char *show_rcs(void);
70 static jb_err show_defines(struct map *exports);
71 static jb_err cgi_show_file(struct client_state *csp,
72 struct http_response *rsp,
73 const struct map *parameters);
74 static jb_err load_file(const char *filename, char **buffer, size_t *length);
76 /*********************************************************************
78 * Function : cgi_default
80 * Description : CGI function that is called for the CGI_SITE_1_HOST
81 * and CGI_SITE_2_HOST/CGI_SITE_2_PATH base URLs.
82 * Boring - only exports the default exports.
85 * 1 : csp = Current client state (buffers, headers, etc...)
86 * 2 : rsp = http_response data structure for output
87 * 3 : parameters = map of cgi parameters
89 * CGI Parameters : none
91 * Returns : JB_ERR_OK on success
92 * JB_ERR_MEMORY on out-of-memory
94 *********************************************************************/
95 jb_err cgi_default(struct client_state *csp,
96 struct http_response *rsp,
97 const struct map *parameters)
106 if (NULL == (exports = default_exports(csp, "")))
108 return JB_ERR_MEMORY;
111 return template_fill_for_cgi(csp, "default", exports, rsp);
115 /*********************************************************************
117 * Function : cgi_error_404
119 * Description : CGI function that is called if an unknown action was
123 * 1 : csp = Current client state (buffers, headers, etc...)
124 * 2 : rsp = http_response data structure for output
125 * 3 : parameters = map of cgi parameters
127 * CGI Parameters : none
129 * Returns : JB_ERR_OK on success
130 * JB_ERR_MEMORY on out-of-memory error.
132 *********************************************************************/
133 jb_err cgi_error_404(struct client_state *csp,
134 struct http_response *rsp,
135 const struct map *parameters)
143 if (NULL == (exports = default_exports(csp, NULL)))
145 return JB_ERR_MEMORY;
148 rsp->status = strdup("404 Privoxy configuration page not found");
149 if (rsp->status == NULL)
152 return JB_ERR_MEMORY;
155 return template_fill_for_cgi(csp, "cgi-error-404", exports, rsp);
159 #ifdef FEATURE_GRACEFUL_TERMINATION
160 /*********************************************************************
164 * Description : CGI function to shut down Privoxy.
165 * NOTE: Turning this on in a production build
166 * would be a BAD idea. An EXTREMELY BAD idea.
167 * In short, don't do it.
170 * 1 : csp = Current client state (buffers, headers, etc...)
171 * 2 : rsp = http_response data structure for output
172 * 3 : parameters = map of cgi parameters
174 * CGI Parameters : none
176 * Returns : JB_ERR_OK on success
177 * JB_ERR_MEMORY on out-of-memory error.
179 *********************************************************************/
180 jb_err cgi_die (struct client_state *csp,
181 struct http_response *rsp,
182 const struct map *parameters)
184 static const char status[] = "200 OK Privoxy shutdown request received";
185 static const char body[] =
188 " <title>Privoxy shutdown request received</title>\n"
189 " <link rel=\"shortcut icon\" href=\"" CGI_PREFIX "error-favicon.ico\" type=\"image/x-icon\">\n"
190 " <link rel=\"stylesheet\" type=\"text/css\" href=\"http://config.privoxy.org/send-stylesheet\">\n"
193 "<h1>Privoxy shutdown request received</h1>\n"
194 "<p>Privoxy is going to shut down after the next request.</p>\n"
205 rsp->content_length = 0;
206 rsp->head_length = 0;
209 rsp->body = strdup(body);
210 rsp->status = strdup(status);
212 if ((rsp->body == NULL) || (rsp->status == NULL))
214 return JB_ERR_MEMORY;
219 #endif /* def FEATURE_GRACEFUL_TERMINATION */
222 /*********************************************************************
224 * Function : cgi_show_request
226 * Description : Show the client's request and what sed() would have
230 * 1 : csp = Current client state (buffers, headers, etc...)
231 * 2 : rsp = http_response data structure for output
232 * 3 : parameters = map of cgi parameters
234 * CGI Parameters : none
236 * Returns : JB_ERR_OK on success
237 * JB_ERR_MEMORY on out-of-memory error.
239 *********************************************************************/
240 jb_err cgi_show_request(struct client_state *csp,
241 struct http_response *rsp,
242 const struct map *parameters)
251 if (NULL == (exports = default_exports(csp, "show-request")))
253 return JB_ERR_MEMORY;
257 * Repair the damage done to the IOB by get_header()
259 for (p = csp->iob->buf; p < csp->iob->eod; p++)
261 if (*p == '\0') *p = '\n';
265 * Export the original client's request and the one we would
266 * be sending to the server if this wasn't a CGI call
269 if (map(exports, "client-request", 1, html_encode(csp->iob->buf), 0))
272 return JB_ERR_MEMORY;
275 if (map(exports, "processed-request", 1,
276 html_encode_and_free_original(list_to_text(csp->headers)), 0))
279 return JB_ERR_MEMORY;
282 return template_fill_for_cgi(csp, "show-request", exports, rsp);
286 /*********************************************************************
288 * Function : cgi_send_banner
290 * Description : CGI function that returns a banner.
293 * 1 : csp = Current client state (buffers, headers, etc...)
294 * 2 : rsp = http_response data structure for output
295 * 3 : parameters = map of cgi parameters
298 * type : Selects the type of banner between "trans", "logo",
299 * and "auto". Defaults to "logo" if absent or invalid.
300 * "auto" means to select as if we were image-blocking.
301 * (Only the first character really counts; b and t are
304 * Returns : JB_ERR_OK on success
305 * JB_ERR_MEMORY on out-of-memory error.
307 *********************************************************************/
308 jb_err cgi_send_banner(struct client_state *csp,
309 struct http_response *rsp,
310 const struct map *parameters)
312 char imagetype = lookup(parameters, "type")[0];
315 * If type is auto, then determine the right thing
316 * to do from the set-image-blocker action
318 if (imagetype == 'a')
325 #ifdef FEATURE_IMAGE_BLOCKING
326 if ((csp->action->flags & ACTION_IMAGE_BLOCKER) != 0)
328 static const char prefix1[] = CGI_PREFIX "send-banner?type=";
329 static const char prefix2[] = "http://" CGI_SITE_1_HOST "/send-banner?type=";
330 const char *p = csp->action->string[ACTION_STRING_IMAGE_BLOCKER];
334 /* Use default - nothing to do here. */
336 else if (0 == strcmpic(p, "blank"))
340 else if (0 == strcmpic(p, "pattern"))
346 * If the action is to call this CGI, determine
349 else if (0 == strncmpic(p, prefix1, sizeof(prefix1) - 1))
351 imagetype = p[sizeof(prefix1) - 1];
353 else if (0 == strncmpic(p, prefix2, sizeof(prefix2) - 1))
355 imagetype = p[sizeof(prefix2) - 1];
359 * Everything else must (should) be a URL to
367 #endif /* def FEATURE_IMAGE_BLOCKING */
371 * Now imagetype is either the non-auto type we were called with,
372 * or it was auto and has since been determined. In any case, we
373 * can proceed to actually answering the request by sending a redirect
374 * or an image as appropriate:
376 if (imagetype == 'r')
378 rsp->status = strdup("302 Local Redirect from Privoxy");
379 if (rsp->status == NULL)
381 return JB_ERR_MEMORY;
383 if (enlist_unique_header(rsp->headers, "Location",
384 csp->action->string[ACTION_STRING_IMAGE_BLOCKER]))
386 return JB_ERR_MEMORY;
391 if ((imagetype == 'b') || (imagetype == 't'))
393 rsp->body = bindup(image_blank_data, image_blank_length);
394 rsp->content_length = image_blank_length;
398 rsp->body = bindup(image_pattern_data, image_pattern_length);
399 rsp->content_length = image_pattern_length;
402 if (rsp->body == NULL)
404 return JB_ERR_MEMORY;
406 if (enlist(rsp->headers, "Content-Type: " BUILTIN_IMAGE_MIMETYPE))
408 return JB_ERR_MEMORY;
419 /*********************************************************************
421 * Function : cgi_transparent_image
423 * Description : CGI function that sends a 1x1 transparent image.
426 * 1 : csp = Current client state (buffers, headers, etc...)
427 * 2 : rsp = http_response data structure for output
428 * 3 : parameters = map of cgi parameters
430 * CGI Parameters : None
432 * Returns : JB_ERR_OK on success
433 * JB_ERR_MEMORY on out-of-memory error.
435 *********************************************************************/
436 jb_err cgi_transparent_image(struct client_state *csp,
437 struct http_response *rsp,
438 const struct map *parameters)
443 rsp->body = bindup(image_blank_data, image_blank_length);
444 rsp->content_length = image_blank_length;
446 if (rsp->body == NULL)
448 return JB_ERR_MEMORY;
451 if (enlist(rsp->headers, "Content-Type: " BUILTIN_IMAGE_MIMETYPE))
453 return JB_ERR_MEMORY;
463 /*********************************************************************
465 * Function : cgi_send_default_favicon
467 * Description : CGI function that sends the standard favicon.
470 * 1 : csp = Current client state (buffers, headers, etc...)
471 * 2 : rsp = http_response data structure for output
472 * 3 : parameters = map of cgi parameters
474 * CGI Parameters : None
476 * Returns : JB_ERR_OK on success
477 * JB_ERR_MEMORY on out-of-memory error.
479 *********************************************************************/
480 jb_err cgi_send_default_favicon(struct client_state *csp,
481 struct http_response *rsp,
482 const struct map *parameters)
484 static const char default_favicon_data[] =
485 "\000\000\001\000\001\000\020\020\002\000\000\000\000\000\260"
486 "\000\000\000\026\000\000\000\050\000\000\000\020\000\000\000"
487 "\040\000\000\000\001\000\001\000\000\000\000\000\100\000\000"
488 "\000\000\000\000\000\000\000\000\000\002\000\000\000\000\000"
489 "\000\000\377\377\377\000\377\000\052\000\017\360\000\000\077"
490 "\374\000\000\161\376\000\000\161\376\000\000\361\377\000\000"
491 "\361\377\000\000\360\017\000\000\360\007\000\000\361\307\000"
492 "\000\361\307\000\000\361\307\000\000\360\007\000\000\160\036"
493 "\000\000\177\376\000\000\077\374\000\000\017\360\000\000\360"
494 "\017\000\000\300\003\000\000\200\001\000\000\200\001\000\000"
495 "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
496 "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
497 "\000\000\200\001\000\000\200\001\000\000\300\003\000\000\360"
499 static const size_t favicon_length = sizeof(default_favicon_data) - 1;
504 rsp->body = bindup(default_favicon_data, favicon_length);
505 rsp->content_length = favicon_length;
507 if (rsp->body == NULL)
509 return JB_ERR_MEMORY;
512 if (enlist(rsp->headers, "Content-Type: image/x-icon"))
514 return JB_ERR_MEMORY;
524 /*********************************************************************
526 * Function : cgi_send_error_favicon
528 * Description : CGI function that sends the favicon for error pages.
531 * 1 : csp = Current client state (buffers, headers, etc...)
532 * 2 : rsp = http_response data structure for output
533 * 3 : parameters = map of cgi parameters
535 * CGI Parameters : None
537 * Returns : JB_ERR_OK on success
538 * JB_ERR_MEMORY on out-of-memory error.
540 *********************************************************************/
541 jb_err cgi_send_error_favicon(struct client_state *csp,
542 struct http_response *rsp,
543 const struct map *parameters)
545 static const char error_favicon_data[] =
546 "\000\000\001\000\001\000\020\020\002\000\000\000\000\000\260"
547 "\000\000\000\026\000\000\000\050\000\000\000\020\000\000\000"
548 "\040\000\000\000\001\000\001\000\000\000\000\000\100\000\000"
549 "\000\000\000\000\000\000\000\000\000\002\000\000\000\000\000"
550 "\000\000\377\377\377\000\000\000\377\000\017\360\000\000\077"
551 "\374\000\000\161\376\000\000\161\376\000\000\361\377\000\000"
552 "\361\377\000\000\360\017\000\000\360\007\000\000\361\307\000"
553 "\000\361\307\000\000\361\307\000\000\360\007\000\000\160\036"
554 "\000\000\177\376\000\000\077\374\000\000\017\360\000\000\360"
555 "\017\000\000\300\003\000\000\200\001\000\000\200\001\000\000"
556 "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
557 "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
558 "\000\000\200\001\000\000\200\001\000\000\300\003\000\000\360"
560 static const size_t favicon_length = sizeof(error_favicon_data) - 1;
565 rsp->body = bindup(error_favicon_data, favicon_length);
566 rsp->content_length = favicon_length;
568 if (rsp->body == NULL)
570 return JB_ERR_MEMORY;
573 if (enlist(rsp->headers, "Content-Type: image/x-icon"))
575 return JB_ERR_MEMORY;
585 /*********************************************************************
587 * Function : cgi_send_stylesheet
589 * Description : CGI function that sends a css stylesheet found
590 * in the cgi-style.css template
593 * 1 : csp = Current client state (buffers, headers, etc...)
594 * 2 : rsp = http_response data structure for output
595 * 3 : parameters = map of cgi parameters
597 * CGI Parameters : None
599 * Returns : JB_ERR_OK on success
600 * JB_ERR_MEMORY on out-of-memory error.
602 *********************************************************************/
603 jb_err cgi_send_stylesheet(struct client_state *csp,
604 struct http_response *rsp,
605 const struct map *parameters)
614 err = template_load(csp, &rsp->body, "cgi-style.css", 0);
616 if (err == JB_ERR_FILE)
619 * No way to tell user; send empty stylesheet
621 log_error(LOG_LEVEL_ERROR, "Could not find cgi-style.css template");
625 return err; /* JB_ERR_MEMORY */
628 if (enlist(rsp->headers, "Content-Type: text/css"))
630 return JB_ERR_MEMORY;
638 /*********************************************************************
640 * Function : cgi_send_url_info_osd
642 * Description : CGI function that sends the OpenSearch Description
643 * template for the show-url-info page. It allows to
644 * access the page through "search engine plugins".
647 * 1 : csp = Current client state (buffers, headers, etc...)
648 * 2 : rsp = http_response data structure for output
649 * 3 : parameters = map of cgi parameters
651 * CGI Parameters : None
653 * Returns : JB_ERR_OK on success
654 * JB_ERR_MEMORY on out-of-memory error.
656 *********************************************************************/
657 jb_err cgi_send_url_info_osd(struct client_state *csp,
658 struct http_response *rsp,
659 const struct map *parameters)
661 jb_err err = JB_ERR_MEMORY;
662 struct map *exports = default_exports(csp, NULL);
669 err = template_fill_for_cgi(csp, "url-info-osd.xml", exports, rsp);
670 if (JB_ERR_OK == err)
672 err = enlist(rsp->headers,
673 "Content-Type: application/opensearchdescription+xml");
682 /*********************************************************************
684 * Function : get_content_type
686 * Description : Use the file extension to guess the content type
687 * header we should use to serve the file.
690 * 1 : filename = Name of the file whose content type
693 * Returns : The guessed content type.
695 *********************************************************************/
696 static const char *get_content_type(const char *filename)
701 const char *extension;
702 const char *content_type;
704 static const struct content_type content_types[] =
706 {".css", "text/css"},
707 {".jpg", "image/jpeg"},
708 {".jpeg", "image/jpeg"},
709 {".png", "image/png"},
712 for (i = 0; i < SZ(content_types); i++)
714 if (strstr(filename, content_types[i].extension))
716 return content_types[i].content_type;
720 /* No match by extension, default to html */
724 /*********************************************************************
726 * Function : cgi_send_user_manual
728 * Description : CGI function that sends a file in the user
732 * 1 : csp = Current client state (buffers, headers, etc...)
733 * 2 : rsp = http_response data structure for output
734 * 3 : parameters = map of cgi parameters
736 * CGI Parameters : file=name.html, the name of the HTML file
737 * (relative to user-manual from config)
739 * Returns : JB_ERR_OK on success
740 * JB_ERR_MEMORY on out-of-memory error.
742 *********************************************************************/
743 jb_err cgi_send_user_manual(struct client_state *csp,
744 struct http_response *rsp,
745 const struct map *parameters)
747 const char *filename;
749 jb_err err = JB_ERR_OK;
750 const char *content_type;
756 if (0 == strncmpic(csp->config->usermanual, "http://", 7))
758 log_error(LOG_LEVEL_CGI, "Request for local user-manual "
759 "received while user-manual delivery is disabled.");
760 return cgi_error_404(csp, rsp, parameters);
763 if (!parameters->first)
765 /* requested http://p.p/user-manual (without trailing slash) */
766 return cgi_redirect(rsp, CGI_PREFIX "user-manual/");
769 get_string_param(parameters, "file", &filename);
770 if (filename == NULL)
772 /* It's '/' so serve the index.html if there is one. */
773 filename = "index.html";
775 else if (NULL != strchr(filename, '/') || NULL != strstr(filename, ".."))
778 * We currently only support a flat file
779 * hierachy for the documentation.
781 log_error(LOG_LEVEL_ERROR,
782 "Rejecting the request to serve '%s' as it contains '/' or '..'",
784 return JB_ERR_CGI_PARAMS;
787 full_path = make_path(csp->config->usermanual, filename);
788 if (full_path == NULL)
790 return JB_ERR_MEMORY;
793 err = load_file(full_path, &rsp->body, &rsp->content_length);
794 if (JB_ERR_OK != err)
796 assert((JB_ERR_FILE == err) || (JB_ERR_MEMORY == err));
797 if (JB_ERR_FILE == err)
799 err = cgi_error_no_template(csp, rsp, full_path);
806 content_type = get_content_type(filename);
807 log_error(LOG_LEVEL_CGI,
808 "Content-Type guessed for %s: %s", filename, content_type);
810 return enlist_unique_header(rsp->headers, "Content-Type", content_type);
815 /*********************************************************************
817 * Function : cgi_show_version
819 * Description : CGI function that returns a a web page describing the
820 * file versions of Privoxy.
823 * 1 : csp = Current client state (buffers, headers, etc...)
824 * 2 : rsp = http_response data structure for output
825 * 3 : parameters = map of cgi parameters
827 * CGI Parameters : none
829 * Returns : JB_ERR_OK on success
830 * JB_ERR_MEMORY on out-of-memory error.
832 *********************************************************************/
833 jb_err cgi_show_version(struct client_state *csp,
834 struct http_response *rsp,
835 const struct map *parameters)
843 if (NULL == (exports = default_exports(csp, "show-version")))
845 return JB_ERR_MEMORY;
848 if (map(exports, "sourceversions", 1, show_rcs(), 0))
851 return JB_ERR_MEMORY;
854 return template_fill_for_cgi(csp, "show-version", exports, rsp);
858 /*********************************************************************
860 * Function : cgi_show_status
862 * Description : CGI function that returns a web page describing the
863 * current status of Privoxy.
866 * 1 : csp = Current client state (buffers, headers, etc...)
867 * 2 : rsp = http_response data structure for output
868 * 3 : parameters = map of cgi parameters
871 * file : Which file to show. Only first letter is checked,
876 * Default is to show menu and other information.
878 * Returns : JB_ERR_OK on success
879 * JB_ERR_MEMORY on out-of-memory error.
881 *********************************************************************/
882 jb_err cgi_show_status(struct client_state *csp,
883 struct http_response *rsp,
884 const struct map *parameters)
890 char buf[BUFFER_SIZE];
891 #ifdef FEATURE_STATISTICS
892 float perc_rej; /* Percentage of http requests rejected */
894 int local_urls_rejected;
895 #endif /* ndef FEATURE_STATISTICS */
896 jb_err err = JB_ERR_OK;
904 if ('\0' != *(lookup(parameters, "file")))
906 return cgi_show_file(csp, rsp, parameters);
909 if (NULL == (exports = default_exports(csp, "show-status")))
911 return JB_ERR_MEMORY;
915 for (j = 0; (s != NULL) && (j < Argc); j++)
917 if (!err) err = string_join (&s, html_encode(Argv[j]));
918 if (!err) err = string_append(&s, " ");
920 if (!err) err = map(exports, "invocation", 1, s, 0);
922 if (!err) err = map(exports, "options", 1, csp->config->proxy_args, 1);
923 if (!err) err = show_defines(exports);
928 return JB_ERR_MEMORY;
931 #ifdef FEATURE_STATISTICS
932 local_urls_read = urls_read;
933 local_urls_rejected = urls_rejected;
936 * Need to alter the stats not to include the fetch of this
939 * Can't do following thread safely! doh!
942 * urls_rejected--; * This will be incremented subsequently *
945 if (local_urls_read == 0)
947 if (!err) err = map_block_killer(exports, "have-stats");
951 if (!err) err = map_block_killer(exports, "have-no-stats");
953 perc_rej = (float)local_urls_rejected * 100.0F /
954 (float)local_urls_read;
956 snprintf(buf, sizeof(buf), "%d", local_urls_read);
957 if (!err) err = map(exports, "requests-received", 1, buf, 1);
959 snprintf(buf, sizeof(buf), "%d", local_urls_rejected);
960 if (!err) err = map(exports, "requests-blocked", 1, buf, 1);
962 snprintf(buf, sizeof(buf), "%6.2f", perc_rej);
963 if (!err) err = map(exports, "percent-blocked", 1, buf, 1);
966 #else /* ndef FEATURE_STATISTICS */
967 err = err || map_block_killer(exports, "statistics");
968 #endif /* ndef FEATURE_STATISTICS */
971 * List all action files in use, together with view and edit links,
972 * except for standard.action, which should only be viewable. (Not
973 * enforced in the editor itself)
974 * FIXME: Shouldn't include hardwired HTML here, use line template instead!
977 for (i = 0; i < MAX_AF_FILES; i++)
979 if (csp->actions_list[i] != NULL)
981 if (!err) err = string_append(&s, "<tr><td>");
982 if (!err) err = string_join(&s, html_encode(csp->actions_list[i]->filename));
983 snprintf(buf, sizeof(buf),
984 "</td><td class=\"buttons\"><a href=\"/show-status?file=actions&index=%u\">View</a>", i);
985 if (!err) err = string_append(&s, buf);
987 #ifdef FEATURE_CGI_EDIT_ACTIONS
988 if ((csp->config->feature_flags & RUNTIME_FEATURE_CGI_EDIT_ACTIONS)
989 && (NULL == strstr(csp->actions_list[i]->filename, "standard.action"))
990 && (NULL != csp->config->actions_file_short[i]))
993 if (access(csp->config->actions_file[i], W_OK) == 0)
995 #endif /* def HAVE_ACCESS */
996 snprintf(buf, sizeof(buf), " <a href=\"/edit-actions-list?f=%u\">Edit</a>", i);
997 if (!err) err = string_append(&s, buf);
1002 if (!err) err = string_append(&s, " <strong>No write access.</strong>");
1004 #endif /* def HAVE_ACCESS */
1008 if (!err) err = string_append(&s, "</td></tr>\n");
1013 if (!err) err = map(exports, "actions-filenames", 1, s, 0);
1017 if (!err) err = map(exports, "actions-filenames", 1, "<tr><td>None specified</td></tr>", 1);
1021 * List all re_filterfiles in use, together with view options.
1022 * FIXME: Shouldn't include hardwired HTML here, use line template instead!
1025 for (i = 0; i < MAX_AF_FILES; i++)
1027 if (csp->rlist[i] != NULL)
1029 if (!err) err = string_append(&s, "<tr><td>");
1030 if (!err) err = string_join(&s, html_encode(csp->rlist[i]->filename));
1031 snprintf(buf, sizeof(buf),
1032 "</td><td class=\"buttons\"><a href=\"/show-status?file=filter&index=%u\">View</a>", i);
1033 if (!err) err = string_append(&s, buf);
1034 if (!err) err = string_append(&s, "</td></tr>\n");
1039 if (!err) err = map(exports, "re-filter-filenames", 1, s, 0);
1043 if (!err) err = map(exports, "re-filter-filenames", 1, "<tr><td>None specified</td></tr>", 1);
1044 if (!err) err = map_block_killer(exports, "have-filterfile");
1047 #ifdef FEATURE_TRUST
1050 if (!err) err = map(exports, "trust-filename", 1, html_encode(csp->tlist->filename), 0);
1054 if (!err) err = map(exports, "trust-filename", 1, "None specified", 1);
1055 if (!err) err = map_block_killer(exports, "have-trustfile");
1058 if (!err) err = map_block_killer(exports, "trust-support");
1059 #endif /* ndef FEATURE_TRUST */
1061 #ifdef FEATURE_CGI_EDIT_ACTIONS
1062 if (!err && (csp->config->feature_flags & RUNTIME_FEATURE_CGI_EDIT_ACTIONS))
1064 err = map_block_killer(exports, "cgi-editor-is-disabled");
1066 #endif /* ndef CGI_EDIT_ACTIONS */
1071 return JB_ERR_MEMORY;
1074 return template_fill_for_cgi(csp, "show-status", exports, rsp);
1078 /*********************************************************************
1080 * Function : cgi_show_url_info
1082 * Description : CGI function that determines and shows which actions
1083 * Privoxy will perform for a given url, and which
1084 * matches starting from the defaults have lead to that.
1087 * 1 : csp = Current client state (buffers, headers, etc...)
1088 * 2 : rsp = http_response data structure for output
1089 * 3 : parameters = map of cgi parameters
1092 * url : The url whose actions are to be determined.
1093 * If url is unset, the url-given conditional will be
1094 * set, so that all but the form can be suppressed in
1097 * Returns : JB_ERR_OK on success
1098 * JB_ERR_MEMORY on out-of-memory error.
1100 *********************************************************************/
1101 jb_err cgi_show_url_info(struct client_state *csp,
1102 struct http_response *rsp,
1103 const struct map *parameters)
1106 struct map *exports;
1113 if (NULL == (exports = default_exports(csp, "show-url-info")))
1115 return JB_ERR_MEMORY;
1119 * Get the url= parameter (if present) and remove any leading/trailing spaces.
1121 url_param = strdup(lookup(parameters, "url"));
1122 if (url_param == NULL)
1125 return JB_ERR_MEMORY;
1130 * Handle prefixes. 4 possibilities:
1131 * 1) "http://" or "https://" prefix present and followed by URL - OK
1132 * 2) Only the "http://" or "https://" part is present, no URL - change
1133 * to empty string so it will be detected later as "no URL".
1134 * 3) Parameter specified but doesn't start with "http(s?)://" - add a
1136 * 4) Parameter not specified or is empty string - let this fall through
1137 * for now, next block of code will handle it.
1139 if (0 == strncmp(url_param, "http://", 7))
1141 if (url_param[7] == '\0')
1144 * Empty URL (just prefix).
1145 * Make it totally empty so it's caught by the next if()
1147 url_param[0] = '\0';
1150 else if (0 == strncmp(url_param, "https://", 8))
1152 if (url_param[8] == '\0')
1155 * Empty URL (just prefix).
1156 * Make it totally empty so it's caught by the next if()
1158 url_param[0] = '\0';
1161 else if ((url_param[0] != '\0')
1162 && ((NULL == strstr(url_param, "://")
1163 || (strstr(url_param, "://") > strstr(url_param, "/")))))
1166 * No prefix or at least no prefix before
1167 * the first slash - assume http://
1169 char *url_param_prefixed = strdup("http://");
1171 if (JB_ERR_OK != string_join(&url_param_prefixed, url_param))
1174 return JB_ERR_MEMORY;
1176 url_param = url_param_prefixed;
1180 * Hide "toggle off" warning if Privoxy is toggled on.
1183 #ifdef FEATURE_TOGGLE
1184 (global_toggle_state == 1) &&
1185 #endif /* def FEATURE_TOGGLE */
1186 map_block_killer(exports, "privoxy-is-toggled-off")
1190 return JB_ERR_MEMORY;
1193 if (url_param[0] == '\0')
1195 /* URL paramater not specified, display query form only. */
1197 if (map_block_killer(exports, "url-given")
1198 || map(exports, "url", 1, "", 1))
1201 return JB_ERR_MEMORY;
1206 /* Given a URL, so query it. */
1211 struct file_list *fl;
1212 struct url_actions *b;
1213 struct http_request url_to_query[1];
1214 struct current_action_spec action[1];
1217 if (map(exports, "url", 1, html_encode(url_param), 0))
1221 return JB_ERR_MEMORY;
1224 init_current_action(action);
1226 if (map(exports, "default", 1, current_action_to_html(csp, action), 0))
1228 free_current_action(action);
1231 return JB_ERR_MEMORY;
1234 memset(url_to_query, '\0', sizeof(url_to_query));
1235 err = parse_http_url(url_param, url_to_query, REQUIRE_PROTOCOL);
1236 assert((err != JB_ERR_OK) || (url_to_query->ssl == !strncmpic(url_param, "https://", 8)));
1240 if (err == JB_ERR_MEMORY)
1242 free_http_request(url_to_query);
1243 free_current_action(action);
1245 return JB_ERR_MEMORY;
1251 err = map(exports, "matches", 1, "<b>[Invalid URL specified!]</b>" , 1);
1252 if (!err) err = map(exports, "final", 1, lookup(exports, "default"), 1);
1253 if (!err) err = map_block_killer(exports, "valid-url");
1255 free_current_action(action);
1256 free_http_request(url_to_query);
1261 return JB_ERR_MEMORY;
1264 return template_fill_for_cgi(csp, "show-url-info", exports, rsp);
1268 * We have a warning about SSL paths. Hide it for unencrypted sites.
1270 if (!url_to_query->ssl)
1272 if (map_block_killer(exports, "https"))
1274 free_current_action(action);
1276 free_http_request(url_to_query);
1277 return JB_ERR_MEMORY;
1281 matches = strdup("<table summary=\"\" class=\"transparent\">");
1283 for (i = 0; i < MAX_AF_FILES; i++)
1285 if (NULL == csp->config->actions_file_short[i]
1286 || !strcmp(csp->config->actions_file_short[i], "standard.action")) continue;
1290 if ((fl = csp->actions_list[i]) != NULL)
1292 if ((b = fl->f) != NULL)
1294 /* FIXME: Hardcoded HTML! */
1295 string_append(&matches, "<tr><th>In file: ");
1296 string_join (&matches, html_encode(csp->config->actions_file_short[i]));
1297 snprintf(buf, sizeof(buf), " <a class=\"cmd\" href=\"/show-status?file=actions&index=%d\">", i);
1298 string_append(&matches, buf);
1299 string_append(&matches, "View</a>");
1300 #ifdef FEATURE_CGI_EDIT_ACTIONS
1301 if (csp->config->feature_flags & RUNTIME_FEATURE_CGI_EDIT_ACTIONS)
1304 if (access(csp->config->actions_file[i], W_OK) == 0)
1306 #endif /* def HAVE_ACCESS */
1307 snprintf(buf, sizeof(buf),
1308 " <a class=\"cmd\" href=\"/edit-actions-list?f=%d\">", i);
1309 string_append(&matches, buf);
1310 string_append(&matches, "Edit</a>");
1315 string_append(&matches, " <strong>No write access.</strong>");
1317 #endif /* def HAVE_ACCESS */
1319 #endif /* FEATURE_CGI_EDIT_ACTIONS */
1321 string_append(&matches, "</th></tr>\n");
1328 for (; (b != NULL) && (matches != NULL); b = b->next)
1330 if (url_match(b->url, url_to_query))
1332 string_append(&matches, "<tr><td>{");
1333 string_join (&matches, actions_to_html(csp, b->action));
1334 string_append(&matches, " }<br>\n<code>");
1335 string_join (&matches, html_encode(b->url->spec));
1336 string_append(&matches, "</code></td></tr>\n");
1338 if (merge_current_action(action, b->action))
1341 free_http_request(url_to_query);
1342 free_current_action(action);
1344 return JB_ERR_MEMORY;
1352 string_append(&matches, "<tr><td>(no matches in this file)</td></tr>\n");
1355 string_append(&matches, "</table>\n");
1358 * XXX: Kludge to make sure the "Forward settings" section
1359 * shows what forward-override{} would do with the requested URL.
1360 * No one really cares how the CGI request would be forwarded
1361 * if it wasn't intercepted as CGI request in the first place.
1363 * From here on the action bitmask will no longer reflect
1364 * the real url (http://config.privoxy.org/show-url-info?url=.*),
1365 * but luckily it's no longer required later on anyway.
1367 free_current_action(csp->action);
1368 get_url_actions(csp, url_to_query);
1371 * Fill in forwarding settings.
1373 * The possibilities are:
1375 * - http forwarding only
1376 * - socks4(a) forwarding only
1377 * - socks4(a) and http forwarding.
1379 * XXX: Parts of this code could be reused for the
1380 * "forwarding-failed" template which currently doesn't
1381 * display the proxy port and an eventual second forwarder.
1384 const struct forward_spec *fwd = forward_url(csp, url_to_query);
1386 if ((fwd->gateway_host == NULL) && (fwd->forward_host == NULL))
1388 if (!err) err = map_block_killer(exports, "socks-forwarder");
1389 if (!err) err = map_block_killer(exports, "http-forwarder");
1393 char port[10]; /* We save proxy ports as int but need a string here */
1395 if (!err) err = map_block_killer(exports, "no-forwarder");
1397 if (fwd->gateway_host != NULL)
1399 char *socks_type = NULL;
1404 socks_type = "socks4";
1407 socks_type = "socks4a";
1410 socks_type = "socks5";
1413 log_error(LOG_LEVEL_FATAL, "Unknown socks type: %d.", fwd->type);
1416 if (!err) err = map(exports, "socks-type", 1, socks_type, 1);
1417 if (!err) err = map(exports, "gateway-host", 1, fwd->gateway_host, 1);
1418 snprintf(port, sizeof(port), "%d", fwd->gateway_port);
1419 if (!err) err = map(exports, "gateway-port", 1, port, 1);
1423 if (!err) err = map_block_killer(exports, "socks-forwarder");
1426 if (fwd->forward_host != NULL)
1428 if (!err) err = map(exports, "forward-host", 1, fwd->forward_host, 1);
1429 snprintf(port, sizeof(port), "%d", fwd->forward_port);
1430 if (!err) err = map(exports, "forward-port", 1, port, 1);
1434 if (!err) err = map_block_killer(exports, "http-forwarder");
1439 free_http_request(url_to_query);
1441 if (err || matches == NULL)
1443 free_current_action(action);
1445 return JB_ERR_MEMORY;
1448 #ifdef FEATURE_CGI_EDIT_ACTIONS
1449 if ((csp->config->feature_flags & RUNTIME_FEATURE_CGI_EDIT_ACTIONS))
1451 err = map_block_killer(exports, "cgi-editor-is-disabled");
1453 #endif /* FEATURE_CGI_EDIT_ACTIONS */
1456 * If zlib support is available, if no content filters
1457 * are enabled or if the prevent-compression action is enabled,
1458 * suppress the "compression could prevent filtering" warning.
1460 #ifndef FEATURE_ZLIB
1461 if (!content_filters_enabled(action) ||
1462 (action->flags & ACTION_NO_COMPRESSION))
1465 if (!err) err = map_block_killer(exports, "filters-might-be-ineffective");
1468 if (err || map(exports, "matches", 1, matches , 0))
1470 free_current_action(action);
1472 return JB_ERR_MEMORY;
1475 s = current_action_to_html(csp, action);
1477 free_current_action(action);
1479 if (map(exports, "final", 1, s, 0))
1482 return JB_ERR_MEMORY;
1486 return template_fill_for_cgi(csp, "show-url-info", exports, rsp);
1490 /*********************************************************************
1492 * Function : cgi_robots_txt
1494 * Description : CGI function to return "/robots.txt".
1497 * 1 : csp = Current client state (buffers, headers, etc...)
1498 * 2 : rsp = http_response data structure for output
1499 * 3 : parameters = map of cgi parameters
1501 * CGI Parameters : None
1503 * Returns : JB_ERR_OK on success
1504 * JB_ERR_MEMORY on out-of-memory error.
1506 *********************************************************************/
1507 jb_err cgi_robots_txt(struct client_state *csp,
1508 struct http_response *rsp,
1509 const struct map *parameters)
1518 "# This is the Privoxy control interface.\n"
1519 "# It isn't very useful to index it, and you're likely to break stuff.\n"
1525 if (rsp->body == NULL)
1527 return JB_ERR_MEMORY;
1530 err = enlist_unique(rsp->headers, "Content-Type: text/plain", 13);
1534 get_http_time(7 * 24 * 60 * 60, buf, sizeof(buf)); /* 7 days into future */
1535 if (!err) err = enlist_unique_header(rsp->headers, "Expires", buf);
1537 return (err ? JB_ERR_MEMORY : JB_ERR_OK);
1541 /*********************************************************************
1543 * Function : show_defines
1545 * Description : Add to a map the state od all conditional #defines
1546 * used when building
1549 * 1 : exports = map to extend
1551 * Returns : JB_ERR_OK on success
1552 * JB_ERR_MEMORY on out-of-memory error.
1554 *********************************************************************/
1555 static jb_err show_defines(struct map *exports)
1557 jb_err err = JB_ERR_OK;
1559 #ifdef FEATURE_ACCEPT_FILTER
1560 if (!err) err = map_conditional(exports, "FEATURE_ACCEPT_FILTER", 1);
1561 #else /* ifndef FEATURE_ACCEPT_FILTER */
1562 if (!err) err = map_conditional(exports, "FEATURE_ACCEPT_FILTER", 0);
1563 #endif /* ndef FEATURE_ACCEPT_FILTER */
1566 if (!err) err = map_conditional(exports, "FEATURE_ACL", 1);
1567 #else /* ifndef FEATURE_ACL */
1568 if (!err) err = map_conditional(exports, "FEATURE_ACL", 0);
1569 #endif /* ndef FEATURE_ACL */
1571 #ifdef FEATURE_CGI_EDIT_ACTIONS
1572 if (!err) err = map_conditional(exports, "FEATURE_CGI_EDIT_ACTIONS", 1);
1573 #else /* ifndef FEATURE_CGI_EDIT_ACTIONS */
1574 if (!err) err = map_conditional(exports, "FEATURE_CGI_EDIT_ACTIONS", 0);
1575 #endif /* ndef FEATURE_CGI_EDIT_ACTIONS */
1577 #ifdef FEATURE_CONNECTION_KEEP_ALIVE
1578 if (!err) err = map_conditional(exports, "FEATURE_CONNECTION_KEEP_ALIVE", 1);
1579 #else /* ifndef FEATURE_CONNECTION_KEEP_ALIVE */
1580 if (!err) err = map_conditional(exports, "FEATURE_CONNECTION_KEEP_ALIVE", 0);
1581 #endif /* ndef FEATURE_CONNECTION_KEEP_ALIVE */
1583 #ifdef FEATURE_CONNECTION_SHARING
1584 if (!err) err = map_conditional(exports, "FEATURE_CONNECTION_SHARING", 1);
1585 #else /* ifndef FEATURE_CONNECTION_SHARING */
1586 if (!err) err = map_conditional(exports, "FEATURE_CONNECTION_SHARING", 0);
1587 #endif /* ndef FEATURE_CONNECTION_SHARING */
1589 #ifdef FEATURE_FAST_REDIRECTS
1590 if (!err) err = map_conditional(exports, "FEATURE_FAST_REDIRECTS", 1);
1591 #else /* ifndef FEATURE_FAST_REDIRECTS */
1592 if (!err) err = map_conditional(exports, "FEATURE_FAST_REDIRECTS", 0);
1593 #endif /* ndef FEATURE_FAST_REDIRECTS */
1595 #ifdef FEATURE_FORCE_LOAD
1596 if (!err) err = map_conditional(exports, "FEATURE_FORCE_LOAD", 1);
1597 if (!err) err = map(exports, "FORCE_PREFIX", 1, FORCE_PREFIX, 1);
1598 #else /* ifndef FEATURE_FORCE_LOAD */
1599 if (!err) err = map_conditional(exports, "FEATURE_FORCE_LOAD", 0);
1600 if (!err) err = map(exports, "FORCE_PREFIX", 1, "(none - disabled)", 1);
1601 #endif /* ndef FEATURE_FORCE_LOAD */
1603 #ifdef FEATURE_GRACEFUL_TERMINATION
1604 if (!err) err = map_conditional(exports, "FEATURE_GRACEFUL_TERMINATION", 1);
1605 #else /* ifndef FEATURE_GRACEFUL_TERMINATION */
1606 if (!err) err = map_conditional(exports, "FEATURE_GRACEFUL_TERMINATION", 0);
1607 #endif /* ndef FEATURE_GRACEFUL_TERMINATION */
1609 #ifdef FEATURE_IMAGE_BLOCKING
1610 if (!err) err = map_conditional(exports, "FEATURE_IMAGE_BLOCKING", 1);
1611 #else /* ifndef FEATURE_IMAGE_BLOCKING */
1612 if (!err) err = map_conditional(exports, "FEATURE_IMAGE_BLOCKING", 0);
1613 #endif /* ndef FEATURE_IMAGE_BLOCKING */
1615 #ifdef FEATURE_IMAGE_DETECT_MSIE
1616 if (!err) err = map_conditional(exports, "FEATURE_IMAGE_DETECT_MSIE", 1);
1617 #else /* ifndef FEATURE_IMAGE_DETECT_MSIE */
1618 if (!err) err = map_conditional(exports, "FEATURE_IMAGE_DETECT_MSIE", 0);
1619 #endif /* ndef FEATURE_IMAGE_DETECT_MSIE */
1622 if (!err) err = map_conditional(exports, "FEATURE_IPV6_SUPPORT", 1);
1623 #else /* ifndef HAVE_RFC2553 */
1624 if (!err) err = map_conditional(exports, "FEATURE_IPV6_SUPPORT", 0);
1625 #endif /* ndef HAVE_RFC2553 */
1627 #ifdef FEATURE_NO_GIFS
1628 if (!err) err = map_conditional(exports, "FEATURE_NO_GIFS", 1);
1629 #else /* ifndef FEATURE_NO_GIFS */
1630 if (!err) err = map_conditional(exports, "FEATURE_NO_GIFS", 0);
1631 #endif /* ndef FEATURE_NO_GIFS */
1633 #ifdef FEATURE_PTHREAD
1634 if (!err) err = map_conditional(exports, "FEATURE_PTHREAD", 1);
1635 #else /* ifndef FEATURE_PTHREAD */
1636 if (!err) err = map_conditional(exports, "FEATURE_PTHREAD", 0);
1637 #endif /* ndef FEATURE_PTHREAD */
1639 #ifdef FEATURE_STATISTICS
1640 if (!err) err = map_conditional(exports, "FEATURE_STATISTICS", 1);
1641 #else /* ifndef FEATURE_STATISTICS */
1642 if (!err) err = map_conditional(exports, "FEATURE_STATISTICS", 0);
1643 #endif /* ndef FEATURE_STATISTICS */
1645 #ifdef FEATURE_TOGGLE
1646 if (!err) err = map_conditional(exports, "FEATURE_TOGGLE", 1);
1647 #else /* ifndef FEATURE_TOGGLE */
1648 if (!err) err = map_conditional(exports, "FEATURE_TOGGLE", 0);
1649 #endif /* ndef FEATURE_TOGGLE */
1651 #ifdef FEATURE_TRUST
1652 if (!err) err = map_conditional(exports, "FEATURE_TRUST", 1);
1653 #else /* ifndef FEATURE_TRUST */
1654 if (!err) err = map_conditional(exports, "FEATURE_TRUST", 0);
1655 #endif /* ndef FEATURE_TRUST */
1658 if (!err) err = map_conditional(exports, "FEATURE_ZLIB", 1);
1659 #else /* ifndef FEATURE_ZLIB */
1660 if (!err) err = map_conditional(exports, "FEATURE_ZLIB", 0);
1661 #endif /* ndef FEATURE_ZLIB */
1664 if (!err) err = map_conditional(exports, "STATIC_PCRE", 1);
1665 #else /* ifndef STATIC_PCRE */
1666 if (!err) err = map_conditional(exports, "STATIC_PCRE", 0);
1667 #endif /* ndef STATIC_PCRE */
1670 if (!err) err = map_conditional(exports, "STATIC_PCRS", 1);
1671 #else /* ifndef STATIC_PCRS */
1672 if (!err) err = map_conditional(exports, "STATIC_PCRS", 0);
1673 #endif /* ndef STATIC_PCRS */
1679 /*********************************************************************
1681 * Function : show_rcs
1683 * Description : Create a string with the rcs info for all sourcefiles
1687 * Returns : A string, or NULL on out-of-memory.
1689 *********************************************************************/
1690 static char *show_rcs(void)
1692 char *result = strdup("");
1693 char buf[BUFFER_SIZE];
1695 /* Instead of including *all* dot h's in the project (thus creating a
1696 * tremendous amount of dependencies), I will concede to declaring them
1697 * as extern's. This forces the developer to add to this list, but oh well.
1700 #define SHOW_RCS(__x) \
1702 extern const char __x[]; \
1703 snprintf(buf, sizeof(buf), " %s\n", __x); \
1704 string_append(&result, buf); \
1707 /* In alphabetical order */
1708 SHOW_RCS(actions_h_rcs)
1709 SHOW_RCS(actions_rcs)
1711 SHOW_RCS(amiga_h_rcs)
1713 #endif /* def AMIGA */
1716 #ifdef FEATURE_CGI_EDIT_ACTIONS
1717 SHOW_RCS(cgiedit_h_rcs)
1718 SHOW_RCS(cgiedit_rcs)
1719 #endif /* def FEATURE_CGI_EDIT_ACTIONS */
1720 SHOW_RCS(cgisimple_h_rcs)
1721 SHOW_RCS(cgisimple_rcs)
1723 SHOW_RCS(cygwin_h_rcs)
1725 SHOW_RCS(deanimate_h_rcs)
1726 SHOW_RCS(deanimate_rcs)
1727 SHOW_RCS(encode_h_rcs)
1728 SHOW_RCS(encode_rcs)
1729 SHOW_RCS(errlog_h_rcs)
1730 SHOW_RCS(errlog_rcs)
1731 SHOW_RCS(filters_h_rcs)
1732 SHOW_RCS(filters_rcs)
1733 SHOW_RCS(gateway_h_rcs)
1734 SHOW_RCS(gateway_rcs)
1735 SHOW_RCS(jbsockets_h_rcs)
1736 SHOW_RCS(jbsockets_rcs)
1739 SHOW_RCS(list_h_rcs)
1741 SHOW_RCS(loadcfg_h_rcs)
1742 SHOW_RCS(loadcfg_rcs)
1743 SHOW_RCS(loaders_h_rcs)
1744 SHOW_RCS(loaders_rcs)
1745 SHOW_RCS(miscutil_h_rcs)
1746 SHOW_RCS(miscutil_rcs)
1747 SHOW_RCS(parsers_h_rcs)
1748 SHOW_RCS(parsers_rcs)
1750 SHOW_RCS(pcrs_h_rcs)
1751 SHOW_RCS(project_h_rcs)
1752 SHOW_RCS(ssplit_h_rcs)
1753 SHOW_RCS(ssplit_rcs)
1754 SHOW_RCS(urlmatch_h_rcs)
1755 SHOW_RCS(urlmatch_rcs)
1757 #ifndef _WIN_CONSOLE
1758 SHOW_RCS(w32log_h_rcs)
1759 SHOW_RCS(w32log_rcs)
1760 SHOW_RCS(w32res_h_rcs)
1761 SHOW_RCS(w32taskbar_h_rcs)
1762 SHOW_RCS(w32taskbar_rcs)
1763 #endif /* ndef _WIN_CONSOLE */
1764 SHOW_RCS(win32_h_rcs)
1766 #endif /* def _WIN32 */
1775 /*********************************************************************
1777 * Function : cgi_show_file
1779 * Description : CGI function that shows the content of a
1780 * configuration file.
1783 * 1 : csp = Current client state (buffers, headers, etc...)
1784 * 2 : rsp = http_response data structure for output
1785 * 3 : parameters = map of cgi parameters
1788 * file : Which file to show. Only first letter is checked,
1793 * Default is to show menu and other information.
1795 * Returns : JB_ERR_OK on success
1796 * JB_ERR_MEMORY on out-of-memory error.
1798 *********************************************************************/
1799 static jb_err cgi_show_file(struct client_state *csp,
1800 struct http_response *rsp,
1801 const struct map *parameters)
1804 const char * filename = NULL;
1805 char * file_description = NULL;
1811 switch (*(lookup(parameters, "file")))
1814 if (!get_number_param(csp, parameters, "index", &i) && i < MAX_AF_FILES && csp->actions_list[i])
1816 filename = csp->actions_list[i]->filename;
1817 file_description = "Actions File";
1822 if (!get_number_param(csp, parameters, "index", &i) && i < MAX_AF_FILES && csp->rlist[i])
1824 filename = csp->rlist[i]->filename;
1825 file_description = "Filter File";
1829 #ifdef FEATURE_TRUST
1833 filename = csp->tlist->filename;
1834 file_description = "Trust File";
1837 #endif /* def FEATURE_TRUST */
1840 if (NULL != filename)
1842 struct map *exports;
1847 exports = default_exports(csp, "show-status");
1848 if (NULL == exports)
1850 return JB_ERR_MEMORY;
1853 if ( map(exports, "file-description", 1, file_description, 1)
1854 || map(exports, "filepath", 1, html_encode(filename), 0) )
1857 return JB_ERR_MEMORY;
1860 err = load_file(filename, &s, &length);
1861 if (JB_ERR_OK != err)
1863 if (map(exports, "contents", 1, "<h1>ERROR OPENING FILE!</h1>", 1))
1866 return JB_ERR_MEMORY;
1871 s = html_encode_and_free_original(s);
1874 return JB_ERR_MEMORY;
1877 if (map(exports, "contents", 1, s, 0))
1880 return JB_ERR_MEMORY;
1884 return template_fill_for_cgi(csp, "show-status-file", exports, rsp);
1887 return JB_ERR_CGI_PARAMS;
1891 /*********************************************************************
1893 * Function : load_file
1895 * Description : Loads a file into a buffer.
1898 * 1 : filename = Name of the file to be loaded.
1899 * 2 : buffer = Used to return the file's content.
1900 * 3 : length = Used to return the size of the file.
1902 * Returns : JB_ERR_OK in case of success,
1903 * JB_ERR_FILE in case of ordinary file loading errors
1904 * (fseek() and ftell() errors are fatal)
1905 * JB_ERR_MEMORY in case of out-of-memory.
1907 *********************************************************************/
1908 static jb_err load_file(const char *filename, char **buffer, size_t *length)
1912 jb_err err = JB_ERR_OK;
1914 fp = fopen(filename, "rb");
1917 log_error(LOG_LEVEL_ERROR, "Failed to open %s: %E", filename);
1921 /* Get file length */
1922 if (fseek(fp, 0, SEEK_END))
1924 log_error(LOG_LEVEL_FATAL,
1925 "Unexpected error while fseek()ing to the end of %s: %E",
1931 log_error(LOG_LEVEL_FATAL,
1932 "Unexpected ftell() error while loading %s: %E",
1935 *length = (size_t)ret;
1937 /* Go back to the beginning. */
1938 if (fseek(fp, 0, SEEK_SET))
1940 log_error(LOG_LEVEL_FATAL,
1941 "Unexpected error while fseek()ing to the beginning of %s: %E",
1945 *buffer = (char *)zalloc(*length + 1);
1946 if (NULL == *buffer)
1948 err = JB_ERR_MEMORY;
1950 else if (!fread(*buffer, *length, 1, fp))
1953 * May happen if the file size changes between fseek() and
1954 * fread(). If it does, we just log it and serve what we got.
1956 log_error(LOG_LEVEL_ERROR,
1957 "Couldn't completely read file %s.", filename);