*/
if (NULL == (from_p = strstr(from_p, "\r\n")))
{
- log_error(LOG_LEVEL_ERROR, "Parse error while stripping \"chunked\" transfer coding");
+ log_error(LOG_LEVEL_ERROR,
+ "Failed to strip \"chunked\" transfer coding. "
+ "Line with chunk size doesn't seem to end properly.");
return JB_ERR_PARSE;
}
from_p += 2;
if (from_p + chunksize >= end_of_buffer)
{
log_error(LOG_LEVEL_ERROR,
- "End of chunk is beyond the end of the buffer.");
+ "Failed to decode content for filtering. "
+ "One chunk end is beyond the end of the buffer.");
return JB_ERR_PARSE;
}
* Function : execute_client_body_filters
*
* Description : Executes client body filters for the request that is buffered
- * in the client_iob. Upon success moves client_iob cur pointer
- * to the end of the processed data.
+ * in the client_iob. The client_iob is updated with the filtered
+ * content.
*
* Parameters :
* 1 : csp = Current client state (buffers, headers, etc...)
* 2 : content_length = content length. Upon successful filtering
* the passed value is updated with the new content length.
*
- * Returns : Pointer to the modified buffer, or
- * NULL if filtering failed or wasn't necessary.
+ * Returns : 1 if the content has been filterd. 0 if it hasn't.
*
*********************************************************************/
-char *execute_client_body_filters(struct client_state *csp, size_t *content_length)
+int execute_client_body_filters(struct client_state *csp, size_t *content_length)
{
- char *ret;
+ char *filtered_content;
assert(client_body_filters_enabled(csp->action));
/*
* No content, no filtering necessary.
*/
- return NULL;
+ return 0;
}
- ret = pcrs_filter_request_body(csp, csp->client_iob->cur, content_length);
- if (ret != NULL)
+ filtered_content = pcrs_filter_request_body(csp, csp->client_iob->cur, content_length);
+ if (filtered_content != NULL)
{
- csp->client_iob->cur = csp->client_iob->eod;
+ freez(csp->client_iob->buf);
+ csp->client_iob->buf = filtered_content;
+ csp->client_iob->cur = csp->client_iob->buf;
+ csp->client_iob->eod = csp->client_iob->cur + *content_length;
+ csp->client_iob->size = *content_length;
+
+ return 1;
+ }
+
+ return 0;
+}
+
+
+/*********************************************************************
+ *
+ * Function : execute_client_body_taggers
+ *
+ * Description : Executes client body taggers for the request that is
+ * buffered in the client_iob.
+ * XXX: Lots of code shared with header_tagger
+ *
+ * Parameters :
+ * 1 : csp = Current client state (buffers, headers, etc...)
+ * 2 : content_length = content length.
+ *
+ * Returns : XXX
+ *
+ *********************************************************************/
+jb_err execute_client_body_taggers(struct client_state *csp, size_t content_length)
+{
+ enum filter_type wanted_filter_type = FT_CLIENT_BODY_TAGGER;
+ int multi_action_index = ACTION_MULTI_CLIENT_BODY_TAGGER;
+ pcrs_job *job;
+
+ struct re_filterfile_spec *b;
+ struct list_entry *tag_name;
+
+ assert(client_body_taggers_enabled(csp->action));
+
+ if (content_length == 0)
+ {
+ /*
+ * No content, no tagging necessary.
+ */
+ return JB_ERR_OK;
+ }
+
+ log_error(LOG_LEVEL_INFO, "Got to execute tagger on %N",
+ content_length, csp->client_iob->cur);
+
+ if (list_is_empty(csp->action->multi[multi_action_index])
+ || filters_available(csp) == FALSE)
+ {
+ /* Return early if no taggers apply or if none are available. */
+ return JB_ERR_OK;
+ }
+
+ /* Execute all applying taggers */
+ for (tag_name = csp->action->multi[multi_action_index]->first;
+ NULL != tag_name; tag_name = tag_name->next)
+ {
+ char *modified_tag = NULL;
+ char *tag = csp->client_iob->cur;
+ size_t size = content_length;
+ pcrs_job *joblist;
+
+ b = get_filter(csp, tag_name->str, wanted_filter_type);
+ if (b == NULL)
+ {
+ continue;
+ }
+
+ joblist = b->joblist;
+
+ if (b->dynamic) joblist = compile_dynamic_pcrs_job_list(csp, b);
+
+ if (NULL == joblist)
+ {
+ log_error(LOG_LEVEL_TAGGING,
+ "Tagger %s has empty joblist. Nothing to do.", b->name);
+ continue;
+ }
+
+ /* execute their pcrs_joblist on the body. */
+ for (job = joblist; NULL != job; job = job->next)
+ {
+ const int hits = pcrs_execute(job, tag, size, &modified_tag, &size);
+
+ if (0 < hits)
+ {
+ /* Success, continue with the modified version. */
+ if (tag != csp->client_iob->cur)
+ {
+ freez(tag);
+ }
+ tag = modified_tag;
+ }
+ else
+ {
+ /* Tagger doesn't match */
+ if (0 > hits)
+ {
+ /* Regex failure, log it but continue anyway. */
+ log_error(LOG_LEVEL_ERROR,
+ "Problems with tagger \'%s\': %s",
+ b->name, pcrs_strerror(hits));
+ }
+ freez(modified_tag);
+ }
+ }
+
+ if (b->dynamic) pcrs_free_joblist(joblist);
+
+ /* If this tagger matched */
+ if (tag != csp->client_iob->cur)
+ {
+ if (0 == size)
+ {
+ /*
+ * There is no technical limitation which makes
+ * it impossible to use empty tags, but I assume
+ * no one would do it intentionally.
+ */
+ freez(tag);
+ 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))
+ {
+ log_error(LOG_LEVEL_ERROR,
+ "Insufficient memory to add tag \'%s\', "
+ "based on tagger \'%s\'",
+ tag, b->name);
+ }
+ else
+ {
+ char *action_message;
+ /*
+ * update the action bits right away, to make
+ * tagging based on tags set by earlier taggers
+ * of the same kind possible.
+ */
+ if (update_action_bits_for_tag(csp, tag))
+ {
+ action_message = "Action bits updated accordingly.";
+ }
+ else
+ {
+ action_message = "No action bits update necessary.";
+ }
+
+ 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_TAGGING,
+ "Tagger \'%s\' didn't add tag \'%s\'. Tag already present",
+ b->name, tag);
+ }
+ freez(tag);
+ }
}
- return ret;
+
+ return JB_ERR_OK;
}
}
+/*********************************************************************
+ *
+ * Function : client_body_taggers_enabled
+ *
+ * Description : Checks whether there are any client body taggers
+ * enabled for the current request.
+ *
+ * Parameters :
+ * 1 : action = Action spec to check.
+ *
+ * Returns : TRUE for yes, FALSE otherwise
+ *
+ *********************************************************************/
+int client_body_taggers_enabled(const struct current_action_spec *action)
+{
+ return !list_is_empty(action->multi[ACTION_MULTI_CLIENT_BODY_TAGGER]);
+}
+
/*********************************************************************
*
* Function : filters_available
{
struct block_statistics_entry *entry;
- privoxy_mutex_lock(&block_statistics_mutex);
+ privoxy_mutex_lock(&block_reason_statistics_mutex);
if (block_statistics == NULL)
{
block_statistics = zalloc_or_die(sizeof(struct block_statistics_entry));
entry = block_statistics;
entry->block_reason = strdup_or_die(block_reason);
- privoxy_mutex_unlock(&block_statistics_mutex);
+ privoxy_mutex_unlock(&block_reason_statistics_mutex);
return;
}
entry = block_statistics;
entry = entry->next;
}
- privoxy_mutex_unlock(&block_statistics_mutex);
+ privoxy_mutex_unlock(&block_reason_statistics_mutex);
}
{
struct block_statistics_entry *entry;
- privoxy_mutex_lock(&block_statistics_mutex);
+ privoxy_mutex_lock(&block_reason_statistics_mutex);
entry = block_statistics;
while (entry != NULL)
entry = entry->next;
}
- privoxy_mutex_unlock(&block_statistics_mutex);
+ privoxy_mutex_unlock(&block_reason_statistics_mutex);
}
{
struct block_statistics_entry *entry;
- privoxy_mutex_lock(&block_statistics_mutex);
+ privoxy_mutex_lock(&block_reason_statistics_mutex);
entry = block_statistics;
while (entry != NULL)
entry = entry->next;
}
- privoxy_mutex_unlock(&block_statistics_mutex);
+ privoxy_mutex_unlock(&block_reason_statistics_mutex);
}