-const char cgi_rcs[] = "$Id: cgi.c,v 1.116 2009/03/15 14:59:34 fabiankeil Exp $";
+const char cgi_rcs[] = "$Id: cgi.c,v 1.130 2011/04/19 13:00:47 fabiankeil Exp $";
/*********************************************************************
*
* File : $Source: /cvsroot/ijbswa/current/cgi.c,v $
#include <limits.h>
#include <assert.h>
+#ifdef FEATURE_COMPRESSION
+#include <zlib.h>
+#endif
+
#include "project.h"
#include "cgi.h"
#include "list.h"
#if defined(FEATURE_CGI_EDIT_ACTIONS) || defined(FEATURE_TOGGLE)
#include "cgiedit.h"
#endif /* defined(FEATURE_CGI_EDIT_ACTIONS) || defined (FEATURE_TOGGLE) */
-#include "loadcfg.h"
+
/* loadcfg.h is for global_toggle_state only */
-#ifdef FEATURE_PTHREAD
-#include "jcc.h"
+#include "loadcfg.h"
/* jcc.h is for mutex semaphore globals only */
-#endif /* def FEATURE_PTHREAD */
+#include "jcc.h"
+
const char cgi_h_rcs[] = CGI_H_VERSION;
/*
if (!err)
{
/* It worked */
- rsp->reason = RSP_REASON_CGI_CALL;
+ rsp->crunch_reason = CGI_CALL;
return finish_http_response(csp, rsp);
}
else
* Parameters :
* 1 : csp = Current client state (buffers, headers, etc...)
* 2 : templatename = Which template should be used for the answer
- * 3 : sys_err = system error number
*
* Returns : A http_response. If we run out of memory, this
* will be cgi_error_memory().
*
*********************************************************************/
struct http_response *error_response(struct client_state *csp,
- const char *templatename,
- int sys_err)
+ const char *templatename)
{
jb_err err;
struct http_response *rsp;
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, "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)
{
if (!strcmp(templatename, "no-such-domain"))
{
rsp->status = strdup("404 No such domain");
- if (rsp->status == NULL)
- {
- free_map(exports);
- free_http_response(rsp);
- return cgi_error_memory();
- }
- rsp->reason = RSP_REASON_NO_SUCH_DOMAIN;
+ rsp->crunch_reason = NO_SUCH_DOMAIN;
}
else if (!strcmp(templatename, "forwarding-failed"))
{
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 (!err) rsp->status = strdup("503 Forwarding failure");
- if ((rsp->status == NULL) || (NULL == csp->error_message) || err)
+ if ((NULL == csp->error_message) || err)
{
free_map(exports);
free_http_response(rsp);
return cgi_error_memory();
}
- rsp->reason = RSP_REASON_FORWARDING_FAILED;
+
+ rsp->status = strdup("503 Forwarding failure");
+ rsp->crunch_reason = FORWARDING_FAILED;
}
else if (!strcmp(templatename, "connect-failed"))
{
rsp->status = strdup("503 Connect failed");
- if (rsp->status == NULL)
- {
- free_map(exports);
- free_http_response(rsp);
- return cgi_error_memory();
- }
- rsp->reason = RSP_REASON_CONNECT_FAILED;
+ rsp->crunch_reason = CONNECT_FAILED;
+ }
+ else if (!strcmp(templatename, "connection-timeout"))
+ {
+ rsp->status = strdup("504 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->crunch_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);
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;
}
rsp->content_length = 0;
rsp->head_length = 0;
rsp->is_static = 0;
- rsp->reason = RSP_REASON_INTERNAL_ERROR;
+ rsp->crunch_reason = INTERNAL_ERROR;
snprintf(errnumbuf, sizeof(errnumbuf), "%d", error_to_report);
string_join (&result, string_toupper(item));
string_append(&result, "\">");
string_append(&result, item);
- string_append(&result, "</a> ");
+ string_append(&result, "</a>");
return result;
}
/* get and save the gmt */
#if HAVE_GMTIME_R
t = gmtime_r(¤t_time, &dummy);
-#elif FEATURE_PTHREAD
+#elif defined(MUTEX_LOCKS_AVAILABLE)
privoxy_mutex_lock(&gmtime_mutex);
t = gmtime(¤t_time);
privoxy_mutex_unlock(&gmtime_mutex);
#if HAVE_LOCALTIME_R
timeptr = localtime_r(¤t_time, &dummy);
-#elif FEATURE_PTHREAD
+#elif defined(MUTEX_LOCKS_AVAILABLE)
privoxy_mutex_lock(&localtime_mutex);
timeptr = localtime(¤t_time);
privoxy_mutex_unlock(&localtime_mutex);
}
+
+#ifdef FEATURE_COMPRESSION
+/*********************************************************************
+ *
+ * Function : compress_buffer
+ *
+ * Description : Compresses the content of a buffer with zlib's deflate
+ * Allocates a new buffer for the result, free'ing it is
+ * up to the caller.
+ *
+ * XXX: We should add a config option for the
+ * compression level.
+ *
+ *
+ * Parameters :
+ * 1 : buffer = buffer whose content should be compressed
+ * 2 : buffer_length = length of the buffer
+ *
+ * Returns : NULL on error, otherwise a pointer to the compressed
+ * content of the input buffer.
+ *
+ *********************************************************************/
+char *compress_buffer(char *buffer, size_t *buffer_length)
+{
+ char *compressed_buffer;
+ size_t new_length = *buffer_length;
+
+ compressed_buffer = malloc(new_length);
+ if (NULL == compressed_buffer)
+ {
+ log_error(LOG_LEVEL_FATAL,
+ "Out of memory allocation compression buffer.");
+ }
+
+ if (Z_OK != compress2((Bytef *)compressed_buffer, &new_length,
+ (Bytef *)buffer, *buffer_length, Z_DEFAULT_COMPRESSION))
+ {
+ log_error(LOG_LEVEL_ERROR, "Error in compress2()");
+ freez(compressed_buffer);
+ return NULL;
+ }
+
+ log_error(LOG_LEVEL_RE_FILTER,
+ "Compressed content from %d to %d bytes.", *buffer_length, new_length);
+
+ *buffer_length = new_length;
+
+ return compressed_buffer;
+
+}
+#endif
+
+
/*********************************************************************
*
* Function : finish_http_response
{
rsp->content_length = rsp->body ? strlen(rsp->body) : 0;
}
+
+#ifdef FEATURE_COMPRESSION
+ if (!err && (csp->flags & CSP_FLAG_CLIENT_SUPPORTS_DEFLATE)
+ && (rsp->content_length > LOWER_LENGTH_LIMIT_FOR_COMRPESSION))
+ {
+ char *compressed_content;
+
+ compressed_content = compress_buffer(rsp->body, &rsp->content_length);
+ if (NULL != compressed_content)
+ {
+ freez(rsp->body);
+ rsp->body = compressed_content;
+ }
+ err = enlist_unique_header(rsp->headers, "Content-Encoding", "deflate");
+ }
+#endif
+
if (!err)
{
snprintf(buf, sizeof(buf), "Content-Length: %d", (int)rsp->content_length);
if (!err) err = enlist_unique_header(rsp->headers, "Date", buf);
if (!strncmpic(rsp->status, "403", 3)
|| !strncmpic(rsp->status, "404", 3)
- || !strncmpic(rsp->status, "503", 3))
+ || !strncmpic(rsp->status, "502", 3)
+ || !strncmpic(rsp->status, "503", 3)
+ || !strncmpic(rsp->status, "504", 3))
{
if (!err) err = enlist_unique_header(rsp->headers, "Last-Modified", "Wed, 08 Jun 1955 12:00:00 GMT");
}
if (!err) err = enlist_unique_header(rsp->headers, "Pragma", "no-cache");
}
- /*
- * Quoting RFC 2616:
- *
- * HTTP/1.1 applications that do not support persistent connections MUST
- * include the "close" connection option in every message.
- */
- if (!err) err = enlist_unique_header(rsp->headers, "Connection", "close");
+ if (!err && !(csp->flags & CSP_FLAG_CLIENT_CONNECTION_KEEP_ALIVE))
+ {
+ err = enlist_unique_header(rsp->headers, "Connection", "close");
+ }
/*
* Write the head
* HTML template by replacing @name@ with value using
* pcrs, for each item in the output map.
*
- * Note that a leading '$' charachter in the export map's
+ * Note that a leading '$' character in the export map's
* values will be stripped and toggle on backreference
* interpretation.
*