X-Git-Url: http://www.privoxy.org/gitweb/?p=privoxy.git;a=blobdiff_plain;f=parsers.c;h=bdf36cbc5d451d78ebd4560f8bb59d76172ef92a;hp=11845600fdb50b49700c85a8e9cc8d152df81c71;hb=ea4c4776a6816a05cdad45bd9b6b65a5641c703a;hpb=f7b5dc65ad09236147cd10027921c7a652d6ccbe diff --git a/parsers.c b/parsers.c index 11845600..bdf36cbc 100644 --- a/parsers.c +++ b/parsers.c @@ -1,4 +1,4 @@ -const char parsers_rcs[] = "$Id: parsers.c,v 1.222 2011/04/19 13:00:47 fabiankeil Exp $"; +const char parsers_rcs[] = "$Id: parsers.c,v 1.236 2011/10/23 11:23:55 fabiankeil Exp $"; /********************************************************************* * * File : $Source: /cvsroot/ijbswa/current/parsers.c,v $ @@ -187,10 +187,10 @@ 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; }; @@ -252,7 +252,6 @@ 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, */ client_connection_header_adder, NULL }; @@ -350,7 +349,7 @@ jb_err add_to_iob(struct client_state *csp, char *buf, long n) { want *= 2; } - + if (want <= csp->config->buffer_limit && NULL != (p = (char *)realloc(iob->buf, want))) { iob->size = want; @@ -406,7 +405,7 @@ jb_err add_to_iob(struct client_state *csp, char *buf, long n) jb_err decompress_iob(struct client_state *csp) { char *buf; /* new, uncompressed buffer */ - char *cur; /* Current iob position (to keep the original + char *cur; /* Current iob position (to keep the original * iob->cur unmodified if we return early) */ size_t bufsize; /* allocated size of the new buffer */ size_t old_size; /* Content size before decompression */ @@ -554,7 +553,7 @@ jb_err decompress_iob(struct client_state *csp) * * Fortunately, add_to_iob() has thoughtfully null-terminated * the buffer; we can just increment the end pointer to include - * the dummy byte. + * the dummy byte. */ csp->iob->eod++; } @@ -638,7 +637,7 @@ jb_err decompress_iob(struct client_state *csp) { bufsize = csp->config->buffer_limit; } - + /* Try to allocate the new buffer. */ tmpbuf = realloc(buf, bufsize); if (NULL == tmpbuf) @@ -710,7 +709,7 @@ jb_err decompress_iob(struct client_state *csp) csp->iob->cur = csp->iob->buf + skip_size; csp->iob->eod = (char *)zstr.next_out; csp->iob->size = bufsize; - + /* * Make sure the new uncompressed iob obeys some minimal * consistency conditions. @@ -882,7 +881,7 @@ char *get_header(struct iob *iob) * Header spans multiple lines, append the next one. */ char *continued_header; - + continued_header = get_header_line(iob); if ((continued_header == NULL) || (*continued_header == '\0')) { @@ -1014,7 +1013,7 @@ char *get_header_value(const struct list *header_list, const char *header_name) } } - /* + /* * Not found */ return NULL; @@ -1026,7 +1025,7 @@ char *get_header_value(const struct list *header_list, const char *header_name) * * Function : scan_headers * - * Description : Scans headers, applies tags and updates action bits. + * Description : Scans headers, applies tags and updates action bits. * * Parameters : * 1 : csp = Current client state (buffers, headers, etc...) @@ -1187,6 +1186,18 @@ jb_err update_server_headers(struct client_state *csp) } #endif /* def FEATURE_CONNECTION_KEEP_ALIVE */ +#ifdef FEATURE_COMPRESSION + if ((JB_ERR_OK == err) + && (csp->flags & CSP_FLAG_BUFFERED_CONTENT_DEFLATED)) + { + err = enlist_unique_header(csp->headers, "Content-Encoding", "deflate"); + if (JB_ERR_OK == err) + { + log_error(LOG_LEVEL_HEADER, "Added header: Content-Encoding: deflate"); + } + } +#endif + return err; } @@ -1332,7 +1343,7 @@ static jb_err header_tagger(struct client_state *csp, char *header) b->name); continue; } - + if (!list_contains_item(csp->tags, tag)) { if (JB_ERR_OK != enlist(csp->tags, tag)) @@ -1496,7 +1507,7 @@ static jb_err filter_header(struct client_state *csp, char **header) matches = pcrs_execute(job, *header, size, &newheader, &size); if ( 0 < matches ) { - current_hits += matches; + current_hits += matches; log_error(LOG_LEVEL_HEADER, "Transforming \"%s\" to \"%s\"", *header, newheader); freez(*header); *header = newheader; @@ -1810,7 +1821,7 @@ static jb_err client_save_content_length(struct client_state *csp, char **header * Function : client_connection * * Description : Makes sure a proper "Connection:" header is - * set and signals connection_header_adder + * set and signals connection_header_adder * to do nothing. * * Parameters : @@ -1838,6 +1849,11 @@ static jb_err client_connection(struct client_state *csp, char **header) log_error(LOG_LEVEL_HEADER, "Removing \'%s\' to imply keep-alive.", *header); freez(*header); + /* + * While we imply keep-alive to the server, + * we have to remember that the client didn't. + */ + csp->flags &= ~CSP_FLAG_CLIENT_CONNECTION_KEEP_ALIVE; } else { @@ -1947,7 +1963,7 @@ static jb_err crunch_server_header(struct client_state *csp, char **header) /* Is the current header the lucky one? */ if (strstr(*header, crunch_pattern)) { - log_error(LOG_LEVEL_HEADER, "Crunching server header: %s (contains: %s)", *header, crunch_pattern); + log_error(LOG_LEVEL_HEADER, "Crunching server header: %s (contains: %s)", *header, crunch_pattern); freez(*header); } } @@ -2028,7 +2044,7 @@ static jb_err server_content_type(struct client_state *csp, char **header) { /* * Make sure the user doesn't accidentally - * change the content type of binary documents. + * change the content type of binary documents. */ if ((csp->content_type & CT_TEXT) || (csp->action->flags & ACTION_FORCE_TEXT_MODE)) { @@ -2127,7 +2143,7 @@ static jb_err server_transfer_coding(struct client_state *csp, char **header) * * If FEATURE_ZLIB is enabled and the compression type * supported, the content is marked for decompression. - * + * * XXX: Doesn't properly deal with multiple or with * unsupported but unknown encodings. * Is case-sensitive but shouldn't be. @@ -2248,7 +2264,7 @@ static jb_err server_adjust_content_encoding(struct client_state *csp, char **he /* * We successfully decompressed the content, * and have to clean the header now, so the - * client no longer expects compressed data.. + * client no longer expects compressed data. * * XXX: There is a difference between cleaning * and removing it completely. @@ -2416,7 +2432,7 @@ static jb_err server_content_disposition(struct client_state *csp, char **header return JB_ERR_OK; } else - { + { /* * Replacing Content-Disposition header */ @@ -2456,7 +2472,6 @@ static jb_err server_content_disposition(struct client_state *csp, char **header static jb_err server_last_modified(struct client_state *csp, char **header) { const char *newval; - char buf[BUFFER_SIZE]; time_t last_modified; char newheader[50]; @@ -2481,18 +2496,19 @@ static jb_err server_last_modified(struct client_state *csp, char **header) return JB_ERR_OK; } else if (0 == strcmpic(newval, "reset-to-request-time")) - { + { /* * Setting Last-Modified Header to now. */ + char buf[30]; get_http_time(0, buf, sizeof(buf)); freez(*header); *header = strdup("Last-Modified: "); - string_append(header, buf); + string_append(header, buf); if (*header == NULL) { - log_error(LOG_LEVEL_HEADER, "Insufficient memory. Last-Modified header got lost, boohoo."); + log_error(LOG_LEVEL_HEADER, "Insufficient memory. Last-Modified header got lost, boohoo."); } else { @@ -2527,7 +2543,7 @@ static jb_err server_last_modified(struct client_state *csp, char **header) if (negative_delta) { - rtime *= -1; + rtime *= -1; log_error(LOG_LEVEL_HEADER, "Server time in the future."); } rtime = pick_from_range(rtime); @@ -2562,7 +2578,7 @@ static jb_err server_last_modified(struct client_state *csp, char **header) if (*header == NULL) { log_error(LOG_LEVEL_ERROR, "Insufficient memory, header crunched without replacement."); - return JB_ERR_MEMORY; + return JB_ERR_MEMORY; } days = rtime / (3600 * 24); @@ -2607,6 +2623,13 @@ static jb_err server_last_modified(struct client_state *csp, char **header) *********************************************************************/ static jb_err client_accept_encoding(struct client_state *csp, char **header) { +#ifdef FEATURE_COMPRESSION + if ((csp->config->feature_flags & RUNTIME_FEATURE_COMPRESSION) + && strstr(*header, "deflate")) + { + csp->flags |= CSP_FLAG_CLIENT_SUPPORTS_DEFLATE; + } +#endif if ((csp->action->flags & ACTION_NO_COMPRESSION) != 0) { log_error(LOG_LEVEL_HEADER, "Suppressed offer to compress content"); @@ -2671,7 +2694,7 @@ static jb_err client_referrer(struct client_state *csp, char **header) /* 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 @@ -2769,18 +2792,18 @@ static jb_err client_accept_language(struct client_state *csp, char **header) return JB_ERR_OK; } else - { + { /* * Replacing Accept-Language header */ freez(*header); *header = strdup("Accept-Language: "); - string_append(header, newval); + string_append(header, newval); if (*header == NULL) { log_error(LOG_LEVEL_ERROR, - "Insufficient memory. Accept-Language header crunched without replacement."); + "Insufficient memory. Accept-Language header crunched without replacement."); } else { @@ -2821,7 +2844,7 @@ static jb_err crunch_client_header(struct client_state *csp, char **header) /* Is the current header the lucky one? */ if (strstr(*header, crunch_pattern)) { - log_error(LOG_LEVEL_HEADER, "Crunching client header: %s (contains: %s)", *header, crunch_pattern); + log_error(LOG_LEVEL_HEADER, "Crunching client header: %s (contains: %s)", *header, crunch_pattern); freez(*header); } } @@ -3126,10 +3149,10 @@ static jb_err client_host(struct client_state *csp, char **header) return JB_ERR_OK; } - if (!csp->http->hostport || (*csp->http->hostport == '*') || + if (!csp->http->hostport || (*csp->http->hostport == '*') || *csp->http->hostport == ' ' || *csp->http->hostport == '\0') { - + if (NULL == (p = strdup((*header)+6))) { return JB_ERR_MEMORY; @@ -3192,13 +3215,13 @@ static jb_err client_if_modified_since(struct client_state *csp, char **header) struct tm gmt; #endif struct tm *timeptr = NULL; - time_t tm = 0; + time_t tm = 0; const char *newval; char * endptr; - + 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, * the problem is gone and the client now tries to revalidate our * error message on the real server. The revalidation would always @@ -3238,7 +3261,7 @@ static jb_err client_if_modified_since(struct client_state *csp, char **header) *header, rtime, (rtime == 1 || rtime == -1) ? "e": "es"); if (negative_range) { - rtime *= -1; + rtime *= -1; } rtime *= 60; rtime = pick_from_range(rtime); @@ -3275,7 +3298,7 @@ static jb_err client_if_modified_since(struct client_state *csp, char **header) if (*header == NULL) { log_error(LOG_LEVEL_HEADER, "Insufficient memory, header crunched without replacement."); - return JB_ERR_MEMORY; + return JB_ERR_MEMORY; } hours = rtime / 3600; @@ -3315,7 +3338,7 @@ static jb_err client_if_modified_since(struct client_state *csp, char **header) static jb_err client_if_none_match(struct client_state *csp, char **header) { if (csp->action->flags & ACTION_CRUNCH_IF_NONE_MATCH) - { + { log_error(LOG_LEVEL_HEADER, "Crunching %s", *header); freez(*header); } @@ -3357,7 +3380,7 @@ jb_err client_x_filter(struct client_state *csp, char **header) "force-text-mode overruled the client's request to fetch without filtering!"); } else - { + { csp->content_type = CT_TABOO; /* XXX: This hack shouldn't be necessary */ csp->flags |= CSP_FLAG_NO_FILTERING; log_error(LOG_LEVEL_HEADER, "Accepted the client's request to fetch without filtering."); @@ -3366,7 +3389,7 @@ jb_err client_x_filter(struct client_state *csp, char **header) freez(*header); } } - return JB_ERR_OK; + return JB_ERR_OK; } @@ -3400,7 +3423,7 @@ static jb_err client_range(struct client_state *csp, char **header) freez(*header); } - return JB_ERR_OK; + return JB_ERR_OK; } /* the following functions add headers directly to the header list */ @@ -3457,36 +3480,6 @@ static jb_err client_host_adder(struct client_state *csp) } -#if 0 -/********************************************************************* - * - * Function : client_accept_encoding_adder - * - * Description : Add an Accept-Encoding header to the client's request - * that disables compression if the action applies, and - * the header is not already there. Called from `sed'. - * Note: For HTTP/1.0, the absence of the header is enough. - * - * 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_accept_encoding_adder(struct client_state *csp) -{ - if ( ((csp->action->flags & ACTION_NO_COMPRESSION) != 0) - && (!strcmpic(csp->http->ver, "HTTP/1.1")) ) - { - return enlist_unique(csp->headers, "Accept-Encoding: identity;q=1.0, *;q=0", 16); - } - - return JB_ERR_OK; -} -#endif - - /********************************************************************* * * Function : client_xtra_adder @@ -3769,7 +3762,7 @@ static jb_err server_http(struct client_state *csp, char **header) static jb_err server_set_cookie(struct client_state *csp, char **header) { time_t now; - time_t cookie_time; + time_t cookie_time; time(&now); @@ -3979,7 +3972,7 @@ int strclean(char *string, const char *substring) * to get the numerical respresentation. * * Parameters : - * 1 : header_time = HTTP header time as string. + * 1 : header_time = HTTP header time as string. * 2 : result = storage for header_time in seconds * * Returns : JB_ERR_OK if the time format was recognized, or @@ -3989,34 +3982,49 @@ int strclean(char *string, const char *substring) static jb_err parse_header_time(const char *header_time, time_t *result) { struct tm gmt; - /* - * Zero out gmt to prevent time zone offsets. - * - * While this is only necessary on some platforms - * (mingw32 for example), I don't know how to - * detect these automatically and doing it everywhere - * shouldn't hurt. + * Checking for two-digit years first in an + * attempt to work around GNU libc's strptime() + * reporting negative year values when using %Y. */ - memset(&gmt, 0, sizeof(gmt)); - - /* Tue, 02 Jun 2037 20:00:00 */ - if ((NULL == strptime(header_time, "%a, %d %b %Y %H:%M:%S", &gmt)) - /* Tue, 02-Jun-2037 20:00:00 */ - && (NULL == strptime(header_time, "%a, %d-%b-%Y %H:%M:%S", &gmt)) - /* Tue, 02-Jun-37 20:00:00 */ - && (NULL == strptime(header_time, "%a, %d-%b-%y %H:%M:%S", &gmt)) - /* Tuesday, 02-Jun-2037 20:00:00 */ - && (NULL == strptime(header_time, "%A, %d-%b-%Y %H:%M:%S", &gmt)) - /* Tuesday Jun 02 20:00:00 2037 */ - && (NULL == strptime(header_time, "%A %b %d %H:%M:%S %Y", &gmt))) + static const char * const time_formats[] = { + /* Tue, 02-Jun-37 20:00:00 */ + "%a, %d-%b-%y %H:%M:%S", + /* Tue, 02 Jun 2037 20:00:00 */ + "%a, %d %b %Y %H:%M:%S", + /* Tue, 02-Jun-2037 20:00:00 */ + "%a, %d-%b-%Y %H:%M:%S", + /* Tuesday, 02-Jun-2037 20:00:00 */ + "%A, %d-%b-%Y %H:%M:%S", + /* Tuesday Jun 02 20:00:00 2037 */ + "%A %b %d %H:%M:%S %Y" + }; + unsigned int i; + + for (i = 0; i < SZ(time_formats); i++) { - return JB_ERR_PARSE; - } + /* + * Zero out gmt to prevent time zone offsets. + * Documented to be required for GNU libc. + */ + memset(&gmt, 0, sizeof(gmt)); - *result = timegm(&gmt); + if (NULL != strptime(header_time, time_formats[i], &gmt)) + { + /* Sanity check for GNU libc. */ + if (gmt.tm_year < 0) + { + log_error(LOG_LEVEL_HEADER, + "Failed to parse '%s' using '%s'. Moving on.", + header_time, time_formats[i]); + continue; + } + *result = timegm(&gmt); + return JB_ERR_OK; + } + } - return JB_ERR_OK; + return JB_ERR_PARSE; } @@ -4035,7 +4043,7 @@ static jb_err parse_header_time(const char *header_time, time_t *result) * Parameters : * 1 : headers = List of headers (one of them hopefully being * the "Host:" header) - * 2 : http = storage for the result (host, port and hostport). + * 2 : http = storage for the result (host, port and hostport). * * Returns : JB_ERR_MEMORY in case of memory problems, * JB_ERR_PARSE if the host header couldn't be found, @@ -4110,7 +4118,7 @@ jb_err get_destination_from_headers(const struct list *headers, struct http_requ * * Description : Helper for client_referrer to forge a referer as * 'http://[hostname:port/' to fool stupid - * checks for in-site links + * checks for in-site links * * Parameters : * 1 : header = Pointer to header pointer