X-Git-Url: http://www.privoxy.org/gitweb/?a=blobdiff_plain;f=cgi.c;h=f81443ee199173a335e9593731f716c00cea6989;hb=e3b4e32a3b3b44f80fdd04818357732f9aa0289e;hp=8f1807f0814a129c268952f2aa044ebf592ee11d;hpb=12019a6754666e6cc48ca4bb10db095d0228b21e;p=privoxy.git
diff --git a/cgi.c b/cgi.c
index 8f1807f0..f81443ee 100644
--- a/cgi.c
+++ b/cgi.c
@@ -1,4 +1,4 @@
-const char cgi_rcs[] = "$Id: cgi.c,v 1.126 2009/10/29 16:53:56 fabiankeil Exp $";
+const char cgi_rcs[] = "$Id: cgi.c,v 1.157 2012/11/09 10:47:42 fabiankeil Exp $";
/*********************************************************************
*
* File : $Source: /cvsroot/ijbswa/current/cgi.c,v $
@@ -7,18 +7,15 @@ const char cgi_rcs[] = "$Id: cgi.c,v 1.126 2009/10/29 16:53:56 fabiankeil Exp $"
* html or gif answers, and to compose HTTP resonses.
* This only contains the framework functions, the
* actual handler functions are declared elsewhere.
- *
- * Functions declared include:
- *
*
* Copyright : Written by and Copyright (C) 2001-2004, 2006-2008
* the SourceForge Privoxy team. http://www.privoxy.org/
*
* Based on the Internet Junkbuster originally written
- * by and Copyright (C) 1997 Anonymous Coders and
+ * by and Copyright (C) 1997 Anonymous Coders and
* Junkbusters Corporation. http://www.junkbusters.com
*
- * This program is free software; you can redistribute it
+ * This program is free software; you can redistribute it
* and/or modify it under the terms of the GNU General
* Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at
@@ -49,6 +46,10 @@ const char cgi_rcs[] = "$Id: cgi.c,v 1.126 2009/10/29 16:53:56 fabiankeil Exp $"
#include
#include
+#ifdef FEATURE_COMPRESSION
+#include
+#endif
+
#include "project.h"
#include "cgi.h"
#include "list.h"
@@ -81,126 +82,126 @@ static const struct cgi_dispatcher cgi_dispatchers[] = {
"Privoxy main page",
TRUE },
#ifdef FEATURE_GRACEFUL_TERMINATION
- { "die",
- cgi_die,
+ { "die",
+ cgi_die,
"Shut down - Do not deploy this build in a production environment, "
"this is a one click Denial Of Service attack!!!",
- FALSE },
+ FALSE },
#endif
- { "show-status",
- cgi_show_status,
+ { "show-status",
+ cgi_show_status,
#ifdef FEATURE_CGI_EDIT_ACTIONS
"View & change the current configuration",
#else
"View the current configuration",
#endif
- TRUE },
- { "show-version",
- cgi_show_version,
+ TRUE },
+ { "show-version",
+ cgi_show_version,
"View the source code version numbers",
- TRUE },
- { "show-request",
- cgi_show_request,
+ TRUE },
+ { "show-request",
+ cgi_show_request,
"View the request headers",
- TRUE },
+ TRUE },
{ "show-url-info",
- cgi_show_url_info,
+ cgi_show_url_info,
"Look up which actions apply to a URL and why",
TRUE },
#ifdef FEATURE_TOGGLE
{ "toggle",
- cgi_toggle,
+ cgi_toggle,
"Toggle Privoxy on or off",
FALSE },
#endif /* def FEATURE_TOGGLE */
#ifdef FEATURE_CGI_EDIT_ACTIONS
{ "edit-actions", /* Edit the actions list */
- cgi_edit_actions,
+ cgi_edit_actions,
NULL, FALSE },
{ "eaa", /* Shortcut for edit-actions-add-url-form */
- cgi_edit_actions_add_url_form,
+ cgi_edit_actions_add_url_form,
NULL, FALSE },
{ "eau", /* Shortcut for edit-actions-url-form */
- cgi_edit_actions_url_form,
+ cgi_edit_actions_url_form,
NULL, FALSE },
{ "ear", /* Shortcut for edit-actions-remove-url-form */
- cgi_edit_actions_remove_url_form,
+ cgi_edit_actions_remove_url_form,
NULL, FALSE },
{ "eal", /* Shortcut for edit-actions-list */
- cgi_edit_actions_list,
+ cgi_edit_actions_list,
NULL, FALSE },
{ "eafu", /* Shortcut for edit-actions-for-url */
- cgi_edit_actions_for_url,
+ cgi_edit_actions_for_url,
NULL, FALSE },
{ "eas", /* Shortcut for edit-actions-submit */
- cgi_edit_actions_submit,
+ cgi_edit_actions_submit,
NULL, FALSE },
{ "easa", /* Shortcut for edit-actions-section-add */
- cgi_edit_actions_section_add,
+ cgi_edit_actions_section_add,
NULL, FALSE },
{ "easr", /* Shortcut for edit-actions-section-remove */
- cgi_edit_actions_section_remove,
+ cgi_edit_actions_section_remove,
NULL, FALSE },
{ "eass", /* Shortcut for edit-actions-section-swap */
- cgi_edit_actions_section_swap,
+ cgi_edit_actions_section_swap,
NULL, FALSE },
{ "edit-actions-for-url",
- cgi_edit_actions_for_url,
+ cgi_edit_actions_for_url,
NULL, FALSE /* Edit the actions for (a) specified URL(s) */ },
{ "edit-actions-list",
- cgi_edit_actions_list,
+ cgi_edit_actions_list,
NULL, TRUE /* Edit the actions list */ },
{ "edit-actions-submit",
- cgi_edit_actions_submit,
+ cgi_edit_actions_submit,
NULL, FALSE /* Change the actions for (a) specified URL(s) */ },
{ "edit-actions-url",
- cgi_edit_actions_url,
+ cgi_edit_actions_url,
NULL, FALSE /* Change a URL pattern in the actionsfile */ },
{ "edit-actions-url-form",
- cgi_edit_actions_url_form,
+ cgi_edit_actions_url_form,
NULL, FALSE /* Form to change a URL pattern in the actionsfile */ },
{ "edit-actions-add-url",
- cgi_edit_actions_add_url,
+ cgi_edit_actions_add_url,
NULL, FALSE /* Add a URL pattern to the actionsfile */ },
{ "edit-actions-add-url-form",
- cgi_edit_actions_add_url_form,
+ cgi_edit_actions_add_url_form,
NULL, FALSE /* Form to add a URL pattern to the actionsfile */ },
{ "edit-actions-remove-url",
- cgi_edit_actions_remove_url,
+ cgi_edit_actions_remove_url,
NULL, FALSE /* Remove a URL pattern from the actionsfile */ },
{ "edit-actions-remove-url-form",
- cgi_edit_actions_remove_url_form,
+ cgi_edit_actions_remove_url_form,
NULL, FALSE /* Form to remove a URL pattern from the actionsfile */ },
{ "edit-actions-section-add",
- cgi_edit_actions_section_add,
+ cgi_edit_actions_section_add,
NULL, FALSE /* Remove a section from the actionsfile */ },
{ "edit-actions-section-remove",
- cgi_edit_actions_section_remove,
+ cgi_edit_actions_section_remove,
NULL, FALSE /* Remove a section from the actionsfile */ },
{ "edit-actions-section-swap",
- cgi_edit_actions_section_swap,
+ cgi_edit_actions_section_swap,
NULL, FALSE /* Swap two sections in the actionsfile */ },
#endif /* def FEATURE_CGI_EDIT_ACTIONS */
- { "error-favicon.ico",
- cgi_send_error_favicon,
+ { "error-favicon.ico",
+ cgi_send_error_favicon,
NULL, TRUE /* Sends the favicon image for error pages. */ },
- { "favicon.ico",
- cgi_send_default_favicon,
+ { "favicon.ico",
+ cgi_send_default_favicon,
NULL, TRUE /* Sends the default favicon image. */ },
- { "robots.txt",
- cgi_robots_txt,
- NULL, TRUE /* Sends a robots.txt file to tell robots to go away. */ },
+ { "robots.txt",
+ cgi_robots_txt,
+ NULL, TRUE /* Sends a robots.txt file to tell robots to go away. */ },
{ "send-banner",
- cgi_send_banner,
+ cgi_send_banner,
NULL, TRUE /* Send a built-in image */ },
{ "send-stylesheet",
- cgi_send_stylesheet,
+ cgi_send_stylesheet,
NULL, FALSE /* Send templates/cgi-style.css */ },
{ "t",
- cgi_transparent_image,
+ cgi_transparent_image,
NULL, TRUE /* Send a transparent image (short name) */ },
{ "url-info-osd.xml",
- cgi_send_url_info_osd,
+ cgi_send_url_info_osd,
NULL, TRUE /* Send templates/url-info-osd.xml */ },
{ "user-manual",
cgi_send_user_manual,
@@ -267,6 +268,13 @@ const char image_blank_data[] =
const size_t image_pattern_length = sizeof(image_pattern_data) - 1;
const size_t image_blank_length = sizeof(image_blank_data) - 1;
+#ifdef FEATURE_COMPRESSION
+/*
+ * Minimum length which a buffer has to reach before
+ * we bother to (re-)compress it. Completely arbitrary.
+ */
+const size_t LOWER_LENGTH_LIMIT_FOR_COMPRESSION = 1024U;
+#endif
static struct http_response cgi_error_memory_response[1];
@@ -276,7 +284,7 @@ static struct map *parse_cgi_parameters(char *argstring);
/*********************************************************************
- *
+ *
* Function : dispatch_cgi
*
* Description : Checks if a request URL has either the magical
@@ -306,15 +314,15 @@ struct http_response *dispatch_cgi(struct client_state *csp)
/* Either the host matches CGI_SITE_1_HOST ..*/
if ( ( (0 == strcmpic(host, CGI_SITE_1_HOST))
|| (0 == strcmpic(host, CGI_SITE_1_HOST ".")))
- && (path[0] == '/') )
+ && (path[0] == '/'))
{
/* ..then the path will all be for us. Remove leading '/' */
path++;
}
/* Or it's the host part CGI_SITE_2_HOST, and the path CGI_SITE_2_PATH */
- else if ( ( (0 == strcmpic(host, CGI_SITE_2_HOST ))
- || (0 == strcmpic(host, CGI_SITE_2_HOST ".")) )
- && (0 == strncmpic(path, CGI_SITE_2_PATH, strlen(CGI_SITE_2_PATH))) )
+ else if (( (0 == strcmpic(host, CGI_SITE_2_HOST))
+ || (0 == strcmpic(host, CGI_SITE_2_HOST ".")))
+ && (0 == strncmpic(path, CGI_SITE_2_PATH, strlen(CGI_SITE_2_PATH))))
{
/* take everything following CGI_SITE_2_PATH */
path += strlen(CGI_SITE_2_PATH);
@@ -338,7 +346,22 @@ struct http_response *dispatch_cgi(struct client_state *csp)
return NULL;
}
- /*
+ if (strcmpic(csp->http->gpc, "GET")
+ && strcmpic(csp->http->gpc, "HEAD"))
+ {
+ log_error(LOG_LEVEL_ERROR,
+ "CGI request with unsupported method received: %s", csp->http->gpc);
+ /*
+ * The CGI pages currently only support GET and HEAD requests.
+ *
+ * If the client used a different method, ditch any data following
+ * the current headers to reduce the likelihood of parse errors
+ * with the following request.
+ */
+ csp->client_iob->eod = csp->client_iob->cur;
+ }
+
+ /*
* This is a CGI call.
*/
@@ -383,7 +406,7 @@ static char *grep_cgi_referrer(const struct client_state *csp)
/*********************************************************************
- *
+ *
* Function : referrer_is_safe
*
* Description : Decides whether we trust the Referer for
@@ -431,7 +454,7 @@ static int referrer_is_safe(const struct client_state *csp)
}
/*********************************************************************
- *
+ *
* Function : dispatch_known_cgi
*
* Description : Processes a CGI once dispatch_cgi has determined that
@@ -469,7 +492,7 @@ static struct http_response *dispatch_known_cgi(struct client_state * csp,
{
query_args_start++;
}
- if (*query_args_start == '/')
+ if (*query_args_start == '/')
{
*query_args_start++ = '\0';
if ((param_list = new_map()))
@@ -504,7 +527,7 @@ static struct http_response *dispatch_known_cgi(struct client_state * csp,
return cgi_error_memory();
}
- /*
+ /*
* Find and start the right CGI function
*/
d = cgi_dispatchers;
@@ -547,13 +570,15 @@ static struct http_response *dispatch_known_cgi(struct client_state * csp,
if (err && (err != JB_ERR_MEMORY))
{
/* Unexpected error! Shouldn't get here */
- log_error(LOG_LEVEL_ERROR, "Unexpected CGI error %d in top-level handler. Please file a bug report!", err);
+ log_error(LOG_LEVEL_ERROR,
+ "Unexpected CGI error %d in top-level handler. "
+ "Please file a bug report!", err);
err = cgi_error_unknown(csp, rsp, err);
}
if (!err)
{
/* It worked */
- rsp->reason = RSP_REASON_CGI_CALL;
+ rsp->crunch_reason = CGI_CALL;
return finish_http_response(csp, rsp);
}
else
@@ -566,8 +591,8 @@ static struct http_response *dispatch_known_cgi(struct client_state * csp,
d++;
}
}
-
-
+
+
/*********************************************************************
*
* Function : parse_cgi_parameters
@@ -584,16 +609,35 @@ static struct http_response *dispatch_known_cgi(struct client_state * csp,
static struct map *parse_cgi_parameters(char *argstring)
{
char *p;
- char *vector[BUFFER_SIZE];
+ char **vector;
int pairs, i;
struct map *cgi_params;
+ /*
+ * XXX: This estimate is guaranteed to be high enough as we
+ * let ssplit() ignore empty fields, but also a bit wasteful.
+ * The same hack is used in get_last_url() so it looks like
+ * a real solution is needed.
+ */
+ size_t max_segments = strlen(argstring) / 2;
+ if (max_segments == 0)
+ {
+ /*
+ * XXX: If the argstring is empty, there's really
+ * no point in creating a param list, but currently
+ * other parts of Privoxy depend on the list's existence.
+ */
+ max_segments = 1;
+ }
+ vector = malloc_or_die(max_segments * sizeof(char *));
+
if (NULL == (cgi_params = new_map()))
{
+ freez(vector);
return NULL;
}
- /*
+ /*
* IE 5 does, of course, violate RFC 2316 Sect 4.1 and sends
* the fragment identifier along with the request, so we must
* cut it off here, so it won't pollute the CGI params:
@@ -603,7 +647,14 @@ static struct map *parse_cgi_parameters(char *argstring)
*p = '\0';
}
- pairs = ssplit(argstring, "&", vector, SZ(vector), 1, 1);
+ pairs = ssplit(argstring, "&", vector, max_segments);
+ assert(pairs != -1);
+ if (pairs == -1)
+ {
+ freez(vector);
+ free_map(cgi_params);
+ return NULL;
+ }
for (i = 0; i < pairs; i++)
{
@@ -612,12 +663,15 @@ static struct map *parse_cgi_parameters(char *argstring)
*p = '\0';
if (map(cgi_params, url_decode(vector[i]), 0, url_decode(++p), 0))
{
+ freez(vector);
free_map(cgi_params);
return NULL;
}
}
}
+ freez(vector);
+
return cgi_params;
}
@@ -713,8 +767,8 @@ jb_err get_string_param(const struct map *parameters,
s = param;
while ((ch = *s++) != '\0')
{
- if ( ((unsigned char)ch < (unsigned char)' ')
- || (ch == '}') )
+ if (((unsigned char)ch < (unsigned char)' ')
+ || (ch == '}'))
{
/* Probable hack attempt, or user accidentally used '}'. */
return JB_ERR_CGI_PARAMS;
@@ -762,7 +816,7 @@ jb_err get_number_param(struct client_state *csp,
assert(name);
assert(pvalue);
- *pvalue = 0;
+ *pvalue = 0;
param = lookup(parameters, name);
if (!*param)
@@ -854,7 +908,7 @@ struct http_response *error_response(struct client_state *csp,
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_and_free_original(path), 0);
- if (!err) err = map(exports, "protocol", 1, csp->http->ssl ? "https://" : "http://", 1);
+ if (!err) err = map(exports, "protocol", 1, csp->http->ssl ? "https://" : "http://", 1);
if (!err)
{
err = map(exports, "host-ip", 1, html_encode(csp->http->host_ip_addr_str), 0);
@@ -876,7 +930,7 @@ struct http_response *error_response(struct client_state *csp,
if (!strcmp(templatename, "no-such-domain"))
{
rsp->status = strdup("404 No such domain");
- rsp->reason = RSP_REASON_NO_SUCH_DOMAIN;
+ rsp->crunch_reason = NO_SUCH_DOMAIN;
}
else if (!strcmp(templatename, "forwarding-failed"))
{
@@ -924,6 +978,9 @@ struct http_response *error_response(struct client_state *csp,
case SOCKS_5:
socks_type = "socks5-";
break;
+ case SOCKS_5T:
+ socks_type = "socks5t-";
+ break;
default:
log_error(LOG_LEVEL_FATAL, "Unknown socks type: %d.", fwd->type);
}
@@ -938,22 +995,22 @@ struct http_response *error_response(struct client_state *csp,
}
rsp->status = strdup("503 Forwarding failure");
- rsp->reason = RSP_REASON_FORWARDING_FAILED;
+ rsp->crunch_reason = FORWARDING_FAILED;
}
else if (!strcmp(templatename, "connect-failed"))
{
rsp->status = strdup("503 Connect failed");
- rsp->reason = RSP_REASON_CONNECT_FAILED;
+ rsp->crunch_reason = CONNECT_FAILED;
}
else if (!strcmp(templatename, "connection-timeout"))
{
rsp->status = strdup("504 Connection timeout");
- rsp->reason = RSP_REASON_CONNECTION_TIMEOUT;
+ rsp->crunch_reason = CONNECTION_TIMEOUT;
}
else if (!strcmp(templatename, "no-server-data"))
{
rsp->status = strdup("502 No data received from server or forwarder");
- rsp->reason = RSP_REASON_NO_SERVER_DATA;
+ rsp->crunch_reason = NO_SERVER_DATA;
}
if (rsp->status == NULL)
@@ -1037,23 +1094,23 @@ void cgi_init_error_messages(void)
"Content-Type: text/html\r\n"
"\r\n";
cgi_error_memory_response->body =
- "\r\n"
- "\r\n"
- " 500 Internal Privoxy Error\r\n"
+ "\n"
+ "\n"
+ " 500 Internal Privoxy Error\n"
" "
- "\r\n"
- "\r\n"
- "
500 Internal Privoxy Error
\r\n"
- "
Privoxy ran out of memory while processing your request.
\r\n"
- "
Please contact your proxy administrator, or try again later
\r\n"
- "\r\n"
- "\r\n";
+ "\n"
+ "\n"
+ "
500 Internal Privoxy Error
\n"
+ "
Privoxy ran out of memory while processing your request.
\n"
+ "
Please contact your proxy administrator, or try again later
\n"
+ "\n"
+ "\n";
cgi_error_memory_response->head_length =
strlen(cgi_error_memory_response->head);
cgi_error_memory_response->content_length =
strlen(cgi_error_memory_response->body);
- cgi_error_memory_response->reason = RSP_REASON_OUT_OF_MEMORY;
+ cgi_error_memory_response->crunch_reason = OUT_OF_MEMORY;
}
@@ -1085,7 +1142,7 @@ struct http_response *cgi_error_memory(void)
*
* Description : Almost-CGI function that is called if a template
* cannot be loaded. Note this is not a true CGI,
- * it takes a template name rather than a map of
+ * it takes a template name rather than a map of
* parameters.
*
* Parameters :
@@ -1095,7 +1152,7 @@ struct http_response *cgi_error_memory(void)
* be loaded.
*
* Returns : JB_ERR_OK on success
- * JB_ERR_MEMORY on out-of-memory error.
+ * JB_ERR_MEMORY on out-of-memory error.
*
*********************************************************************/
jb_err cgi_error_no_template(const struct client_state *csp,
@@ -1105,18 +1162,18 @@ jb_err cgi_error_no_template(const struct client_state *csp,
static const char status[] =
"500 Internal Privoxy Error";
static const char body_prefix[] =
- "\r\n"
- "\r\n"
- " 500 Internal Privoxy Error\r\n"
+ "\n"
+ "\n"
+ " 500 Internal Privoxy Error\n"
" "
- "\r\n"
- "\r\n"
- "
500 Internal Privoxy Error
\r\n"
- "
Privoxy encountered an error while processing your request:
\r\n"
+ "\n"
+ "\n"
+ "
500 Internal Privoxy Error
\n"
+ "
Privoxy encountered an error while processing your request:
\n"
"
Could not load template file ";
static const char body_suffix[] =
- " or one of its included components.
\r\n"
- "
Please contact your proxy administrator.
\r\n"
+ " or one of its included components.
\n"
+ "
Please contact your proxy administrator.
\n"
"
If you are the proxy administrator, please put the required file(s)"
"in the (confdir)/templates directory. The "
"location of the (confdir) directory "
@@ -1125,9 +1182,9 @@ jb_err cgi_error_no_template(const struct client_state *csp,
#ifndef _WIN32
", or /etc/privoxy/"
#endif /* ndef _WIN32 */
- ").