-const char filters_rcs[] = "$Id: filters.c,v 1.91 2007/09/02 15:31:20 fabiankeil Exp $";
+const char filters_rcs[] = "$Id: filters.c,v 1.98 2008/01/04 17:43:45 fabiankeil Exp $";
/*********************************************************************
*
* File : $Source: /cvsroot/ijbswa/current/filters.c,v $
*
* Revisions :
* $Log: filters.c,v $
+ * Revision 1.98 2008/01/04 17:43:45 fabiankeil
+ * Improve the warning messages that get logged if the action files
+ * "enable" filters but no filters of that type have been loaded.
+ *
+ * Revision 1.97 2007/11/30 15:37:03 fabiankeil
+ * Use freez instead of free.
+ *
+ * Revision 1.96 2007/10/19 16:53:28 fabiankeil
+ * Add helper function to check if any content filters are enabled.
+ *
+ * Revision 1.95 2007/10/17 19:31:20 fabiankeil
+ * Omitting the zero chunk that ends the chunk transfer encoding seems
+ * to be the new black. Log the problem and continue filtering anyway.
+ *
+ * Revision 1.94 2007/09/29 13:20:20 fabiankeil
+ * Remove two redundant and one useless log messages.
+ *
+ * Revision 1.93 2007/09/29 10:21:16 fabiankeil
+ * - Move get_filter_function() from jcc.c to filters.c
+ * so the filter functions can be static.
+ * - Don't bother filtering body-less responses.
+ *
+ * Revision 1.92 2007/09/28 16:38:55 fabiankeil
+ * - Execute content filters through execute_content_filter().
+ * - Add prepare_for_filtering() so filter functions don't have to
+ * care about de-chunking and decompression. As a side effect this enables
+ * decompression for gif_deanimate_response() and jpeg_inspect_response().
+ * - Change remove_chunked_transfer_coding()'s return type to jb_err.
+ * Some clowns feel like chunking empty responses in which case
+ * (size == 0) is valid but previously would be interpreted as error.
+ *
* Revision 1.91 2007/09/02 15:31:20 fabiankeil
* Move match_portlist() from filter.c to urlmatch.c.
* It's used for url matching, not for filtering.
*p++ = '\0';
if (ijb_isdigit(*p) == 0)
{
- free(acl_spec);
+ freez(acl_spec);
return(-1);
}
masklength = atoi(p);
if ((masklength < 0) || (masklength > 32))
{
- free(acl_spec);
+ freez(acl_spec);
return(-1);
}
if (port <= 0 || port > 65535 || *endptr != '\0')
{
- free(acl_spec);
+ freez(acl_spec);
return(-1);
}
}
aca->port = (unsigned long)port;
aca->addr = ntohl(resolve_hostname_to_ip(acl_spec));
- free(acl_spec);
+ freez(acl_spec);
if (aca->addr == INADDR_NONE)
{
log_error(LOG_LEVEL_ERROR, "Failed to append \'%s\' to trustfile \'%s\': %E",
new_entry, csp->config->trustfile);
}
- free(new_entry);
+ freez(new_entry);
}
else
{
* or NULL if there were no hits or something went wrong
*
*********************************************************************/
-char *pcrs_filter_response(struct client_state *csp)
+static char *pcrs_filter_response(struct client_state *csp)
{
int hits=0;
size_t size, prev_size;
if (0 == found_filters)
{
- log_error(LOG_LEVEL_ERROR, "Unable to get current state of regexp filtering.");
+ log_error(LOG_LEVEL_ERROR, "Inconsistent configuration: "
+ "content filtering enabled, but no content filters available.");
return(NULL);
}
current_hits += job_hits;
if (old != csp->iob->cur)
{
- free(old);
+ freez(old);
}
old = new;
}
*/
if (!hits)
{
- free(new);
+ freez(new);
return(NULL);
}
* or NULL in case something went wrong.
*
*********************************************************************/
-char *gif_deanimate_response(struct client_state *csp)
+static char *gif_deanimate_response(struct client_state *csp)
{
struct binbuffer *in, *out;
char *p;
if (gif_deanimate(in, out, strncmp("last", csp->action->string[ACTION_STRING_DEANIMATE], 4)))
{
log_error(LOG_LEVEL_DEANIMATE, "failed! (gif parsing)");
- free(in);
+ freez(in);
buf_free(out);
return(NULL);
}
csp->content_length = out->offset;
csp->flags |= CSP_FLAG_MODIFIED;
p = out->buffer;
- free(in);
- free(out);
+ freez(in);
+ freez(out);
return(p);
}
* or NULL in case something went wrong.
*
*********************************************************************/
-char *jpeg_inspect_response(struct client_state *csp)
+static char *jpeg_inspect_response(struct client_state *csp)
{
struct binbuffer *in = NULL;
struct binbuffer *out = NULL;
if (jpeg_inspect(in, out))
{
log_error(LOG_LEVEL_DEANIMATE, "failed! (jpeg parsing)");
- free(in);
+ freez(in);
buf_free(out);
return(NULL);
csp->content_length = out->offset;
csp->flags |= CSP_FLAG_MODIFIED;
p = out->buffer;
- free(in);
- free(out);
+ freez(in);
+ freez(out);
return(p);
}
}
+/*********************************************************************
+ *
+ * Function : get_filter_function
+ *
+ * Description : Decides which content filter function has
+ * to be applied (if any).
+ *
+ * XXX: Doesn't handle filter_popups()
+ * because of the different prototype. Probably
+ * we should ditch filter_popups() anyway, it's
+ * even less reliable than popup blocking based
+ * on pcrs filters.
+ *
+ * Parameters :
+ * 1 : csp = Current client state (buffers, headers, etc...)
+ *
+ * Returns : The content filter function to run, or
+ * NULL if no content filter is active
+ *
+ *********************************************************************/
+filter_function_ptr get_filter_function(struct client_state *csp)
+{
+ filter_function_ptr filter_function = NULL;
+
+ /*
+ * Are we enabling text mode by force?
+ */
+ if (csp->action->flags & ACTION_FORCE_TEXT_MODE)
+ {
+ /*
+ * Do we really have to?
+ */
+ if (csp->content_type & CT_TEXT)
+ {
+ log_error(LOG_LEVEL_HEADER, "Text mode is already enabled.");
+ }
+ else
+ {
+ csp->content_type |= CT_TEXT;
+ log_error(LOG_LEVEL_HEADER, "Text mode enabled by force. Take cover!");
+ }
+ }
+
+ if (!(csp->content_type & CT_DECLARED))
+ {
+ /*
+ * The server didn't bother to declare a MIME-Type.
+ * Assume it's text that can be filtered.
+ *
+ * This also regulary happens with 304 responses,
+ * therefore logging anything here would cause
+ * too much noise.
+ */
+ csp->content_type |= CT_TEXT;
+ }
+
+ /*
+ * Choose the applying filter function based on
+ * the content type and action settings.
+ */
+ if ((csp->content_type & CT_TEXT) &&
+ (csp->rlist != NULL) &&
+ (!list_is_empty(csp->action->multi[ACTION_MULTI_FILTER])))
+ {
+ filter_function = pcrs_filter_response;
+ }
+ else if ((csp->content_type & CT_GIF) &&
+ (csp->action->flags & ACTION_DEANIMATE))
+ {
+ filter_function = gif_deanimate_response;
+ }
+ else if ((csp->content_type & CT_JPEG) &&
+ (csp->action->flags & ACTION_JPEG_INSPECT))
+ {
+ filter_function = jpeg_inspect_response;
+ }
+
+ return filter_function;
+}
+
+
/*********************************************************************
*
* Function : remove_chunked_transfer_coding
if (sscanf(from_p, "%x", &chunksize) != 1)
{
- log_error(LOG_LEVEL_ERROR, "Parse error while stripping \"chunked\" transfer coding");
- return JB_ERR_PARSE;
+ log_error(LOG_LEVEL_INFO, "Invalid \"chunked\" transfer encoding detected and ignored.");
+ break;
}
}
- if (0 == newsize)
- {
- log_error(LOG_LEVEL_RE_FILTER, "Need to de-chunk first");
- }
-
/* XXX: Should get its own loglevel. */
log_error(LOG_LEVEL_RE_FILTER, "De-chunking successful. Shrunk from %d to %d", *size, newsize);
}
else
{
- log_error(LOG_LEVEL_ERROR, "Failed to de-chunk content.");
return JB_ERR_PARSE;
}
}
*/
if (csp->content_type & (CT_GZIP|CT_DEFLATE))
{
+ if (0 == csp->iob->eod - csp->iob->cur)
+ {
+ /* Nothing left after de-chunking. */
+ return JB_ERR_OK;
+ }
+
err = decompress_iob(csp);
if (JB_ERR_OK == err)
*/
csp->content_type &= ~CT_GZIP;
csp->content_type &= ~CT_DEFLATE;
- log_error(LOG_LEVEL_ERROR, "Failed to decompress content.");
}
}
#endif
* 1 : csp = Current client state (buffers, headers, etc...)
* 2 : content_filter = The filter function to execute
*
- * Returns : JB_ERR_OK for success,
- * JB_ERR_PARSE otherwise
+ * Returns : Pointer to the modified buffer, or
+ * NULL if filtering failed or wasn't necessary.
*
*********************************************************************/
char *execute_content_filter(struct client_state *csp, filter_function_ptr content_filter)
{
+ if (0 == csp->iob->eod - csp->iob->cur)
+ {
+ /*
+ * No content (probably status code 301, 302 ...),
+ * no filtering necessary.
+ */
+ return NULL;
+ }
+
if (JB_ERR_OK != prepare_for_filtering(csp))
{
/*
* failed to de-chunk or decompress.
- * XXX: if possible, we should continue anyway.
*/
return NULL;
}
if (0 == csp->iob->eod - csp->iob->cur)
{
- /* Empty buffer, nothing to do. */
+ /*
+ * Clown alarm: chunked and/or compressed nothing delivered.
+ */
return NULL;
}
fwd->type = SOCKS_4A;
socks_proxy = vec[1];
}
+ else if (!strcasecmp(vec[0], "forward-socks5"))
+ {
+ fwd->type = SOCKS_5;
+ socks_proxy = vec[1];
+ }
if (NULL != socks_proxy)
{
}
+/*********************************************************************
+ *
+ * Function : content_filters_enabled
+ *
+ * Description : Checks whether there are any content filters
+ * enabled for the current request.
+ *
+ * Parameters :
+ * 1 : csp = Current client state (buffers, headers, etc...)
+ *
+ * Returns : TRUE for yes, FALSE otherwise
+ *
+ *********************************************************************/
+inline int content_filters_enabled(const struct client_state *csp)
+{
+ return (((csp->rlist != NULL) &&
+ (!list_is_empty(csp->action->multi[ACTION_MULTI_FILTER]))) ||
+ (csp->action->flags & (ACTION_DEANIMATE|ACTION_JPEG_INSPECT|ACTION_NO_POPUPS)));
+}
+
/*
Local Variables:
tab-width: 3