+
+ if (!err) err = map(exports, "forwarding-type", 1, socks_type, 1);
+ if (!err) err = map(exports, "error-message", 1, html_encode(csp->error_message), 0);
+ if ((NULL == csp->error_message) || err)
+ {
+ free_map(exports);
+ free_http_response(rsp);
+ return cgi_error_memory();
+ }
+
+ rsp->status = strdup("503 Forwarding failure");
+ rsp->reason = RSP_REASON_FORWARDING_FAILED;
+ }
+ else if (!strcmp(templatename, "connect-failed"))
+ {
+ rsp->status = strdup("503 Connect failed");
+ rsp->reason = RSP_REASON_CONNECT_FAILED;
+ }
+ else if (!strcmp(templatename, "connection-timeout"))
+ {
+ rsp->status = strdup("504 Connection timeout");
+ rsp->reason = RSP_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;
+ }
+
+ if (rsp->status == NULL)
+ {
+ free_map(exports);
+ free_http_response(rsp);
+ return cgi_error_memory();
+ }
+
+ err = template_fill_for_cgi(csp, templatename, exports, rsp);
+ if (err)
+ {
+ free_http_response(rsp);
+ return cgi_error_memory();
+ }
+
+ return finish_http_response(csp, rsp);
+}
+
+
+/*********************************************************************
+ *
+ * Function : cgi_error_disabled
+ *
+ * Description : CGI function that is called to generate an error
+ * response if the actions editor or toggle CGI are
+ * accessed despite having being disabled at compile-
+ * or run-time, or if the user followed an untrusted link
+ * to access a unsafe CGI feature that is only reachable
+ * through Privoxy directly.
+ *
+ * Parameters :
+ * 1 : csp = Current client state (buffers, headers, etc...)
+ * 2 : rsp = http_response data structure for output
+ *
+ * CGI Parameters : none
+ *
+ * Returns : JB_ERR_OK on success
+ * JB_ERR_MEMORY on out-of-memory error.
+ *
+ *********************************************************************/
+jb_err cgi_error_disabled(const struct client_state *csp,
+ struct http_response *rsp)
+{
+ struct map *exports;
+
+ assert(csp);
+ assert(rsp);
+
+ if (NULL == (exports = default_exports(csp, "cgi-error-disabled")))
+ {
+ return JB_ERR_MEMORY;
+ }
+ if (map(exports, "url", 1, html_encode(csp->http->url), 0))
+ {
+ /* Not important enough to do anything */
+ log_error(LOG_LEVEL_ERROR, "Failed to fill in url.");
+ }
+
+ return template_fill_for_cgi(csp, "cgi-error-disabled", exports, rsp);
+}
+
+
+/*********************************************************************
+ *
+ * Function : cgi_init_error_messages
+ *
+ * Description : Call at the start of the program to initialize
+ * the error message used by cgi_error_memory().
+ *
+ * Parameters : N/A
+ *
+ * Returns : N/A
+ *
+ *********************************************************************/
+void cgi_init_error_messages(void)
+{
+ memset(cgi_error_memory_response, '\0', sizeof(*cgi_error_memory_response));
+ cgi_error_memory_response->head =
+ "HTTP/1.0 500 Internal Privoxy Error\r\n"
+ "Content-Type: text/html\r\n"
+ "\r\n";
+ cgi_error_memory_response->body =
+ "<html>\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"
+ "<p>Please contact your proxy administrator, or try again later</p>\r\n"
+ "</body>\r\n"
+ "</html>\r\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;
+}
+
+
+/*********************************************************************
+ *
+ * Function : cgi_error_memory
+ *
+ * Description : Called if a CGI function runs out of memory.
+ * Returns a statically-allocated error response.
+ *
+ * Parameters : N/A
+ *
+ * Returns : http_response data structure for output. This is
+ * statically allocated, for obvious reasons.
+ *
+ *********************************************************************/
+struct http_response *cgi_error_memory(void)
+{
+ /* assert that it's been initialized. */
+ assert(cgi_error_memory_response->head);
+
+ return cgi_error_memory_response;
+}
+
+
+/*********************************************************************
+ *
+ * Function : cgi_error_no_template
+ *
+ * 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
+ * parameters.
+ *
+ * Parameters :
+ * 1 : csp = Current client state (buffers, headers, etc...)
+ * 2 : rsp = http_response data structure for output
+ * 3 : template_name = Name of template that could not
+ * be loaded.
+ *
+ * Returns : JB_ERR_OK on success
+ * JB_ERR_MEMORY on out-of-memory error.
+ *
+ *********************************************************************/
+jb_err cgi_error_no_template(const struct client_state *csp,
+ struct http_response *rsp,
+ const char *template_name)
+{
+ static const char status[] =
+ "500 Internal Privoxy Error";
+ static const char body_prefix[] =
+ "<html>\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><b>Could not load template file <code>";
+ static const char body_suffix[] =
+ "</code> or one of its included components.</b></p>\r\n"
+ "<p>Please contact your proxy administrator.</p>\r\n"
+ "<p>If you are the proxy administrator, please put the required file(s)"
+ "in the <code><i>(confdir)</i>/templates</code> directory. The "
+ "location of the <code><i>(confdir)</i></code> directory "
+ "is specified in the main Privoxy <code>config</code> "
+ "file. (It's typically the Privoxy install directory"
+#ifndef _WIN32
+ ", or <code>/etc/privoxy/</code>"
+#endif /* ndef _WIN32 */
+ ").</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);
+ assert(template_name);
+
+ /* Reset rsp, if needed */
+ freez(rsp->status);
+ freez(rsp->head);
+ freez(rsp->body);
+ rsp->content_length = 0;
+ rsp->head_length = 0;
+ rsp->is_static = 0;
+
+ rsp->body = malloc(body_size);
+ if (rsp->body == NULL)
+ {
+ return JB_ERR_MEMORY;
+ }
+ 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)
+ {
+ return JB_ERR_MEMORY;
+ }
+
+ return JB_ERR_OK;
+}
+
+
+/*********************************************************************
+ *
+ * Function : cgi_error_unknown
+ *
+ * Description : Almost-CGI function that is called if an unexpected
+ * error occurs in the top-level CGI dispatcher.
+ * In this context, "unexpected" means "anything other
+ * than JB_ERR_MEMORY or JB_ERR_CGI_PARAMS" - CGIs are
+ * expected to handle all other errors internally,
+ * since they can give more relavent error messages
+ * that way.
+ *
+ * Note this is not a true CGI, it takes an error
+ * code rather than a map of parameters.
+ *
+ * Parameters :
+ * 1 : csp = Current client state (buffers, headers, etc...)
+ * 2 : rsp = http_response data structure for output
+ * 3 : error_to_report = Error code to report.
+ *
+ * Returns : JB_ERR_OK on success
+ * JB_ERR_MEMORY on out-of-memory error.
+ *
+ *********************************************************************/
+jb_err cgi_error_unknown(const struct client_state *csp,
+ struct http_response *rsp,
+ jb_err error_to_report)
+{
+ static const char status[] =
+ "500 Internal Privoxy Error";
+ static const char body_prefix[] =
+ "<html>\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><b>Unexpected internal error: ";
+ static const char body_suffix[] =
+ "</b></p>\r\n"
+ "<p>Please "
+ "<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);
+
+ /* Reset rsp, if needed */
+ freez(rsp->status);
+ freez(rsp->head);
+ freez(rsp->body);
+ 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(body_size);
+ if (rsp->body == NULL)
+ {
+ return JB_ERR_MEMORY;
+ }
+ 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)
+ {
+ return JB_ERR_MEMORY;
+ }
+
+ return JB_ERR_OK;
+}
+
+
+/*********************************************************************
+ *
+ * Function : cgi_error_bad_param
+ *
+ * Description : CGI function that is called if the parameters
+ * (query string) for a CGI were wrong.
+ *
+ * Parameters :
+ * 1 : csp = Current client state (buffers, headers, etc...)
+ * 2 : rsp = http_response data structure for output
+ *
+ * CGI Parameters : none
+ *
+ * Returns : JB_ERR_OK on success
+ * JB_ERR_MEMORY on out-of-memory error.
+ *
+ *********************************************************************/
+jb_err cgi_error_bad_param(const struct client_state *csp,
+ struct http_response *rsp)
+{
+ struct map *exports;
+
+ assert(csp);
+ assert(rsp);
+
+ if (NULL == (exports = default_exports(csp, NULL)))
+ {
+ return JB_ERR_MEMORY;