X-Git-Url: http://www.privoxy.org/gitweb/?p=privoxy.git;a=blobdiff_plain;f=parsers.c;h=a9730786023f2da32070028956c59fa5806dd2ab;hp=ca0eb5c65679204266fe098d6079aac4b6a2516a;hb=c5245d06d667d761dc6b19f6a3b810dbdf9e5c9b;hpb=640ef193745c0bab70ded93c34dff846655aa73f diff --git a/parsers.c b/parsers.c index ca0eb5c6..a9730786 100644 --- a/parsers.c +++ b/parsers.c @@ -1,4 +1,4 @@ -const char parsers_rcs[] = "$Id: parsers.c,v 1.197 2009/07/13 17:10:57 fabiankeil Exp $"; +const char parsers_rcs[] = "$Id: parsers.c,v 1.223 2011/06/23 13:57:47 fabiankeil Exp $"; /********************************************************************* * * File : $Source: /cvsroot/ijbswa/current/parsers.c,v $ @@ -152,11 +152,16 @@ static jb_err server_http (struct client_state *csp, char **header static jb_err crunch_server_header (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_ZLIB +static jb_err server_adjust_content_encoding(struct client_state *csp, char **header); +#endif #ifdef FEATURE_CONNECTION_KEEP_ALIVE static jb_err server_save_content_length(struct client_state *csp, char **header); static jb_err server_keep_alive(struct client_state *csp, char **header); +static jb_err server_proxy_connection(struct client_state *csp, char **header); static jb_err client_keep_alive(struct client_state *csp, char **header); +static jb_err client_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); @@ -203,6 +208,7 @@ static const struct parsers client_patterns[] = { { "if-modified-since:", 18, client_if_modified_since }, #ifdef FEATURE_CONNECTION_KEEP_ALIVE { "Keep-Alive:", 11, client_keep_alive }, + { "Content-Length:", 15, client_save_content_length }, #else { "Keep-Alive:", 11, crumble }, #endif @@ -230,6 +236,7 @@ static const struct parsers server_patterns[] = { #ifdef FEATURE_CONNECTION_KEEP_ALIVE { "Content-Length:", 15, server_save_content_length }, { "Keep-Alive:", 11, server_keep_alive }, + { "Proxy-Connection:", 17, server_proxy_connection }, #else { "Keep-Alive:", 11, crumble }, #endif /* def FEATURE_CONNECTION_KEEP_ALIVE */ @@ -314,7 +321,7 @@ long flush_socket(jb_socket fd, struct iob *iob) jb_err add_to_iob(struct client_state *csp, char *buf, long n) { struct iob *iob = csp->iob; - size_t used, offset, need, want; + size_t used, offset, need; char *p; if (n <= 0) return JB_ERR_OK; @@ -337,7 +344,12 @@ jb_err add_to_iob(struct client_state *csp, char *buf, long n) if (need > iob->size) { - for (want = csp->iob->size ? csp->iob->size : 512; want <= need;) want *= 2; + size_t want = csp->iob->size ? csp->iob->size : 512; + + while (want <= need) + { + want *= 2; + } if (want <= csp->config->buffer_limit && NULL != (p = (char *)realloc(iob->buf, want))) { @@ -584,7 +596,7 @@ jb_err decompress_iob(struct client_state *csp) assert(bufsize >= skip_size); memcpy(buf, csp->iob->buf, skip_size); - zstr.avail_out = bufsize - skip_size; + zstr.avail_out = (uInt)(bufsize - skip_size); zstr.next_out = (Bytef *)buf + skip_size; /* Try to decompress the whole stream in one shot. */ @@ -607,10 +619,12 @@ jb_err decompress_iob(struct client_state *csp) } /* - * If we tried the limit and still didn't have enough - * memory, just give up. + * If we reached the buffer limit and still didn't have enough + * memory, just give up. Due to the ceiling enforced by the next + * if block we could actually check for equality here, but as it + * can be easily mistaken for a bug we don't. */ - if (bufsize == csp->config->buffer_limit) + if (bufsize >= csp->config->buffer_limit) { log_error(LOG_LEVEL_ERROR, "Buffer limit reached while decompressing iob"); return JB_ERR_MEMORY; @@ -642,7 +656,7 @@ jb_err decompress_iob(struct client_state *csp) * buffer, which may be in a location different from * the old one. */ - zstr.avail_out += bufsize - oldbufsize; + zstr.avail_out += (uInt)(bufsize - oldbufsize); zstr.next_out = (Bytef *)tmpbuf + bufsize - zstr.avail_out; /* @@ -651,7 +665,6 @@ jb_err decompress_iob(struct client_state *csp) */ assert(zstr.avail_out == tmpbuf + bufsize - (char *)zstr.next_out); assert((char *)zstr.next_out == tmpbuf + ((char *)oldnext_out - buf)); - assert(zstr.avail_out > 0U); buf = tmpbuf; } @@ -1129,7 +1142,7 @@ jb_err update_server_headers(struct client_state *csp) { "Content-Length:", 15, server_adjust_content_length }, { "Transfer-Encoding:", 18, server_transfer_coding }, #ifdef FEATURE_ZLIB - { "Content-Encoding:", 17, server_content_encoding }, + { "Content-Encoding:", 17, server_adjust_content_encoding }, #endif /* def FEATURE_ZLIB */ { NULL, 0, NULL } }; @@ -1174,6 +1187,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; } @@ -1206,7 +1231,6 @@ static jb_err header_tagger(struct client_state *csp, char *header) struct re_filterfile_spec *b; struct list_entry *tag_name; - int found_filters = 0; const size_t header_length = strlen(header); if (csp->flags & CSP_FLAG_CLIENT_HEADER_PARSING_DONE) @@ -1220,21 +1244,7 @@ static jb_err header_tagger(struct client_state *csp, char *header) multi_action_index = ACTION_MULTI_CLIENT_HEADER_TAGGER; } - /* Check if there are any filters */ - for (i = 0; i < MAX_AF_FILES; i++) - { - fl = csp->rlist[i]; - if (NULL != fl) - { - if (NULL != fl->f) - { - found_filters = 1; - break; - } - } - } - - if (0 == found_filters) + if (filters_available(csp) == FALSE) { log_error(LOG_LEVEL_ERROR, "Inconsistent configuration: " "tagging enabled, but no taggers available."); @@ -1417,7 +1427,7 @@ static jb_err filter_header(struct client_state *csp, char **header) struct re_filterfile_spec *b; struct list_entry *filtername; - int i, found_filters = 0; + int i; int wanted_filter_type; int multi_action_index; @@ -1437,23 +1447,7 @@ static jb_err filter_header(struct client_state *csp, char **header) multi_action_index = ACTION_MULTI_CLIENT_HEADER_FILTER; } - /* - * Need to check the set of re_filterfiles... - */ - for (i = 0; i < MAX_AF_FILES; i++) - { - fl = csp->rlist[i]; - if (NULL != fl) - { - if (NULL != fl->f) - { - found_filters = 1; - break; - } - } - } - - if (0 == found_filters) + if (filters_available(csp) == FALSE) { log_error(LOG_LEVEL_ERROR, "Inconsistent configuration: " "header filtering enabled, but no matching filters available."); @@ -1671,6 +1665,30 @@ static jb_err server_keep_alive(struct client_state *csp, char **header) } +/********************************************************************* + * + * Function : server_proxy_connection + * + * Description : Figures out whether or not we should add a + * Proxy-Connection header. + * + * 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 server_proxy_connection(struct client_state *csp, char **header) +{ + csp->flags |= CSP_FLAG_SERVER_PROXY_CONNECTION_HEADER_SET; + return JB_ERR_OK; +} + + /********************************************************************* * * Function : client_keep_alive @@ -1725,6 +1743,76 @@ static jb_err client_keep_alive(struct client_state *csp, char **header) return JB_ERR_OK; } + + +/********************************************************************* + * + * Function : get_content_length + * + * Description : Gets the content length specified in a + * Content-Length header. + * + * Parameters : + * 1 : header = The Content-Length header. + * 2 : length = Storage to return the value. + * + * Returns : JB_ERR_OK on success, or + * JB_ERR_PARSE if no value is recognized. + * + *********************************************************************/ +static jb_err get_content_length(const char *header, unsigned long long *length) +{ + assert(header[14] == ':'); + +#ifdef _WIN32 + assert(sizeof(unsigned long long) > 4); + if (1 != sscanf(header+14, ": %I64u", length)) +#else + if (1 != sscanf(header+14, ": %llu", length)) +#endif + { + return JB_ERR_PARSE; + } + + return JB_ERR_OK; +} + + +/********************************************************************* + * + * Function : client_save_content_length + * + * Description : Save the Content-Length sent by the client. + * + * 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_save_content_length(struct client_state *csp, char **header) +{ + unsigned long long content_length = 0; + + assert(*(*header+14) == ':'); + + if (JB_ERR_OK != get_content_length(*header, &content_length)) + { + log_error(LOG_LEVEL_ERROR, "Crunching invalid header: %s", *header); + freez(*header); + } + else + { + csp->expected_client_content_length = content_length; + } + + return JB_ERR_OK; +} #endif /* def FEATURE_CONNECTION_KEEP_ALIVE */ @@ -1776,7 +1864,6 @@ static jb_err client_connection(struct client_state *csp, char **header) "Replaced: \'%s\' with \'%s\'", old_header, *header); freez(old_header); } - csp->flags |= CSP_FLAG_CLIENT_CONNECTION_KEEP_ALIVE; } else { @@ -1786,7 +1873,18 @@ static jb_err client_connection(struct client_state *csp, char **header) *header); csp->flags &= ~CSP_FLAG_CLIENT_CONNECTION_KEEP_ALIVE; } -#else + } + else if ((csp->config->feature_flags & RUNTIME_FEATURE_CONNECTION_KEEP_ALIVE)) + { + log_error(LOG_LEVEL_HEADER, + "Keeping the client header '%s' around. " + "The server connection will be kept alive if possible.", + *header); + csp->flags |= CSP_FLAG_CLIENT_CONNECTION_KEEP_ALIVE; +#endif /* def FEATURE_CONNECTION_KEEP_ALIVE */ + } + else + { char *old_header = *header; *header = strdup(connection_close); @@ -1797,18 +1895,7 @@ static jb_err client_connection(struct client_state *csp, char **header) log_error(LOG_LEVEL_HEADER, "Replaced: \'%s\' with \'%s\'", old_header, *header); freez(old_header); -#endif /* def FEATURE_CONNECTION_KEEP_ALIVE */ - } -#ifdef FEATURE_CONNECTION_KEEP_ALIVE - else - { - log_error(LOG_LEVEL_HEADER, - "Keeping the client header '%s' around. " - "The server connection will be kept alive if possible.", - *header); - csp->flags |= CSP_FLAG_CLIENT_CONNECTION_KEEP_ALIVE; } -#endif /* def FEATURE_CONNECTION_KEEP_ALIVE */ /* Signal client_connection_adder() to return early. */ csp->flags |= CSP_FLAG_CLIENT_CONNECTION_HEADER_SET; @@ -1886,7 +1973,7 @@ static jb_err crunch_server_header(struct client_state *csp, char **header) * Function : server_content_type * * Description : Set the content-type for filterable types (text/.*, - * .*xml.*, javascript and image/gif) unless filtering has been + * .*xml.*, .*script.* and image/gif) unless filtering has been * forbidden (CT_TABOO) while parsing earlier headers. * NOTE: Since text/plain is commonly used by web servers * for files whose correct type is unknown, we don't @@ -1936,7 +2023,7 @@ static jb_err server_content_type(struct client_state *csp, char **header) */ if ((strstr(*header, "text/") && !strstr(*header, "plain")) || strstr(*header, "xml") - || strstr(*header, "application/x-javascript")) + || strstr(*header, "script")) { csp->content_type |= CT_TEXT; } @@ -1952,7 +2039,7 @@ static jb_err server_content_type(struct client_state *csp, char **header) if (csp->action->flags & ACTION_CONTENT_TYPE_OVERWRITE) { /* - * Make sure the user doesn't accidently + * Make sure the user doesn't accidentally * change the content type of binary documents. */ if ((csp->content_type & CT_TEXT) || (csp->action->flags & ACTION_FORCE_TEXT_MODE)) @@ -2046,16 +2133,16 @@ static jb_err server_transfer_coding(struct client_state *csp, char **header) * * Function : server_content_encoding * - * Description : This function is run twice for each request, - * unless FEATURE_ZLIB and filtering are disabled. + * Description : Used to check if the content is compressed, and if + * FEATURE_ZLIB is disabled, filtering is disabled as + * well. * - * The first run is used to check if the content - * is compressed, if FEATURE_ZLIB is disabled - * filtering is then disabled as well, if FEATURE_ZLIB - * is enabled the content is marked for decompression. + * If FEATURE_ZLIB is enabled and the compression type + * supported, the content is marked for decompression. * - * The second run is used to remove the Content-Encoding - * header if the decompression was successful. + * XXX: Doesn't properly deal with multiple or with + * unsupported but unknown encodings. + * Is case-sensitive but shouldn't be. * * Parameters : * 1 : csp = Current client state (buffers, headers, etc...) @@ -2071,19 +2158,25 @@ static jb_err server_transfer_coding(struct client_state *csp, char **header) static jb_err server_content_encoding(struct client_state *csp, char **header) { #ifdef FEATURE_ZLIB - if ((csp->flags & CSP_FLAG_MODIFIED) - && (csp->content_type & (CT_GZIP | CT_DEFLATE))) + if (strstr(*header, "sdch")) { /* - * We successfully decompressed the content, - * and have to clean the header now, so the - * client no longer expects compressed data.. - * - * XXX: There is a difference between cleaning - * and removing it completely. + * Shared Dictionary Compression over HTTP isn't supported, + * filtering it anyway is pretty much guaranteed to mess up + * the encoding. */ - log_error(LOG_LEVEL_HEADER, "Crunching: %s", *header); - freez(*header); + csp->content_type |= CT_TABOO; + + /* + * Log a warning if the user expects the content to be filtered. + */ + if ((csp->rlist != NULL) && + (!list_is_empty(csp->action->multi[ACTION_MULTI_FILTER]))) + { + log_error(LOG_LEVEL_INFO, + "SDCH-compressed content detected, content filtering disabled. " + "Consider suppressing SDCH offers made by the client."); + } } else if (strstr(*header, "gzip")) { @@ -2104,7 +2197,16 @@ static jb_err server_content_encoding(struct client_state *csp, char **header) csp->content_type |= CT_TABOO; } #else /* !defined(FEATURE_ZLIB) */ - if (strstr(*header, "gzip") || strstr(*header, "compress") || strstr(*header, "deflate")) + /* + * XXX: Using a black list here isn't the right approach. + * + * In case of SDCH, building with zlib support isn't + * going to help. + */ + if (strstr(*header, "gzip") || + strstr(*header, "compress") || + strstr(*header, "deflate") || + strstr(*header, "sdch")) { /* * Body is compressed, turn off pcrs and gif filtering. @@ -2130,6 +2232,49 @@ static jb_err server_content_encoding(struct client_state *csp, char **header) } +#ifdef FEATURE_ZLIB +/********************************************************************* + * + * Function : server_adjust_content_encoding + * + * Description : Remove the Content-Encoding header if the + * decompression was successful and the content + * has been modifed. + * + * 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_adjust_content_encoding(struct client_state *csp, char **header) +{ + if ((csp->flags & CSP_FLAG_MODIFIED) + && (csp->content_type & (CT_GZIP | CT_DEFLATE))) + { + /* + * We successfully decompressed the content, + * and have to clean the header now, so the + * client no longer expects compressed data.. + * + * XXX: There is a difference between cleaning + * and removing it completely. + */ + log_error(LOG_LEVEL_HEADER, "Crunching: %s", *header); + freez(*header); + } + + return JB_ERR_OK; + +} +#endif /* defined(FEATURE_ZLIB) */ + + /********************************************************************* * * Function : server_adjust_content_length @@ -2193,11 +2338,7 @@ static jb_err server_save_content_length(struct client_state *csp, char **header assert(*(*header+14) == ':'); -#ifdef _WIN32 - if (1 != sscanf(*header+14, ": %I64u", &content_length)) -#else - if (1 != sscanf(*header+14, ": %llu", &content_length)) -#endif + if (JB_ERR_OK != get_content_length(*header, &content_length)) { log_error(LOG_LEVEL_ERROR, "Crunching invalid header: %s", *header); freez(*header); @@ -2328,15 +2469,9 @@ 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]; -#ifdef HAVE_GMTIME_R - struct tm gmt; -#endif - struct tm *timeptr = NULL; - time_t now, last_modified; - long int days, hours, minutes, seconds; - + /* * Are we messing with the Last-Modified header? */ @@ -2381,16 +2516,7 @@ static jb_err server_last_modified(struct client_state *csp, char **header) const char *header_time = *header + sizeof("Last-Modified:"); log_error(LOG_LEVEL_HEADER, "Randomizing: %s", *header); - now = time(NULL); -#ifdef HAVE_GMTIME_R - gmtime_r(&now, &gmt); -#elif defined(MUTEX_LOCKS_AVAILABLE) - privoxy_mutex_lock(&gmtime_mutex); - gmtime(&now); - privoxy_mutex_unlock(&gmtime_mutex); -#else - gmtime(&now); -#endif + if (JB_ERR_OK != parse_header_time(header_time, &last_modified)) { log_error(LOG_LEVEL_HEADER, "Couldn't parse: %s in %s (crunching!)", header_time, *header); @@ -2398,9 +2524,17 @@ static jb_err server_last_modified(struct client_state *csp, char **header) } else { - long int rtime = (long int)difftime(now, last_modified); + time_t now; + struct tm *timeptr = NULL; + long int rtime; +#ifdef HAVE_GMTIME_R + struct tm gmt; +#endif + now = time(NULL); + rtime = (long int)difftime(now, last_modified); if (rtime) { + long int days, hours, minutes, seconds; const int negative_delta = (rtime < 0); if (negative_delta) @@ -2485,25 +2619,16 @@ 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 (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"); - freez(*header); - - /* Temporarily disable the correct behaviour to - * work around a PHP bug. - * - * if (!strcmpic(csp->http->ver, "HTTP/1.1")) - * { - * *header = strdup("Accept-Encoding: identity;q=1.0, *;q=0"); - * if (*header == NULL) - * { - * return JB_ERR_MEMORY; - * } - * } - * - */ } return JB_ERR_OK; @@ -3087,7 +3212,6 @@ static jb_err client_if_modified_since(struct client_state *csp, char **header) struct tm *timeptr = NULL; time_t tm = 0; const char *newval; - long int hours, minutes, seconds; char * endptr; if ( 0 == strcmpic(*header, "If-Modified-Since: Wed, 08 Jun 1955 12:00:00 GMT")) @@ -3122,6 +3246,7 @@ static jb_err client_if_modified_since(struct client_state *csp, char **header) } else { + long int hours, minutes, seconds; long int rtime = strtol(newval, &endptr, 0); const int negative_range = (rtime < 0); @@ -3464,7 +3589,7 @@ static jb_err client_x_forwarded_for_adder(struct client_state *csp) * * Function : server_connection_adder * - * Description : Adds an appropiate "Connection:" header to csp->headers + * Description : Adds an appropriate "Connection:" header to csp->headers * unless the header was already present. Called from `sed'. * * Parameters : @@ -3517,7 +3642,7 @@ static jb_err server_connection_adder(struct client_state *csp) * * Description : Adds a "Proxy-Connection: keep-alive" header to * csp->headers if the client asked for keep-alive. - * XXX: We should reuse existant ones. + * XXX: We should reuse existent ones. * * Parameters : * 1 : csp = Current client state (buffers, headers, etc...) @@ -3532,7 +3657,8 @@ static jb_err server_proxy_connection_adder(struct client_state *csp) jb_err err = JB_ERR_OK; if ((csp->flags & CSP_FLAG_CLIENT_CONNECTION_KEEP_ALIVE) - && !(csp->flags & CSP_FLAG_SERVER_SOCKET_TAINTED)) + && !(csp->flags & CSP_FLAG_SERVER_SOCKET_TAINTED) + && !(csp->flags & CSP_FLAG_SERVER_PROXY_CONNECTION_HEADER_SET)) { log_error(LOG_LEVEL_HEADER, "Adding: %s", proxy_connection_header); err = enlist(csp->headers, proxy_connection_header); @@ -3640,8 +3766,7 @@ static jb_err server_http(struct client_state *csp, char **header) * Function : server_set_cookie * * Description : Handle the server "cookie" header properly. - * Log cookie to the jar file. Then "crunch", - * accept or rewrite it to a session cookie. + * Crunch, accept or rewrite it to a session cookie. * Called from `sed'. * * TODO: Allow the user to specify a new expiration @@ -3719,6 +3844,17 @@ static jb_err server_set_cookie(struct client_state *csp, char **header) { char *expiration_date = cur_tag + 8; /* Skip "[Ee]xpires=" */ + if ((expiration_date[0] == '"') + && (expiration_date[1] != '\0')) + { + /* + * Skip quotation mark. RFC 2109 10.1.2 seems to hint + * that the expiration date isn't supposed to be quoted, + * but some servers do it anyway. + */ + expiration_date++; + } + /* Did we detect the date properly? */ if (JB_ERR_OK != parse_header_time(expiration_date, &cookie_time)) { @@ -3818,7 +3954,7 @@ static jb_err server_set_cookie(struct client_state *csp, char **header) * * Function : strclean * - * Description : In-Situ-Eliminate all occurances of substring in + * Description : In-Situ-Eliminate all occurrences of substring in * string * * Parameters : @@ -3938,7 +4074,8 @@ jb_err get_destination_from_headers(const struct list *headers, struct http_requ return JB_ERR_PARSE; } - if (NULL == (p = strdup((host)))) + p = strdup(host); + if (NULL == p) { log_error(LOG_LEVEL_ERROR, "Out of memory while parsing \"Host:\" header"); return JB_ERR_MEMORY; @@ -4082,7 +4219,7 @@ 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); + const size_t hostlength = strlen(host); const char *referer_url = NULL; if (NULL == referer) @@ -4092,14 +4229,14 @@ static jb_err handle_conditional_hide_referrer_parameter(char **header, } /* referer begins with 'Referer: http[s]://' */ - if ((hostlenght+17) < strlen(referer)) + if ((hostlength+17) < strlen(referer)) { /* * 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'; + referer[hostlength+17] = '\0'; } referer_url = strstr(referer, "http://"); if ((NULL == referer_url) || (NULL == strstr(referer_url, host)))