*
* Purpose : Declares functions to parse/crunch headers and pages.
*
- * Copyright : Written by and Copyright (C) 2001-2020 the
+ * Copyright : Written by and Copyright (C) 2001-2021 the
* Privoxy team. https://www.privoxy.org/
*
* Based on the Internet Junkbuster originally written
}
+/*********************************************************************
+ *
+ * Function : can_add_to_iob
+ *
+ * Description : Checks if the given number of bytes can be added to the given iob
+ * without exceeding the given buffer limit.
+ *
+ * Parameters :
+ * 1 : iob = Destination buffer.
+ * 2 : buffer_limit = Limit to which the destination may grow
+ * 3 : n = number of bytes to be added
+ *
+ * Returns : TRUE if the given iob can handle given number of bytes
+ * FALSE buffer limit will be exceeded
+ *
+ *********************************************************************/
+int can_add_to_iob(const struct iob *iob, const size_t buffer_limit, size_t n)
+{
+ return ((size_t)(iob->eod - iob->buf) + n + 1) > buffer_limit ? FALSE : TRUE;
+}
+
/*********************************************************************
*
* Function : add_to_iob
* or buffer limit reached.
*
*********************************************************************/
-jb_err add_to_iob(struct iob *iob, const size_t buffer_limit, char *src, long n)
+jb_err add_to_iob(struct iob *iob, const size_t buffer_limit, const char *src, long n)
{
size_t used, offset, need;
char *p;
cur = csp->iob->cur;
- if (bufsize < (size_t)10)
+ if (old_size < (size_t)10)
{
/*
* This is to protect the parsing of gzipped data,
|| ((*cur++ & 0xff) != GZIP_IDENTIFIER_2)
|| (*cur++ != Z_DEFLATED))
{
- log_error(LOG_LEVEL_ERROR, "Invalid gzip header when decompressing");
+ log_error(LOG_LEVEL_ERROR,
+ "Invalid gzip header when decompressing.");
return JB_ERR_COMPRESS;
}
else
if (flags & GZIP_FLAG_RESERVED_BITS)
{
/* The gzip header has reserved bits set; bail out. */
- log_error(LOG_LEVEL_ERROR, "Invalid gzip header flags when decompressing");
+ log_error(LOG_LEVEL_ERROR,
+ "Invalid gzip header flags when decompressing.");
return JB_ERR_COMPRESS;
}
if ((skip_bytes < 0) || (skip_bytes >= (csp->iob->eod - cur)))
{
log_error(LOG_LEVEL_ERROR,
- "Unreasonable amount of bytes to skip (%d). Stopping decompression",
+ "Unreasonable amount of bytes to skip (%d). "
+ "Stopping decompression.",
skip_bytes);
return JB_ERR_COMPRESS;
}
log_error(LOG_LEVEL_INFO,
- "Skipping %d bytes for gzip compression. Does this sound right?",
+ "Skipping %d bytes for gzip compression. "
+ "Does this sound right?",
skip_bytes);
cur += skip_bytes;
}
else
{
log_error(LOG_LEVEL_ERROR,
- "Unable to determine compression format for decompression");
+ "Unable to determine compression format for decompression.");
return JB_ERR_COMPRESS;
}
*/
if (inflateInit2(&zstr, -MAX_WBITS) != Z_OK)
{
- log_error(LOG_LEVEL_ERROR, "Error initializing decompression");
+ log_error(LOG_LEVEL_ERROR, "Error initializing decompression.");
return JB_ERR_COMPRESS;
}
/*
* Next, we allocate new storage for the inflated data.
* We don't modify the existing iob yet, so in case there
- * is error in decompression we can recover gracefully.
+ * is an error in decompression we can recover gracefully.
*/
buf = zalloc(bufsize);
if (NULL == buf)
{
- log_error(LOG_LEVEL_ERROR, "Out of memory decompressing iob");
+ log_error(LOG_LEVEL_ERROR, "Out of memory decompressing iob.");
return JB_ERR_MEMORY;
}
*/
if (bufsize >= csp->config->buffer_limit)
{
- log_error(LOG_LEVEL_ERROR, "Buffer limit reached while decompressing iob");
+ log_error(LOG_LEVEL_ERROR,
+ "Buffer limit reached while decompressing iob.");
freez(buf);
inflateEnd(&zstr);
return JB_ERR_MEMORY;
tmpbuf = realloc(buf, bufsize);
if (NULL == tmpbuf)
{
- log_error(LOG_LEVEL_ERROR, "Out of memory decompressing iob");
+ log_error(LOG_LEVEL_ERROR,
+ "Out of memory decompressing iob.");
freez(buf);
inflateEnd(&zstr);
return JB_ERR_MEMORY;
log_error(LOG_LEVEL_ERROR,
"Unexpected error while decompressing to the buffer (iob): %s",
zstr.msg);
+ freez(buf);
return JB_ERR_COMPRESS;
}
else
{
/* It seems that zlib did something weird. */
- log_error(LOG_LEVEL_ERROR, "Inconsistent buffer after decompression");
+ log_error(LOG_LEVEL_ERROR,
+ "Inconsistent buffer after decompression.");
return JB_ERR_COMPRESS;
}
}
list_remove_all(headers);
- list_duplicate(headers, new_headers);
- list_remove_all(new_headers);
+ headers->first = new_headers->first;
+ headers->last = new_headers->last;
return;
}
f++;
}
- if (!filter_server_headers && !list_is_empty(csp->config->ordered_client_headers))
+ if (!filter_server_headers &&
+ !list_is_empty(csp->config->ordered_client_headers) &&
+ csp->headers->first->str != NULL)
{
enforce_header_order(csp->headers, csp->config->ordered_client_headers);
}
csp->flags |= CSP_FLAG_CLIENT_HEADER_PARSING_DONE;
/*
- * Update the last header which may have changed
- * due to header additions,
+ * Update the https headers list which may have
+ * been modified due to header additions or header
+ * reordering.
*/
+ csp->https_headers->first = csp->headers->first;
csp->https_headers->last = csp->headers->last;
csp->headers->first = headers.first;
if (NULL == joblist)
{
- log_error(LOG_LEVEL_RE_FILTER,
+ log_error(LOG_LEVEL_TAGGING,
"Tagger %s has empty joblist. Nothing to do.", b->name);
continue;
}
* no one would do it intentionally.
*/
freez(tag);
- log_error(LOG_LEVEL_INFO,
+ log_error(LOG_LEVEL_TAGGING,
"Tagger \'%s\' created an empty tag. Ignored.", b->name);
continue;
}
+ if (list_contains_item(csp->action->multi[ACTION_MULTI_SUPPRESS_TAG], tag))
+ {
+ log_error(LOG_LEVEL_TAGGING,
+ "Tagger \'%s\' didn't add tag \'%s\': suppressed",
+ b->name, tag);
+ freez(tag);
+ continue;
+ }
+
if (!list_contains_item(csp->tags, tag))
{
if (JB_ERR_OK != enlist(csp->tags, tag))
action_message = "No action bits update necessary.";
}
- log_error(LOG_LEVEL_HEADER,
+ log_error(LOG_LEVEL_TAGGING,
"Tagger \'%s\' added tag \'%s\'. %s",
b->name, tag, action_message);
}
else
{
/* XXX: Is this log-worthy? */
- log_error(LOG_LEVEL_HEADER,
+ log_error(LOG_LEVEL_TAGGING,
"Tagger \'%s\' didn't add tag \'%s\'. Tag already present",
b->name, tag);
}
if (NULL == joblist)
{
- log_error(LOG_LEVEL_RE_FILTER, "Filter %s has empty joblist. Nothing to do.", b->name);
+ log_error(LOG_LEVEL_RE_FILTER,
+ "Filter %s has empty joblist. Nothing to do.", b->name);
continue;
}
if (0 < matches)
{
current_hits += matches;
- log_error(LOG_LEVEL_HEADER, "Transforming \"%s\" to \"%s\"", *header, newheader);
+ log_error(LOG_LEVEL_HEADER,
+ "Transforming \"%s\" to \"%s\"", *header, newheader);
freez(*header);
*header = newheader;
}
else
{
/* RegEx failure */
- log_error(LOG_LEVEL_ERROR, "Filtering \'%s\' with \'%s\' didn't work out: %s",
+ log_error(LOG_LEVEL_ERROR,
+ "Filtering \'%s\' with \'%s\' didn't work out: %s",
*header, b->name, pcrs_strerror(matches));
if (newheader != NULL)
{
*
* 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.
+ * 2 : header = pointer to the Content-Length header
*
* Returns : JB_ERR_OK on success, or
* JB_ERR_MEMORY on out-of-memory error.
#endif /* defined(FEATURE_ZLIB) */
+/*********************************************************************
+ *
+ * Function : header_adjust_content_length
+ *
+ * Description : Replace given header with new Content-Length header.
+ *
+ * Parameters :
+ * 1 : 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.
+ * 2 : content_length = content length value to set
+ *
+ * Returns : JB_ERR_OK on success, or
+ * JB_ERR_MEMORY on out-of-memory error.
+ *
+ *********************************************************************/
+jb_err header_adjust_content_length(char **header, size_t content_length)
+{
+ const size_t header_length = 50;
+ freez(*header);
+ *header = malloc(header_length);
+ if (*header == NULL)
+ {
+ return JB_ERR_MEMORY;
+ }
+ create_content_length_header(content_length, *header, header_length);
+ return JB_ERR_OK;
+}
+
+
/*********************************************************************
*
* Function : server_adjust_content_length
/* Regenerate header if the content was modified. */
if (csp->flags & CSP_FLAG_MODIFIED)
{
- const size_t header_length = 50;
- freez(*header);
- *header = malloc(header_length);
- if (*header == NULL)
+ if (JB_ERR_OK != header_adjust_content_length(header, csp->content_length))
{
return JB_ERR_MEMORY;
}
- create_content_length_header(csp->content_length, *header, header_length);
log_error(LOG_LEVEL_HEADER,
"Adjusted Content-Length to %llu", csp->content_length);
}
return JB_ERR_PARSE;
}
- if (csp->http->status == 206)
+ if (csp->http->status == 101 ||
+ csp->http->status == 206)
{
csp->content_type = CT_TABOO;
}
return JB_ERR_PARSE;
}
- p = strdup_or_die(host);
+ p = string_tolower(host);
+ if (p == NULL)
+ {
+ return JB_ERR_MEMORY;
+ }
chomp(p);
q = strdup_or_die(p);
return JB_ERR_PARSE;
}
- p = strdup_or_die(host);
+ p = string_tolower(host);
+ if (p == NULL)
+ {
+ return JB_ERR_MEMORY;
+ }
chomp(p);
q = strdup_or_die(p);
referer[hostlength+17] = '\0';
}
referer_url = strstr(referer, "http://");
+ if (NULL == referer_url)
+ {
+ referer_url = strstr(referer, "https://");
+ }
if ((NULL == referer_url) || (NULL == strstr(referer_url, host)))
{
/* Host has changed, Referer is invalid or a https URL. */