-const char parsers_rcs[] = "$Id: parsers.c,v 1.130 2008/05/19 17:18:04 fabiankeil Exp $";
+const char parsers_rcs[] = "$Id: parsers.c,v 1.151 2009/02/15 14:46:35 fabiankeil Exp $";
/*********************************************************************
*
* File : $Source: /cvsroot/ijbswa/current/parsers.c,v $
* `client_if_none_match', `get_destination_from_headers',
* `parse_header_time', `decompress_iob' and `server_set_cookie'.
*
- * Copyright : Written by and Copyright (C) 2001-2008 the SourceForge
+ * Copyright : Written by and Copyright (C) 2001-2009 the
* Privoxy team. http://www.privoxy.org/
*
* Based on the Internet Junkbuster originally written
*
* Revisions :
* $Log: parsers.c,v $
+ * Revision 1.151 2009/02/15 14:46:35 fabiankeil
+ * Don't let hide-referrer{conditional-*}} pass
+ * Referer headers without http URLs.
+ *
+ * Revision 1.150 2008/12/04 18:12:19 fabiankeil
+ * Fix some cparser warnings.
+ *
+ * Revision 1.149 2008/11/21 18:39:53 fabiankeil
+ * In case of CONNECT requests there's no point
+ * in trying to keep the connection alive.
+ *
+ * Revision 1.148 2008/11/16 12:43:49 fabiankeil
+ * Turn keep-alive support into a runtime feature
+ * that is disabled by setting keep-alive-timeout
+ * to a negative value.
+ *
+ * Revision 1.147 2008/11/04 17:20:31 fabiankeil
+ * HTTP/1.1 responses without Connection
+ * header imply keep-alive. Act accordingly.
+ *
+ * Revision 1.146 2008/10/12 16:46:35 fabiankeil
+ * Remove obsolete warning about delayed delivery with chunked
+ * transfer encoding and FEATURE_CONNECTION_KEEP_ALIVE enabled.
+ *
+ * Revision 1.145 2008/10/09 18:21:41 fabiankeil
+ * Flush work-in-progress changes to keep outgoing connections
+ * alive where possible. Incomplete and mostly #ifdef'd out.
+ *
+ * Revision 1.144 2008/09/21 13:59:33 fabiankeil
+ * Treat unknown change-x-forwarded-for parameters as fatal errors.
+ *
+ * Revision 1.143 2008/09/21 13:36:52 fabiankeil
+ * If change-x-forwarded-for{add} is used and the client
+ * sends multiple X-Forwarded-For headers, append the client's
+ * IP address to each one of them. "Traditionally" we would
+ * lose all but the last one.
+ *
+ * Revision 1.142 2008/09/20 10:04:33 fabiankeil
+ * Remove hide-forwarded-for-headers action which has
+ * been obsoleted by change-x-forwarded-for{block}.
+ *
+ * Revision 1.141 2008/09/19 15:26:28 fabiankeil
+ * Add change-x-forwarded-for{} action to block or add
+ * X-Forwarded-For headers. Mostly based on code removed
+ * before 3.0.7.
+ *
+ * Revision 1.140 2008/09/12 17:51:43 fabiankeil
+ * - A few style fixes.
+ * - Remove a pointless cast.
+ *
+ * Revision 1.139 2008/09/04 08:13:58 fabiankeil
+ * Prepare for critical sections on Windows by adding a
+ * layer of indirection before the pthread mutex functions.
+ *
+ * Revision 1.138 2008/08/30 12:03:07 fabiankeil
+ * Remove FEATURE_COOKIE_JAR.
+ *
+ * Revision 1.137 2008/05/30 15:50:08 fabiankeil
+ * Remove questionable micro-optimizations
+ * whose usefulness has never been measured.
+ *
+ * Revision 1.136 2008/05/26 16:02:24 fabiankeil
+ * s@Insufficent@Insufficient@
+ *
+ * Revision 1.135 2008/05/21 20:12:10 fabiankeil
+ * The whole point of strclean() is to modify the
+ * first parameter, so don't mark it immutable,
+ * even though the compiler lets us get away with it.
+ *
+ * Revision 1.134 2008/05/21 19:27:25 fabiankeil
+ * As the wafer actions are gone, we can stop including encode.h.
+ *
+ * Revision 1.133 2008/05/21 15:50:47 fabiankeil
+ * Ditch cast from (char **) to (char **).
+ *
+ * Revision 1.132 2008/05/21 15:47:14 fabiankeil
+ * Streamline sed()'s prototype and declare
+ * the header parse and add structures static.
+ *
+ * Revision 1.131 2008/05/20 20:13:30 fabiankeil
+ * Factor update_server_headers() out of sed(), ditch the
+ * first_run hack and make server_patterns_light static.
+ *
* Revision 1.130 2008/05/19 17:18:04 fabiankeil
* Wrap memmove() calls in string_move()
* to document the purpose in one place.
#endif /* def FEATURE_PTHREAD */
#include "list.h"
#include "parsers.h"
-#include "encode.h"
#include "ssplit.h"
#include "errlog.h"
#include "jbsockets.h"
static jb_err parse_header_time(const char *header_time, time_t *result);
static jb_err crumble (struct client_state *csp, char **header);
-static jb_err connection (struct client_state *csp, char **header);
static jb_err filter_header (struct client_state *csp, char **header);
+static jb_err client_connection (struct client_state *csp, char **header);
static jb_err client_referrer (struct client_state *csp, char **header);
static jb_err client_uagent (struct client_state *csp, char **header);
static jb_err client_ua (struct client_state *csp, char **header);
static jb_err client_x_filter (struct client_state *csp, char **header);
static jb_err client_range (struct client_state *csp, char **header);
static jb_err server_set_cookie (struct client_state *csp, char **header);
+static jb_err server_connection (struct client_state *csp, char **header);
static jb_err server_content_type (struct client_state *csp, char **header);
-static jb_err server_content_length (struct client_state *csp, char **header);
+static jb_err server_adjust_content_length(struct client_state *csp, char **header);
static jb_err server_content_md5 (struct client_state *csp, char **header);
static jb_err server_content_encoding (struct client_state *csp, char **header);
static jb_err server_transfer_coding (struct client_state *csp, char **header);
static jb_err server_last_modified (struct client_state *csp, char **header);
static jb_err server_content_disposition(struct client_state *csp, char **header);
+#ifdef FEATURE_CONNECTION_KEEP_ALIVE
+static jb_err server_save_content_length(struct client_state *csp, char **header);
+#endif /* def FEATURE_CONNECTION_KEEP_ALIVE */
+
static jb_err client_host_adder (struct client_state *csp);
static jb_err client_xtra_adder (struct client_state *csp);
-static jb_err connection_close_adder (struct client_state *csp);
+static jb_err client_x_forwarded_for_adder(struct client_state *csp);
+static jb_err client_connection_header_adder(struct client_state *csp);
+static jb_err server_connection_close_adder(struct client_state *csp);
static jb_err create_forged_referrer(char **header, const char *hostport);
static jb_err create_fake_referrer(char **header, const char *fake_referrer);
static jb_err handle_conditional_hide_referrer_parameter(char **header,
const char *host, const int parameter_conditional_block);
+static const char *get_appropiate_connection_header(const struct client_state *csp);
+
+/*
+ * List of functions to run on a list of headers.
+ */
+struct parsers
+{
+ /** The header prefix to match */
+ const char *str;
+
+ /** The length of the prefix to match */
+ const size_t len;
+
+ /** The function to apply to this line */
+ const parser_func_ptr parser;
+};
-const struct parsers client_patterns[] = {
+static const struct parsers client_patterns[] = {
{ "referer:", 8, client_referrer },
{ "user-agent:", 11, client_uagent },
{ "ua-", 3, client_ua },
{ "Host:", 5, client_host },
{ "if-modified-since:", 18, client_if_modified_since },
{ "Keep-Alive:", 11, crumble },
- { "connection:", 11, connection },
+ { "connection:", 11, client_connection },
{ "proxy-connection:", 17, crumble },
{ "max-forwards:", 13, client_max_forwards },
{ "Accept-Language:", 16, client_accept_language },
{ NULL, 0, NULL }
};
-const struct parsers server_patterns[] = {
+static const struct parsers server_patterns[] = {
{ "HTTP/", 5, server_http },
{ "set-cookie:", 11, server_set_cookie },
- { "connection:", 11, connection },
+ { "connection:", 11, server_connection },
{ "Content-Type:", 13, server_content_type },
{ "Content-MD5:", 12, server_content_md5 },
{ "Content-Encoding:", 17, server_content_encoding },
+#ifdef FEATURE_CONNECTION_KEEP_ALIVE
+ { "Content-Length:", 15, server_save_content_length },
+#endif /* def FEATURE_CONNECTION_KEEP_ALIVE */
{ "Transfer-Encoding:", 18, server_transfer_coding },
{ "Keep-Alive:", 11, crumble },
{ "content-disposition:", 20, server_content_disposition },
{ "Last-Modified:", 14, server_last_modified },
{ "*", 0, crunch_server_header },
{ "*", 0, filter_header },
- { NULL, 0, NULL }
+ { NULL, 0, NULL }
};
-const add_header_func_ptr add_client_headers[] = {
+static const add_header_func_ptr add_client_headers[] = {
client_host_adder,
+ client_x_forwarded_for_adder,
client_xtra_adder,
/* Temporarily disabled: client_accept_encoding_adder, */
- connection_close_adder,
+ client_connection_header_adder,
NULL
};
-const add_header_func_ptr add_server_headers[] = {
- connection_close_adder,
+static const add_header_func_ptr add_server_headers[] = {
+ server_connection_close_adder,
NULL
};
*/
if (need > csp->config->buffer_limit)
{
- log_error(LOG_LEVEL_INFO, "Buffer limit reached while extending the buffer (iob)");
+ log_error(LOG_LEVEL_INFO,
+ "Buffer limit reached while extending the buffer (iob). Needed: %d. Limit: %d",
+ need, csp->config->buffer_limit);
return JB_ERR_MEMORY;
}
cur = csp->iob->cur;
- if (bufsize < 10)
+ if (bufsize < (size_t)10)
{
/*
* This is to protect the parsing of gzipped data,
*/
assert(zstr.avail_out == tmpbuf + bufsize - (char *)zstr.next_out);
assert((char *)zstr.next_out == tmpbuf + ((char *)oldnext_out - buf));
- assert(zstr.avail_out > 0);
+ assert(zstr.avail_out > 0U);
buf = tmpbuf;
}
&& (csp->iob->eod <= csp->iob->buf + csp->iob->size))
{
const size_t new_size = (size_t)(csp->iob->eod - csp->iob->cur);
- if (new_size > 0)
+ if (new_size > (size_t)0)
{
log_error(LOG_LEVEL_RE_FILTER,
"Decompression successful. Old size: %d, new size: %d.",
/* FIXME No way to handle error properly */
log_error(LOG_LEVEL_FATAL, "Out of memory in get_header_line()");
}
+ assert(ret != NULL);
iob->cur = p+1;
if (*ret == '\0')
{
freez(ret);
- return(NULL);
+ return NULL;
}
- return(ret);
+ return ret;
}
/*
* Found: return pointer to start of value
*/
- ret = (char *) (cur_entry->str + length);
+ ret = cur_entry->str + length;
while (*ret && ijb_isspace(*ret)) ret++;
- return(ret);
+ return ret;
}
}
}
* header lines.
*
* Parameters :
- * 1 : pats = list of patterns to match against headers
- * 2 : more_headers = list of functions to add more
- * headers (client or server)
- * 3 : csp = Current client state (buffers, headers, etc...)
+ * 1 : csp = Current client state (buffers, headers, etc...)
+ * 2 : filter_server_headers = Boolean to switch between
+ * server and header filtering.
*
* Returns : JB_ERR_OK in case off success, or
* JB_ERR_MEMORY on out-of-memory error.
*
*********************************************************************/
-jb_err sed(const struct parsers pats[],
- const add_header_func_ptr more_headers[],
- struct client_state *csp)
+jb_err sed(struct client_state *csp, int filter_server_headers)
{
+ /* XXX: use more descriptive names. */
struct list_entry *p;
const struct parsers *v;
const add_header_func_ptr *f;
jb_err err = JB_ERR_OK;
- assert(more_headers != NULL);
+ if (filter_server_headers)
+ {
+ v = server_patterns;
+ f = add_server_headers;
+ }
+ else
+ {
+ v = client_patterns;
+ f = add_client_headers;
+ }
scan_headers(csp);
- for (v = pats; (err == JB_ERR_OK) && (v->str != NULL); v++)
+ while ((err == JB_ERR_OK) && (v->str != NULL))
{
for (p = csp->headers->first; (err == JB_ERR_OK) && (p != NULL); p = p->next)
{
if ((strncmpic(p->str, v->str, v->len) == 0) ||
(v->len == CHECK_EVERY_HEADER_REMAINING))
{
- err = v->parser(csp, (char **)&(p->str));
+ err = v->parser(csp, &(p->str));
}
}
+ v++;
}
- /* place any additional headers on the csp->headers list */
- for (f = more_headers; (err == JB_ERR_OK) && (*f) ; f++)
+ /* place additional headers on the csp->headers list */
+ while ((err == JB_ERR_OK) && (*f))
{
err = (*f)(csp);
+ f++;
}
return err;
jb_err err = JB_ERR_OK;
static const struct parsers server_patterns_light[] = {
- { "Content-Length:", 15, server_content_length },
+ { "Content-Length:", 15, server_adjust_content_length },
{ "Transfer-Encoding:", 18, server_transfer_coding },
#ifdef FEATURE_ZLIB
{ "Content-Encoding:", 17, server_content_encoding },
#endif /* def FEATURE_ZLIB */
- { NULL, 0, NULL }
+ { NULL, 0, NULL }
};
if (strncmpic(csp->http->cmd, "HEAD", 4))
{
log_error(LOG_LEVEL_ERROR, "Inconsistent configuration: "
"tagging enabled, but no taggers available.");
- return(JB_ERR_OK);
+ return JB_ERR_OK;
}
for (i = 0; i < MAX_AF_FILES; i++)
if (0 > hits)
{
/* Regex failure, log it but continue anyway. */
+ assert(NULL != header);
log_error(LOG_LEVEL_ERROR,
"Problems with tagger \'%s\' and header \'%s\': %s",
b->name, *header, pcrs_strerror(hits));
{
log_error(LOG_LEVEL_ERROR, "Inconsistent configuration: "
"header filtering enabled, but no matching filters available.");
- return(JB_ERR_OK);
+ return JB_ERR_OK;
}
for (i = 0; i < MAX_AF_FILES; i++)
freez(*header);
}
- return(JB_ERR_OK);
+ return JB_ERR_OK;
}
/*********************************************************************
*
- * Function : connection
+ * Function : server_connection
*
* Description : Makes sure that the value of the Connection: header
- * is "close" and signals connection_close_adder
+ * is "close" and signals server_connection_close_adder
* to do nothing.
*
* Parameters :
* JB_ERR_MEMORY on out-of-memory error.
*
*********************************************************************/
-static jb_err connection(struct client_state *csp, char **header)
+static jb_err server_connection(struct client_state *csp, char **header)
{
char *old_header = *header;
/* Do we have a 'Connection: close' header? */
if (strcmpic(*header, "Connection: close"))
{
- /* No, create one */
+#ifdef FEATURE_CONNECTION_KEEP_ALIVE
+ if ((csp->config->feature_flags &
+ RUNTIME_FEATURE_CONNECTION_KEEP_ALIVE)
+ && !strcmpic(*header, "Connection: keep-alive"))
+ {
+ /* Remember to keep the connection alive. */
+ csp->flags |= CSP_FLAG_SERVER_CONNECTION_KEEP_ALIVE;
+ }
+#endif /* FEATURE_CONNECTION_KEEP_ALIVE */
+
*header = strdup("Connection: close");
if (header == NULL)
{
freez(old_header);
}
- /* Signal connection_close_adder() to return early. */
- if (csp->flags & CSP_FLAG_CLIENT_HEADER_PARSING_DONE)
- {
- csp->flags |= CSP_FLAG_SERVER_CONNECTION_CLOSE_SET;
- }
- else
+ /* Signal server_connection_close_adder() to return early. */
+ csp->flags |= CSP_FLAG_SERVER_CONNECTION_CLOSE_SET;
+
+ return JB_ERR_OK;
+}
+
+/*********************************************************************
+ *
+ * Function : client_connection
+ *
+ * Description : Makes sure a proper "Connection:" header is
+ * set and signals connection_header_adder
+ * to do nothing.
+ *
+ * Parameters :
+ * 1 : csp = Current client state (buffers, headers, etc...)
+ * 2 : header = On input, pointer to header to modify.
+ * On output, pointer to the modified header, or NULL
+ * to remove the header. This function frees the
+ * original string if necessary.
+ *
+ * Returns : JB_ERR_OK on success, or
+ * JB_ERR_MEMORY on out-of-memory error.
+ *
+ *********************************************************************/
+static jb_err client_connection(struct client_state *csp, char **header)
+{
+ char *old_header = *header;
+ const char *wanted_header = get_appropiate_connection_header(csp);
+
+ if (strcmpic(*header, wanted_header))
{
- csp->flags |= CSP_FLAG_CLIENT_CONNECTION_CLOSE_SET;
+ *header = strdup(wanted_header);
+ if (header == NULL)
+ {
+ return JB_ERR_MEMORY;
+ }
+ log_error(LOG_LEVEL_HEADER,
+ "Replaced: \'%s\' with \'%s\'", old_header, *header);
+ freez(old_header);
}
+ /* Signal client_connection_close_adder() to return early. */
+ csp->flags |= CSP_FLAG_CLIENT_CONNECTION_HEADER_SET;
+
return JB_ERR_OK;
}
*********************************************************************/
static jb_err crumble(struct client_state *csp, char **header)
{
+ (void)csp;
log_error(LOG_LEVEL_HEADER, "crumble crunched: %s!", *header);
freez(*header);
return JB_ERR_OK;
/*********************************************************************
*
- * Function : server_content_length
+ * Function : server_adjust_content_length
*
* Description : Adjust Content-Length header if we modified
* the body.
* JB_ERR_MEMORY on out-of-memory error.
*
*********************************************************************/
-static jb_err server_content_length(struct client_state *csp, char **header)
+static jb_err server_adjust_content_length(struct client_state *csp, char **header)
{
const size_t max_header_length = 80;
}
+#ifdef FEATURE_CONNECTION_KEEP_ALIVE
+/*********************************************************************
+ *
+ * Function : server_save_content_length
+ *
+ * Description : Save the Content-Length sent by the server.
+ *
+ * Parameters :
+ * 1 : csp = Current client state (buffers, headers, etc...)
+ * 2 : header = On input, pointer to header to modify.
+ * On output, pointer to the modified header, or NULL
+ * to remove the header. This function frees the
+ * original string if necessary.
+ *
+ * Returns : JB_ERR_OK on success, or
+ * JB_ERR_MEMORY on out-of-memory error.
+ *
+ *********************************************************************/
+static jb_err server_save_content_length(struct client_state *csp, char **header)
+{
+ unsigned int content_length = 0;
+
+ assert(*(*header+14) == ':');
+
+ if (1 != sscanf(*header+14, ": %u", &content_length))
+ {
+ log_error(LOG_LEVEL_ERROR, "Crunching invalid header: %s", *header);
+ freez(*header);
+ }
+ else
+ {
+ csp->expected_content_length = content_length;
+ csp->flags |= CSP_FLAG_CONTENT_LENGTH_SET;
+ }
+
+ return JB_ERR_OK;
+}
+#endif /* def FEATURE_CONNECTION_KEEP_ALIVE */
+
+
/*********************************************************************
*
* Function : server_content_md5
if (*header == NULL)
{
- log_error(LOG_LEVEL_HEADER, "Insufficent memory. Last-Modified header got lost, boohoo.");
+ log_error(LOG_LEVEL_HEADER, "Insufficient memory. Last-Modified header got lost, boohoo.");
}
else
{
#ifdef HAVE_GMTIME_R
timeptr = gmtime_r(&now, &gmt);
#elif FEATURE_PTHREAD
- pthread_mutex_lock(&gmtime_mutex);
+ privoxy_mutex_lock(&gmtime_mutex);
timeptr = gmtime(&now);
- pthread_mutex_unlock(&gmtime_mutex);
+ privoxy_mutex_unlock(&gmtime_mutex);
#else
timeptr = gmtime(&now);
#endif
#ifdef HAVE_GMTIME_R
timeptr = gmtime_r(&last_modified, &gmt);
#elif FEATURE_PTHREAD
- pthread_mutex_lock(&gmtime_mutex);
+ privoxy_mutex_lock(&gmtime_mutex);
timeptr = gmtime(&last_modified);
- pthread_mutex_unlock(&gmtime_mutex);
+ privoxy_mutex_unlock(&gmtime_mutex);
#else
timeptr = gmtime(&last_modified);
#endif
if (*header == NULL)
{
- log_error(LOG_LEVEL_ERROR, "Insufficent memory, header crunched without replacement.");
+ log_error(LOG_LEVEL_ERROR, "Insufficient memory, header crunched without replacement.");
return JB_ERR_MEMORY;
}
- if (LOG_LEVEL_HEADER & debug) /* Save cycles if the user isn't interested. */
- {
- days = rtime / (3600 * 24);
- hours = rtime / 3600 % 24;
- minutes = rtime / 60 % 60;
- seconds = rtime % 60;
-
- log_error(LOG_LEVEL_HEADER, "Randomized: %s (added %d da%s %d hou%s %d minut%s %d second%s",
- *header, days, (days == 1) ? "y" : "ys", hours, (hours == 1) ? "r" : "rs",
- minutes, (minutes == 1) ? "e" : "es", seconds, (seconds == 1) ? ")" : "s)");
- }
+ days = rtime / (3600 * 24);
+ hours = rtime / 3600 % 24;
+ minutes = rtime / 60 % 60;
+ seconds = rtime % 60;
+
+ log_error(LOG_LEVEL_HEADER,
+ "Randomized: %s (added %d da%s %d hou%s %d minut%s %d second%s",
+ *header, days, (days == 1) ? "y" : "ys", hours, (hours == 1) ? "r" : "rs",
+ minutes, (minutes == 1) ? "e" : "es", seconds, (seconds == 1) ? ")" : "s)");
}
else
{
if (*header == NULL)
{
log_error(LOG_LEVEL_ERROR,
- "Insufficent memory. Accept-Language header crunched without replacement.");
+ "Insufficient memory. Accept-Language header crunched without replacement.");
}
else
{
*********************************************************************/
jb_err client_x_forwarded(struct client_state *csp, char **header)
{
- if ((csp->action->flags & ACTION_HIDE_FORWARDED) != 0)
+ if (0 != (csp->action->flags & ACTION_CHANGE_X_FORWARDED_FOR))
{
- freez(*header);
- log_error(LOG_LEVEL_HEADER, "crunched x-forwarded-for!");
+ const char *parameter = csp->action->string[ACTION_STRING_CHANGE_X_FORWARDED_FOR];
+
+ if (0 == strcmpic(parameter, "block"))
+ {
+ freez(*header);
+ log_error(LOG_LEVEL_HEADER, "crunched x-forwarded-for!");
+ }
+ else if (0 == strcmpic(parameter, "add"))
+ {
+ string_append(header, ", ");
+ string_append(header, csp->ip_addr_str);
+
+ if (*header == NULL)
+ {
+ return JB_ERR_MEMORY;
+ }
+ log_error(LOG_LEVEL_HEADER,
+ "Appended client IP address to %s", *header);
+ csp->flags |= CSP_FLAG_X_FORWARDED_FOR_APPENDED;
+ }
+ else
+ {
+ log_error(LOG_LEVEL_FATAL,
+ "Invalid change-x-forwarded-for parameter: '%s'", parameter);
+ }
}
return JB_ERR_OK;
(0 == strcmpic(csp->http->gpc, "options")))
{
assert(*(*header+12) == ':');
- if (1 == sscanf(*header+12, ": %u", &max_forwards))
+ if (1 == sscanf(*header+12, ": %d", &max_forwards))
{
if (max_forwards > 0)
{
- snprintf(*header, strlen(*header)+1, "Max-Forwards: %u", --max_forwards);
- log_error(LOG_LEVEL_HEADER, "Max-Forwards value for %s request reduced to %u.",
+ snprintf(*header, strlen(*header)+1, "Max-Forwards: %d", --max_forwards);
+ log_error(LOG_LEVEL_HEADER,
+ "Max-Forwards value for %s request reduced to %d.",
csp->http->gpc, max_forwards);
}
else if (max_forwards < 0)
#ifdef HAVE_GMTIME_R
timeptr = gmtime_r(&tm, &gmt);
#elif FEATURE_PTHREAD
- pthread_mutex_lock(&gmtime_mutex);
+ privoxy_mutex_lock(&gmtime_mutex);
timeptr = gmtime(&tm);
- pthread_mutex_unlock(&gmtime_mutex);
+ privoxy_mutex_unlock(&gmtime_mutex);
#else
timeptr = gmtime(&tm);
#endif
if (*header == NULL)
{
- log_error(LOG_LEVEL_HEADER, "Insufficent memory, header crunched without replacement.");
+ log_error(LOG_LEVEL_HEADER, "Insufficient memory, header crunched without replacement.");
return JB_ERR_MEMORY;
}
- if (LOG_LEVEL_HEADER & debug) /* Save cycles if the user isn't interested. */
- {
- hours = rtime / 3600;
- minutes = rtime / 60 % 60;
- seconds = rtime % 60;
+ hours = rtime / 3600;
+ minutes = rtime / 60 % 60;
+ seconds = rtime % 60;
- log_error(LOG_LEVEL_HEADER, "Randomized: %s (%s %d hou%s %d minut%s %d second%s",
- *header, (negative) ? "subtracted" : "added", hours, (hours == 1) ? "r" : "rs",
- minutes, (minutes == 1) ? "e" : "es", seconds, (seconds == 1) ? ")" : "s)");
- }
+ log_error(LOG_LEVEL_HEADER,
+ "Randomized: %s (%s %d hou%s %d minut%s %d second%s",
+ *header, (negative) ? "subtracted" : "added", hours,
+ (hours == 1) ? "r" : "rs", minutes, (minutes == 1) ? "e" : "es",
+ seconds, (seconds == 1) ? ")" : "s)");
}
}
}
/*********************************************************************
*
- * Function : connection_close_adder
+ * Function : client_x_forwarded_for_adder
+ *
+ * Description : Used in the add_client_headers list. Called from `sed'.
+ *
+ * Parameters :
+ * 1 : csp = Current client state (buffers, headers, etc...)
+ *
+ * Returns : JB_ERR_OK on success, or
+ * JB_ERR_MEMORY on out-of-memory error.
+ *
+ *********************************************************************/
+static jb_err client_x_forwarded_for_adder(struct client_state *csp)
+{
+ char *header = NULL;
+ jb_err err;
+
+ if (!((csp->action->flags & ACTION_CHANGE_X_FORWARDED_FOR)
+ && (0 == strcmpic(csp->action->string[ACTION_STRING_CHANGE_X_FORWARDED_FOR], "add")))
+ || (csp->flags & CSP_FLAG_X_FORWARDED_FOR_APPENDED))
+ {
+ /*
+ * If we aren't adding X-Forwarded-For headers,
+ * or we already appended an existing X-Forwarded-For
+ * header, there's nothing left to do here.
+ */
+ return JB_ERR_OK;
+ }
+
+ header = strdup("X-Forwarded-For: ");
+ string_append(&header, csp->ip_addr_str);
+
+ if (header == NULL)
+ {
+ return JB_ERR_MEMORY;
+ }
+
+ log_error(LOG_LEVEL_HEADER, "addh: %s", header);
+ err = enlist(csp->headers, header);
+ freez(header);
+
+ return err;
+}
+
+
+/*********************************************************************
+ *
+ * Function : server_connection_close_adder
*
* Description : "Temporary" fix for the needed but missing HTTP/1.1
* support. Adds a "Connection: close" header to csp->headers
* JB_ERR_MEMORY on out-of-memory error.
*
*********************************************************************/
-static jb_err connection_close_adder(struct client_state *csp)
+static jb_err server_connection_close_adder(struct client_state *csp)
{
const unsigned int flags = csp->flags;
+ const char *response_status_line = csp->headers->first->str;
+
+ if ((flags & CSP_FLAG_CLIENT_HEADER_PARSING_DONE)
+ && (flags & CSP_FLAG_SERVER_CONNECTION_CLOSE_SET))
+ {
+ return JB_ERR_OK;
+ }
/*
- * Return right away if
- *
- * - we're parsing server headers and the server header
- * "Connection: close" is already set, or if
- *
- * - we're parsing client headers and the client header
- * "Connection: close" is already set.
+ * XXX: if we downgraded the response, this check will fail.
*/
- if ((flags & CSP_FLAG_CLIENT_HEADER_PARSING_DONE
- && flags & CSP_FLAG_SERVER_CONNECTION_CLOSE_SET)
- ||(!(flags & CSP_FLAG_CLIENT_HEADER_PARSING_DONE)
- && flags & CSP_FLAG_CLIENT_CONNECTION_CLOSE_SET))
+ if ((csp->config->feature_flags &
+ RUNTIME_FEATURE_CONNECTION_KEEP_ALIVE)
+ && (NULL != response_status_line)
+ && !strncmpic(response_status_line, "HTTP/1.1", 8))
{
- return JB_ERR_OK;
+ log_error(LOG_LEVEL_HEADER, "A HTTP/1.1 response "
+ "without Connection header implies keep-alive.");
+ csp->flags |= CSP_FLAG_SERVER_CONNECTION_KEEP_ALIVE;
}
log_error(LOG_LEVEL_HEADER, "Adding: Connection: close");
}
+/*********************************************************************
+ *
+ * Function : client_connection_header_adder
+ *
+ * Description : Adds a proper "Connection:" header to csp->headers
+ * unless the header was already present. Called from `sed'.
+ *
+ * Parameters :
+ * 1 : csp = Current client state (buffers, headers, etc...)
+ *
+ * Returns : JB_ERR_OK on success, or
+ * JB_ERR_MEMORY on out-of-memory error.
+ *
+ *********************************************************************/
+static jb_err client_connection_header_adder(struct client_state *csp)
+{
+ const unsigned int flags = csp->flags;
+ const char *wanted_header = get_appropiate_connection_header(csp);
+
+ if (!(flags & CSP_FLAG_CLIENT_HEADER_PARSING_DONE)
+ && (flags & CSP_FLAG_CLIENT_CONNECTION_HEADER_SET))
+ {
+ return JB_ERR_OK;
+ }
+
+ log_error(LOG_LEVEL_HEADER, "Adding: %s", wanted_header);
+
+ return enlist(csp->headers, wanted_header);
+}
+
+
/*********************************************************************
*
* Function : server_http
{
time_t now;
time_t cookie_time;
- struct tm tm_now;
- time(&now);
-
-#ifdef FEATURE_COOKIE_JAR
- if (csp->config->jar)
- {
- /*
- * Write timestamp into outbuf.
- *
- * Complex because not all OSs have tm_gmtoff or
- * the %z field in strftime()
- */
- char tempbuf[ BUFFER_SIZE ];
-
-#ifdef HAVE_LOCALTIME_R
- tm_now = *localtime_r(&now, &tm_now);
-#elif FEATURE_PTHREAD
- pthread_mutex_lock(&localtime_mutex);
- tm_now = *localtime (&now);
- pthread_mutex_unlock(&localtime_mutex);
-#else
- tm_now = *localtime (&now);
-#endif
- strftime(tempbuf, BUFFER_SIZE-6, "%b %d %H:%M:%S ", &tm_now);
- /* strlen("set-cookie: ") = 12 */
- fprintf(csp->config->jar, "%s %s\t%s\n", tempbuf, csp->http->host, *header + 12);
- }
-#endif /* def FEATURE_COOKIE_JAR */
+ time(&now);
if ((csp->action->flags & ACTION_NO_COOKIE_SET) != 0)
{
* Returns : Number of eliminations
*
*********************************************************************/
-int strclean(const char *string, const char *substring)
+int strclean(char *string, const char *substring)
{
int hits = 0;
size_t len;
{
char *referer = strdup(*header);
const size_t hostlenght = strlen(host);
+ const char *referer_url = NULL;
if (NULL == referer)
{
}
/* referer begins with 'Referer: http[s]://' */
- if (hostlenght < (strlen(referer)-17))
+ if ((hostlenght+17) < strlen(referer))
{
/*
* Shorten referer to make sure the referer is blocked
*/
referer[hostlenght+17] = '\0';
}
- if (NULL == strstr(referer, host))
+ referer_url = strstr(referer, "http://");
+ if ((NULL == referer_url) || (NULL == strstr(referer_url, host)))
{
- /* Host has changed */
+ /* Host has changed, Referer is invalid or a https URL. */
if (parameter_conditional_block)
{
log_error(LOG_LEVEL_HEADER, "New host is: %s. Crunching %s!", host, *header);
}
+
+/*********************************************************************
+ *
+ * Function : get_appropiate_connection_header
+ *
+ * Description : Returns an appropiate Connection header
+ * depending on whether or not we try to keep
+ * the connection to the server alive.
+ *
+ * Parameters :
+ * 1 : csp = Current client state (buffers, headers, etc...)
+ *
+ * Returns : Pointer to statically allocated header buffer.
+ *
+ *********************************************************************/
+static const char *get_appropiate_connection_header(const struct client_state *csp)
+{
+ static const char connection_keep_alive[] = "Connection: keep-alive";
+ static const char connection_close[] = "Connection: close";
+
+ if ((csp->config->feature_flags & RUNTIME_FEATURE_CONNECTION_KEEP_ALIVE)
+ && (csp->http->ssl == 0))
+ {
+ return connection_keep_alive;
+ }
+ return connection_close;
+}
/*
Local Variables:
tab-width: 3