speed up big config parsing by 2x using gperf

This commit is contained in:
rofl0r 2020-09-16 18:23:35 +01:00
parent caeab31fca
commit 45323584a0
6 changed files with 157 additions and 31 deletions

View File

@ -29,6 +29,7 @@ tinyproxy_SOURCES = \
buffer.c buffer.h \
child.c child.h \
common.h \
conf-tokens.c conf-tokens.h \
conf.c conf.h \
conns.c conns.h \
daemon.c daemon.h \
@ -58,3 +59,6 @@ EXTRA_tinyproxy_SOURCES = filter.c filter.h \
transparent-proxy.c transparent-proxy.h
tinyproxy_DEPENDENCIES = @ADDITIONAL_OBJECTS@
tinyproxy_LDADD = @ADDITIONAL_OBJECTS@ -lpthread
conf-tokens.c: conf-tokens.gperf
gperf $< > $@

61
src/conf-tokens.gperf Normal file
View File

@ -0,0 +1,61 @@
%{
#include <string.h>
#include <stdlib.h>
#include "conf-tokens.h"
%}
struct config_directive_entry { const char* name; enum config_directive value; };
%struct-type
%define slot-name name
%define initializer-suffix ,CD_NIL
%define lookup-function-name config_directive_find
%ignore-case
%7bit
%compare-lengths
%readonly-tables
%define constants-prefix CDS_
%omit-struct-type
%%
logfile, CD_logfile
pidfile, CD_pidfile
anonymous, CD_anonymous
viaproxyname, CD_viaproxyname
defaulterrorfile, CD_defaulterrorfile
statfile, CD_statfile
stathost, CD_stathost
xtinyproxy, CD_xtinyproxy
syslog, CD_syslog
bindsame, CD_bindsame
disableviaheader, CD_disableviaheader
port, CD_port
maxclients, CD_maxclients
maxspareservers, CD_maxspareservers
minspareservers, CD_minspareservers
startservers, CD_startservers
maxrequestsperchild, CD_maxrequestsperchild
timeout, CD_timeout
connectport, CD_connectport
user, CD_user
group, CD_group
listen, CD_listen
allow, CD_allow
deny, CD_deny
bind, CD_bind
basicauth, CD_basicauth
errorfile, CD_errorfile
addheader, CD_addheader
filter, CD_filter
filterurls, CD_filterurls
filterextended, CD_filterextended
filterdefaultdeny, CD_filterdefaultdeny
filtercasesensitive, CD_filtercasesensitive
reversebaseurl, CD_reversebaseurl
reverseonly, CD_reverseonly
reversemagic, CD_reversemagic
reversepath, CD_reversepath
upstream, CD_upstream
loglevel, CD_loglevel
%%

53
src/conf-tokens.h Normal file
View File

@ -0,0 +1,53 @@
#ifndef CONF_TOKENS_H
#define CONF_TOKENS_H
enum config_directive {
CD_NIL = 0,
CD_logfile,
CD_pidfile,
CD_anonymous,
CD_viaproxyname,
CD_defaulterrorfile,
CD_statfile,
CD_stathost,
CD_xtinyproxy,
CD_syslog,
CD_bindsame,
CD_disableviaheader,
CD_port,
CD_maxclients,
CD_maxspareservers,
CD_minspareservers,
CD_startservers,
CD_maxrequestsperchild,
CD_timeout,
CD_connectport,
CD_user,
CD_group,
CD_listen,
CD_allow,
CD_deny,
CD_bind,
CD_basicauth,
CD_errorfile,
CD_addheader,
CD_filter,
CD_filterurls,
CD_filterextended,
CD_filterdefaultdeny,
CD_filtercasesensitive,
CD_reversebaseurl,
CD_reverseonly,
CD_reversemagic,
CD_reversepath,
CD_upstream,
CD_loglevel,
};
struct config_directive_entry { const char* name; enum config_directive value; };
const struct config_directive_entry *
config_directive_find (register const char *str, register size_t len);
#endif

View File

@ -37,6 +37,7 @@
#include "upstream.h"
#include "connect-ports.h"
#include "basicauth.h"
#include "conf-tokens.h"
/*
* The configuration directives are defined in the structure below. Each
@ -98,10 +99,13 @@ typedef int (*CONFFILE_HANDLER) (struct config_s *, const char *,
* List all the handling functions. These are defined later, but they need
* to be in-scope before the big structure below.
*/
static HANDLE_FUNC (handle_nop)
static HANDLE_FUNC (handle_disabled_feature)
{
return 0;
} /* do nothing function */
fprintf (stderr, "ERROR: accessing feature that was disabled at compiletime on line %lu\n",
lineno);
return -1;
}
static HANDLE_FUNC (handle_allow);
static HANDLE_FUNC (handle_basicauth);
@ -161,7 +165,7 @@ static void config_free_regex (void);
* do not follow the pattern above. This macro is for convenience
* only.
*/
#define STDCONF(d, re, func) { BEGIN "(" #d ")" WS re END, func, NULL }
#define STDCONF(d, re, func) [CD_ ## d] = { BEGIN "()" WS re END, func, NULL }
/*
* Holds the regular expression used to match the configuration directive,
@ -174,14 +178,6 @@ struct {
CONFFILE_HANDLER handler;
regex_t *cre;
} directives[] = {
/* comments */
{
BEGIN "#", handle_nop, NULL
},
/* blank lines */
{
"^[[:space:]]+$", handle_nop, NULL
},
/* string arguments */
STDCONF (logfile, STR, handle_logfile),
STDCONF (pidfile, STR, handle_pidfile),
@ -326,20 +322,25 @@ void free_config (struct config_s *conf)
}
/*
* Initializes Config parser. Currently this means:
* Compiles the regular expressions used by the configuration file. This
* routine MUST be called before trying to parse the configuration file.
*
* Returns 0 on success; negative upon failure.
*/
int
config_compile_regex (void)
config_init (void)
{
unsigned int i, r;
for (i = 0; i != ndirectives; ++i) {
assert (directives[i].handler);
assert (!directives[i].cre);
if (!directives[i].handler) {
directives[i].handler = handle_disabled_feature;
continue;
}
directives[i].cre = (regex_t *) safemalloc (sizeof (regex_t));
if (!directives[i].cre)
return -1;
@ -383,20 +384,17 @@ config_free_regex (void)
* a negative number is returned.
*/
static int check_match (struct config_s *conf, const char *line,
unsigned long lineno)
unsigned long lineno, enum config_directive cd)
{
regmatch_t match[RE_MAX_MATCHES];
unsigned int i;
unsigned int i = cd;
assert (ndirectives > 0);
for (i = 0; i != ndirectives; ++i) {
assert (directives[i].cre);
if (!regexec
(directives[i].cre, line, RE_MAX_MATCHES, match, 0))
return (*directives[i].handler) (conf, line, lineno, match);
}
if (!directives[i].cre)
return (*directives[i].handler) (conf, line, lineno, match);
if (!regexec
(directives[i].cre, line, RE_MAX_MATCHES, match, 0))
return (*directives[i].handler) (conf, line, lineno, match);
return -1;
}
@ -405,15 +403,25 @@ static int check_match (struct config_s *conf, const char *line,
*/
static int config_parse (struct config_s *conf, FILE * f)
{
char buffer[LINE_MAX];
char buffer[LINE_MAX], *p, *q, c;
const struct config_directive_entry *e;
unsigned long lineno = 1;
while (fgets (buffer, sizeof (buffer), f)) {
if (check_match (conf, buffer, lineno)) {
printf ("Syntax error on line %ld\n", lineno);
for (;fgets (buffer, sizeof (buffer), f);++lineno) {
if(buffer[0] == '#') continue;
p = buffer;
while(isspace(*p))p++;
if(!*p) continue;
q = p;
while(!isspace(*q))q++;
c = *q;
*q = 0;
e = config_directive_find(p, strlen(p));
*q = c;
if (!e || e->value == CD_NIL || check_match (conf, q, lineno, e->value)) {
fprintf (stderr, "ERROR: Syntax error on line %lu\n", lineno);
return 1;
}
++lineno;
}
return 0;
}

View File

@ -115,7 +115,7 @@ struct config_s {
extern int reload_config_file (const char *config_fname, struct config_s *conf);
int config_compile_regex (void);
int config_init (void);
void free_config (struct config_s *conf);
#endif

View File

@ -300,7 +300,7 @@ main (int argc, char **argv)
log_message (LOG_NOTICE, "Initializing " PACKAGE " ...");
if (config_compile_regex()) {
if (config_init()) {
exit (EX_SOFTWARE);
}