[core] split cond cache from cond matches
parent
5977ce2b4a
commit
c193da3404
31
src/base.h
31
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;
|
||||
|
|
|
@ -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 <pcre.h>
|
||||
#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
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue