-const char cgi_rcs[] = "$Id: cgi.c,v 1.89 2007/01/23 15:51:16 fabiankeil Exp $";
+const char cgi_rcs[] = "$Id: cgi.c,v 1.97 2007/04/09 18:11:35 fabiankeil Exp $";
/*********************************************************************
*
* File : $Source: /cvsroot/ijbswa/current/cgi.c,v $
*
* Revisions :
* $Log: cgi.c,v $
+ * Revision 1.97 2007/04/09 18:11:35 fabiankeil
+ * Don't mistake VC++'s _snprintf() for a snprintf() replacement.
+ *
+ * Revision 1.96 2007/03/08 17:41:05 fabiankeil
+ * Use sizeof() more often.
+ *
+ * Revision 1.95 2007/02/10 17:01:37 fabiankeil
+ * Don't overlook map result for the forwarding-type.
+ *
+ * Revision 1.94 2007/02/08 19:44:49 fabiankeil
+ * Use a transparent background for the PNG replacement pattern.
+ *
+ * Revision 1.93 2007/02/07 10:45:22 fabiankeil
+ * - Save the reason for generating http_responses.
+ * - Fix --disable-toggle (again).
+ * - Use TBL birthday hack for 403 responses as well.
+ * - Uglify the @menu@ again to fix JavaScript
+ * errors on the "blocked" template.
+ * - Escape an ampersand in cgi_error_unknown().
+ *
+ * Revision 1.92 2007/01/28 13:41:17 fabiankeil
+ * - Add HEAD support to finish_http_response.
+ * - Add error favicon to internal HTML error messages.
+ *
+ * Revision 1.91 2007/01/27 13:09:16 fabiankeil
+ * Add new config option "templdir" to
+ * change the templates directory.
+ *
+ * Revision 1.90 2007/01/25 13:47:26 fabiankeil
+ * Added "forwarding-failed" template support for error_response().
+ *
* Revision 1.89 2007/01/23 15:51:16 fabiankeil
* Add favicon delivery functions.
*
#include <limits.h>
#include <assert.h>
-#ifdef _WIN32
-#define snprintf _snprintf
-#endif /* def _WIN32 */
-
#include "project.h"
#include "cgi.h"
#include "list.h"
*/
const char image_pattern_data[] =
"\211\120\116\107\015\012\032\012\000\000\000\015\111\110\104"
- "\122\000\000\000\004\000\000\000\004\010\002\000\000\000\046"
- "\223\011\051\000\000\000\006\142\113\107\104\000\310\000\310"
- "\000\310\052\045\225\037\000\000\000\032\111\104\101\124\170"
- "\332\143\070\161\342\304\377\377\377\041\044\003\234\165\342"
- "\304\011\006\234\062\000\125\200\052\251\125\174\360\223\000"
- "\000\000\000\111\105\116\104\256\102\140\202";
+ "\122\000\000\000\004\000\000\000\004\010\006\000\000\000\251"
+ "\361\236\176\000\000\000\006\142\113\107\104\000\000\000\000"
+ "\000\000\371\103\273\177\000\000\000\033\111\104\101\124\010"
+ "\327\143\140\140\140\060\377\377\377\077\003\234\106\341\060"
+ "\060\230\063\020\124\001\000\161\021\031\241\034\364\030\143"
+ "\000\000\000\000\111\105\116\104\256\102\140\202";
/*
* 1x1 transparant PNG.
return cgi_error_memory();
}
- log_error(LOG_LEVEL_GPC, "%s%s cgi call", csp->http->hostport, csp->http->path);
- log_error(LOG_LEVEL_CLF, "%s - - [%T] \"%s\" 200 3",
- csp->ip_addr_str, csp->http->cmd);
-
/*
* Find and start the right CGI function
*/
if (!err)
{
/* It worked */
- return finish_http_response(rsp);
+ rsp->reason = RSP_REASON_CGI_CALL;
+ return finish_http_response(csp, rsp);
}
else
{
return cgi_error_memory();
}
+#ifdef FEATURE_FORCE_LOAD
if (csp->flags & CSP_FLAG_FORCED)
{
path = strdup(FORCE_PREFIX);
}
else
+#endif /* def FEATURE_FORCE_LOAD */
{
path = strdup("");
}
free_http_response(rsp);
return cgi_error_memory();
}
+ rsp->reason = RSP_REASON_NO_SUCH_DOMAIN;
}
else if (!strcmp(templatename, "forwarding-failed"))
{
csp->error_message = strdup("Failure reason missing. Check the log file for details.");
}
if (!err) err = map(exports, "gateway", 1, fwd->gateway_host, 1);
- if (!err) map(exports, "forwarding-type", 1, (fwd->type == SOCKS_4) ?
- "socks4-" : "socks4a-", 1);
+ if (!err) err = map(exports, "forwarding-type", 1, (fwd->type == SOCKS_4) ?
+ "socks4-" : "socks4a-", 1);
if (!err) err = map(exports, "error-message", 1, html_encode(csp->error_message), 0);
if (!err) rsp->status = strdup("503 Forwarding failure");
free_http_response(rsp);
return cgi_error_memory();
}
+ rsp->reason = RSP_REASON_FORWARDING_FAILED;
}
else if (!strcmp(templatename, "connect-failed"))
{
free_http_response(rsp);
return cgi_error_memory();
}
+ rsp->reason = RSP_REASON_CONNECT_FAILED;
}
err = template_fill_for_cgi(csp, templatename, exports, rsp);
return cgi_error_memory();
}
- return finish_http_response(rsp);
+ return finish_http_response(csp, rsp);
}
"\r\n";
cgi_error_memory_response->body =
"<html>\r\n"
- "<head><title>500 Internal Privoxy Error</title></head>\r\n"
+ "<head>\r\n"
+ " <title>500 Internal Privoxy Error</title>\r\n"
+ " <link rel=\"shortcut icon\" href=\"" CGI_PREFIX "error-favicon.ico\" type=\"image/x-icon\">"
+ "</head>\r\n"
"<body>\r\n"
"<h1>500 Internal Privoxy Error</h1>\r\n"
"<p>Privoxy <b>ran out of memory</b> while processing your request.</p>\r\n"
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;
}
"500 Internal Privoxy Error";
static const char body_prefix[] =
"<html>\r\n"
- "<head><title>500 Internal Privoxy Error</title></head>\r\n"
+ "<head>\r\n"
+ " <title>500 Internal Privoxy Error</title>\r\n"
+ " <link rel=\"shortcut icon\" href=\"" CGI_PREFIX "error-favicon.ico\" type=\"image/x-icon\">"
+ "</head>\r\n"
"<body>\r\n"
"<h1>500 Internal Privoxy Error</h1>\r\n"
"<p>Privoxy encountered an error while processing your request:</p>\r\n"
").</p>\r\n"
"</body>\r\n"
"</html>\r\n";
+ const size_t body_size = strlen(body_prefix) + strlen(template_name) + strlen(body_suffix) + 1;
assert(csp);
assert(rsp);
rsp->head_length = 0;
rsp->is_static = 0;
- rsp->body = malloc(strlen(body_prefix) + strlen(template_name) + strlen(body_suffix) + 1);
+ rsp->body = malloc(body_size);
if (rsp->body == NULL)
{
return JB_ERR_MEMORY;
}
- strcpy(rsp->body, body_prefix);
- strcat(rsp->body, template_name);
- strcat(rsp->body, body_suffix);
+ strlcpy(rsp->body, body_prefix, body_size);
+ strlcat(rsp->body, template_name, body_size);
+ strlcat(rsp->body, body_suffix, body_size);
rsp->status = strdup(status);
if (rsp->status == NULL)
"500 Internal Privoxy Error";
static const char body_prefix[] =
"<html>\r\n"
- "<head><title>500 Internal Privoxy Error</title></head>\r\n"
+ "<head>\r\n"
+ " <title>500 Internal Privoxy Error</title>\r\n"
+ " <link rel=\"shortcut icon\" href=\"" CGI_PREFIX "error-favicon.ico\" type=\"image/x-icon\">"
+ "</head>\r\n"
"<body>\r\n"
"<h1>500 Internal Privoxy Error</h1>\r\n"
"<p>Privoxy encountered an error while processing your request:</p>\r\n"
static const char body_suffix[] =
"</b></p>\r\n"
"<p>Please "
- "<a href=\"http://sourceforge.net/tracker/?group_id=11118&atid=111118\">"
+ "<a href=\"http://sourceforge.net/tracker/?group_id=11118&atid=111118\">"
"file a bug report</a>.</p>\r\n"
"</body>\r\n"
"</html>\r\n";
char errnumbuf[30];
+ /*
+ * Due to sizeof(errnumbuf), body_size will be slightly
+ * bigger than necessary but it doesn't really matter.
+ */
+ const size_t body_size = strlen(body_prefix) + sizeof(errnumbuf) + strlen(body_suffix) + 1;
assert(csp);
assert(rsp);
rsp->content_length = 0;
rsp->head_length = 0;
rsp->is_static = 0;
+ rsp->reason = RSP_REASON_INTERNAL_ERROR;
snprintf(errnumbuf, sizeof(errnumbuf), "%d", error_to_report);
- rsp->body = malloc(strlen(body_prefix) + strlen(errnumbuf) + strlen(body_suffix) + 1);
+ rsp->body = malloc(body_size);
if (rsp->body == NULL)
{
return JB_ERR_MEMORY;
}
- strcpy(rsp->body, body_prefix);
- strcat(rsp->body, errnumbuf);
- strcat(rsp->body, body_suffix);
+ strlcpy(rsp->body, body_prefix, body_size);
+ strlcat(rsp->body, errnumbuf, body_size);
+ strlcat(rsp->body, body_suffix, body_size);
rsp->status = strdup(status);
if (rsp->status == NULL)
* HTTP header - e.g.:
* "Sun, 06 Nov 1994 08:49:37 GMT"
*
+ * XXX: Should probably get a third parameter for
+ * the buffer size.
+ *
* Parameters :
* 1 : time_offset = Time returned will be current time
* plus this number of seconds.
*
* Description : Fill in the missing headers in an http response,
* and flatten the headers to an http head.
+ * For HEAD requests the body is freed once
+ * the Content-Length header is set.
*
* Parameters :
* 1 : rsp = pointer to http_response to be processed
* On error, free()s rsp and returns cgi_error_memory()
*
*********************************************************************/
-struct http_response *finish_http_response(struct http_response *rsp)
+struct http_response *finish_http_response(const struct client_state *csp, struct http_response *rsp)
{
char buf[BUFFER_SIZE];
jb_err err;
err = enlist(rsp->headers, buf);
}
+ if (0 == strcmpic(csp->http->gpc, "head"))
+ {
+ /*
+ * The client only asked for the head. Dispose
+ * the body and log an offensive message.
+ *
+ * While it may seem to be a bit inefficient to
+ * prepare the body if it isn't needed, it's the
+ * only way to get the Content-Length right for
+ * dynamic pages. We could have disposed the body
+ * earlier, but not without duplicating the
+ * Content-Length setting code above.
+ */
+ log_error(LOG_LEVEL_CGI, "Preparing to give head to %s.", csp->ip_addr_str);
+ freez(rsp->body);
+ rsp->content_length = 0;
+ }
+
if (strncmpic(rsp->status, "302", 3))
{
/*
* is older than Privoxy's error message, the server would send status code
* 304 and the browser would display the outdated error message again and again.
*
- * For documents delivered with status code 404 or 503 we set "Last-Modified"
+ * For documents delivered with status code 403, 404 and 503 we set "Last-Modified"
* to Tim Berners-Lee's birthday, which predates the age of any page on the web
* and can be safely used to "revalidate" without getting a status code 304.
*
get_http_time(0, buf);
if (!err) err = enlist_unique_header(rsp->headers, "Date", buf);
- if (!strncmpic(rsp->status, "404", 3) || !strncmpic(rsp->status, "503", 3))
+ if (!strncmpic(rsp->status, "403", 3)
+ || !strncmpic(rsp->status, "404", 3)
+ || !strncmpic(rsp->status, "503", 3))
{
if (!err) err = enlist_unique_header(rsp->headers, "Last-Modified", "Wed, 08 Jun 1955 12:00:00 GMT");
}
* Function : template_load
*
* Description : CGI support function that loads a given HTML
- * template from the confdir, ignoring comment
- * lines and following #include statements up to
- * a depth of 1.
+ * template, ignoring comment lines and following
+ * #include statements up to a depth of 1.
*
* Parameters :
* 1 : csp = Current client state (buffers, headers, etc...)
}
}
- /* Generate full path */
+ /*
+ * Generate full path using either templdir
+ * or confdir/templates as base directory.
+ */
+ if (NULL != csp->config->templdir)
+ {
+ templates_dir_path = strdup(csp->config->templdir);
+ }
+ else
+ {
+ templates_dir_path = make_path(csp->config->confdir, "templates");
+ }
- templates_dir_path = make_path(csp->config->confdir, "templates");
if (templates_dir_path == NULL)
{
+ log_error(LOG_LEVEL_ERROR, "Out of memory while generating template path for %s.",
+ templatename);
return JB_ERR_MEMORY;
}
free(templates_dir_path);
if (full_path == NULL)
{
+ log_error(LOG_LEVEL_ERROR, "Out of memory while generating full template path for %s.",
+ templatename);
return JB_ERR_MEMORY;
}
file_buffer = strdup("");
if (file_buffer == NULL)
{
+ log_error(LOG_LEVEL_ERROR, "Not enough free memory to buffer %s.", full_path);
free(full_path);
return JB_ERR_MEMORY;
}
if (!err) err = map_block_killer(exports, "can-toggle");
#endif
- snprintf(buf, 20, "%d", csp->config->hport);
+ snprintf(buf, sizeof(buf), "%d", csp->config->hport);
if (!err) err = map(exports, "my-port", 1, buf, 1);
if(!strcmp(CODE_STATUS, "stable"))
assert(name);
assert(strlen(name) < 490);
- snprintf(buf, 1000, "if-%s-start.*if-%s-end", name, name);
+ snprintf(buf, sizeof(buf), "if-%s-start.*if-%s-end", name, name);
return map(exports, buf, 1, "", 1);
}
assert(name);
assert(strlen(name) < 490);
- snprintf(buf, 500, "if-%s-start", name);
+ snprintf(buf, sizeof(buf), "if-%s-start", name);
err = map(exports, buf, 1, "", 1);
if (err)
return err;
}
- snprintf(buf, 500, "if-%s-end", name);
+ snprintf(buf, sizeof(buf), "if-%s-end", name);
return map(exports, buf, 1, "", 1);
}
assert(name);
assert(strlen(name) < 480);
- snprintf(buf, 1000, (choose_first
+ snprintf(buf, sizeof(buf), (choose_first
? "else-not-%s@.*@endif-%s"
: "if-%s-then@.*@else-not-%s"),
name, name);
return err;
}
- snprintf(buf, 1000, (choose_first ? "if-%s-then" : "endif-%s"), name);
+ snprintf(buf, sizeof(buf), (choose_first ? "if-%s-then" : "endif-%s"), name);
return map(exports, buf, 1, "", 1);
}
{
char *html_encoded_prefix;
+ /*
+ * Line breaks would be great, but break
+ * the "blocked" template's JavaScript.
+ */
string_append(&result, "<li><a href=\"");
html_encoded_prefix = html_encode(CGI_PREFIX);
if (html_encoded_prefix == NULL)
string_append(&result, d->name);
string_append(&result, "\">");
string_append(&result, d->description);
- string_append(&result, "</a></li>\n");
+ string_append(&result, "</a></li>");
}
}