-const char cgi_rcs[] = "$Id: cgi.c,v 1.76 2006/09/07 14:06:38 fabiankeil Exp $";
+const char cgi_rcs[] = "$Id: cgi.c,v 1.85 2007/01/05 14:19:02 fabiankeil Exp $";
/*********************************************************************
*
* File : $Source: /cvsroot/ijbswa/current/cgi.c,v $
* Functions declared include:
*
*
- * Copyright : Written by and Copyright (C) 2001 the SourceForge
- * Privoxy team. http://www.privoxy.org/
+ * Copyright : Written by and Copyright (C) 2001-2004, 2006
+ * the SourceForge Privoxy team. http://www.privoxy.org/
*
* Based on the Internet Junkbuster originally written
* by and Copyright (C) 1997 Anonymous Coders and
*
* Revisions :
* $Log: cgi.c,v $
+ * Revision 1.85 2007/01/05 14:19:02 fabiankeil
+ * Handle pcrs_execute() errors in template_fill() properly.
+ *
+ * Revision 1.84 2006/12/28 17:54:22 fabiankeil
+ * Fixed gcc43 conversion warnings and replaced sprintf
+ * calls with snprintf to give OpenBSD's gcc one less reason
+ * to complain.
+ *
+ * Revision 1.83 2006/12/17 19:35:19 fabiankeil
+ * Escape ampersand in Privoxy menu.
+ *
+ * Revision 1.82 2006/12/17 17:53:39 fabiankeil
+ * Suppress the toggle link if remote toggling is disabled.
+ *
+ * Revision 1.81 2006/12/09 13:49:16 fabiankeil
+ * Fix configure option --disable-toggle.
+ * Thanks to Peter Thoenen for reporting this.
+ *
+ * Revision 1.80 2006/12/08 14:45:32 fabiankeil
+ * Don't lose the FORCE_PREFIX in case of
+ * connection problems. Fixes #612235.
+ *
+ * Revision 1.79 2006/11/13 19:05:50 fabiankeil
+ * Make pthread mutex locking more generic. Instead of
+ * checking for OSX and OpenBSD, check for FEATURE_PTHREAD
+ * and use mutex locking unless there is an _r function
+ * available. Better safe than sorry.
+ *
+ * Fixes "./configure --disable-pthread" and should result
+ * in less threading-related problems on pthread-using platforms,
+ * but it still doesn't fix BR#1122404.
+ *
+ * Revision 1.78 2006/09/21 19:22:07 fabiankeil
+ * Use CGI_PREFIX to check the referrer.
+ * The check for "http://config.privoxy.org/" fails
+ * if the user modified CGI_SITE_2_HOST.
+ *
+ * Revision 1.77 2006/09/21 15:17:23 fabiankeil
+ * Adjusted headers for Privoxy's cgi responses:
+ * Don't set Last-Modified, Expires and Cache-Control
+ * headers for redirects; always set "Connection: close".
+ *
* Revision 1.76 2006/09/07 14:06:38 fabiankeil
* Only predate the Last-Modified header for cgi responses
* that are delivered with status code 404 or 503.
#include "loadcfg.h"
/* loadcfg.h is for global_toggle_state only */
#ifdef FEATURE_PTHREAD
-#include <pthread.h>
#include "jcc.h"
/* jcc.h is for mutex semaphore globals only */
#endif /* def FEATURE_PTHREAD */
{ "show-status",
cgi_show_status,
#ifdef FEATURE_CGI_EDIT_ACTIONS
- "View & change the current configuration",
+ "View & change the current configuration",
#else
"View the current configuration",
#endif
"Look up which actions apply to a URL and why",
TRUE },
#ifdef FEATURE_CGI_EDIT_ACTIONS
+#ifdef FEATURE_TOGGLE
{ "toggle",
cgi_toggle,
"Toggle Privoxy on or off",
FALSE },
+#endif /* def FEATURE_TOGGLE */
{ "edit-actions", /* Edit the actions list */
cgi_edit_actions,
NULL, FALSE },
*/
if (d->harmless
|| ((NULL != (referrer = grep_cgi_referrer(csp)))
- && (0 == strncmp(referrer, "http://config.privoxy.org/", 26)))
+ && (0 == strncmp(referrer, CGI_PREFIX, sizeof(CGI_PREFIX)-1)))
)
{
err = (d->handler)(csp, rsp, param_list);
ch = *(lookup(parameters, param_name));
if ((ch >= 'a') && (ch <= 'z'))
{
- ch = ch - 'a' + 'A';
+ ch = (char)(ch - 'a' + 'A');
}
return ch;
return JB_ERR_CGI_PARAMS;
}
- ch -= '0';
+ ch = (char)(ch - '0');
/* Note:
*
return JB_ERR_CGI_PARAMS;
}
- value = value * 10 + ch;
+ value = value * 10 + (unsigned)ch;
}
/* Success */
{
jb_err err;
struct http_response *rsp;
- struct map * exports = default_exports(csp, NULL);
+ struct map *exports = default_exports(csp, NULL);
+ char *path = NULL;
+
if (exports == NULL)
{
return cgi_error_memory();
return cgi_error_memory();
}
- err = map(exports, "host", 1, html_encode(csp->http->host), 0);
+ if (csp->flags & CSP_FLAG_FORCED)
+ {
+ path = strdup(FORCE_PREFIX);
+ }
+ else
+ {
+ path = strdup("");
+ }
+ err = string_append(&path, csp->http->path);
+
+ if (!err) err = map(exports, "host", 1, html_encode(csp->http->host), 0);
if (!err) err = map(exports, "hostport", 1, html_encode(csp->http->hostport), 0);
- if (!err) err = map(exports, "path", 1, html_encode(csp->http->path), 0);
+ if (!err) err = map(exports, "path", 1, html_encode_and_free_original(path), 0);
if (!err) err = map(exports, "error", 1, html_encode_and_free_original(safe_strerror(sys_err)), 0);
if (!err) err = map(exports, "protocol", 1, csp->http->ssl ? "https://" : "http://", 1);
if (!err)
strcat(rsp->body, body_suffix);
rsp->status = strdup(status);
- if (rsp->body == NULL)
+ if (rsp->status == NULL)
{
return JB_ERR_MEMORY;
}
rsp->head_length = 0;
rsp->is_static = 0;
- sprintf(errnumbuf, "%d", error_to_report);
+ snprintf(errnumbuf, sizeof(errnumbuf), "%d", error_to_report);
rsp->body = malloc(strlen(body_prefix) + strlen(errnumbuf) + strlen(body_suffix) + 1);
if (rsp->body == NULL)
strcat(rsp->body, body_suffix);
rsp->status = strdup(status);
- if (rsp->body == NULL)
+ if (rsp->status == NULL)
{
return JB_ERR_MEMORY;
}
struct tm *t;
time_t current_time;
-#if defined(HAVE_GMTIME_R) && !defined(OSX_DARWIN)
+#if defined(HAVE_GMTIME_R)
/*
* Declare dummy up here (instead of inside get/set gmt block) so it
* doesn't go out of scope before it's potentially used in snprintf later.
/* get and save the gmt */
{
-#ifdef OSX_DARWIN
+#if HAVE_GMTIME_R
+ t = gmtime_r(¤t_time, &dummy);
+#elif FEATURE_PTHREAD
pthread_mutex_lock(&gmtime_mutex);
t = gmtime(¤t_time);
pthread_mutex_unlock(&gmtime_mutex);
-#elif HAVE_GMTIME_R
- t = gmtime_r(¤t_time, &dummy);
#else
t = gmtime(¤t_time);
#endif
/*
* Fill in the HTTP Status
*/
- sprintf(buf, "HTTP/1.0 %s", rsp->status ? rsp->status : "200 OK");
+ snprintf(buf, sizeof(buf), "HTTP/1.0 %s", rsp->status ? rsp->status : "200 OK");
err = enlist_first(rsp->headers, buf);
/*
}
if (!err)
{
- sprintf(buf, "Content-Length: %d", (int)rsp->content_length);
+ snprintf(buf, sizeof(buf), "Content-Length: %d", (int)rsp->content_length);
err = enlist(rsp->headers, buf);
}
* Caller must free().
* 2 : exports = map with fill in symbol -> name pairs
*
- * Returns : JB_ERR_OK on success
+ * Returns : JB_ERR_OK on success (and for uncritical errors)
* JB_ERR_MEMORY on out-of-memory error
*
*********************************************************************/
}
else
{
- pcrs_execute(job, file_buffer, size, &tmp_out_buffer, &size);
- free(file_buffer);
+ error = pcrs_execute(job, file_buffer, size, &tmp_out_buffer, &size);
+
pcrs_free_job(job);
if (NULL == tmp_out_buffer)
{
*template_ptr = NULL;
return JB_ERR_MEMORY;
}
- file_buffer = tmp_out_buffer;
+
+ if (error < 0)
+ {
+ /*
+ * Substitution failed, keep the original buffer,
+ * log the problem and ignore it.
+ *
+ * The user might see some unresolved @CGI_VARIABLES@,
+ * but returning a special CGI error page seems unreasonable
+ * and could mask more important error messages.
+ */
+ free(tmp_out_buffer);
+ log_error(LOG_LEVEL_ERROR, "Failed to execute s/%s/%s/%s. %s",
+ buf, m->value, flags, pcrs_strerror(error));
+ }
+ else
+ {
+ /* Substitution succeeded, use modified buffer. */
+ free(file_buffer);
+ file_buffer = tmp_out_buffer;
+ }
}
}
if (!err) err = map(exports, "my-hostname", 1, html_encode(csp->my_hostname ? csp->my_hostname : "unknown"), 0);
if (!err) err = map(exports, "homepage", 1, html_encode(HOME_PAGE_URL), 0);
if (!err) err = map(exports, "default-cgi", 1, html_encode(CGI_PREFIX), 0);
- if (!err) err = map(exports, "menu", 1, make_menu(caller), 0);
+ if (!err) err = map(exports, "menu", 1, make_menu(caller, csp->config->feature_flags), 0);
if (!err) err = map(exports, "code-status", 1, CODE_STATUS, 1);
if (!strncmpic(csp->config->usermanual, "file://", 7) ||
!strncmpic(csp->config->usermanual, "http", 4))
*
* Description : Returns an HTML-formatted menu of the available
* unhidden CGIs, excluding the one given in <self>
+ * and the toggle CGI if toggling is disabled.
*
- * Parameters : self = name of CGI to leave out, can be NULL for
+ * Parameters :
+ * 1 : self = name of CGI to leave out, can be NULL for
* complete listing.
+ * 2 : feature_flags = feature bitmap from csp->config
+ *
*
* Returns : menu string, or NULL on out-of-memory error.
*
*********************************************************************/
-char *make_menu(const char *self)
+char *make_menu(const char *self, const unsigned feature_flags)
{
const struct cgi_dispatcher *d;
char *result = strdup("");
/* List available unhidden CGI's and export as "other-cgis" */
for (d = cgi_dispatchers; d->name; d++)
{
+
+#ifdef FEATURE_TOGGLE
+ if (!(feature_flags & RUNTIME_FEATURE_CGI_TOGGLE) && !strcmp(d->name, "toggle"))
+ {
+ /*
+ * Suppress the toggle link if remote toggling is disabled.
+ */
+ continue;
+ }
+#endif /* def FEATURE_TOGGLE */
+
if (d->description && strcmp(d->name, self))
{
string_append(&result, "<li><a href=\"" CGI_PREFIX);