-const char parsers_rcs[] = "$Id: parsers.c,v 1.237 2011/11/06 11:36:27 fabiankeil Exp $";
+const char parsers_rcs[] = "$Id: parsers.c,v 1.245 2012/04/06 15:17:10 fabiankeil Exp $";
/*********************************************************************
*
* File : $Source: /cvsroot/ijbswa/current/parsers.c,v $
*
* Purpose : Declares functions to parse/crunch headers and pages.
*
- * Copyright : Written by and Copyright (C) 2001-2009 the
+ * Copyright : Written by and Copyright (C) 2001-2012 the
* Privoxy team. http://www.privoxy.org/
*
* Based on the Internet Junkbuster originally written
const char parsers_h_rcs[] = PARSERS_H_VERSION;
-/* Fix a problem with Solaris. There should be no effect on other
- * platforms.
- * Solaris's isspace() is a macro which uses its argument directly
- * as an array index. Therefore we need to make sure that high-bit
- * characters generate +ve values, and ideally we also want to make
- * the argument match the declared parameter type of "int".
- *
- * Why did they write a character function that can't take a simple
- * "char" argument? Doh!
- */
-#define ijb_isupper(__X) isupper((int)(unsigned char)(__X))
-#define ijb_tolower(__X) tolower((int)(unsigned char)(__X))
-
static char *get_header_line(struct iob *iob);
static jb_err scan_headers(struct client_state *csp);
static jb_err header_tagger(struct client_state *csp, char *header);
while (*p != '\0')
{
- if (ijb_isspace(*p) && ijb_isspace(*(p+1)))
+ if (privoxy_isspace(*p) && privoxy_isspace(*(p+1)))
{
char *q = p+1;
- while (ijb_isspace(*q))
+ while (privoxy_isspace(*q))
{
q++;
}
}
p = strchr(header, ':');
- if ((p != NULL) && (p != header) && ijb_isspace(*(p-1)))
+ if ((p != NULL) && (p != header) && privoxy_isspace(*(p-1)))
{
/*
* There's still space before the colon.
* Found: return pointer to start of value
*/
ret = cur_entry->str + length;
- while (*ret && ijb_isspace(*ret)) ret++;
+ while (*ret && privoxy_isspace(*ret)) ret++;
return ret;
}
}
for (job = joblist; NULL != job; job = job->next)
{
matches = pcrs_execute(job, *header, size, &newheader, &size);
- if ( 0 < matches )
+ if (0 < matches)
{
current_hits += matches;
log_error(LOG_LEVEL_HEADER, "Transforming \"%s\" to \"%s\"", *header, newheader);
freez(*header);
*header = newheader;
}
- else if ( 0 == matches )
+ else if (0 == matches)
{
/* Filter doesn't change header */
freez(newheader);
* 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.
+ * Returns : JB_ERR_OK on success.
*
*********************************************************************/
static jb_err server_connection(struct client_state *csp, char **header)
#ifdef FEATURE_CONNECTION_KEEP_ALIVE
&& !(csp->flags & CSP_FLAG_SERVER_SOCKET_TAINTED)
#endif
- )
+ )
{
#ifdef FEATURE_CONNECTION_KEEP_ALIVE
if ((csp->config->feature_flags & RUNTIME_FEATURE_CONNECTION_KEEP_ALIVE))
{
char *old_header = *header;
- *header = strdup("Connection: close");
- if (header == NULL)
- {
- return JB_ERR_MEMORY;
- }
+ *header = strdup_or_die("Connection: close");
log_error(LOG_LEVEL_HEADER, "Replaced: \'%s\' with \'%s\'", old_header, *header);
freez(old_header);
}
* 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.
+ * Returns : JB_ERR_OK on success.
*
*********************************************************************/
static jb_err client_connection(struct client_state *csp, char **header)
{
char *old_header = *header;
- *header = strdup("Connection: keep-alive");
- if (header == NULL)
- {
- return JB_ERR_MEMORY;
- }
+ *header = strdup_or_die("Connection: keep-alive");
log_error(LOG_LEVEL_HEADER,
"Replaced: \'%s\' with \'%s\'", old_header, *header);
freez(old_header);
{
char *old_header = *header;
- *header = strdup(connection_close);
- if (header == NULL)
- {
- return JB_ERR_MEMORY;
- }
+ *header = strdup_or_die(connection_close);
log_error(LOG_LEVEL_HEADER,
"Replaced: \'%s\' with \'%s\'", old_header, *header);
freez(old_header);
if ((csp->content_type & CT_TEXT) || (csp->action->flags & ACTION_FORCE_TEXT_MODE))
{
freez(*header);
- *header = strdup("Content-Type: ");
+ *header = strdup_or_die("Content-Type: ");
string_append(header, csp->action->string[ACTION_STRING_CONTENT_TYPE]);
if (header == NULL)
newval = csp->action->string[ACTION_STRING_LAST_MODIFIED];
- if (0 == strcmpic(newval, "block") )
+ if (0 == strcmpic(newval, "block"))
{
/*
* Blocking Last-Modified header. Useless but why not.
newval = csp->action->string[ACTION_STRING_LANGUAGE];
- if ((newval == NULL) || (0 == strcmpic(newval, "block")) )
+ if ((newval == NULL) || (0 == strcmpic(newval, "block")))
{
/*
* Blocking Accept-Language header
/*
* Are we blocking the e-mail address?
*/
- if ((newval == NULL) || (0 == strcmpic(newval, "block")) )
+ if ((newval == NULL) || (0 == strcmpic(newval, "block")))
{
log_error(LOG_LEVEL_HEADER, "crunched From!");
return JB_ERR_OK;
*csp->http->hostport == ' ' || *csp->http->hostport == '\0')
{
- if (NULL == (p = strdup((*header)+6)))
- {
- return JB_ERR_MEMORY;
- }
+ p = strdup_or_die((*header)+6);
chomp(p);
- if (NULL == (q = strdup(p)))
- {
- freez(p);
- return JB_ERR_MEMORY;
- }
+ q = strdup_or_die(p);
freez(csp->http->hostport);
csp->http->hostport = p;
const char *newval;
char * endptr;
- if ( 0 == strcmpic(*header, "If-Modified-Since: Wed, 08 Jun 1955 12:00:00 GMT"))
+ if (0 == strcmpic(*header, "If-Modified-Since: Wed, 08 Jun 1955 12:00:00 GMT"))
{
/*
* The client got an error message because of a temporary problem,
*********************************************************************/
jb_err client_x_filter(struct client_state *csp, char **header)
{
- if ( 0 == strcmpic(*header, "X-Filter: No"))
+ if (0 == strcmpic(*header, "X-Filter: No"))
{
if (!(csp->config->feature_flags & RUNTIME_FEATURE_HTTP_TOGGLE))
{
* Function : client_range
*
* Description : Removes Range, Request-Range and If-Range headers if
- * content filtering is enabled. If the client's version
- * of the document has been altered by Privoxy, the server
- * could interpret the range differently than the client
- * intended in which case the user could end up with
- * corrupted content.
+ * content filtering is enabled and the range doesn't
+ * start at byte 0.
+ *
+ * If the client's version of the document has been
+ * altered by Privoxy, the server could interpret the
+ * range differently than the client intended in which
+ * case the user could end up with corrupted content.
+ *
+ * If the range starts at byte 0 this isn't an issue
+ * so the header can pass. Partial requests like this
+ * are used to render preview images for videos without
+ * downloading the whole video.
+ *
+ * While HTTP doesn't require that range requests are
+ * honoured and the client could simply abort the download
+ * after receiving a sufficient amount of data, various
+ * clients don't handle complete responses to range
+ * requests gracefully and emit misleading error messages
+ * instead.
*
* Parameters :
* 1 : csp = Current client state (buffers, headers, etc...)
*********************************************************************/
static jb_err client_range(struct client_state *csp, char **header)
{
- if (content_filters_enabled(csp->action))
+ if (content_filters_enabled(csp->action)
+ && (0 != strncmpic(strstr(*header, ":"), ": bytes=0-", 10)))
{
log_error(LOG_LEVEL_HEADER, "Content filtering is enabled."
" Crunching: \'%s\' to prevent range-mismatch problems.", *header);
return JB_ERR_OK;
}
- if ( !csp->http->hostport || !*(csp->http->hostport))
+ if (!csp->http->hostport || !*(csp->http->hostport))
{
/* XXX: When does this happen and why is it OK? */
log_error(LOG_LEVEL_INFO, "Weirdness in client_host_adder detected and ignored.");
/*
* remove 'user:pass@' from 'proto://user:pass@host'
*/
- if ( (p = strchr( csp->http->hostport, '@')) != NULL )
+ if ((p = strchr( csp->http->hostport, '@')) != NULL)
{
p++;
}
#ifdef FEATURE_CONNECTION_KEEP_ALIVE
&& !(csp->flags & CSP_FLAG_SERVER_SOCKET_TAINTED)
#endif
- )
+ )
{
log_error(LOG_LEVEL_HEADER, "A HTTP/1.1 response "
"without Connection header implies keep-alive.");
cur_tag = *header + 11;
/* skip whitespace between "Set-Cookie:" and value */
- while (*cur_tag && ijb_isspace(*cur_tag))
+ while (*cur_tag && privoxy_isspace(*cur_tag))
{
cur_tag++;
}
next_tag++;
/* skip whitespace ";" and start of tag */
- while (*next_tag && ijb_isspace(*next_tag))
+ while (*next_tag && privoxy_isspace(*next_tag))
{
next_tag++;
}
* the "Host:" header)
* 2 : http = storage for the result (host, port and hostport).
*
- * Returns : JB_ERR_MEMORY in case of memory problems,
+ * Returns : JB_ERR_MEMORY (or terminates) in case of memory problems,
* JB_ERR_PARSE if the host header couldn't be found,
* JB_ERR_OK otherwise.
*
return JB_ERR_PARSE;
}
- p = strdup(host);
- if (NULL == p)
- {
- log_error(LOG_LEVEL_ERROR, "Out of memory while parsing \"Host:\" header");
- return JB_ERR_MEMORY;
- }
+ p = strdup_or_die(host);
chomp(p);
- if (NULL == (q = strdup(p)))
- {
- freez(p);
- log_error(LOG_LEVEL_ERROR, "Out of memory while parsing \"Host:\" header");
- return JB_ERR_MEMORY;
- }
+ q = strdup_or_die(p);
freez(http->hostport);
http->hostport = p;
* Function : create_forged_referrer
*
* Description : Helper for client_referrer to forge a referer as
- * 'http://[hostname:port/' to fool stupid
+ * 'http://hostname[:port]/' to fool stupid
* checks for in-site links
*
* Parameters :
static jb_err handle_conditional_hide_referrer_parameter(char **header,
const char *host, const int parameter_conditional_block)
{
- char *referer = strdup(*header);
+ char *referer = strdup_or_die(*header);
const size_t hostlength = strlen(host);
const char *referer_url = NULL;
- if (NULL == referer)
- {
- freez(*header);
- return JB_ERR_MEMORY;
- }
-
/* referer begins with 'Referer: http[s]://' */
if ((hostlength+17) < strlen(referer))
{