X-Git-Url: http://www.privoxy.org/gitweb/?a=blobdiff_plain;f=parsers.c;h=e89a64345b3dd77896e595212e589792bb4ef457;hb=e831c877f0a3df606626de7faa49856444298c1b;hp=397deee64ef2a45090e7528d7e788c09cd315195;hpb=939b75b6da234e281a9701f572cdebe392403dcc;p=privoxy.git diff --git a/parsers.c b/parsers.c index 397deee6..e89a6434 100644 --- a/parsers.c +++ b/parsers.c @@ -1,4 +1,4 @@ -const char parsers_rcs[] = "$Id: parsers.c,v 1.107 2007/08/28 18:16:32 fabiankeil Exp $"; +const char parsers_rcs[] = "$Id: parsers.c,v 1.114 2007/10/19 16:56:26 fabiankeil Exp $"; /********************************************************************* * * File : $Source: /cvsroot/ijbswa/current/parsers.c,v $ @@ -44,6 +44,31 @@ const char parsers_rcs[] = "$Id: parsers.c,v 1.107 2007/08/28 18:16:32 fabiankei * * Revisions : * $Log: parsers.c,v $ + * Revision 1.114 2007/10/19 16:56:26 fabiankeil + * - Downgrade "Buffer limit reached" message to LOG_LEVEL_INFO. + * - Use shiny new content_filters_enabled() in client_range(). + * + * Revision 1.113 2007/10/10 17:29:57 fabiankeil + * I forgot about Poland. + * + * Revision 1.112 2007/10/09 16:38:40 fabiankeil + * Remove Range and If-Range headers if content filtering is enabled. + * + * Revision 1.111 2007/10/04 18:07:00 fabiankeil + * Move ACTION_VANILLA_WAFER handling from jcc's chat() into + * client_cookie_adder() to make sure send-vanilla-wafer can be + * controlled through tags (and thus regression-tested). + * + * Revision 1.110 2007/09/29 10:42:37 fabiankeil + * - Remove "scanning headers for" log message again. + * - Some more whitespace fixes. + * + * Revision 1.109 2007/09/08 14:25:48 fabiankeil + * Refactor client_referrer() and add conditional-forge parameter. + * + * Revision 1.108 2007/08/28 18:21:03 fabiankeil + * A bunch of whitespace fixes, pointy hat to me. + * * Revision 1.107 2007/08/28 18:16:32 fabiankeil * Fix possible memory corruption in server_http, make sure it's not * executed for ordinary server headers and mark some problems for later. @@ -782,6 +807,7 @@ static jb_err client_accept_language (struct client_state *csp, char **header static jb_err client_if_none_match (struct client_state *csp, char **header); static jb_err crunch_client_header (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_content_type (struct client_state *csp, char **header); static jb_err server_content_length (struct client_state *csp, char **header); @@ -799,6 +825,11 @@ static jb_err client_xtra_adder (struct client_state *csp); static jb_err client_x_forwarded_adder(struct client_state *csp); static jb_err 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); + const struct parsers client_patterns[] = { { "referer:", 8, client_referrer }, { "user-agent:", 11, client_uagent }, @@ -816,6 +847,8 @@ const struct parsers client_patterns[] = { { "max-forwards:", 13, client_max_forwards }, { "Accept-Language:", 16, client_accept_language }, { "if-none-match:", 14, client_if_none_match }, + { "Range:", 6, client_range }, + { "If-Range:", 9, client_range }, { "X-Filter:", 9, client_x_filter }, { "*", 0, crunch_client_header }, { "*", 0, filter_header }, @@ -857,12 +890,21 @@ const add_header_func_ptr add_client_headers[] = { NULL }; - const add_header_func_ptr add_server_headers[] = { connection_close_adder, NULL }; +/* The vanilla wafer. */ +static const char VANILLA_WAFER[] = + "NOTICE=TO_WHOM_IT_MAY_CONCERN_" + "Do_not_send_me_any_copyrighted_information_other_than_the_" + "document_that_I_am_requesting_or_any_of_its_necessary_components._" + "In_particular_do_not_send_me_any_cookies_that_" + "are_subject_to_a_claim_of_copyright_by_anybody._" + "Take_notice_that_I_refuse_to_be_bound_by_any_license_condition_" + "(copyright_or_otherwise)_applying_to_any_cookie._"; + /********************************************************************* * * Function : flush_socket @@ -935,7 +977,7 @@ jb_err add_to_iob(struct client_state *csp, char *buf, int n) */ if (need > csp->config->buffer_limit) { - log_error(LOG_LEVEL_ERROR, "Buffer limit reached while extending the buffer (iob)"); + log_error(LOG_LEVEL_INFO, "Buffer limit reached while extending the buffer (iob)"); return JB_ERR_MEMORY; } @@ -1096,7 +1138,7 @@ jb_err decompress_iob(struct client_state *csp) * The number of bytes to skip should be positive * and we'd like to stay in the buffer. */ - if((skip_bytes < 0) || (skip_bytes >= (csp->iob->eod - cur))) + if ((skip_bytes < 0) || (skip_bytes >= (csp->iob->eod - cur))) { log_error(LOG_LEVEL_ERROR, "Unreasonable amount of bytes to skip (%d). Stopping decompression", @@ -1473,8 +1515,6 @@ static jb_err scan_headers(struct client_state *csp) struct list_entry *h; /* Header */ jb_err err = JB_ERR_OK; - log_error(LOG_LEVEL_HEADER, "scanning headers for: %s", csp->http->url); - for (h = csp->headers->first; (err == JB_ERR_OK) && (h != NULL) ; h = h->next) { /* Header crunch()ed in previous run? -> ignore */ @@ -1499,6 +1539,8 @@ static jb_err scan_headers(struct client_state *csp) * As a side effect it frees the space used by the original * header lines. * + * XXX: should be split to remove the first_run hack. + * * Parameters : * 1 : pats = list of patterns to match against headers * 2 : more_headers = list of functions to add more @@ -1928,7 +1970,7 @@ static jb_err filter_header(struct client_state *csp, char **header) /* RegEx failure */ log_error(LOG_LEVEL_ERROR, "Filtering \'%s\' with \'%s\' didn't work out: %s", *header, b->name, pcrs_strerror(matches)); - if( newheader != NULL) + if (newheader != NULL) { log_error(LOG_LEVEL_ERROR, "Freeing what's left: %s", newheader); freez(newheader); @@ -2034,6 +2076,7 @@ static jb_err crumble(struct client_state *csp, char **header) return JB_ERR_OK; } + /********************************************************************* * * Function : crunch_server_header @@ -2390,6 +2433,7 @@ static jb_err server_content_md5(struct client_state *csp, char **header) return JB_ERR_OK; } + /********************************************************************* * * Function : server_content_disposition @@ -2453,6 +2497,7 @@ static jb_err server_content_disposition(struct client_state *csp, char **header return (*header == NULL) ? JB_ERR_MEMORY : JB_ERR_OK; } + /********************************************************************* * * Function : server_last_modified @@ -2572,7 +2617,7 @@ static jb_err server_last_modified(struct client_state *csp, char **header) return JB_ERR_MEMORY; } - if(LOG_LEVEL_HEADER & debug) /* Save cycles if the user isn't interested. */ + if (LOG_LEVEL_HEADER & debug) /* Save cycles if the user isn't interested. */ { days = rtime / (3600 * 24); hours = rtime / 3600 % 24; @@ -2670,6 +2715,7 @@ static jb_err client_te(struct client_state *csp, char **header) return JB_ERR_OK; } + /********************************************************************* * * Function : client_referrer @@ -2690,113 +2736,65 @@ static jb_err client_te(struct client_state *csp, char **header) *********************************************************************/ static jb_err client_referrer(struct client_state *csp, char **header) { - const char *newval; - const char *host; - char *referer; - size_t hostlenght; + const char *parameter; + /* booleans for parameters we have to check multiple times */ + int parameter_conditional_block; + int parameter_conditional_forge; #ifdef FEATURE_FORCE_LOAD - /* Since the referrer can include the prefix even + /* + * Since the referrer can include the prefix even * if the request itself is non-forced, we must - * clean it unconditionally + * clean it unconditionally. + * + * XXX: strclean is too broad */ strclean(*header, FORCE_PREFIX); #endif /* def FEATURE_FORCE_LOAD */ - /* - * Are we sending referer? - */ if ((csp->action->flags & ACTION_HIDE_REFERER) == 0) { + /* Nothing left to do */ return JB_ERR_OK; } - newval = csp->action->string[ACTION_STRING_REFERER]; + parameter = csp->action->string[ACTION_STRING_REFERER]; + assert(parameter != NULL); + parameter_conditional_block = (0 == strcmpic(parameter, "conditional-block")); + parameter_conditional_forge = (0 == strcmpic(parameter, "conditional-forge")); - if ((0 != strcmpic(newval, "conditional-block"))) - { - freez(*header); - } - if ((newval == NULL) || (0 == strcmpic(newval, "block")) ) + if (!parameter_conditional_block && !parameter_conditional_forge) { /* - * Blocking referer + * As conditional-block and conditional-forge are the only + * parameters that rely on the original referrer, we can + * remove it now for all the others. */ + freez(*header); + } + + if (0 == strcmpic(parameter, "block")) + { log_error(LOG_LEVEL_HEADER, "Referer crunched!"); return JB_ERR_OK; } - else if (0 == strcmpic(newval, "conditional-block")) + else if (parameter_conditional_block || parameter_conditional_forge) { - /* - * Block referer if host has changed. - */ - - if (NULL == (host = strdup(csp->http->hostport))) - { - freez(*header); - log_error(LOG_LEVEL_HEADER, "Referer crunched! Couldn't allocate memory for temporary host copy."); - return JB_ERR_MEMORY; - } - if (NULL == (referer = strdup(*header))) - { - freez(*header); - freez(host); - log_error(LOG_LEVEL_HEADER, "Referer crunched! Couldn't allocate memory for temporary referer copy."); - return JB_ERR_MEMORY; - } - hostlenght = strlen(host); - if ( hostlenght < (strlen(referer)-17) ) /*referer begins with 'Referer: http[s]://'*/ - { - /*Shorten referer to make sure the referer is blocked - *if www.example.org/www.example.com-shall-see-the-referer/ - *links to www.example.com/ - */ - referer[hostlenght+17] = '\0'; - } - if ( 0 == strstr(referer, host)) /*Host has changed*/ - { - log_error(LOG_LEVEL_HEADER, "New host is: %s. Crunching %s!", host, *header); - freez(*header); - } - else - { - log_error(LOG_LEVEL_HEADER, "%s (not modified, still on %s)", *header, host); - } - freez(referer); - freez(host); - return JB_ERR_OK; + return handle_conditional_hide_referrer_parameter(header, + csp->http->hostport, parameter_conditional_block); } - else if (0 != strcmpic(newval, "forge")) + else if (0 == strcmpic(parameter, "forge")) { - /* - * We have a specific (fixed) referer we want to send. - */ - if ((0 != strncmpic(newval, "http://", 7)) && (0 != strncmpic(newval, "https://", 8))) - { - log_error(LOG_LEVEL_HEADER, "Parameter: +referrer{%s} is a bad idea, but I don't care.", newval); - } - *header = strdup("Referer: "); - string_append(header, newval); - log_error(LOG_LEVEL_HEADER, "Referer overwritten with: %s", *header); - - return (*header == NULL) ? JB_ERR_MEMORY : JB_ERR_OK; + return create_forged_referrer(header, csp->http->hostport); } else { - /* - * Forge a referer as http://[hostname:port of REQUEST]/ - * to fool stupid checks for in-site links - */ - - *header = strdup("Referer: http://"); - string_append(header, csp->http->hostport); - string_append(header, "/"); - log_error(LOG_LEVEL_HEADER, "Referer forged to: %s", *header); - - return (*header == NULL) ? JB_ERR_MEMORY : JB_ERR_OK; + /* interpret parameter as user-supplied referer to fake */ + return create_fake_referrer(header, parameter); } } + /********************************************************************* * * Function : client_accept_language @@ -2943,6 +2941,7 @@ static jb_err client_uagent(struct client_state *csp, char **header) return (*header == NULL) ? JB_ERR_MEMORY : JB_ERR_OK; } + /********************************************************************* * * Function : client_ua @@ -3134,17 +3133,6 @@ static jb_err client_max_forwards(struct client_state *csp, char **header) log_error(LOG_LEVEL_ERROR, "Crunching invalid header: %s", *header); freez(*header); } - else - { - /* - * Not supposed to be reached. direct_response() which - * was already called earlier in chat() should have - * intercepted the request. - */ - log_error(LOG_LEVEL_ERROR, - "Non-intercepted %s request with Max-Forwards zero!", csp->http->gpc); - assert(max_forwards != 0); - } } else { @@ -3236,6 +3224,7 @@ static jb_err client_host(struct client_state *csp, char **header) return JB_ERR_OK; } + /********************************************************************* * * Function : client_if_modified_since @@ -3300,11 +3289,11 @@ static jb_err client_if_modified_since(struct client_state *csp, char **header) else { rtime = strtol(newval, &endptr, 0); - if(rtime) + if (rtime) { log_error(LOG_LEVEL_HEADER, "Randomizing: %s (random range: %d minut%s)", *header, rtime, (rtime == 1 || rtime == -1) ? "e": "es"); - if(rtime < 0) + if (rtime < 0) { rtime *= -1; negative = 1; @@ -3339,7 +3328,7 @@ static jb_err client_if_modified_since(struct client_state *csp, char **header) return JB_ERR_MEMORY; } - if(LOG_LEVEL_HEADER & debug) /* Save cycles if the user isn't interested. */ + if (LOG_LEVEL_HEADER & debug) /* Save cycles if the user isn't interested. */ { hours = rtime / 3600; minutes = rtime / 60 % 60; @@ -3356,6 +3345,7 @@ static jb_err client_if_modified_since(struct client_state *csp, char **header) return JB_ERR_OK; } + /********************************************************************* * * Function : client_if_none_match @@ -3384,6 +3374,7 @@ static jb_err client_if_none_match(struct client_state *csp, char **header) return JB_ERR_OK; } + /********************************************************************* * * Function : client_x_filter @@ -3429,6 +3420,40 @@ jb_err client_x_filter(struct client_state *csp, char **header) return JB_ERR_OK; } + +/********************************************************************* + * + * Function : client_range + * + * Description : Removes 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. + * + * 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 + * + *********************************************************************/ +static jb_err client_range(struct client_state *csp, char **header) +{ + if (content_filters_enabled(csp)) + { + log_error(LOG_LEVEL_HEADER, "Content filtering is enabled." + " Crunching: \'%s\' to prevent range-mismatch problems.", *header); + freez(*header); + } + + return JB_ERR_OK; +} + /* the following functions add headers directly to the header list */ /********************************************************************* @@ -3501,9 +3526,21 @@ jb_err client_cookie_adder(struct client_state *csp) { char *tmp; struct list_entry *wafer; - struct list_entry *wafer_list = csp->action->multi[ACTION_MULTI_WAFER]->first; + struct list_entry *wafer_list; jb_err err; + /* + * If the user has not supplied any wafers, and the user has not + * told us to suppress the vanilla wafer, then send the vanilla wafer. + */ + if ((0 != (csp->action->flags & ACTION_VANILLA_WAFER)) + && list_is_empty(csp->action->multi[ACTION_MULTI_WAFER])) + { + enlist(csp->action->multi[ACTION_MULTI_WAFER], VANILLA_WAFER); + } + + wafer_list = csp->action->multi[ACTION_MULTI_WAFER]->first; + if (NULL == wafer_list) { /* Nothing to do */ @@ -3533,6 +3570,7 @@ jb_err client_cookie_adder(struct client_state *csp) return err; } + #if 0 /********************************************************************* * @@ -3562,6 +3600,7 @@ static jb_err client_accept_encoding_adder(struct client_state *csp) } #endif + /********************************************************************* * * Function : client_xtra_adder @@ -3710,7 +3749,6 @@ static jb_err connection_close_adder(struct client_state *csp) *********************************************************************/ static jb_err server_http(struct client_state *csp, char **header) { - /* XXX: Doesn't belong here. */ sscanf(*header, "HTTP/%*d.%*d %d", &(csp->http->status)); if (csp->http->status == 206) { @@ -3988,6 +4026,7 @@ int strclean(const char *string, const char *substring) } #endif /* def FEATURE_FORCE_LOAD */ + /********************************************************************* * * Function : parse_header_time @@ -4037,6 +4076,7 @@ static jb_err parse_header_time(const char *header_time, time_t *result) } + /********************************************************************* * * Function : get_destination_from_headers @@ -4119,6 +4159,142 @@ jb_err get_destination_from_headers(const struct list *headers, struct http_requ } +/********************************************************************* + * + * Function : create_forged_referrer + * + * Description : Helper for client_referrer to forge a referer as + * 'http://[hostname:port/' to fool stupid + * checks for in-site links + * + * Parameters : + * 1 : header = Pointer to header pointer + * 2 : hostport = Host and optionally port as string + * + * Returns : JB_ERR_OK in case of success, or + * JB_ERR_MEMORY in case of memory problems. + * + *********************************************************************/ +static jb_err create_forged_referrer(char **header, const char *hostport) +{ + assert(NULL == *header); + + *header = strdup("Referer: http://"); + string_append(header, hostport); + string_append(header, "/"); + + if (NULL == *header) + { + return JB_ERR_MEMORY; + } + + log_error(LOG_LEVEL_HEADER, "Referer forged to: %s", *header); + + return JB_ERR_OK; + +} + + +/********************************************************************* + * + * Function : create_fake_referrer + * + * Description : Helper for client_referrer to create a fake referrer + * based on a string supplied by the user. + * + * Parameters : + * 1 : header = Pointer to header pointer + * 2 : hosthost = Referrer to fake + * + * Returns : JB_ERR_OK in case of success, or + * JB_ERR_MEMORY in case of memory problems. + * + *********************************************************************/ +static jb_err create_fake_referrer(char **header, const char *fake_referrer) +{ + assert(NULL == *header); + + if ((0 != strncmpic(fake_referrer, "http://", 7)) && (0 != strncmpic(fake_referrer, "https://", 8))) + { + log_error(LOG_LEVEL_HEADER, + "Parameter: +hide-referrer{%s} is a bad idea, but I don't care.", fake_referrer); + } + *header = strdup("Referer: "); + string_append(header, fake_referrer); + + if (NULL == *header) + { + return JB_ERR_MEMORY; + } + + log_error(LOG_LEVEL_HEADER, "Referer replaced with: %s", *header); + + return JB_ERR_OK; + +} + + +/********************************************************************* + * + * Function : handle_conditional_hide_referrer_parameter + * + * Description : Helper for client_referrer to crunch or forge + * the referrer header if the host has changed. + * + * Parameters : + * 1 : header = Pointer to header pointer + * 2 : host = The target host (may include the port) + * 3 : parameter_conditional_block = Boolean to signal + * if we're in conditional-block mode. If not set, + * we're in conditional-forge mode. + * + * Returns : JB_ERR_OK in case of success, or + * JB_ERR_MEMORY in case of memory problems. + * + *********************************************************************/ +static jb_err handle_conditional_hide_referrer_parameter(char **header, + const char *host, const int parameter_conditional_block) +{ + char *referer = strdup(*header); + const size_t hostlenght = strlen(host); + + if (NULL == referer) + { + freez(*header); + return JB_ERR_MEMORY; + } + + /* referer begins with 'Referer: http[s]://' */ + if (hostlenght < (strlen(referer)-17)) + { + /* + * Shorten referer to make sure the referer is blocked + * if www.example.org/www.example.com-shall-see-the-referer/ + * links to www.example.com/ + */ + referer[hostlenght+17] = '\0'; + } + if (NULL == strstr(referer, host)) + { + /* Host has changed */ + if (parameter_conditional_block) + { + log_error(LOG_LEVEL_HEADER, "New host is: %s. Crunching %s!", host, *header); + freez(*header); + } + else + { + freez(*header); + freez(referer); + return create_forged_referrer(header, host); + } + } + freez(referer); + + return JB_ERR_OK; + +} + /* Local Variables: tab-width: 3