[Privoxy-commits] [privoxy] 03/19: Use separate linked lists for filters of different types
User Git
git at git.privoxy.org
Mon Mar 16 07:54:51 CET 2026
This is an automated email from the git hooks/post-receive script.
git pushed a commit to branch master
in repository privoxy.
commit 6d3d5befaa7e0a4fcbd9a5f1e33cdf0573f6fd43
Author: Fabian Keil <fk at fabiankeil.de>
AuthorDate: Fri Feb 27 14:48:58 2026 +0100
Use separate linked lists for filters of different types
... to be able look up filters more efficiently.
Implements TODO item #96.
---
cgiedit.c | 119 +++++++++++++++++++++++++++++++-----------------------------
cgisimple.c | 32 +++++++---------
filters.c | 9 +----
loaders.c | 56 +++++++++++++++++-----------
project.h | 11 ++++--
5 files changed, 121 insertions(+), 106 deletions(-)
diff --git a/cgiedit.c b/cgiedit.c
index b9244c8f..83989074 100644
--- a/cgiedit.c
+++ b/cgiedit.c
@@ -12,7 +12,7 @@
*
* Stick to the short names in this file for consistency.
*
- * Copyright : Written by and Copyright (C) 2001-2023 the
+ * Copyright : Written by and Copyright (C) 2001-2026 the
* Privoxy team. https://www.privoxy.org/
*
* Based on the Internet Junkbuster originally written
@@ -2864,74 +2864,76 @@ jb_err cgi_edit_actions_for_url(struct client_state *csp,
{
if ((csp->rlist[i] != NULL) && (csp->rlist[i]->f != NULL))
{
- filter_group = csp->rlist[i]->f;
- for (; (!err) && (filter_group != NULL); filter_group = filter_group->next)
+ int filter_type;
+ for (filter_type = 0; filter_type < MAX_FILTER_TYPES; filter_type++)
{
- char current_mode = 'x';
- char number[20];
- struct list_entry *filter_name;
- struct map *line_exports;
- const enum filter_type type = filter_group->type;
- const int multi_action_index = action_type_info[type].multi_action_index;
-
- assert(type < MAX_FILTER_TYPES);
- assert(multi_action_index < ACTION_MULTI_COUNT);
-
- filter_name = cur_line->data.action->multi_add[multi_action_index]->first;
- while ((filter_name != NULL)
- && (0 != strcmp(filter_group->name, filter_name->str)))
+ filter_group = ((struct re_filters *)(csp->rlist[i]->f))->filters[filter_type];
+ for (; (!err) && (filter_group != NULL); filter_group = filter_group->next)
{
- filter_name = filter_name->next;
- }
+ char current_mode = 'x';
+ char number[20];
+ struct list_entry *filter_name;
+ struct map *line_exports;
+ const int multi_action_index = action_type_info[filter_type].multi_action_index;
- if (filter_name != NULL)
- {
- current_mode = 'y';
- }
- else
- {
- filter_name = cur_line->data.action->multi_remove[multi_action_index]->first;
+ assert(multi_action_index < ACTION_MULTI_COUNT);
+
+ filter_name = cur_line->data.action->multi_add[multi_action_index]->first;
while ((filter_name != NULL)
&& (0 != strcmp(filter_group->name, filter_name->str)))
{
filter_name = filter_name->next;
}
+
if (filter_name != NULL)
{
- current_mode = 'n';
+ current_mode = 'y';
+ }
+ else
+ {
+ filter_name = cur_line->data.action->multi_remove[multi_action_index]->first;
+ while ((filter_name != NULL)
+ && (0 != strcmp(filter_group->name, filter_name->str)))
+ {
+ filter_name = filter_name->next;
+ }
+ if (filter_name != NULL)
+ {
+ current_mode = 'n';
+ }
}
- }
-
- /* Generate a unique serial number */
- snprintf(number, sizeof(number), "%x", filter_identifier++);
- number[sizeof(number) - 1] = '\0';
-
- line_exports = new_map();
- if (line_exports == NULL)
- {
- err = JB_ERR_MEMORY;
- }
- else
- {
- char *filter_line;
- if (!err) err = map(line_exports, "index", 1, number, 1);
- if (!err) err = map(line_exports, "name", 1, filter_group->name, 1);
- if (!err) err = map(line_exports, "description", 1, filter_group->description, 1);
- if (!err) err = map_radio(line_exports, "this-filter", "ynx", current_mode);
- if (!err) err = map(line_exports, "filter-type", 1, action_type_info[type].type, 1);
- if (!err) err = map(line_exports, "abbr-action-type", 1, action_type_info[type].abbr_type, 1);
- if (!err) err = map(line_exports, "anchor", 1, action_type_info[type].anchor, 1);
+ /* Generate a unique serial number */
+ snprintf(number, sizeof(number), "%x", filter_identifier++);
+ number[sizeof(number) - 1] = '\0';
- if (!err)
+ line_exports = new_map();
+ if (line_exports == NULL)
{
- filter_line = strdup(filter_template);
- if (filter_line == NULL) err = JB_ERR_MEMORY;
+ err = JB_ERR_MEMORY;
+ }
+ else
+ {
+ char *filter_line;
+
+ if (!err) err = map(line_exports, "index", 1, number, 1);
+ if (!err) err = map(line_exports, "name", 1, filter_group->name, 1);
+ if (!err) err = map(line_exports, "description", 1, filter_group->description, 1);
+ if (!err) err = map_radio(line_exports, "this-filter", "ynx", current_mode);
+ if (!err) err = map(line_exports, "filter-type", 1, action_type_info[filter_type].type, 1);
+ if (!err) err = map(line_exports, "abbr-action-type", 1, action_type_info[filter_type].abbr_type, 1);
+ if (!err) err = map(line_exports, "anchor", 1, action_type_info[filter_type].anchor, 1);
+
+ if (!err)
+ {
+ filter_line = strdup(filter_template);
+ if (filter_line == NULL) err = JB_ERR_MEMORY;
+ }
+ if (!err) err = template_fill(&filter_line, line_exports);
+ if (!err) err = string_join(&prepared_templates[filter_type], filter_line);
+
+ free_map(line_exports);
}
- if (!err) err = template_fill(&filter_line, line_exports);
- if (!err) err = string_join(&prepared_templates[type], filter_line);
-
- free_map(line_exports);
}
}
}
@@ -2994,6 +2996,7 @@ static int get_number_of_filters(const struct client_state *csp)
struct re_filterfile_spec *b;
struct file_list *fl;
int number_of_filters = 0;
+ int filter_type;
for (i = 0; i < MAX_AF_FILES; i++)
{
@@ -3009,10 +3012,12 @@ static int get_number_of_filters(const struct client_state *csp)
*/
continue;
}
-
- for (b = fl->f; b != NULL; b = b->next)
+ for (filter_type = 0; filter_type < MAX_FILTER_TYPES; filter_type++)
{
- number_of_filters++;
+ for (b = ((struct re_filters *)fl->f)->filters[filter_type]; b != NULL; b = b->next)
+ {
+ number_of_filters++;
+ }
}
}
diff --git a/cgisimple.c b/cgisimple.c
index a6a8fada..d2735ca9 100644
--- a/cgisimple.c
+++ b/cgisimple.c
@@ -5,7 +5,7 @@
* Purpose : Simple CGIs to get information about Privoxy's
* status.
*
- * Copyright : Written by and Copyright (C) 2001-2022 the
+ * Copyright : Written by and Copyright (C) 2001-2026 the
* Privoxy team. https://www.privoxy.org/
*
* Based on the Internet Junkbuster originally written
@@ -1202,24 +1202,20 @@ static char *get_filter_statistics_table(const struct client_state *csp)
*/
continue;
}
-
- for (b = fl->f; b != NULL; b = b->next)
+ for (b = ((struct re_filters *)(fl->f))->filters[FT_CONTENT_FILTER]; b != NULL; b = b->next)
{
- if (b->type == FT_CONTENT_FILTER)
- {
- unsigned long long executions;
- unsigned long long response_bodies_modified;
- unsigned long long hits;
-
- get_filter_statistics(b->name, &executions, &response_bodies_modified, &hits);
- snprintf(buf, sizeof(buf),
- "<tr><td>%s</td><td style=\"text-align: right\">%llu</td>"
- "<td style=\"text-align: right\">%llu</td>"
- "<td style=\"text-align: right\">%llu</td><tr>\n",
- b->name, executions, response_bodies_modified, hits);
-
- if (!err) err = string_append(&statistics, buf);
- }
+ unsigned long long executions;
+ unsigned long long response_bodies_modified;
+ unsigned long long hits;
+
+ get_filter_statistics(b->name, &executions, &response_bodies_modified, &hits);
+ snprintf(buf, sizeof(buf),
+ "<tr><td>%s</td><td style=\"text-align: right\">%llu</td>"
+ "<td style=\"text-align: right\">%llu</td>"
+ "<td style=\"text-align: right\">%llu</td><tr>\n",
+ b->name, executions, response_bodies_modified, hits);
+
+ if (!err) err = string_append(&statistics, buf);
}
}
diff --git a/filters.c b/filters.c
index 04fa77fa..8bda3caa 100644
--- a/filters.c
+++ b/filters.c
@@ -4,7 +4,7 @@
*
* Purpose : Declares functions to parse/crunch headers and pages.
*
- * Copyright : Written by and Copyright (C) 2001-2024 the
+ * Copyright : Written by and Copyright (C) 2001-2026 the
* Privoxy team. https://www.privoxy.org/
*
* Based on the Internet Junkbuster originally written
@@ -1560,13 +1560,8 @@ struct re_filterfile_spec *get_filter(const struct client_state *csp,
continue;
}
- for (b = fl->f; b != NULL; b = b->next)
+ for (b = ((struct re_filters *)(fl->f))->filters[requested_type]; b != NULL; b = b->next)
{
- if (b->type != requested_type)
- {
- /* The callers isn't interested in this filter type. */
- continue;
- }
if (strcmp(b->name, requested_name) == 0)
{
/* The requested filter has been found. Abort search. */
diff --git a/loaders.c b/loaders.c
index a9820df5..b973d40a 100644
--- a/loaders.c
+++ b/loaders.c
@@ -7,7 +7,7 @@
* the list of active loaders, and to automatically
* unload files that are no longer in use.
*
- * Copyright : Written by and Copyright (C) 2001-2014 the
+ * Copyright : Written by and Copyright (C) 2001-2026 the
* Privoxy team. https://www.privoxy.org/
*
* Based on the Internet Junkbuster originally written
@@ -967,20 +967,27 @@ load_trustfile_error:
*********************************************************************/
static void unload_re_filterfile(void *f)
{
- struct re_filterfile_spec *a, *b = (struct re_filterfile_spec *)f;
+ int filter_type;
- while (b != NULL)
+ for (filter_type = 0; filter_type < MAX_FILTER_TYPES; filter_type++)
{
- a = b->next;
+ struct re_filterfile_spec *a, *b;
- destroy_list(b->patterns);
- pcrs_free_joblist(b->joblist);
- freez(b->name);
- freez(b->description);
- freez(b);
+ b = ((struct re_filters *)f)->filters[filter_type];
+ while (b != NULL)
+ {
+ a = b->next;
+
+ destroy_list(b->patterns);
+ pcrs_free_joblist(b->joblist);
+ freez(b->name);
+ freez(b->description);
+ freez(b);
- b = a;
+ b = a;
+ }
}
+ freez(f);
return;
}
@@ -1103,11 +1110,14 @@ int load_one_re_filterfile(struct client_state *csp, int fileid)
struct re_filterfile_spec *new_bl, *bl = NULL;
struct file_list *fs;
+ struct re_filters last_filters;
char *buf = NULL;
unsigned long linenum = 0;
pcrs_job *dummy, *lastjob = NULL;
+ enum filter_type current_filter = FT_INVALID_FILTER;
+ memset(&last_filters, 0, sizeof(last_filters));
/*
* No need to reload if unchanged
*/
@@ -1179,6 +1189,7 @@ int load_one_re_filterfile(struct client_state *csp, int fileid)
*/
if (new_filter != FT_INVALID_FILTER)
{
+ current_filter = new_filter;
new_bl = zalloc_or_die(sizeof(*bl));
if (new_filter == FT_CONTENT_FILTER)
{
@@ -1202,7 +1213,6 @@ int load_one_re_filterfile(struct client_state *csp, int fileid)
{
new_bl->name = chomp(buf + 21);
}
- new_bl->type = new_filter;
/*
* If a filter description is available,
@@ -1225,23 +1235,27 @@ int load_one_re_filterfile(struct client_state *csp, int fileid)
new_bl->name = strdup_or_die(chomp(new_bl->name));
- /*
- * If this is the first filter block, chain it
- * to the file_list rather than its (nonexistent)
- * predecessor
- */
if (fs->f == NULL)
{
- fs->f = new_bl;
+ fs->f = zalloc_or_die(sizeof(struct re_filters));
+ }
+
+ if (((struct re_filters *)(fs->f))->filters[new_filter] == NULL)
+ {
+ ((struct re_filters *)(fs->f))->filters[new_filter] = new_bl;
}
else
{
- assert(NULL != bl);
- bl->next = new_bl;
+ if (last_filters.filters[new_filter] != NULL)
+ {
+ last_filters.filters[new_filter]->next = new_bl;
+ }
}
bl = new_bl;
+ last_filters.filters[new_filter] = new_bl;
- log_error(LOG_LEVEL_RE_FILTER, "Reading in filter \"%s\" (\"%s\")", bl->name, bl->description);
+ log_error(LOG_LEVEL_RE_FILTER, "Reading in filter \"%s\" (\"%s\"). Type %d.",
+ bl->name, bl->description, new_filter);
#ifdef FEATURE_EXTENDED_STATISTICS
register_filter_for_statistics(bl->name);
#endif
@@ -1250,7 +1264,7 @@ int load_one_re_filterfile(struct client_state *csp, int fileid)
}
#ifdef FEATURE_EXTERNAL_FILTERS
- if ((bl != NULL) && (bl->type == FT_EXTERNAL_CONTENT_FILTER))
+ if ((bl != NULL) && (current_filter == FT_EXTERNAL_CONTENT_FILTER))
{
jb_err jb_error;
/* Save the code as "pattern", but do not compile anything. */
diff --git a/project.h b/project.h
index 9f3c36ef..9075c9b7 100644
--- a/project.h
+++ b/project.h
@@ -8,7 +8,7 @@
* project. Does not define any variables or functions
* (though it does declare some macros).
*
- * Copyright : Written by and Copyright (C) 2001-2021 the
+ * Copyright : Written by and Copyright (C) 2001-2026 the
* Privoxy team. https://www.privoxy.org/
*
* Based on the Internet Junkbuster originally written
@@ -1338,7 +1338,8 @@ enum filter_type
* This struct represents one filter (one block) from
* the re_filterfile. If there is more than one filter
* in the file, the file will be represented by a
- * chained list of re_filterfile specs.
+ * chained list of re_filterfile specs of the same filter
+ * type.
*/
struct re_filterfile_spec
{
@@ -1346,12 +1347,16 @@ struct re_filterfile_spec
char *description; /**< Description from FILTER: statement in re_filterfile. */
struct list patterns[1]; /**< The patterns from the re_filterfile. */
pcrs_job *joblist; /**< The resulting compiled pcrs_jobs. */
- enum filter_type type; /**< Filter type (content, client-header, server-header). */
int dynamic; /**< Set to one if the pattern might contain variables
and has to be recompiled for every request. */
struct re_filterfile_spec *next; /**< The pointer for chaining. */
};
+struct re_filters
+{
+ struct re_filterfile_spec *filters[MAX_FILTER_TYPES];
+};
+
#ifdef FEATURE_ACL
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.
More information about the Privoxy-commits
mailing list