diff --git a/src/configfile.c b/src/configfile.c index 952b70f2..171deb01 100644 --- a/src/configfile.c +++ b/src/configfile.c @@ -241,11 +241,16 @@ static void config_burl_normalize_cond (server * const srv) { } static int config_pcre_keyvalue (server * const srv) { + const int pcre_jit = + !srv->srvconf.feature_flags + || config_plugin_value_tobool( + array_get_element_klen(srv->srvconf.feature_flags, + CONST_STR_LEN("server.pcre_jit")), 1); for (uint32_t i = 0; i < srv->config_context->used; ++i) { data_config * const dc = (data_config *)srv->config_context->data[i]; if (dc->cond != CONFIG_COND_NOMATCH && dc->cond != CONFIG_COND_MATCH) continue; - if (!data_config_pcre_compile(dc)) + if (!data_config_pcre_compile(dc, pcre_jit, srv->errh)) return 0; } diff --git a/src/configfile.h b/src/configfile.h index b99af11d..903ea34e 100644 --- a/src/configfile.h +++ b/src/configfile.h @@ -49,7 +49,7 @@ __attribute_cold__ data_config *data_config_init(void); __attribute_cold__ -int data_config_pcre_compile(data_config *dc); +int data_config_pcre_compile(data_config *dc, int pcre_jit, log_error_st *errh); /*struct cond_cache_t;*/ /* declaration */ /*(moved to plugin_config.h)*/ /*int data_config_pcre_exec(const data_config *dc, struct cond_cache_t *cache, buffer *b);*/ diff --git a/src/data_config.c b/src/data_config.c index a63bbe18..59787a8d 100644 --- a/src/data_config.c +++ b/src/data_config.c @@ -9,6 +9,10 @@ #ifdef HAVE_PCRE_H #include +#ifndef PCRE_STUDY_JIT_COMPILE +#define PCRE_STUDY_JIT_COMPILE 0 +#define pcre_free_study(x) pcre_free(x) +#endif #endif __attribute_cold__ @@ -39,7 +43,7 @@ static void data_config_free(data_unset *d) { free(ds->string.ptr); #ifdef HAVE_PCRE_H if (ds->regex) pcre_free(ds->regex); - if (ds->regex_study) pcre_free(ds->regex_study); + if (ds->regex_study) pcre_free_study(ds->regex_study); #endif free(d); @@ -145,45 +149,51 @@ data_config *data_config_init(void) { return ds; } -int data_config_pcre_compile(data_config *dc) { +#include "log.h" + +int data_config_pcre_compile(data_config * const dc, const int pcre_jit, log_error_st * const errh) { #ifdef HAVE_PCRE_H - /* (use fprintf() on error, as this is called from configparser.y) */ const char *errptr; int erroff, captures; - if (dc->regex) pcre_free(dc->regex); - if (dc->regex_study) pcre_free(dc->regex_study); - dc->regex = pcre_compile(dc->string.ptr, 0, &errptr, &erroff, NULL); if (NULL == dc->regex) { - fprintf(stderr, "parsing regex failed: %s -> %s at offset %d\n", - dc->string.ptr, errptr, erroff); + log_error(errh, __FILE__, __LINE__, + "parsing regex failed: %s -> %s at offset %d\n", + dc->string.ptr, errptr, erroff); return 0; } - dc->regex_study = pcre_study(dc->regex, 0, &errptr); + const int study_options = pcre_jit ? PCRE_STUDY_JIT_COMPILE : 0; + dc->regex_study = pcre_study(dc->regex, study_options, &errptr); if (NULL == dc->regex_study && errptr != NULL) { - fprintf(stderr, "studying regex failed: %s -> %s\n", - dc->string.ptr, errptr); + log_error(errh, __FILE__, __LINE__, + "studying regex failed: %s -> %s\n", + dc->string.ptr, errptr); return 0; } erroff = pcre_fullinfo(dc->regex, dc->regex_study, PCRE_INFO_CAPTURECOUNT, &captures); if (0 != erroff) { - fprintf(stderr, "getting capture count for regex failed: %s\n", - dc->string.ptr); + log_error(errh, __FILE__, __LINE__, + "getting capture count for regex failed: %s\n", + dc->string.ptr); return 0; - } else if (captures > 9) { - fprintf(stderr, "Too many captures in regex, use (?:...) instead of (...): %s\n", - dc->string.ptr); + } + else if (captures > 9) { + log_error(errh, __FILE__, __LINE__, + "Too many captures in regex, use (?:...) instead of (...): %s\n", + dc->string.ptr); return 0; } return 1; #else - fprintf(stderr, "can't handle '%s' as you compiled without pcre support. \n" - "(perhaps just a missing pcre-devel package ?) \n", - dc->comp_key); + UNUSED(pcre_jit); + log_error(errh, __FILE__, __LINE__, + "can't handle '%s' as you compiled without pcre support. \n" + "(perhaps just a missing pcre-devel package ?) \n", + dc->comp_key); return 0; #endif } diff --git a/src/keyvalue.c b/src/keyvalue.c index 2adde419..8aa21844 100644 --- a/src/keyvalue.c +++ b/src/keyvalue.c @@ -17,6 +17,10 @@ #ifdef HAVE_PCRE_H #include +#ifndef PCRE_STUDY_JIT_COMPILE +#define PCRE_STUDY_JIT_COMPILE 0 +#define pcre_free_study(x) pcre_free(x) +#endif #endif typedef struct pcre_keyvalue { @@ -36,7 +40,7 @@ pcre_keyvalue_buffer *pcre_keyvalue_buffer_init(void) { return kvb; } -int pcre_keyvalue_buffer_append(log_error_st *errh, pcre_keyvalue_buffer *kvb, const buffer *key, const buffer *value) { +int pcre_keyvalue_buffer_append(log_error_st *errh, pcre_keyvalue_buffer *kvb, const buffer *key, const buffer *value, const int pcre_jit) { #ifdef HAVE_PCRE_H const char *errptr; int erroff; @@ -62,8 +66,12 @@ int pcre_keyvalue_buffer_append(log_error_st *errh, pcre_keyvalue_buffer *kvb, c return 0; } - if (NULL == (kv->key_extra = pcre_study(kv->key, 0, &errptr)) && - errptr != NULL) { + const int study_options = pcre_jit ? PCRE_STUDY_JIT_COMPILE : 0; + if (NULL == (kv->key_extra = pcre_study(kv->key, study_options, &errptr)) + && errptr != NULL) { + log_error(errh, __FILE__, __LINE__, + "studying regex failed: %s -> %s\n", + key->ptr, errptr); return 0; } #else @@ -75,6 +83,7 @@ int pcre_keyvalue_buffer_append(log_error_st *errh, pcre_keyvalue_buffer *kvb, c UNUSED(kvb); UNUSED(key); UNUSED(value); + UNUSED(pcre_jit); #endif return 1; @@ -85,7 +94,7 @@ void pcre_keyvalue_buffer_free(pcre_keyvalue_buffer *kvb) { for (uint32_t i = 0; i < kvb->used; ++i) { pcre_keyvalue * const kv = kvb->kv+i; if (kv->key) pcre_free(kv->key); - if (kv->key_extra) pcre_free(kv->key_extra); + if (kv->key_extra) pcre_free_study(kv->key_extra); /*free (kv->value.ptr);*//*(see pcre_keyvalue_buffer_append)*/ } diff --git a/src/keyvalue.h b/src/keyvalue.h index 27831fe1..277bddd3 100644 --- a/src/keyvalue.h +++ b/src/keyvalue.h @@ -27,7 +27,7 @@ __attribute_cold__ pcre_keyvalue_buffer *pcre_keyvalue_buffer_init(void); __attribute_cold__ -int pcre_keyvalue_buffer_append(log_error_st *errh, pcre_keyvalue_buffer *kvb, const buffer *key, const buffer *value); +int pcre_keyvalue_buffer_append(log_error_st *errh, pcre_keyvalue_buffer *kvb, const buffer *key, const buffer *value, int pcre_jit); __attribute_cold__ void pcre_keyvalue_buffer_free(pcre_keyvalue_buffer *kvb); diff --git a/src/mod_redirect.c b/src/mod_redirect.c index 45fbb845..2e35e599 100644 --- a/src/mod_redirect.c +++ b/src/mod_redirect.c @@ -76,9 +76,13 @@ static void mod_redirect_patch_config(request_st * const r, plugin_data * const } static pcre_keyvalue_buffer * mod_redirect_parse_list(server *srv, const array *a, const int condidx) { - pcre_keyvalue_buffer * const redirect = pcre_keyvalue_buffer_init(); - redirect->x0 = (unsigned short)condidx; - log_error_st * const errh = srv->errh; + const int pcre_jit = + !srv->srvconf.feature_flags + || config_plugin_value_tobool( + array_get_element_klen(srv->srvconf.feature_flags, + CONST_STR_LEN("server.pcre_jit")), 1); + pcre_keyvalue_buffer * const kvb = pcre_keyvalue_buffer_init(); + kvb->x0 = (unsigned short)condidx; buffer * const tb = srv->tmp_buf; for (uint32_t j = 0; j < a->used; ++j) { data_string *ds = (data_string *)a->data[j]; @@ -86,14 +90,15 @@ static pcre_keyvalue_buffer * mod_redirect_parse_list(server *srv, const array * pcre_keyvalue_burl_normalize_key(&ds->key, tb); pcre_keyvalue_burl_normalize_value(&ds->value, tb); } - if (!pcre_keyvalue_buffer_append(errh, redirect, &ds->key, &ds->value)){ - log_error(errh, __FILE__, __LINE__, + if (!pcre_keyvalue_buffer_append(srv->errh, kvb, &ds->key, &ds->value, + pcre_jit)) { + log_error(srv->errh, __FILE__, __LINE__, "pcre-compile failed for %s", ds->key.ptr); - pcre_keyvalue_buffer_free(redirect); + pcre_keyvalue_buffer_free(kvb); return NULL; } } - return redirect; + return kvb; } SETDEFAULTS_FUNC(mod_redirect_set_defaults) { diff --git a/src/mod_rewrite.c b/src/mod_rewrite.c index 724affc0..195e6589 100644 --- a/src/mod_rewrite.c +++ b/src/mod_rewrite.c @@ -94,6 +94,11 @@ static void mod_rewrite_patch_config(request_st * const r, plugin_data * const p } static pcre_keyvalue_buffer * mod_rewrite_parse_list(server *srv, const array *a, pcre_keyvalue_buffer *kvb, const int condidx) { + const int pcre_jit = + !srv->srvconf.feature_flags + || config_plugin_value_tobool( + array_get_element_klen(srv->srvconf.feature_flags, + CONST_STR_LEN("server.pcre_jit")), 1); int allocated = 0; if (NULL == kvb) { allocated = 1; @@ -108,7 +113,8 @@ static pcre_keyvalue_buffer * mod_rewrite_parse_list(server *srv, const array *a pcre_keyvalue_burl_normalize_key(&ds->key, tb); pcre_keyvalue_burl_normalize_value(&ds->value, tb); } - if (!pcre_keyvalue_buffer_append(srv->errh, kvb, &ds->key, &ds->value)){ + if (!pcre_keyvalue_buffer_append(srv->errh, kvb, &ds->key, &ds->value, + pcre_jit)) { log_error(srv->errh, __FILE__, __LINE__, "pcre-compile failed for %s", ds->key.ptr); if (allocated) pcre_keyvalue_buffer_free(kvb); diff --git a/src/t/test_keyvalue.c b/src/t/test_keyvalue.c index 2d5aaa38..68034a2c 100644 --- a/src/t/test_keyvalue.c +++ b/src/t/test_keyvalue.c @@ -29,10 +29,10 @@ static pcre_keyvalue_buffer * test_keyvalue_test_kvb_init (void) { { "/?file=$1&$2", sizeof("/?file=$1&$2"), 0 } }; - assert(pcre_keyvalue_buffer_append(errh, kvb, kvstr+0, kvstr+1)); - assert(pcre_keyvalue_buffer_append(errh, kvb, kvstr+2, kvstr+3)); - assert(pcre_keyvalue_buffer_append(errh, kvb, kvstr+4, kvstr+5)); - assert(pcre_keyvalue_buffer_append(errh, kvb, kvstr+6, kvstr+7)); + assert(pcre_keyvalue_buffer_append(errh, kvb, kvstr+0, kvstr+1, 1)); + assert(pcre_keyvalue_buffer_append(errh, kvb, kvstr+2, kvstr+3, 1)); + assert(pcre_keyvalue_buffer_append(errh, kvb, kvstr+4, kvstr+5, 1)); + assert(pcre_keyvalue_buffer_append(errh, kvb, kvstr+6, kvstr+7, 1)); log_error_st_free(errh);