--------------------- PatchSet 1423 Date: 2001/01/30 04:28:30 Author: rbcollins Branch: rbcollins_filters Tag: (none) Log: reply_filter_access running smoothly Members: src/Makefile.in:1.1.1.3.8.8.2.1->1.1.1.3.8.8.2.2 src/cache_cf.c:1.1.1.3.4.1.4.7.4.2->1.1.1.3.4.1.4.7.4.3 src/cf.data.pre:1.1.1.3.4.1.4.11.4.2->1.1.1.3.4.1.4.11.4.3 src/client_side.c:1.1.1.3.4.1.4.15.2.11->1.1.1.3.4.1.4.15.2.12 src/filters.c:1.1->1.1.2.1 src/protos.h:1.1.1.3.8.11.2.3->1.1.1.3.8.11.2.4 src/structs.h:1.1.1.3.4.1.4.12.2.8->1.1.1.3.4.1.4.12.2.9 src/typedefs.h:1.1.1.3.8.7.4.7->1.1.1.3.8.7.4.8 Index: squid/src/Makefile.in =================================================================== RCS file: /cvsroot/squid-sf//squid/src/Attic/Makefile.in,v retrieving revision 1.1.1.3.8.8.2.1 retrieving revision 1.1.1.3.8.8.2.2 diff -u -r1.1.1.3.8.8.2.1 -r1.1.1.3.8.8.2.2 --- squid/src/Makefile.in 30 Jan 2001 00:53:04 -0000 1.1.1.3.8.8.2.1 +++ squid/src/Makefile.in 30 Jan 2001 04:28:30 -0000 1.1.1.3.8.8.2.2 @@ -1,7 +1,7 @@ # # Makefile for the Squid Object Cache server # -# $Id: Makefile.in,v 1.1.1.3.8.8.2.1 2001/01/30 00:53:04 rbcollins Exp $ +# $Id: Makefile.in,v 1.1.1.3.8.8.2.2 2001/01/30 04:28:30 rbcollins Exp $ # # Uncomment and customize the following to suit your needs: # @@ -115,6 +115,7 @@ event.o \ fd.o \ filemap.o \ + filters.o \ forward.o \ fqdncache.o \ ftp.o \ Index: squid/src/cache_cf.c =================================================================== RCS file: /cvsroot/squid-sf//squid/src/cache_cf.c,v retrieving revision 1.1.1.3.4.1.4.7.4.2 retrieving revision 1.1.1.3.4.1.4.7.4.3 diff -u -r1.1.1.3.4.1.4.7.4.2 -r1.1.1.3.4.1.4.7.4.3 --- squid/src/cache_cf.c 30 Jan 2001 02:11:04 -0000 1.1.1.3.4.1.4.7.4.2 +++ squid/src/cache_cf.c 30 Jan 2001 04:28:30 -0000 1.1.1.3.4.1.4.7.4.3 @@ -1,6 +1,6 @@ /* - * $Id: cache_cf.c,v 1.1.1.3.4.1.4.7.4.2 2001/01/30 02:11:04 rbcollins Exp $ + * $Id: cache_cf.c,v 1.1.1.3.4.1.4.7.4.3 2001/01/30 04:28:30 rbcollins Exp $ * * DEBUG: section 3 Configuration File Parsing * AUTHOR: Harvest Derived @@ -990,6 +990,85 @@ } } +/* allocate new filteraccess record. Caveats with changing address apply as per + * new_filterinstance */ +void +allocate_new_filteraccess(filterAccessConfig * cfg) +{ + if (cfg->filters == NULL) { + cfg->n_allocated = 4; + cfg->filters = xcalloc(cfg->n_allocated, sizeof(filterAccess)); + } + if (cfg->n_allocated == cfg->n_configured) { + filterAccess *tmp; + cfg->n_allocated <<= 1; + tmp = xcalloc(cfg->n_allocated, sizeof(filterAccess)); + xmemcpy(tmp, cfg->filters, cfg->n_configured * sizeof(filterAccess)); + xfree(cfg->filters); + cfg->filters = tmp; + } +} + +static void +parse_filter_access(filterAccessConfig * cfg) +{ + char *instance_str; + filterAccess *filter = NULL; + FILTER_instance *instance = NULL; + int type, i; + + if ((instance_str = strtok(NULL, w_space)) == NULL) + self_destruct(); + + if ((instance = filterInstanceByName(instance_str, &Config.filters)) == NULL) { + debug(3, 0) ("Parsing Config File: Unknown filter instance '%s'\n", instance_str); + return; + } + for (i = 0; i < cfg->n_configured; i++) { + if (cfg->filters[i].instance==instance) { + /* new line for existing access list */ + filter= cfg->filters+i; + } + } + + if (filter == NULL) { + allocate_new_filteraccess(cfg); + filter = cfg->filters + cfg->n_configured; + cfg->n_configured++; + filter->instance=instance; + } + parse_acl_access(&filter->apply); +} + +static void +free_filter_access(filterAccessConfig * cfg) +{ + filterAccess *filter; + int i; + for (i = 0; i < cfg->n_configured; i++) { + filter = cfg->filters + i; + free_acl_access(&filter->apply); + } + safe_free(cfg->filters); + cfg->filters = NULL; + cfg->n_allocated = 0; + cfg->n_configured = 0; +} + +static void +dump_filter_access(StoreEntry * entry, const char *name, filterAccessConfig cfg) +{ +#if 0 + authScheme *scheme; + int i; + for (i = 0; i < cfg.n_configured; i++) { + scheme = cfg.schemes + i; + authscheme_list[scheme->Id].dump(entry, name, scheme); + } +#endif +} + + /* allocate new instance during config. Changing address is ok here as long * as all instances are allocated before any filter configs are created */ void @@ -1023,7 +1102,7 @@ if ((instance_str = strtok(NULL, w_space)) == NULL) self_destruct(); - if ((module = clientReplyFilterByName(name_str)) == NULL) { + if ((module = filterByName(name_str)) == NULL) { debug(3, 0) ("Parsing Config File: Unknown filter '%s'.\n", name_str); return; } @@ -1079,7 +1158,7 @@ if ((param_str = strtok(NULL, w_space)) == NULL) self_destruct(); - if ((instance = clientReplyFilterInstanceByName(instance_str, cfg)) == NULL) { + if ((instance = filterInstanceByName(instance_str, cfg)) == NULL) { debug(3, 0) ("Parsing Config File: Unknown filter instance '%s'.\n", instance_str); return; } Index: squid/src/cf.data.pre =================================================================== RCS file: /cvsroot/squid-sf//squid/src/cf.data.pre,v retrieving revision 1.1.1.3.4.1.4.11.4.2 retrieving revision 1.1.1.3.4.1.4.11.4.3 diff -u -r1.1.1.3.4.1.4.11.4.2 -r1.1.1.3.4.1.4.11.4.3 --- squid/src/cf.data.pre 30 Jan 2001 02:11:05 -0000 1.1.1.3.4.1.4.11.4.2 +++ squid/src/cf.data.pre 30 Jan 2001 04:28:30 -0000 1.1.1.3.4.1.4.11.4.3 @@ -1,6 +1,6 @@ # -# $Id: cf.data.pre,v 1.1.1.3.4.1.4.11.4.2 2001/01/30 02:11:05 rbcollins Exp $ +# $Id: cf.data.pre,v 1.1.1.3.4.1.4.11.4.3 2001/01/30 04:28:30 rbcollins Exp $ # # # SQUID Internet Object Cache http://squid.nlanr.net/Squid/ @@ -1697,47 +1697,6 @@ DOC_END COMMENT_START - CONTENT PROCESSING FILTERS - ----------------------------------------------------------------------------- -COMMENT_END - -NAME: filter_add -TYPE: filter_add -LOC: Config.reply_filter_config -DEFAULT: none -DOC_START - Using content processing filters - - filter_add filtername instancename - - creates an instance of a filter. - - IMPORTANT: Place all your filter_add calls at the same location, - followed immediately by all your filter_config calls. - - Then use filter_config to configure that instance. - For example: - - filter_add textreplace onunload - filter_config onunload search onunload - filter_config onunload replace nonsense - -DOC_END - -NAME: filter_config -TYPE: filter_config -LOC: Config.reply_filter_config -DEFAULT: none -DOC_START - Config a content processing filter - - filter_config instancename parameter parametervalue ... - - Passes a parameter onto a filter instance for processing - See filter_add for an example. -DOC_END - -COMMENT_START ACCESS CONTROLS ----------------------------------------------------------------------------- COMMENT_END @@ -1941,25 +1900,6 @@ NOCOMMENT_END DOC_END -NAME: onunload_access -TYPE: acl_access -LOC: Config.accessList.onunload -DEFAULT: none -DEFAULT_IF_NONE: deny all -DOC_START - Allowing the filter onunload to be applied to a reply - - onunload_access allow|deny [![ aclname ... - - NOTE: if there are no access lines present, the default is to never - use the filter. - - If none of the access lines cause a match, then the opposite of the - last line will apply. Thus it is good practice to end the rules - with an "allow all" or "deny all" entry. -DOC_END - - NAME: icp_access TYPE: acl_access LOC: Config.accessList.icp @@ -2047,6 +1987,64 @@ COMMENT_START + CONTENT PROCESSING FILTERS + ----------------------------------------------------------------------------- +COMMENT_END + +NAME: filter_add +TYPE: filter_add +LOC: Config.filters +DEFAULT: none +DOC_START + Using content processing filters + + filter_add filtername instancename + + creates an instance of a filter. + + IMPORTANT: Place all your filter_add calls at the same location, + followed immediately by all your filter_config calls. + + Then use filter_config to configure that instance. + For example: + + filter_add textreplace onunload + filter_config onunload search onunload + filter_config onunload replace nonsense + +DOC_END + +NAME: filter_config +TYPE: filter_config +LOC: Config.filters +DEFAULT: none +DOC_START + Config a content processing filter + + filter_config instancename parameter parametervalue ... + + Passes a parameter onto a filter instance for processing + See filter_add for an example. +DOC_END + +NAME: reply_filter_access +TYPE: filter_access +LOC: Config.reply_filters +DEFAULT: none +DOC_START + Apply filters to http replies + + reply_filter_access filtername allow|deny [!]acl ... ... + + NOTE: if there are no access lines present, the default is to never + use the filter. + + If none of the access lines cause a match, then the opposite of the + last line will apply. Thus it is good practice to end the rules + with an "allow all" or "deny all" entry. +DOC_END + +COMMENT_START ADMINISTRATIVE PARAMETERS ----------------------------------------------------------------------------- COMMENT_END Index: squid/src/client_side.c =================================================================== RCS file: /cvsroot/squid-sf//squid/src/client_side.c,v retrieving revision 1.1.1.3.4.1.4.15.2.11 retrieving revision 1.1.1.3.4.1.4.15.2.12 diff -u -r1.1.1.3.4.1.4.15.2.11 -r1.1.1.3.4.1.4.15.2.12 --- squid/src/client_side.c 30 Jan 2001 02:11:05 -0000 1.1.1.3.4.1.4.15.2.11 +++ squid/src/client_side.c 30 Jan 2001 04:28:30 -0000 1.1.1.3.4.1.4.15.2.12 @@ -1,6 +1,6 @@ /* - * $Id: client_side.c,v 1.1.1.3.4.1.4.15.2.11 2001/01/30 02:11:05 rbcollins Exp $ + * $Id: client_side.c,v 1.1.1.3.4.1.4.15.2.12 2001/01/30 04:28:30 rbcollins Exp $ * * DEBUG: section 33 Client-side Routines * AUTHOR: Duane Wessels @@ -1280,7 +1280,6 @@ static DATAFILTER clientDoTEReply; static DATAFILTER clientWriteReplyHeaders; -static DATAFILTER clientFilterOnUnload; static DATAFILTER clientDoCommWriteMemBuf; void @@ -1333,189 +1332,25 @@ } -typedef struct _onunloadcfg OnUnloadConfig; -typedef struct _onunloadstate OnUnloadState; -struct _onunloadstate { - OnUnloadConfig *config; - /* allow for searching across buffer breaks */ - /* not implemented just yet :] */ - char *pos; -}; -struct _onunloadcfg { - char *searchstring, *replace; -}; - -static REMOVEFILTER clientFilterOnUnload_Remove; -static ADDFILTER clientFilterOnUnload_Add; -static FILTERMKSTATE clientFilterOnUnload_MakeState; -static FILTERPARSE clientFilterOnUnload_Parse; - -MOD_INSTALL mod_install_textreplace; - -void -clientFilterFreeConfig(void *data) { - OnUnloadConfig *config=data; - xfree(config->searchstring); - config->searchstring=NULL; - xfree(config->replace); - config->replace=NULL; - xfree(config); -} - -void -clientFilterOnUnload_AddInstance(FILTER_instance *instance) { - OnUnloadConfig *config; - instance->Add=clientFilterOnUnload_Add; - instance->MakeState=clientFilterOnUnload_MakeState; - instance->Parse =clientFilterOnUnload_Parse; - instance->data=xmalloc(sizeof(OnUnloadConfig)); - /* Set defaults, if sensible defaults exist */ - config=instance->data; - config->searchstring=NULL; - config->replace=NULL; -} - -void -clientFilterOnUnload_RemInstance(FILTER_instance *instance) { - instance->Add=NULL; - instance->MakeState=NULL; - clientFilterFreeConfig(instance->data); - instance->data=NULL; -} - -static void -clientFilterOnUnload_Add(dlink_list *filters, void *filter_config) { - FILTER_list *temp_filter; - temp_filter=xmalloc(sizeof(FILTER_list)); - temp_filter->filter=clientFilterOnUnload; - temp_filter->Remove=clientFilterOnUnload_Remove; - temp_filter->data=filter_config; - /* cbDataLock(http); ? */ - dlinkAddTail(temp_filter, &temp_filter->node, filters); -} - -static void * -clientFilterOnUnload_MakeState(void * data) { - OnUnloadState *state; - OnUnloadConfig *config=data; - if (!config) - return NULL; - /* it's up to the filter writer wether to refcount the config, - * or copy it. For now, to save learning cbdata, I copy it - */ - state=xmalloc(sizeof(OnUnloadState)); - state->config=xmalloc(sizeof(OnUnloadConfig)); - state->config->searchstring=xstrdup(config->searchstring); - state->config->replace=xstrdup(config->replace); - return state; -} - -static void -clientFilterOnUnload_Remove(FILTER_list *filters, dlink_list *filter_list, void *data) { - OnUnloadState *state=data; - dlinkDelete(&filters->node, filter_list); - xfree(filters); - clientFilterFreeConfig(state->config); - state->config=NULL; - xfree(state); -} - -static void -clientFilterOnUnload_Parse(void *data, const char *namestr, char *param_str) { - OnUnloadConfig *config=data; -#if 0 - if (scheme->scheme_data == NULL) { - assert(basicConfig == NULL); - /* this is the first param to be found */ - scheme->scheme_data = xmalloc(sizeof(auth_basic_config)); - memset(scheme->scheme_data, 0, sizeof(auth_basic_config)); - basicConfig = scheme->scheme_data; - basicConfig->authenticateChildren = 5; - } -#endif - if (strcasecmp(param_str, "replace") == 0) { - parse_eol(&config->replace); - } else if (strcasecmp(param_str, "search") == 0) { - parse_eol(&config->searchstring); - } else { - debug(33, 0) ("unrecognised parameter '%s' for filter %s\n", param_str,namestr); - } -} - -void clientRegisterReplyFilter(const char *, ADDFILTERINSTANCE *, REMFILTERINSTANCE *); - -void -mod_install_textreplace(const char *namestr) { - /* Register as a potential client_side reply filter */ - clientRegisterReplyFilter(namestr,clientFilterOnUnload_AddInstance, - clientFilterOnUnload_RemInstance); -} - -static FILTER_module *replyfilter_list= NULL; - -void -clientRegisterReplyFilter(const char *namestr, ADDFILTERINSTANCE *add, - REMFILTERINSTANCE *remove) { - int i; - debug(33,4)("clientRegisterReplyFilter: Registering filter '%s'\n",namestr); - /* find the current count */ - for (i = 0; replyfilter_list && replyfilter_list[i].namestr; i++) { - /* don't allow double additions. FIXME: this should be a debug and - * abort action, to allow for dynamic registration */ - assert(strcmp(replyfilter_list[i].namestr, namestr) != 0); - } - /* add the filter */ - /* FIXME: xrealloc may be ad - if the array moves arround after initalisation - ie - * with dynamic module additions, then pointers to the modules will get corrupted - */ - replyfilter_list = xrealloc(replyfilter_list, (i+2) * sizeof(FILTER_module)); - memset(&replyfilter_list[i+1], 0, sizeof(FILTER_module)); - replyfilter_list[i].namestr=xstrdup(namestr); - replyfilter_list[i].AddInstance=add; - replyfilter_list[i].RemInstance=remove; -} - -FILTER_module * -clientReplyFilterByName(const char *namestr) { - int i = 0; - for (i = 0; replyfilter_list && replyfilter_list[i].namestr; i++) { - if (strncasecmp(namestr, replyfilter_list[i].namestr, strlen(replyfilter_list[i].namestr)) == 0) { - return &replyfilter_list[i]; - } - } - return NULL; -} - -FILTER_instance * -clientReplyFilterInstanceByName(const char *namestr, filterConfig *cfg) { - FILTER_instance *instance; - int i = 0; - for (i = 0; i < cfg->n_configured; i++) { - instance = cfg->instances + i; - if (strncasecmp(namestr, instance->namestr, strlen(instance->namestr)) == 0) { - return instance; - } - } - return NULL; -} - /* iterate through the configured filters, applying their access tests and adding * if appropriate */ static void -clientBuildReplyAddFilters(filterConfig * cfg, dlink_list *filter_list, +clientBuildReplyAddFilters(filterAccessConfig * cfg, dlink_list *filter_list, clientHttpRequest * http, HttpReply *rep) { aclCheck_t *ch; int rv; + filterAccess *filter; FILTER_instance *instance; int i = 0; for (i = 0; i < cfg->n_configured; i++) { - instance = cfg->instances + i; - ch = aclChecklistCreate(Config.accessList.onunload, http->request, NULL); + filter = cfg->filters +i; + instance = filter->instance; + ch = aclChecklistCreate(filter->apply, http->request, NULL); ch->reply = rep; - rv = aclCheckFast(Config.accessList.onunload, ch); + rv = aclCheckFast(filter->apply, ch); aclChecklistFree(ch); if (rv==1) { - debug(33,8)("\n\nAdding the filter OnUnload!!\n\n"); + debug(33,8)("\n\nAdding the filter instance %s\n\n", instance->namestr); /* hmm. what should the parameters be? the list and a config? * that allows all four cases with one insertion routine. * but perhaps the filter needs to know the direction? @@ -1589,7 +1424,7 @@ stringClean(&strConnection); } - clientBuildReplyAddFilters(&Config.reply_filter_config, &http->repfilters, http, rep); + clientBuildReplyAddFilters(&Config.reply_filters, &http->repfilters, http, rep); /* Handle Ranges */ if (request->range) @@ -2215,106 +2050,6 @@ // comm_write(http->conn->fd, buf, len, clientWriteBodyComplete, http, NULL); } -#define TESTFILTER 1 -#if TESTFILTER - -char * -strnchr(const char *str, char chr, size_t len) { - size_t pos=0; - while (posconfig; - char *chr, *searchstring=config->searchstring; - const char *startpos,*pos; - size_t replacelen=strlen(config->replace); - - /* this looks for browser DOM handlers of the type onunload="..." and - * removes them from the data passed to the client - * caveats and problems: - * 1. theres probably a set of library functions for matching patterns at arbitrary - * places in a datastream (ie handles buffer edge issues, optimum search patterns - * and the like. Well this is a proof of concept filter - live with it :-] - * 2. Some code may not quote the handler properly. I haven't tried to build - * a full blown parser here - see 1. - * 3. this will match patterns in jpegs etc as well at this point. It needs a - * acl or content type check in clientSendMoreData before adding the filter to the - * list. - * - * 4. I'm making use of the properties of the fixed search string to simplify - * the search. IT IS NOT GENERAL PURPOSE - - - * The compiled expression isn't cached. This _is_ a performance issue. - * !!! !!!!!!!! !!!!!!!!!! - */ - - - temp_filter=filters->node.next->data; - - chr=searchstring; - pos=0; - startpos=buf; - - while (startpos) { - startpos=strnchr(startpos, *chr, len-(startpos-buf)); - - if (startpos) { - /* possibly present in this buffer */ - chr++; - pos=startpos+1; - while (pos) { - if (tolower(*pos)==tolower(*chr)) { - chr++; - pos++; - } - if (pos-buf>=len){ - /* end of data */ - temp_filter->filter(buf,len,filter_list, temp_filter, flags, temp_filter->data); - return; - } - if (*chr=='\0') { - /* end of search string - we've got a match */ - /* send the first set of data */ - if (startpos-buf) - temp_filter->filter(buf,startpos-buf,filter_list, temp_filter, flags, temp_filter->data); - /* send the filter set of data */ - temp_filter->filter(config->replace,replacelen,filter_list, temp_filter, flags, temp_filter->data); - /* and the rest */ - temp_filter->filter(startpos+replacelen,len-(startpos-buf)-replacelen,filter_list, temp_filter, flags,temp_filter->data); - return; - } - if(tolower(*pos)!=tolower(*chr)) { - /* reset the search criteria to after the corrent position */ - startpos=pos; - pos=NULL; - chr=searchstring; - } - } - } - else { - temp_filter->filter(buf,len,filter_list, temp_filter, flags, temp_filter->data); - return; - } - - } - temp_filter->filter(buf,len,filter_list, temp_filter, flags, temp_filter->data); - -} -#endif - - /* * accepts chunk of a http message in buf, parses prefix, filters headers and * such, calls filter init routines, and then calls the filters. --- /dev/null Wed Feb 14 00:48:56 2007 +++ squid/src/filters.c Wed Feb 14 00:49:28 2007 @@ -0,0 +1,299 @@ + +/* + * $Id: filters.c,v 1.1.2.1 2001/01/30 04:28:55 rbcollins Exp $ + * + * DEBUG: section 83 Content Processing Filters + * AUTHOR: Robert Collins + * + * SQUID Internet Object Cache http://squid.nlanr.net/Squid/ + * ---------------------------------------------------------- + * + * Squid is the result of efforts by numerous individuals from the + * Internet community. Development is led by Duane Wessels of the + * National Laboratory for Applied Network Research and funded by the + * National Science Foundation. Squid is Copyrighted (C) 1998 by + * the Regents of the University of California. Please see the + * COPYRIGHT file for full details. Squid incorporates software + * developed and/or copyrighted by other sources. Please see the + * CREDITS file for full details. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA. + * + */ + +#include "squid.h" + +/* globals */ +static FILTER_module *filter_list= NULL; + + +/* filter framework */ +void +filterRegisterModule(const char *namestr, ADDFILTERINSTANCE *add, + REMFILTERINSTANCE *remove) { + int i; + debug(33,4)("filterRegisterModule: Registering filter '%s'\n",namestr); + /* find the current count */ + for (i = 0; filter_list && filter_list[i].namestr; i++) { + /* don't allow double additions. FIXME: this should be a debug and + * abort action, to allow for dynamic registration */ + assert(strcmp(filter_list[i].namestr, namestr) != 0); + } + /* add the filter */ + /* FIXME: xrealloc may be ad - if the array moves arround after initalisation - ie + * with dynamic module additions, then pointers to the modules will get corrupted + */ + filter_list = xrealloc(filter_list, (i+2) * sizeof(FILTER_module)); + memset(&filter_list[i+1], 0, sizeof(FILTER_module)); + filter_list[i].namestr=xstrdup(namestr); + filter_list[i].AddInstance=add; + filter_list[i].RemInstance=remove; +} + +FILTER_module * +filterByName(const char *namestr) { + int i = 0; + for (i = 0; filter_list && filter_list[i].namestr; i++) { + if (strncasecmp(namestr, filter_list[i].namestr, strlen(filter_list[i].namestr)) == 0) { + return &filter_list[i]; + } + } + return NULL; +} + +FILTER_instance * +filterInstanceByName(const char *namestr, filterConfig *cfg) { + FILTER_instance *instance; + int i = 0; + for (i = 0; i < cfg->n_configured; i++) { + instance = cfg->instances + i; + if (strncasecmp(namestr, instance->namestr, strlen(instance->namestr)) == 0) { + return instance; + } + } + return NULL; +} + + + +/* the textreplace filter */ +typedef struct _onunloadcfg OnUnloadConfig; +typedef struct _onunloadstate OnUnloadState; +struct _onunloadstate { + OnUnloadConfig *config; + /* allow for searching across buffer breaks */ + /* not implemented just yet :] */ + char *pos; +}; +struct _onunloadcfg { + char *searchstring, *replace; +}; + + +static REMOVEFILTER clientFilterOnUnload_Remove; +static ADDFILTER clientFilterOnUnload_Add; +static FILTERMKSTATE clientFilterOnUnload_MakeState; +static FILTERPARSE clientFilterOnUnload_Parse; +static DATAFILTER clientFilterOnUnload; + + +MOD_INSTALL mod_install_textreplace; + + +void +clientFilterFreeConfig(void *data) { + OnUnloadConfig *config=data; + xfree(config->searchstring); + config->searchstring=NULL; + xfree(config->replace); + config->replace=NULL; + xfree(config); +} + +void +clientFilterOnUnload_AddInstance(FILTER_instance *instance) { + OnUnloadConfig *config; + instance->Add=clientFilterOnUnload_Add; + instance->MakeState=clientFilterOnUnload_MakeState; + instance->Parse =clientFilterOnUnload_Parse; + instance->data=xmalloc(sizeof(OnUnloadConfig)); + /* Set defaults, if sensible defaults exist */ + config=instance->data; + config->searchstring=NULL; + config->replace=NULL; +} + +void +clientFilterOnUnload_RemInstance(FILTER_instance *instance) { + instance->Add=NULL; + instance->MakeState=NULL; + clientFilterFreeConfig(instance->data); + instance->data=NULL; +} + +static void +clientFilterOnUnload_Add(dlink_list *filters, void *filter_config) { + FILTER_list *temp_filter; + temp_filter=xmalloc(sizeof(FILTER_list)); + temp_filter->filter=clientFilterOnUnload; + temp_filter->Remove=clientFilterOnUnload_Remove; + temp_filter->data=filter_config; + /* cbDataLock(http); ? */ + dlinkAddTail(temp_filter, &temp_filter->node, filters); +} + +static void * +clientFilterOnUnload_MakeState(void * data) { + OnUnloadState *state; + OnUnloadConfig *config=data; + if (!config) + return NULL; + /* it's up to the filter writer wether to refcount the config, + * or copy it. For now, to save learning cbdata, I copy it + */ + state=xmalloc(sizeof(OnUnloadState)); + state->config=xmalloc(sizeof(OnUnloadConfig)); + state->config->searchstring=xstrdup(config->searchstring); + state->config->replace=xstrdup(config->replace); + return state; +} + +static void +clientFilterOnUnload_Remove(FILTER_list *filters, dlink_list *filter_list, void *data) { + OnUnloadState *state=data; + dlinkDelete(&filters->node, filter_list); + xfree(filters); + clientFilterFreeConfig(state->config); + state->config=NULL; + xfree(state); +} + +static void +clientFilterOnUnload_Parse(void *data, const char *namestr, char *param_str) { + OnUnloadConfig *config=data; + if (strcasecmp(param_str, "replace") == 0) { + parse_eol(&config->replace); + } else if (strcasecmp(param_str, "search") == 0) { + parse_eol(&config->searchstring); + } else { + debug(33, 0) ("unrecognised parameter '%s' for filter %s\n", param_str,namestr); + } +} + +void +mod_install_textreplace(const char *namestr) { + /* Register as a potential client_side reply filter */ + filterRegisterModule(namestr,clientFilterOnUnload_AddInstance, + clientFilterOnUnload_RemInstance); +} + + +char * +strnchr(const char *str, char chr, size_t len) { + size_t pos=0; + while (posconfig; + char *chr, *searchstring=config->searchstring; + const char *startpos,*pos; + size_t replacelen=strlen(config->replace); + + /* this looks for browser DOM handlers of the type onunload="..." and + * removes them from the data passed to the client + * caveats and problems: + * 1. theres probably a set of library functions for matching patterns at arbitrary + * places in a datastream (ie handles buffer edge issues, optimum search patterns + * and the like. Well this is a proof of concept filter - live with it :-] + * 2. Some code may not quote the handler properly. I haven't tried to build + * a full blown parser here - see 1. + * 3. this will match patterns in jpegs etc as well at this point. It needs a + * acl or content type check in clientSendMoreData before adding the filter to the + * list. + * + * 4. I'm making use of the properties of the fixed search string to simplify + * the search. IT IS NOT GENERAL PURPOSE + + + * The compiled expression isn't cached. This _is_ a performance issue. + * !!! !!!!!!!! !!!!!!!!!! + */ + + temp_filter=filters->node.next->data; + + chr=searchstring; + pos=0; + startpos=buf; + + while (startpos) { + startpos=strnchr(startpos, *chr, len-(startpos-buf)); + + if (startpos) { + /* possibly present in this buffer */ + chr++; + pos=startpos+1; + while (pos) { + if (tolower(*pos)==tolower(*chr)) { + chr++; + pos++; + } + if (pos-buf>=len){ + /* end of data */ + temp_filter->filter(buf,len,filter_list, temp_filter, flags, temp_filter->data); + return; + } + if (*chr=='\0') { + /* end of search string - we've got a match */ + /* send the first set of data */ + if (startpos-buf) + temp_filter->filter(buf,startpos-buf,filter_list, temp_filter, flags, temp_filter->data); + /* send the filter set of data */ + temp_filter->filter(config->replace,replacelen,filter_list, temp_filter, flags, temp_filter->data); + /* and the rest */ + temp_filter->filter(startpos+replacelen,len-(startpos-buf)-replacelen,filter_list, temp_filter, flags,temp_filter->data); + return; + } + if(tolower(*pos)!=tolower(*chr)) { + /* reset the search criteria to after the corrent position */ + startpos=pos; + pos=NULL; + chr=searchstring; + } + } + } + else { + temp_filter->filter(buf,len,filter_list, temp_filter, flags, temp_filter->data); + return; + } + + } + temp_filter->filter(buf,len,filter_list, temp_filter, flags, temp_filter->data); + +} + + + Index: squid/src/protos.h =================================================================== RCS file: /cvsroot/squid-sf//squid/src/protos.h,v retrieving revision 1.1.1.3.8.11.2.3 retrieving revision 1.1.1.3.8.11.2.4 diff -u -r1.1.1.3.8.11.2.3 -r1.1.1.3.8.11.2.4 --- squid/src/protos.h 30 Jan 2001 02:11:05 -0000 1.1.1.3.8.11.2.3 +++ squid/src/protos.h 30 Jan 2001 04:28:30 -0000 1.1.1.3.8.11.2.4 @@ -1,6 +1,6 @@ /* - * $Id: protos.h,v 1.1.1.3.8.11.2.3 2001/01/30 02:11:05 rbcollins Exp $ + * $Id: protos.h,v 1.1.1.3.8.11.2.4 2001/01/30 04:28:30 rbcollins Exp $ * * * SQUID Internet Object Cache http://squid.nlanr.net/Squid/ @@ -133,8 +133,6 @@ extern int isTcpHit(log_type); extern void clientReadBody(request_t * req, char *buf, size_t size, CBCB * callback, void *data); extern int clientAbortBody(request_t * req); -extern FILTER_module *clientReplyFilterByName(const char *namestr); -FILTER_instance *clientReplyFilterInstanceByName(const char *namestr, filterConfig *cfg); extern int commSetNonBlocking(int fd); extern int commUnsetNonBlocking(int fd); @@ -1309,3 +1307,6 @@ /* modules.c */ extern void mod_register(const char * namestr, MOD_INSTALL *installfunc); +/* filters.c */ +extern FILTER_module *filterByName(const char *namestr); +FILTER_instance *filterInstanceByName(const char *namestr, filterConfig *cfg); Index: squid/src/structs.h =================================================================== RCS file: /cvsroot/squid-sf//squid/src/structs.h,v retrieving revision 1.1.1.3.4.1.4.12.2.8 retrieving revision 1.1.1.3.4.1.4.12.2.9 diff -u -r1.1.1.3.4.1.4.12.2.8 -r1.1.1.3.4.1.4.12.2.9 --- squid/src/structs.h 30 Jan 2001 02:11:05 -0000 1.1.1.3.4.1.4.12.2.8 +++ squid/src/structs.h 30 Jan 2001 04:28:30 -0000 1.1.1.3.4.1.4.12.2.9 @@ -1,6 +1,6 @@ /* - * $Id: structs.h,v 1.1.1.3.4.1.4.12.2.8 2001/01/30 02:11:05 rbcollins Exp $ + * $Id: structs.h,v 1.1.1.3.4.1.4.12.2.9 2001/01/30 04:28:30 rbcollins Exp $ * * * SQUID Internet Object Cache http://squid.nlanr.net/Squid/ @@ -304,7 +304,6 @@ FILTERMKSTATE *MakeState; FILTERPARSE *Parse; void *data; - acl_access *apply; }; struct _FILTER_module { @@ -320,6 +319,16 @@ void *data; }; +struct _filterAccess { + FILTER_instance *instance; + acl_access *apply; +}; + +struct _filterAccessConfig { + filterAccess *filters; + int n_allocated; + int n_configured; +}; #if DELAY_POOLS struct _delaySpec { @@ -582,13 +591,12 @@ acl_access *identLookup; #endif acl_access *redirector; - /* the onunload filter */ - acl_access *onunload; /* test the reply itself once it starts coming through */ acl_access *reply; } accessList; acl_deny_info_list *denyInfoList; - filterConfig reply_filter_config; + filterAccessConfig reply_filters; + filterConfig filters; struct _authConfig { authScheme *schemes; int n_allocated; Index: squid/src/typedefs.h =================================================================== RCS file: /cvsroot/squid-sf//squid/src/typedefs.h,v retrieving revision 1.1.1.3.8.7.4.7 retrieving revision 1.1.1.3.8.7.4.8 diff -u -r1.1.1.3.8.7.4.7 -r1.1.1.3.8.7.4.8 --- squid/src/typedefs.h 30 Jan 2001 02:11:05 -0000 1.1.1.3.8.7.4.7 +++ squid/src/typedefs.h 30 Jan 2001 04:28:31 -0000 1.1.1.3.8.7.4.8 @@ -1,6 +1,6 @@ /* - * $Id: typedefs.h,v 1.1.1.3.8.7.4.7 2001/01/30 02:11:05 rbcollins Exp $ + * $Id: typedefs.h,v 1.1.1.3.8.7.4.8 2001/01/30 04:28:31 rbcollins Exp $ * * * SQUID Internet Object Cache http://squid.nlanr.net/Squid/ @@ -357,6 +357,9 @@ typedef struct _FILTER_list FILTER_list; typedef struct _FILTER_module FILTER_module; typedef struct _FILTER_instance FILTER_instance; +typedef struct _filterAccess filterAccess; +typedef struct _filterAccessConfig filterAccessConfig; + /* buffer, data length, remaining filters pointer, flags, state data */ typedef void DATAFILTER(const char *, size_t , dlink_list *, FILTER_list *, unsigned int, void *); /* self, the list, the state */