diff --git a/src/base.h b/src/base.h index 44d7954e..c29dc390 100644 --- a/src/base.h +++ b/src/base.h @@ -16,6 +16,8 @@ struct fdevents; /* declaration */ struct stat_cache; /* declaration */ +struct cond_cache_t; /* declaration */ +struct cond_match_t; /* declaration */ #define DIRECT 0 /* con->mode */ @@ -147,32 +149,6 @@ typedef enum { CON_STATE_CLOSE } connection_state_t; -typedef enum { - /* condition not active at the moment because itself or some - * pre-condition depends on data not available yet - */ - COND_RESULT_UNSET, - - /* special "unset" for branches not selected due to pre-conditions - * not met (but pre-conditions are not "unset" anymore) - */ - COND_RESULT_SKIP, - - /* actually evaluated the condition itself */ - COND_RESULT_FALSE, /* not active */ - COND_RESULT_TRUE /* active */ -} cond_result_t; - -typedef struct cond_cache_t { - /* current result (with preconditions) */ - cond_result_t result; - /* result without preconditions (must never be "skip") */ - cond_result_t local_result; - const buffer *comp_value; /* just a pointer */ - int patterncount; - int matches[3 * 10]; -} cond_cache_t; - struct connection { connection_state_t state; @@ -242,7 +218,8 @@ struct connection { specific_config conf; /* global connection specific config */ uint32_t conditional_is_valid; - cond_cache_t *cond_cache; + struct cond_cache_t *cond_cache; + struct cond_match_t *cond_match; const buffer *server_name; buffer *proto; diff --git a/src/configfile-glue.c b/src/configfile-glue.c index d1b2cc9f..9b000a21 100644 --- a/src/configfile-glue.c +++ b/src/configfile-glue.c @@ -351,7 +351,7 @@ static int config_addrbuf_eq_remote_ip_mask(connection *con, const buffer *strin return config_addrstr_eq_remote_ip_mask(con, addrstr, nm_bits, rmt); } -static int data_config_pcre_exec(const data_config *dc, cond_cache_t *cache, const buffer *b); +static int data_config_pcre_exec(const data_config *dc, cond_cache_t *cache, const buffer *b, cond_match_t *cond_match); static cond_result_t config_check_cond_nocache(connection *con, const data_config *dc, const int debug_cond, cond_cache_t * const cache) { static struct const_char_buffer { @@ -544,7 +544,8 @@ static cond_result_t config_check_cond_nocache(connection *con, const data_confi } case CONFIG_COND_NOMATCH: case CONFIG_COND_MATCH: { - if (data_config_pcre_exec(dc, cache, l) > 0) { + cond_match_t *cond_match = con->cond_match + dc->context_ndx; + if (data_config_pcre_exec(dc, cache, l, cond_match) > 0) { return (dc->cond == CONFIG_COND_MATCH) ? COND_RESULT_TRUE : COND_RESULT_FALSE; } else { /* cache is already cleared */ @@ -576,38 +577,25 @@ int config_check_cond(connection * const con, const int context_ndx) { cond_cache_t * const cache = &con->cond_cache[context_ndx]; return COND_RESULT_TRUE == (COND_RESULT_UNSET != cache->result - ? cache->result + ? (cond_result_t)cache->result : config_check_cond_calc(con, context_ndx, cache)); } /* if we reset the cache result for a node, we also need to clear all * child nodes and else-branches*/ -static void config_cond_clear_node(server *srv, connection *con, const data_config *dc) { +static void config_cond_clear_node(cond_cache_t * const cond_cache, const data_config * const dc) { /* if a node is "unset" all children are unset too */ - if (con->cond_cache[dc->context_ndx].result != COND_RESULT_UNSET) { - size_t i; + if (cond_cache[dc->context_ndx].result != COND_RESULT_UNSET) { + cond_cache[dc->context_ndx].result = COND_RESULT_UNSET; - #if 0 - /* (redundant; matches not relevant unless COND_RESULT_TRUE) */ - switch (con->cond_cache[dc->context_ndx].local_result) { - case COND_RESULT_TRUE: - case COND_RESULT_FALSE: - break; - default: - con->cond_cache[dc->context_ndx].patterncount = 0; - con->cond_cache[dc->context_ndx].comp_value = NULL; - } - #endif - con->cond_cache[dc->context_ndx].result = COND_RESULT_UNSET; - - for (i = 0; i < dc->children.used; ++i) { + for (uint32_t i = 0; i < dc->children.used; ++i) { const data_config *dc_child = dc->children.data[i]; if (NULL == dc_child->prev) { /* only call for first node in if-else chain */ - config_cond_clear_node(srv, con, dc_child); + config_cond_clear_node(cond_cache, dc_child); } } - if (NULL != dc->next) config_cond_clear_node(srv, con, dc->next); + if (NULL != dc->next) config_cond_clear_node(cond_cache, dc->next); } } @@ -617,14 +605,15 @@ static void config_cond_clear_node(server *srv, connection *con, const data_conf * if the item is COND_LAST_ELEMENT we reset all items */ void config_cond_cache_reset_item(server *srv, connection *con, comp_key_t item) { + cond_cache_t * const cond_cache = con->cond_cache; for (uint32_t i = 0; i < srv->config_context->used; ++i) { const data_config *dc = (data_config *)srv->config_context->data[i]; if (item == dc->comp) { /* clear local_result */ - con->cond_cache[i].local_result = COND_RESULT_UNSET; + cond_cache[i].local_result = COND_RESULT_UNSET; /* clear result in subtree (including the node itself) */ - config_cond_clear_node(srv, con, dc); + config_cond_clear_node(cond_cache, dc); } } } @@ -633,36 +622,34 @@ void config_cond_cache_reset_item(server *srv, connection *con, comp_key_t item) * reset the config cache to its initial state at connection start */ void config_cond_cache_reset(server *srv, connection *con) { - cond_cache_t * const cond_cache = con->cond_cache; con->conditional_is_valid = 0; /* resetting all entries; no need to follow children as in config_cond_cache_reset_item */ - for (uint32_t i = 1, used = srv->config_context->used; i < used; ++i) { - cond_cache[i].result = COND_RESULT_UNSET; - cond_cache[i].local_result = COND_RESULT_UNSET; - cond_cache[i].patterncount = 0; - cond_cache[i].comp_value = NULL; - } + /* static_assert(0 == COND_RESULT_UNSET); */ + const uint32_t used = srv->config_context->used; + if (used > 1) + memset(con->cond_cache, 0, used*sizeof(cond_cache_t)); } #ifdef HAVE_PCRE_H #include #endif -static int data_config_pcre_exec(const data_config *dc, cond_cache_t *cache, const buffer *b) { +static int data_config_pcre_exec(const data_config *dc, cond_cache_t *cache, const buffer *b, cond_match_t *cond_match) { #ifdef HAVE_PCRE_H #ifndef elementsof #define elementsof(x) (sizeof(x) / sizeof(x[0])) #endif cache->patterncount = pcre_exec(dc->regex, dc->regex_study, CONST_BUF_LEN(b), 0, 0, - cache->matches, elementsof(cache->matches)); + cond_match->matches, elementsof(cond_match->matches)); if (cache->patterncount > 0) - cache->comp_value = b; /* holds pointer to b (!) for pattern subst */ + cond_match->comp_value = b; /*holds pointer to b (!) for pattern subst*/ return cache->patterncount; #else UNUSED(dc); UNUSED(cache); UNUSED(b); + UNUSED(cond_match); return 0; #endif } diff --git a/src/connections.c b/src/connections.c index 41e5b181..616e18b2 100644 --- a/src/connections.c +++ b/src/connections.c @@ -587,6 +587,12 @@ static connection *connection_init(server *srv) { con->cond_cache = calloc(srv->config_context->used, sizeof(cond_cache_t)); force_assert(NULL != con->cond_cache); + #ifdef HAVE_PCRE_H + if (srv->config_context->used > 1) {/*save 128b per con if no conditions)*/ + con->cond_match=calloc(srv->config_context->used, sizeof(cond_match_t)); + force_assert(NULL != con->cond_match); + } + #endif config_reset_config(srv, con); return con; @@ -633,6 +639,7 @@ void connections_free(server *srv) { #undef CLEAN free(con->plugin_ctx); free(con->cond_cache); + free(con->cond_match); free(con); } diff --git a/src/keyvalue.c b/src/keyvalue.c index e762c59a..36aa27b8 100644 --- a/src/keyvalue.c +++ b/src/keyvalue.c @@ -1,7 +1,7 @@ #include "first.h" #include "keyvalue.h" -#include "base.h" /* struct cond_cache_t */ +#include "plugin_config.h" /* struct cond_match_t */ #include "burl.h" #include "log.h" @@ -95,9 +95,9 @@ static void pcre_keyvalue_buffer_append_match(buffer *b, const char **list, int } static void pcre_keyvalue_buffer_append_ctxmatch(buffer *b, pcre_keyvalue_ctx *ctx, unsigned int num, int flags) { - const struct cond_cache_t * const cache = ctx->cache; + const struct cond_match_t * const cache = ctx->cache; if (!cache) return; /* no enclosing match context */ - if ((int)num < cache->patterncount) { + if ((int)num < ctx->cond_match_count) { const int off = cache->matches[(num <<= 1)]; /*(num *= 2)*/ const int len = cache->matches[num+1] - off; burl_append(b, cache->comp_value->ptr + off, (size_t)len, flags); diff --git a/src/keyvalue.h b/src/keyvalue.h index a32e6262..27831fe1 100644 --- a/src/keyvalue.h +++ b/src/keyvalue.h @@ -6,12 +6,13 @@ #include "buffer.h" struct burl_parts_t; /* declaration */ -struct cond_cache_t; /* declaration */ +struct cond_match_t; /* declaration */ struct pcre_keyvalue; /* declaration */ typedef struct pcre_keyvalue_ctx { - struct cond_cache_t *cache; + struct cond_match_t *cache; struct burl_parts_t *burl; + int cond_match_count; int m; } pcre_keyvalue_ctx; diff --git a/src/mod_redirect.c b/src/mod_redirect.c index 97b03408..78a0d11f 100644 --- a/src/mod_redirect.c +++ b/src/mod_redirect.c @@ -159,9 +159,12 @@ URIHANDLER_FUNC(mod_redirect_uri_handler) { mod_redirect_patch_config(con, p); if (!p->conf.redirect || !p->conf.redirect->used) return HANDLER_GO_ON; - ctx.cache = p->conf.redirect->x0 - ? &con->cond_cache[p->conf.redirect->x0] - : NULL; + + ctx.cache = NULL; + if (p->conf.redirect->x0) { /*(p->conf.redirect->x0 is context_idx)*/ + ctx.cond_match_count=con->cond_cache[p->conf.redirect->x0].patterncount; + ctx.cache = con->cond_match + p->conf.redirect->x0; + } ctx.burl = &burl; burl.scheme = con->uri.scheme; burl.authority = con->uri.authority; diff --git a/src/mod_rewrite.c b/src/mod_rewrite.c index 2c0a4d96..9abfb3fa 100644 --- a/src/mod_rewrite.c +++ b/src/mod_rewrite.c @@ -287,8 +287,11 @@ static handler_t process_rewrite_rules(server *srv, connection *con, plugin_data if (*hctx & REWRITE_STATE_FINISHED) return HANDLER_GO_ON; } - /*(kvb->x0 is context_idx)*/ - ctx.cache = kvb->x0 ? &con->cond_cache[kvb->x0] : NULL; + ctx.cache = NULL; + if (kvb->x0) { /*(kvb->x0 is context_idx)*/ + ctx.cond_match_count = con->cond_cache[kvb->x0].patterncount; + ctx.cache = con->cond_match + kvb->x0; + } ctx.burl = &burl; burl.scheme = con->uri.scheme; burl.authority = con->uri.authority; diff --git a/src/plugin_config.h b/src/plugin_config.h index 6b3bc31b..16540a37 100644 --- a/src/plugin_config.h +++ b/src/plugin_config.h @@ -123,6 +123,38 @@ int config_plugin_values_init_block(server * const srv, const array * const ca, __attribute_cold__ int config_plugin_values_init(server *srv, void *p_d, const config_plugin_keys_t *cpk, const char *mname); +typedef enum { + /* condition not active at the moment because itself or some + * pre-condition depends on data not available yet + */ + COND_RESULT_UNSET, + + /* special "unset" for branches not selected due to pre-conditions + * not met (but pre-conditions are not "unset" anymore) + */ + COND_RESULT_SKIP, + + /* actually evaluated the condition itself */ + COND_RESULT_FALSE, /* not active */ + COND_RESULT_TRUE /* active */ +} cond_result_t; + +typedef struct cond_cache_t { + /* current result (with preconditions) */ + int8_t result; /*(cond_result_t)*/ + /* result without preconditions (must never be "skip") */ + int8_t local_result; /*(cond_result_t)*/ + int16_t patterncount; +} cond_cache_t; /* 8 bytes (2^3) */ + +typedef struct cond_match_t { + const buffer *comp_value; /* just a pointer */ + #if !(defined(_LP64) || defined(__LP64__) || defined(_WIN64)) /*(not 64-bit)*/ + int dummy_alignment; /*(for alignment in 32-bit)*/ + #endif + int matches[3 * 10]; +} cond_match_t; /* 128 bytes (2^7) */ + int config_check_cond(connection *con, int context_ndx); #endif diff --git a/src/t/test_keyvalue.c b/src/t/test_keyvalue.c index baa4aaaf..fc645135 100644 --- a/src/t/test_keyvalue.c +++ b/src/t/test_keyvalue.c @@ -8,7 +8,8 @@ #include "keyvalue.c" -#include "base.h" /* struct server, struct cond_cache_t */ +#include "base.h" /* struct server */ +#include "plugin_config.h" /* struct cond_match_t */ #ifdef HAVE_PCRE_H static pcre_keyvalue_buffer * test_keyvalue_test_kvb_init (void) { @@ -47,7 +48,7 @@ static void test_keyvalue_pcre_keyvalue_buffer_process (void) { buffer *url = buffer_init(); buffer *result = buffer_init(); struct burl_parts_t burl; - cond_cache_t cache; + cond_match_t cache; pcre_keyvalue_ctx ctx; handler_t rc; buffer *scheme = buffer_init(); @@ -64,9 +65,9 @@ static void test_keyvalue_pcre_keyvalue_buffer_process (void) { buffer_copy_string_len(scheme, CONST_STR_LEN("http")); buffer_copy_string_len(authority, CONST_STR_LEN("www.example.com")); /* model outer conditional match of $HTTP["host"] =~ "^(www).example.com$" */ + ctx.cond_match_count = 2; ctx.cache = &cache; memset(&cache, 0, sizeof(cache)); - cache.patterncount = 2; cache.comp_value = authority; cache.matches[0] = 0; cache.matches[1] = 15;