X-Git-Url: http://www.privoxy.org/gitweb/?p=privoxy.git;a=blobdiff_plain;f=parsers.c;h=6cba35e8b8990d6157b3ae05daf4f012400d1304;hp=37737a74e8173de6e9c738c011caded9574621e0;hb=cfa94e1bc59ff181fe557dc411f252a39605013c;hpb=9a962b219983489e778f24d95e1d6b3ddb8c7a87 diff --git a/parsers.c b/parsers.c index 37737a74..6cba35e8 100644 --- a/parsers.c +++ b/parsers.c @@ -1,4 +1,4 @@ -const char parsers_rcs[] = "$Id: parsers.c,v 1.266 2012/11/24 13:58:17 fabiankeil Exp $"; +const char parsers_rcs[] = "$Id: parsers.c,v 1.273 2013/01/04 12:19:47 fabiankeil Exp $"; /********************************************************************* * * File : $Source: /cvsroot/ijbswa/current/parsers.c,v $ @@ -198,6 +198,9 @@ static const struct parsers client_patterns[] = { { "Request-Range:", 14, client_range }, { "If-Range:", 9, client_range }, { "X-Filter:", 9, client_x_filter }, +#if 0 + { "Transfer-Encoding:", 18, client_transfer_encoding }, +#endif { "*", 0, crunch_client_header }, { "*", 0, filter_header }, { NULL, 0, NULL } @@ -1228,6 +1231,7 @@ jb_err update_server_headers(struct client_state *csp) log_error(LOG_LEVEL_HEADER, "Content modified with no Content-Length header set. " "Created: %s.", header); + csp->flags |= CSP_FLAG_SERVER_CONTENT_LENGTH_SET; } } #endif /* def FEATURE_CONNECTION_KEEP_ALIVE */ @@ -1978,6 +1982,38 @@ static jb_err client_proxy_connection(struct client_state *csp, char **header) #endif /* def FEATURE_CONNECTION_KEEP_ALIVE */ +/********************************************************************* + * + * Function : client_transfer_encoding + * + * Description : Raise the CSP_FLAG_CHUNKED_CLIENT_BODY flag if + * the request body is "chunked" + * + * XXX: Currently not called through sed() as we + * need the flag earlier on. Should be fixed. + * + * 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 client_transfer_encoding(struct client_state *csp, char **header) +{ + if (strstr(*header, "chunked")) + { + csp->flags |= CSP_FLAG_CHUNKED_CLIENT_BODY; + log_error(LOG_LEVEL_HEADER, "Expecting chunked client body"); + } + + return JB_ERR_OK; +} + + /********************************************************************* * * Function : crumble @@ -2069,17 +2105,25 @@ static jb_err server_content_type(struct client_state *csp, char **header) /* Remove header if it isn't the first Content-Type header */ if ((csp->content_type & CT_DECLARED)) { - /* - * Another, slightly slower, way to see if - * we already parsed another Content-Type header. - */ - assert(NULL != get_header_value(csp->headers, "Content-Type:")); - - log_error(LOG_LEVEL_ERROR, - "Multiple Content-Type headers. Removing and ignoring: \'%s\'", - *header); - freez(*header); - + if (content_filters_enabled(csp->action)) + { + /* + * Making sure the client interprets the content the same way + * Privoxy did is only relevant if Privoxy modified it. + * + * Checking for this is "hard" as it's not yet known when + * this function is called, thus go shopping and and just + * check if Privoxy could filter it. + * + * The main thing is that we don't mess with the headers + * unless the user signalled that it's acceptable. + */ + log_error(LOG_LEVEL_HEADER, + "Multiple Content-Type headers detected. " + "Removing and ignoring: %s", + *header); + freez(*header); + } return JB_ERR_OK; } @@ -3894,7 +3938,12 @@ static jb_err server_set_cookie(struct client_state *csp, char **header) time_t now; time_t cookie_time; long cookie_lifetime = 0; - int expiry_date_acceptable = 0; + enum + { + NO_EXPIRY_DATE_SPECIFIED, + EXPIRY_DATE_ACCEPTABLE, + EXPIRY_DATE_UNACCEPTABLE + } expiry_date_status = NO_EXPIRY_DATE_SPECIFIED; /* A variable to store the tag we're working on */ char *cur_tag; @@ -3919,7 +3968,7 @@ static jb_err server_set_cookie(struct client_state *csp, char **header) { log_error(LOG_LEVEL_FATAL, "Invalid cookie lifetime limit: %s", param); } - cookie_lifetime *= 60U; + cookie_lifetime *= 60; } /* Loop through each tag in the cookie */ @@ -3975,7 +4024,7 @@ static jb_err server_set_cookie(struct client_state *csp, char **header) log_error(LOG_LEVEL_ERROR, "Can't parse \'%s\', send by %s. Unsupported time format?", cur_tag, csp->http->url); string_move(cur_tag, next_tag); - expiry_date_acceptable = 0; + expiry_date_status = EXPIRY_DATE_UNACCEPTABLE; } else { @@ -4019,7 +4068,7 @@ static jb_err server_set_cookie(struct client_state *csp, char **header) "Cookie \'%s\' is already expired and can pass unmodified.", *header); /* Just in case some clown sets more then one expiration date */ cur_tag = next_tag; - expiry_date_acceptable = 1; + expiry_date_status = EXPIRY_DATE_ACCEPTABLE; } else if ((cookie_lifetime != 0) && (cookie_time < (now + cookie_lifetime))) { @@ -4027,7 +4076,7 @@ static jb_err server_set_cookie(struct client_state *csp, char **header) "Its lifetime is below the limit.", *header); /* Just in case some clown sets more then one expiration date */ cur_tag = next_tag; - expiry_date_acceptable = 1; + expiry_date_status = EXPIRY_DATE_ACCEPTABLE; } else { @@ -4038,7 +4087,7 @@ static jb_err server_set_cookie(struct client_state *csp, char **header) string_move(cur_tag, next_tag); /* That changed the header, need to issue a log message */ - expiry_date_acceptable = 0; + expiry_date_status = EXPIRY_DATE_UNACCEPTABLE; /* * Note that the next tag has now been moved to *cur_tag, @@ -4055,19 +4104,19 @@ static jb_err server_set_cookie(struct client_state *csp, char **header) } } - if (!expiry_date_acceptable) + if (expiry_date_status != EXPIRY_DATE_ACCEPTABLE) { assert(NULL != *header); - if (cookie_lifetime == 0) - { - log_error(LOG_LEVEL_HEADER, "Cookie rewritten to a temporary one: %s", - *header); - } - else + if (cookie_lifetime != 0) { add_cookie_expiry_date(header, cookie_lifetime); log_error(LOG_LEVEL_HEADER, "Cookie rewritten to: %s", *header); } + else if (expiry_date_status != NO_EXPIRY_DATE_SPECIFIED) + { + log_error(LOG_LEVEL_HEADER, + "Cookie rewritten to a temporary one: %s", *header); + } } } @@ -4171,6 +4220,44 @@ static jb_err parse_header_time(const char *header_time, time_t *result) continue; } *result = timegm(&gmt); + +#ifdef FEATURE_STRPTIME_SANITY_CHECKS + /* + * Verify that parsing the date recreated from the first + * parse operation gets the previous result. If it doesn't, + * either strptime() or strftime() are malfunctioning. + * + * We could string-compare the recreated date with the original + * header date, but this leads to false positives as strptime() + * may let %a accept all day formats while strftime() will only + * create one. + */ + { + char recreated_date[100]; + struct tm *tm; + time_t result2; + + tm = gmtime(result); + strftime(recreated_date, sizeof(recreated_date), time_formats[i], tm); + memset(&gmt, 0, sizeof(gmt)); + if (NULL == strptime(recreated_date, time_formats[i], &gmt)) + { + log_error(LOG_LEVEL_ERROR, + "Failed to parse '%s' generated with '%s' to recreate '%s'.", + recreated_date, time_formats[i], header_time); + continue; + } + result2 = timegm(&gmt); + if (*result != result2) + { + log_error(LOG_LEVEL_ERROR, "strftime() and strptime() disagree. " + "Format: '%s'. In: '%s', out: '%s'. %d != %d. Rejecting.", + time_formats[i], header_time, recreated_date, *result, result2); + continue; + } + } +#endif + return JB_ERR_OK; } }