From 7a3871f63e569b5f338112d63865d069e42d11bf Mon Sep 17 00:00:00 2001 From: Fredrik Tolf Date: Sat, 17 Jul 2021 17:50:25 +0200 Subject: [PATCH] patplex: Replace the `default' handling with arbitrary priorities. --- doc/patplex.doc | 22 ++++++++++-- src/patplex.c | 104 ++++++++++++++++++++++++++++++++------------------------ 2 files changed, 80 insertions(+), 46 deletions(-) diff --git a/doc/patplex.doc b/doc/patplex.doc index 86d6ace..5a60e96 100644 --- a/doc/patplex.doc +++ b/doc/patplex.doc @@ -92,10 +92,14 @@ rules are recognized: 'HEADER', the rule never matches. If 'FLAGS' contain the character `i`, 'REGEX' is matched case-independently. +*all*:: + + The rule always matches. + *default*:: - Matches if and only if no *match* stanza without a *default* - rule has matched. + Convenient shorthand for an *all* line followed by *priority + -10* (see below). In addition to the rules, a *match* stanza must contain exactly one follow-up line specifying the action to take if it matches. Currently, @@ -109,6 +113,20 @@ only the *handler* action is recognized: Additionally, a *match* stanza may contain any of the following, optional lines: +*priority* 'INTEGER':: + + Specifies the priority for the match stanza. In case more than + one stanza match a request, the one with the highest priority + is used. In case more than one stanza with the same highest + priority match a request, it is unspecified which will be + used. Match stanzas without a priority specification will + default to priority 0. Either positive or negative priorities + may be specified. + +*order* 'INTEGER':: + + A synonym for *priority*. Use whichever you like the best. + *set* 'HEADER' 'VALUE':: If the *match* stanza as a whole matches, the named HTTP diff --git a/src/patplex.c b/src/patplex.c index 9939543..f76cc72 100644 --- a/src/patplex.c +++ b/src/patplex.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #ifdef HAVE_CONFIG_H @@ -41,7 +42,6 @@ #define PAT_METHOD 2 #define PAT_HEADER 3 #define PAT_ALL 4 -#define PAT_DEFAULT 5 #define PATFL_MSS 1 #define PATFL_UNQ 2 @@ -69,6 +69,7 @@ struct pattern { char *childnm; struct rule **rules; char *restpat; + int prio; }; static struct config *gconfig, *lconfig; @@ -237,7 +238,14 @@ static struct pattern *parsepattern(struct cfstate *s) } else if(!strcmp(s->argv[0], "all")) { newrule(pat)->type = PAT_ALL; } else if(!strcmp(s->argv[0], "default")) { - newrule(pat)->type = PAT_DEFAULT; + newrule(pat)->type = PAT_ALL; + pat->prio = -10; + } else if(!strcmp(s->argv[0], "order") || !strcmp(s->argv[0], "priority")) { + if(s->argc < 2) { + flog(LOG_WARNING, "%s:%i: missing specification for `%s' directive", s->file, s->lno, s->argv[0]); + continue; + } + pat->prio = atoi(s->argv[1]); } else if(!strcmp(s->argv[0], "handler")) { if(s->argc < 2) { flog(LOG_WARNING, "%s:%i: missing child name for `handler' directive", s->file, s->lno); @@ -394,7 +402,19 @@ static void qoffsets(char *buf, int *obuf, char *pstr, int unquote) } } -static struct pattern *findmatch(struct config *cf, struct hthead *req, int trydefault) +struct match { + struct pattern *pat; + char **mstr; + int rmo; +}; + +static void freematch(struct match *match) +{ + freeca(match->mstr); + free(match); +} + +static struct match *findmatch(struct config *cf, struct hthead *req, struct match *match) { int i, o; struct pattern *pat; @@ -407,6 +427,8 @@ static struct pattern *findmatch(struct config *cf, struct hthead *req, int tryd mstr = NULL; for(pat = cf->patterns; pat != NULL; pat = pat->next) { + if(match && (pat->prio <= match->pat->prio)) + continue; rmo = -1; for(i = 0; (rule = pat->rules[i]) != NULL; i++) { rx = NULL; @@ -451,27 +473,32 @@ static struct pattern *findmatch(struct config *cf, struct hthead *req, int tryd } } } else if(rule->type == PAT_ALL) { - } else if(rule->type == PAT_DEFAULT) { - if(!trydefault) - break; } } if(!rule) { - if(pat->restpat) { - exprestpat(req, pat, mstr); - } else if(rmo != -1) { - replrest(req, req->rest + rmo); - } - if(mstr) - freeca(mstr); - return(pat); - } - if(mstr) { - freeca(mstr); - mstr = NULL; + if(match) + freematch(match); + omalloc(match); + match->pat = pat; + match->mstr = mstr; + match->rmo = rmo; } } - return(NULL); + return(match); +} + +static void execmatch(struct hthead *req, struct match *match) +{ + struct headmod *head; + + if(match->pat->restpat) + exprestpat(req, match->pat, match->mstr); + else if(match->rmo != -1) + replrest(req, req->rest + match->rmo); + for(head = match->pat->headers; head != NULL; head = head->next) { + headrmheader(req, head->name); + headappheader(req, head->name, head->value); + } } static void childerror(struct hthead *req, int fd) @@ -484,44 +511,33 @@ static void childerror(struct hthead *req, int fd) static void serve(struct hthead *req, int fd) { - struct pattern *pat; - struct headmod *head; + struct match *match; struct child *ch; - pat = NULL; - if(pat == NULL) - pat = findmatch(lconfig, req, 0); - if(pat == NULL) - pat = findmatch(lconfig, req, 1); - if(gconfig != NULL) { - if(pat == NULL) - pat = findmatch(gconfig, req, 0); - if(pat == NULL) - pat = findmatch(gconfig, req, 1); - } - if(pat == NULL) { + match = NULL; + match = findmatch(lconfig, req, match); + if(gconfig != NULL) + match = findmatch(gconfig, req, match); + if(match == NULL) { simpleerror(fd, 404, "Not Found", "The requested resource could not be found on this server."); return; } ch = NULL; if(ch == NULL) - ch = getchild(lconfig, pat->childnm); - if(gconfig != NULL) { - if(ch == NULL) - ch = getchild(gconfig, pat->childnm); - } + ch = getchild(lconfig, match->pat->childnm); + if((ch == NULL) && (gconfig != NULL)) + ch = getchild(gconfig, match->pat->childnm); if(ch == NULL) { - flog(LOG_ERR, "child %s requested, but was not declared", pat->childnm); - simpleerror(fd, 500, "Configuration Error", "The server is erroneously configured. Handler %s was requested, but not declared.", pat->childnm); + flog(LOG_ERR, "child %s requested, but was not declared", match->pat->childnm); + simpleerror(fd, 500, "Configuration Error", "The server is erroneously configured. Handler %s was requested, but not declared.", match->pat->childnm); + freematch(match); return; } - for(head = pat->headers; head != NULL; head = head->next) { - headrmheader(req, head->name); - headappheader(req, head->name, head->value); - } + execmatch(req, match); if(childhandle(ch, req, fd, NULL, NULL)) childerror(req, fd); + freematch(match); } static void reloadconf(char *nm) -- 2.11.0