/* * Copyright (C) Yichun Zhang (agentzh) */ #ifndef DDEBUG #define DDEBUG 0 #endif #include "ddebug.h" #if (NGX_PCRE) #include "ngx_http_lua_pcrefix.h" #include "ngx_http_lua_script.h" #include "ngx_http_lua_util.h" #if (PCRE_MAJOR >= 6 || NGX_PCRE2) # define LUA_HAVE_PCRE_DFA 1 #else # define LUA_HAVE_PCRE_DFA 0 #endif #if (NGX_PCRE2) static pcre2_compile_context *ngx_regex_compile_context; static pcre2_match_context *ngx_regex_match_context; static pcre2_match_data *ngx_regex_match_data; static ngx_uint_t ngx_regex_match_data_size = 0; #define PCRE2_VERSION_SIZE 64 static char ngx_pcre2_version[PCRE2_VERSION_SIZE]; #endif #define NGX_LUA_RE_MODE_DFA (1<<1) #define NGX_LUA_RE_MODE_JIT (1<<2) #define NGX_LUA_RE_NO_UTF8_CHECK (1<<4) #define NGX_LUA_RE_DFA_MODE_WORKSPACE_COUNT (100) #define NGX_LUA_RE_MIN_JIT_STACK_SIZE 32 * 1024 typedef struct { ngx_pool_t *pool; u_char *name_table; int name_count; int name_entry_size; int ncaptures; int *captures; #if (NGX_PCRE2) pcre2_code *regex; /* * pcre2 doesn't use pcre_extra any more, * just for keeping same memory layout in the lua ffi cdef */ void *regex_sd; #else pcre *regex; pcre_extra *regex_sd; #endif ngx_http_lua_complex_value_t *replace; /* only for (stap) debugging, and may be an invalid pointer */ const u_char *pattern; } ngx_http_lua_regex_t; typedef struct { ngx_str_t pattern; ngx_pool_t *pool; ngx_int_t options; #if (NGX_PCRE2) pcre2_code *regex; #else pcre *regex; #endif int captures; ngx_str_t err; } ngx_http_lua_regex_compile_t; typedef struct { ngx_http_request_t *request; #if (NGX_PCRE2) pcre2_code *regex; #else pcre *regex; pcre_extra *regex_sd; #endif int ncaptures; int *captures; int captures_len; uint8_t flags; } ngx_http_lua_regex_ctx_t; static ngx_int_t ngx_http_lua_regex_compile(ngx_http_lua_regex_compile_t *rc); #define ngx_http_lua_regex_exec(re, e, s, start, captures, size, opts) \ pcre_exec(re, e, (const char *) (s)->data, (s)->len, start, opts, \ captures, size) #define ngx_http_lua_regex_dfa_exec(re, e, s, start, captures, size, ws, \ wscount, opts) \ pcre_dfa_exec(re, e, (const char *) (s)->data, (s)->len, start, opts, \ captures, size, ws, wscount) static void ngx_http_lua_regex_free_study_data(ngx_pool_t *pool, ngx_http_lua_regex_t *re) { ngx_pool_t *old_pool; #if (NGX_PCRE2) if (re && re->regex) { old_pool = ngx_http_lua_pcre_malloc_init(pool); pcre2_code_free(re->regex); ngx_http_lua_pcre_malloc_done(old_pool); re->regex = NULL; } #else if (re && re->regex_sd) { old_pool = ngx_http_lua_pcre_malloc_init(pool); #if LUA_HAVE_PCRE_JIT pcre_free_study(re->regex_sd); #else pcre_free(re->regex_sd); #endif ngx_http_lua_pcre_malloc_done(old_pool); re->regex_sd = NULL; } #endif } #if (NGX_PCRE2) static ngx_int_t ngx_http_lua_regex_compile(ngx_http_lua_regex_compile_t *rc) { int n, errcode; char *p; size_t erroff; u_char errstr[128]; pcre2_code *re; ngx_pool_t *old_pool; pcre2_general_context *gctx; pcre2_compile_context *cctx; ngx_http_lua_main_conf_t *lmcf; if (ngx_regex_compile_context == NULL) { /* * Allocate a compile context if not yet allocated. This uses * direct allocations from heap, so the result can be cached * even at runtime. */ old_pool = ngx_http_lua_pcre_malloc_init(NULL); gctx = pcre2_general_context_create(ngx_http_lua_pcre_malloc, ngx_http_lua_pcre_free, NULL); if (gctx == NULL) { ngx_http_lua_pcre_malloc_done(old_pool); goto nomem; } cctx = pcre2_compile_context_create(gctx); if (cctx == NULL) { pcre2_general_context_free(gctx); ngx_http_lua_pcre_malloc_done(old_pool); goto nomem; } ngx_regex_compile_context = cctx; ngx_regex_match_context = pcre2_match_context_create(gctx); if (ngx_regex_match_context == NULL) { pcre2_general_context_free(gctx); ngx_http_lua_pcre_malloc_done(old_pool); goto nomem; } lmcf = ngx_http_cycle_get_module_main_conf(ngx_cycle, ngx_http_lua_module); if (lmcf && lmcf->regex_match_limit > 0) { pcre2_set_match_limit(ngx_regex_match_context, lmcf->regex_match_limit); } pcre2_general_context_free(gctx); ngx_http_lua_pcre_malloc_done(old_pool); } old_pool = ngx_http_lua_pcre_malloc_init(rc->pool); re = pcre2_compile(rc->pattern.data, rc->pattern.len, rc->options, &errcode, &erroff, ngx_regex_compile_context); ngx_http_lua_pcre_malloc_done(old_pool); if (re == NULL) { pcre2_get_error_message(errcode, errstr, 128); if ((size_t) erroff == rc->pattern.len) { rc->err.len = ngx_snprintf(rc->err.data, rc->err.len, "pcre2_compile() failed: %s in \"%V\"", errstr, &rc->pattern) - rc->err.data; } else { rc->err.len = ngx_snprintf(rc->err.data, rc->err.len, "pcre2_compile() failed: %s in " "\"%V\" at \"%s\"", errstr, &rc->pattern, rc->pattern.data + erroff) - rc->err.data; } return NGX_ERROR; } rc->regex = re; n = pcre2_pattern_info(re, PCRE2_INFO_CAPTURECOUNT, &rc->captures); if (n < 0) { p = "pcre2_pattern_info(\"%V\", PCRE_INFO_CAPTURECOUNT) failed: %d"; goto failed; } #if (NGX_DEBUG) ngx_log_debug3(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, "pcre2_compile: pattern[%V], options 0x%08Xd, ncaptures %d", &rc->pattern, rc->options, rc->captures); #endif return NGX_OK; failed: rc->err.len = ngx_snprintf(rc->err.data, rc->err.len, p, &rc->pattern, n) - rc->err.data; return NGX_ERROR; nomem: rc->err.len = ngx_snprintf(rc->err.data, rc->err.len, "regex \"%V\" compilation failed: no memory", &rc->pattern) - rc->err.data; return NGX_ERROR; } #else static ngx_int_t ngx_http_lua_regex_compile(ngx_http_lua_regex_compile_t *rc) { int n, erroff; char *p; const char *errstr; pcre *re; ngx_pool_t *old_pool; old_pool = ngx_http_lua_pcre_malloc_init(rc->pool); re = pcre_compile((const char *) rc->pattern.data, (int) rc->options, &errstr, &erroff, NULL); ngx_http_lua_pcre_malloc_done(old_pool); if (re == NULL) { if ((size_t) erroff == rc->pattern.len) { rc->err.len = ngx_snprintf(rc->err.data, rc->err.len, "pcre_compile() failed: %s in \"%V\"", errstr, &rc->pattern) - rc->err.data; } else { rc->err.len = ngx_snprintf(rc->err.data, rc->err.len, "pcre_compile() failed: %s in \"%V\" " "at \"%s\"", errstr, &rc->pattern, rc->pattern.data + erroff) - rc->err.data; } return NGX_ERROR; } rc->regex = re; #if 1 n = pcre_fullinfo(re, NULL, PCRE_INFO_CAPTURECOUNT, &rc->captures); if (n < 0) { p = "pcre_fullinfo(\"%V\", PCRE_INFO_CAPTURECOUNT) failed: %d"; goto failed; } #endif return NGX_OK; failed: rc->err.len = ngx_snprintf(rc->err.data, rc->err.len, p, &rc->pattern, n) - rc->err.data; return NGX_OK; } #endif ngx_int_t ngx_http_lua_ffi_set_jit_stack_size(int size, u_char *errstr, size_t *errstr_size) { #if (LUA_HAVE_PCRE_JIT) ngx_http_lua_main_conf_t *lmcf; ngx_pool_t *pool, *old_pool; lmcf = ngx_http_cycle_get_module_main_conf(ngx_cycle, ngx_http_lua_module); ngx_http_lua_assert(lmcf != NULL); if (size < NGX_LUA_RE_MIN_JIT_STACK_SIZE) { size = NGX_LUA_RE_MIN_JIT_STACK_SIZE; } pool = lmcf->pool; dd("server pool %p", lmcf->pool); if (lmcf->jit_stack) { old_pool = ngx_http_lua_pcre_malloc_init(pool); #if (NGX_PCRE2) pcre2_jit_stack_free(lmcf->jit_stack); #else pcre_jit_stack_free(lmcf->jit_stack); #endif ngx_http_lua_pcre_malloc_done(old_pool); } old_pool = ngx_http_lua_pcre_malloc_init(pool); #if (NGX_PCRE2) lmcf->jit_stack = pcre2_jit_stack_create(NGX_LUA_RE_MIN_JIT_STACK_SIZE, size, NULL); #else lmcf->jit_stack = pcre_jit_stack_alloc(NGX_LUA_RE_MIN_JIT_STACK_SIZE, size); #endif ngx_http_lua_pcre_malloc_done(old_pool); if (lmcf->jit_stack == NULL) { *errstr_size = ngx_snprintf(errstr, *errstr_size, "pcre jit stack allocation failed") - errstr; return NGX_ERROR; } return NGX_OK; #else /* LUA_HAVE_PCRE_JIT */ *errstr_size = ngx_snprintf(errstr, *errstr_size, "no pcre jit support found") - errstr; return NGX_ERROR; #endif } #if (NGX_PCRE2) static void ngx_http_lua_regex_jit_compile(ngx_http_lua_regex_t *re, int flags, ngx_pool_t *pool, ngx_http_lua_main_conf_t *lmcf, ngx_http_lua_regex_compile_t *re_comp) { ngx_int_t ret; ngx_pool_t *old_pool; if (flags & NGX_LUA_RE_MODE_JIT) { old_pool = ngx_http_lua_pcre_malloc_init(pool); ret = pcre2_jit_compile(re_comp->regex, PCRE2_JIT_COMPLETE); if (ret != 0) { ngx_log_error(NGX_LOG_INFO, ngx_cycle->log, 0, "pcre2_jit_compile() failed: %d in \"%V\", " "ignored", ret, &re_comp->pattern); #if (NGX_DEBUG) } else { ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, "pcre2 JIT compiled successfully"); # endif /* !(NGX_DEBUG) */ } ngx_http_lua_pcre_malloc_done(old_pool); } if (lmcf && lmcf->jit_stack) { pcre2_jit_stack_assign(ngx_regex_match_context, NULL, lmcf->jit_stack); } return; } #else static void ngx_http_lua_regex_jit_compile(ngx_http_lua_regex_t *re, int flags, ngx_pool_t *pool, ngx_http_lua_main_conf_t *lmcf, ngx_http_lua_regex_compile_t *re_comp) { const char *msg; pcre_extra *sd = NULL; ngx_pool_t *old_pool; #if (LUA_HAVE_PCRE_JIT) if (flags & NGX_LUA_RE_MODE_JIT) { old_pool = ngx_http_lua_pcre_malloc_init(pool); sd = pcre_study(re_comp->regex, PCRE_STUDY_JIT_COMPILE, &msg); ngx_http_lua_pcre_malloc_done(old_pool); # if (NGX_DEBUG) if (msg != NULL) { ngx_log_debug2(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, "pcre study failed with PCRE_STUDY_JIT_COMPILE: " "%s (%p)", msg, sd); } if (sd != NULL) { int jitted; old_pool = ngx_http_lua_pcre_malloc_init(pool); pcre_fullinfo(re_comp->regex, sd, PCRE_INFO_JIT, &jitted); ngx_http_lua_pcre_malloc_done(old_pool); ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, "pcre JIT compiling result: %d", jitted); } # endif /* !(NGX_DEBUG) */ } else { old_pool = ngx_http_lua_pcre_malloc_init(pool); sd = pcre_study(re_comp->regex, 0, &msg); ngx_http_lua_pcre_malloc_done(old_pool); } if (sd && lmcf && lmcf->jit_stack) { pcre_assign_jit_stack(sd, NULL, lmcf->jit_stack); } if (sd && lmcf && lmcf->regex_match_limit > 0 && !(flags & NGX_LUA_RE_MODE_DFA)) { sd->flags |= PCRE_EXTRA_MATCH_LIMIT; sd->match_limit = lmcf->regex_match_limit; } #endif /* LUA_HAVE_PCRE_JIT */ re->regex_sd = sd; } #endif #if (NGX_PCRE2) void ngx_http_lua_regex_cleanup(void *data) { ngx_pool_t *old_pool; ngx_http_lua_main_conf_t *lmcf; lmcf = data; if (ngx_regex_compile_context) { old_pool = ngx_http_lua_pcre_malloc_init(NULL); pcre2_compile_context_free(ngx_regex_compile_context); ngx_regex_compile_context = NULL; ngx_http_lua_pcre_malloc_done(old_pool); } if (lmcf && lmcf->jit_stack) { old_pool = ngx_http_lua_pcre_malloc_init(NULL); pcre2_jit_stack_free(lmcf->jit_stack); lmcf->jit_stack = NULL; ngx_http_lua_pcre_malloc_done(old_pool); } if (ngx_regex_match_data) { old_pool = ngx_http_lua_pcre_malloc_init(NULL); pcre2_match_data_free(ngx_regex_match_data); ngx_regex_match_data = NULL; ngx_regex_match_data_size = 0; ngx_http_lua_pcre_malloc_done(old_pool); } } #endif ngx_http_lua_regex_t * ngx_http_lua_ffi_compile_regex(const unsigned char *pat, size_t pat_len, int flags, int pcre_opts, u_char *errstr, size_t errstr_size) { int *cap = NULL, ovecsize; u_char *p; ngx_int_t rc; const char *msg; ngx_pool_t *pool, *old_pool; ngx_http_lua_regex_t *re = NULL; ngx_http_lua_main_conf_t *lmcf; ngx_http_lua_regex_compile_t re_comp; pool = ngx_create_pool(512, ngx_cycle->log); if (pool == NULL) { msg = "no memory"; goto error; } pool->log = (ngx_log_t *) &ngx_cycle->new_log; re = ngx_palloc(pool, sizeof(ngx_http_lua_regex_t)); if (re == NULL) { ngx_destroy_pool(pool); pool = NULL; msg = "no memory"; goto error; } re->pool = pool; re->regex = NULL; re->regex_sd = NULL; re_comp.options = pcre_opts; re_comp.pattern.data = (u_char *) pat; re_comp.pattern.len = pat_len; re_comp.err.len = errstr_size - 1; re_comp.err.data = errstr; re_comp.pool = pool; old_pool = ngx_http_lua_pcre_malloc_init(pool); rc = ngx_http_lua_regex_compile(&re_comp); ngx_http_lua_pcre_malloc_done(old_pool); if (rc != NGX_OK) { re_comp.err.data[re_comp.err.len] = '\0'; msg = (char *) re_comp.err.data; goto error; } lmcf = ngx_http_cycle_get_module_main_conf(ngx_cycle, ngx_http_lua_module); ngx_http_lua_assert(lmcf != NULL); ngx_http_lua_regex_jit_compile(re, flags, pool, lmcf, &re_comp); if (flags & NGX_LUA_RE_MODE_DFA) { ovecsize = 2; re_comp.captures = 0; } else { #if (NGX_PCRE2) ovecsize = (re_comp.captures + 1) * 2; #else ovecsize = (re_comp.captures + 1) * 3; #endif } dd("allocating cap with size: %d", (int) ovecsize); cap = ngx_palloc(pool, ovecsize * sizeof(int)); if (cap == NULL) { msg = "no memory"; goto error; } #if (NGX_PCRE2) if (pcre2_pattern_info(re_comp.regex, PCRE2_INFO_NAMECOUNT, &re->name_count) < 0) { msg = "cannot acquire named subpattern count"; goto error; } if (re->name_count > 0) { if (pcre2_pattern_info(re_comp.regex, PCRE2_INFO_NAMEENTRYSIZE, &re->name_entry_size) != 0) { msg = "cannot acquire named subpattern entry size"; goto error; } if (pcre2_pattern_info(re_comp.regex, PCRE2_INFO_NAMETABLE, &re->name_table) != 0) { msg = "cannot acquire named subpattern table"; goto error; } } #else if (pcre_fullinfo(re_comp.regex, NULL, PCRE_INFO_NAMECOUNT, &re->name_count) != 0) { msg = "cannot acquire named subpattern count"; goto error; } if (re->name_count > 0) { if (pcre_fullinfo(re_comp.regex, NULL, PCRE_INFO_NAMEENTRYSIZE, &re->name_entry_size) != 0) { msg = "cannot acquire named subpattern entry size"; goto error; } if (pcre_fullinfo(re_comp.regex, NULL, PCRE_INFO_NAMETABLE, &re->name_table) != 0) { msg = "cannot acquire named subpattern table"; goto error; } } #endif re->regex = re_comp.regex; re->ncaptures = re_comp.captures; re->captures = cap; re->replace = NULL; /* only for (stap) debugging, the pointer might be invalid when the * string is collected later on.... */ re->pattern = pat; return re; error: p = ngx_snprintf(errstr, errstr_size - 1, "%s", msg); *p = '\0'; ngx_http_lua_regex_free_study_data(pool, re); if (pool) { ngx_destroy_pool(pool); } return NULL; } #if (NGX_PCRE2) int ngx_http_lua_ffi_exec_regex(ngx_http_lua_regex_t *re, int flags, const u_char *s, size_t len, int pos) { int rc, exec_opts = 0; size_t *ov; ngx_uint_t ovecpair, n, i; ngx_pool_t *old_pool; if (flags & NGX_LUA_RE_MODE_DFA) { ovecpair = 1; re->ncaptures = 0; } else { ovecpair = re->ncaptures + 1; } old_pool = ngx_http_lua_pcre_malloc_init(NULL); if (ngx_regex_match_data == NULL || ovecpair > ngx_regex_match_data_size) { /* * Allocate a match data if not yet allocated or smaller than * needed. */ if (ngx_regex_match_data) { pcre2_match_data_free(ngx_regex_match_data); } ngx_regex_match_data_size = ovecpair; ngx_regex_match_data = pcre2_match_data_create(ovecpair, NULL); if (ngx_regex_match_data == NULL) { rc = PCRE2_ERROR_NOMEMORY; goto failed; } } if (flags & NGX_LUA_RE_NO_UTF8_CHECK) { exec_opts = PCRE2_NO_UTF_CHECK; } else { exec_opts = 0; } if (flags & NGX_LUA_RE_MODE_DFA) { int ws[NGX_LUA_RE_DFA_MODE_WORKSPACE_COUNT]; rc = pcre2_dfa_match(re->regex, s, len, pos, exec_opts, ngx_regex_match_data, ngx_regex_match_context, ws, sizeof(ws) / sizeof(ws[0])); } else { rc = pcre2_match(re->regex, s, len, pos, exec_opts, ngx_regex_match_data, ngx_regex_match_context); } if (rc < 0) { #if (NGX_DEBUG) ngx_log_debug4(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, "pcre2_match failed: flags 0x%05Xd, options 0x%08Xd, " "rc %d, ovecpair %ui", flags, exec_opts, rc, ovecpair); #endif goto failed; } n = pcre2_get_ovector_count(ngx_regex_match_data); ov = pcre2_get_ovector_pointer(ngx_regex_match_data); #if (NGX_DEBUG) ngx_log_debug5(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, "pcre2_match: flags 0x%05Xd, options 0x%08Xd, rc %d, " "n %ui, ovecpair %ui", flags, exec_opts, rc, n, ovecpair); #endif if (n > ovecpair) { n = ovecpair; } for (i = 0; i < n; i++) { re->captures[i * 2] = ov[i * 2]; re->captures[i * 2 + 1] = ov[i * 2 + 1]; } failed: ngx_http_lua_pcre_malloc_done(old_pool); return rc; } #else int ngx_http_lua_ffi_exec_regex(ngx_http_lua_regex_t *re, int flags, const u_char *s, size_t len, int pos) { int rc, ovecsize, exec_opts, *cap; ngx_str_t subj; pcre_extra *sd; cap = re->captures; sd = re->regex_sd; if (flags & NGX_LUA_RE_MODE_DFA) { ovecsize = 2; re->ncaptures = 0; } else { ovecsize = (re->ncaptures + 1) * 3; } if (flags & NGX_LUA_RE_NO_UTF8_CHECK) { exec_opts = PCRE_NO_UTF8_CHECK; } else { exec_opts = 0; } subj.data = (u_char *) s; subj.len = len; if (flags & NGX_LUA_RE_MODE_DFA) { #if LUA_HAVE_PCRE_DFA int ws[NGX_LUA_RE_DFA_MODE_WORKSPACE_COUNT]; rc = ngx_http_lua_regex_dfa_exec(re->regex, sd, &subj, (int) pos, cap, ovecsize, ws, sizeof(ws) / sizeof(ws[0]), exec_opts); #else return PCRE_ERROR_BADOPTION; #endif /* LUA_HAVE_PCRE_DFA */ } else { rc = ngx_http_lua_regex_exec(re->regex, sd, &subj, (int) pos, cap, ovecsize, exec_opts); } return rc; } #endif void ngx_http_lua_ffi_destroy_regex(ngx_http_lua_regex_t *re) { dd("destroy regex called"); if (re == NULL || re->pool == NULL) { return; } ngx_http_lua_regex_free_study_data(re->pool, re); ngx_destroy_pool(re->pool); } int ngx_http_lua_ffi_compile_replace_template(ngx_http_lua_regex_t *re, const u_char *replace_data, size_t replace_len) { ngx_int_t rc; ngx_str_t tpl; ngx_http_lua_complex_value_t *ctpl; ngx_http_lua_compile_complex_value_t ccv; ctpl = ngx_palloc(re->pool, sizeof(ngx_http_lua_complex_value_t)); if (ctpl == NULL) { return NGX_ERROR; } if (replace_len != 0) { /* copy the string buffer pointed to by tpl.data from Lua VM */ tpl.data = ngx_palloc(re->pool, replace_len + 1); if (tpl.data == NULL) { return NGX_ERROR; } ngx_memcpy(tpl.data, replace_data, replace_len); tpl.data[replace_len] = '\0'; } else { tpl.data = (u_char *) replace_data; } tpl.len = replace_len; ngx_memzero(&ccv, sizeof(ngx_http_lua_compile_complex_value_t)); ccv.pool = re->pool; ccv.log = ngx_cycle->log; ccv.value = &tpl; ccv.complex_value = ctpl; rc = ngx_http_lua_compile_complex_value(&ccv); re->replace = ctpl; return rc; } ngx_http_lua_script_engine_t * ngx_http_lua_ffi_create_script_engine(void) { return ngx_calloc(sizeof(ngx_http_lua_script_engine_t), ngx_cycle->log); } void ngx_http_lua_ffi_init_script_engine(ngx_http_lua_script_engine_t *e, const unsigned char *subj, ngx_http_lua_regex_t *compiled, int count) { e->log = ngx_cycle->log; e->ncaptures = count * 2; e->captures = compiled->captures; e->captures_data = (u_char *) subj; } void ngx_http_lua_ffi_destroy_script_engine(ngx_http_lua_script_engine_t *e) { ngx_free(e); } size_t ngx_http_lua_ffi_script_eval_len(ngx_http_lua_script_engine_t *e, ngx_http_lua_complex_value_t *val) { size_t len; ngx_http_lua_script_len_code_pt lcode; e->ip = val->lengths; len = 0; while (*(uintptr_t *) e->ip) { lcode = *(ngx_http_lua_script_len_code_pt *) e->ip; len += lcode(e); } return len; } void ngx_http_lua_ffi_script_eval_data(ngx_http_lua_script_engine_t *e, ngx_http_lua_complex_value_t *val, u_char *dst) { ngx_http_lua_script_code_pt code; e->ip = val->values; e->pos = dst; while (*(uintptr_t *) e->ip) { code = *(ngx_http_lua_script_code_pt *) e->ip; code(e); } } uint32_t ngx_http_lua_ffi_max_regex_cache_size(void) { ngx_http_lua_main_conf_t *lmcf; lmcf = ngx_http_cycle_get_module_main_conf(ngx_cycle, ngx_http_lua_module); if (lmcf == NULL) { return 0; } return (uint32_t) lmcf->regex_cache_max_entries; } const char * ngx_http_lua_ffi_pcre_version(void) { #if (NGX_PCRE2) pcre2_config(PCRE2_CONFIG_VERSION, ngx_pcre2_version); return ngx_pcre2_version; #else return pcre_version(); #endif } #endif /* NGX_PCRE */ /* vi:set ft=c ts=4 sw=4 et fdm=marker: */