LCOV - code coverage report
Current view: top level - home/build/openresty-1.13.6.1/build/ngx_lua-0.10.11/src - ngx_http_lua_regex.c (source / functions) Hit Total Coverage
Test: coverage ngix Lines: 14 1050 1.3 %
Date: 2020-03-03 04:25:50 Functions: 1 26 3.8 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : 
       2             : /*
       3             :  * Copyright (C) Yichun Zhang (agentzh)
       4             :  */
       5             : 
       6             : 
       7             : #ifndef DDEBUG
       8             : #define DDEBUG 0
       9             : #endif
      10             : #include "ddebug.h"
      11             : 
      12             : 
      13             : #if (NGX_PCRE)
      14             : 
      15             : #include "ngx_http_lua_regex.h"
      16             : #include "ngx_http_lua_pcrefix.h"
      17             : #include "ngx_http_lua_script.h"
      18             : #include "ngx_http_lua_pcrefix.h"
      19             : #include "ngx_http_lua_util.h"
      20             : 
      21             : 
      22             : #if (PCRE_MAJOR >= 6)
      23             : #   define LUA_HAVE_PCRE_DFA 1
      24             : #else
      25             : #   define LUA_HAVE_PCRE_DFA 0
      26             : #endif
      27             : 
      28             : 
      29             : #define NGX_LUA_RE_COMPILE_ONCE      (1<<0)
      30             : #define NGX_LUA_RE_MODE_DFA          (1<<1)
      31             : #define NGX_LUA_RE_MODE_JIT          (1<<2)
      32             : #define NGX_LUA_RE_MODE_DUPNAMES     (1<<3)
      33             : #define NGX_LUA_RE_NO_UTF8_CHECK     (1<<4)
      34             : 
      35             : #define NGX_LUA_RE_DFA_MODE_WORKSPACE_COUNT (100)
      36             : 
      37             : #define NGX_LUA_RE_MIN_JIT_STACK_SIZE 32 * 1024
      38             : 
      39             : 
      40             : typedef struct {
      41             : #ifndef NGX_LUA_NO_FFI_API
      42             :     ngx_pool_t                   *pool;
      43             :     u_char                       *name_table;
      44             :     int                           name_count;
      45             :     int                           name_entry_size;
      46             : #endif
      47             : 
      48             :     int                           ncaptures;
      49             :     int                          *captures;
      50             : 
      51             :     pcre                         *regex;
      52             :     pcre_extra                   *regex_sd;
      53             : 
      54             :     ngx_http_lua_complex_value_t    *replace;
      55             : 
      56             : #ifndef NGX_LUA_NO_FFI_API
      57             :     /* only for (stap) debugging, and may be an invalid pointer */
      58             :     const u_char                 *pattern;
      59             : #endif
      60             : } ngx_http_lua_regex_t;
      61             : 
      62             : 
      63             : typedef struct {
      64             :     ngx_str_t     pattern;
      65             :     ngx_pool_t   *pool;
      66             :     ngx_int_t     options;
      67             : 
      68             :     pcre         *regex;
      69             :     int           captures;
      70             :     ngx_str_t     err;
      71             : } ngx_http_lua_regex_compile_t;
      72             : 
      73             : 
      74             : typedef struct {
      75             :     ngx_http_cleanup_pt     *cleanup;
      76             :     ngx_http_request_t      *request;
      77             :     pcre                    *regex;
      78             :     pcre_extra              *regex_sd;
      79             :     int                      ncaptures;
      80             :     int                     *captures;
      81             :     int                      captures_len;
      82             :     uint8_t                  flags;
      83             : } ngx_http_lua_regex_ctx_t;
      84             : 
      85             : 
      86             : static int ngx_http_lua_ngx_re_gmatch_iterator(lua_State *L);
      87             : static ngx_uint_t ngx_http_lua_ngx_re_parse_opts(lua_State *L,
      88             :     ngx_http_lua_regex_compile_t *re, ngx_str_t *opts, int narg);
      89             : static int ngx_http_lua_ngx_re_sub_helper(lua_State *L, unsigned global);
      90             : static int ngx_http_lua_ngx_re_match_helper(lua_State *L, int wantcaps);
      91             : static int ngx_http_lua_ngx_re_find(lua_State *L);
      92             : static int ngx_http_lua_ngx_re_match(lua_State *L);
      93             : static int ngx_http_lua_ngx_re_gmatch(lua_State *L);
      94             : static int ngx_http_lua_ngx_re_sub(lua_State *L);
      95             : static int ngx_http_lua_ngx_re_gsub(lua_State *L);
      96             : static void ngx_http_lua_regex_free_study_data(ngx_pool_t *pool,
      97             :     pcre_extra *sd);
      98             : static ngx_int_t ngx_http_lua_regex_compile(ngx_http_lua_regex_compile_t *rc);
      99             : static void ngx_http_lua_ngx_re_gmatch_cleanup(void *data);
     100             : static int ngx_http_lua_ngx_re_gmatch_gc(lua_State *L);
     101             : static void ngx_http_lua_re_collect_named_captures(lua_State *L,
     102             :     int res_tb_idx, u_char *name_table, int name_count, int name_entry_size,
     103             :     unsigned flags, ngx_str_t *subj);
     104             : 
     105             : 
     106             : #define ngx_http_lua_regex_exec(re, e, s, start, captures, size, opts)       \
     107             :     pcre_exec(re, e, (const char *) (s)->data, (s)->len, start, opts,        \
     108             :               captures, size)
     109             : 
     110             : 
     111             : #define ngx_http_lua_regex_dfa_exec(re, e, s, start, captures, size, ws,     \
     112             :                                     wscount, opts)                           \
     113             :     pcre_dfa_exec(re, e, (const char *) (s)->data, (s)->len, start, opts,    \
     114             :                   captures, size, ws, wscount)
     115             : 
     116             : 
     117             : static int
     118           0 : ngx_http_lua_ngx_re_match(lua_State *L)
     119             : {
     120           0 :     return ngx_http_lua_ngx_re_match_helper(L, 1 /* want captures */);
     121             : }
     122             : 
     123             : 
     124             : static int
     125           0 : ngx_http_lua_ngx_re_find(lua_State *L)
     126             : {
     127           0 :     return ngx_http_lua_ngx_re_match_helper(L, 0 /* want captures */);
     128             : }
     129             : 
     130             : 
     131             : static int
     132           0 : ngx_http_lua_ngx_re_match_helper(lua_State *L, int wantcaps)
     133             : {
     134             :     /* u_char                      *p; */
     135           0 :     int                          res_tb_idx = 0;
     136             :     ngx_http_request_t          *r;
     137             :     ngx_str_t                    subj;
     138             :     ngx_str_t                    pat;
     139             :     ngx_str_t                    opts;
     140             :     ngx_http_lua_regex_t        *re;
     141             :     const char                  *msg;
     142             :     ngx_int_t                    rc;
     143             :     ngx_uint_t                   n;
     144             :     int                          i;
     145           0 :     ngx_int_t                    pos = 0;
     146             :     int                          nargs;
     147           0 :     int                         *cap = NULL;
     148             :     int                          ovecsize;
     149           0 :     int                          has_ctx = 0;
     150             :     ngx_uint_t                   flags;
     151             :     ngx_pool_t                  *pool, *old_pool;
     152             :     ngx_http_lua_main_conf_t    *lmcf;
     153             :     u_char                       errstr[NGX_MAX_CONF_ERRSTR + 1];
     154           0 :     pcre_extra                  *sd = NULL;
     155           0 :     int                          name_entry_size = 0, name_count;
     156           0 :     u_char                      *name_table = NULL;
     157             :     int                          exec_opts;
     158           0 :     int                          group_id = 0;
     159             : 
     160             :     ngx_http_lua_regex_compile_t      re_comp;
     161             : 
     162           0 :     nargs = lua_gettop(L);
     163             : 
     164           0 :     if (nargs != 2 && nargs != 3 && nargs != 4 && nargs != 5) {
     165           0 :         return luaL_error(L, "expecting 2, 3, 4 or 5 arguments, "
     166             :                           "but got %d", nargs);
     167             :     }
     168             : 
     169           0 :     r = ngx_http_lua_get_req(L);
     170           0 :     if (r == NULL) {
     171           0 :         return luaL_error(L, "no request object found");
     172             :     }
     173             : 
     174           0 :     subj.data = (u_char *) luaL_checklstring(L, 1, &subj.len);
     175           0 :     pat.data = (u_char *) luaL_checklstring(L, 2, &pat.len);
     176             : 
     177           0 :     ngx_memzero(&re_comp, sizeof(ngx_http_lua_regex_compile_t));
     178             : 
     179           0 :     if (nargs >= 3) {
     180           0 :         opts.data = (u_char *) luaL_checklstring(L, 3, &opts.len);
     181             : 
     182           0 :         if (nargs >= 4) {
     183           0 :             if (!lua_isnil(L, 4)) {
     184           0 :                 luaL_checktype(L, 4, LUA_TTABLE);
     185           0 :                 has_ctx = 1;
     186             : 
     187           0 :                 lua_getfield(L, 4, "pos");
     188           0 :                 if (lua_isnumber(L, -1)) {
     189           0 :                     pos = (ngx_int_t) lua_tointeger(L, -1);
     190           0 :                     if (pos <= 0) {
     191           0 :                         pos = 0;
     192             : 
     193             :                     } else {
     194           0 :                         pos--;  /* 1-based on the Lua land */
     195             :                     }
     196             : 
     197           0 :                 } else if (lua_isnil(L, -1)) {
     198           0 :                     pos = 0;
     199             : 
     200             :                 } else {
     201           0 :                     msg = lua_pushfstring(L, "bad pos field type in the ctx "
     202             :                                           "table argument: %s",
     203             :                                           luaL_typename(L, -1));
     204             : 
     205           0 :                     return luaL_argerror(L, 4, msg);
     206             :                 }
     207             : 
     208           0 :                 lua_pop(L, 1);
     209             :             }
     210             :         }
     211             : 
     212             :     } else {
     213           0 :         opts.data = (u_char *) "";
     214           0 :         opts.len = 0;
     215             :     }
     216             : 
     217           0 :     if (nargs == 5) {
     218           0 :         if (wantcaps) {
     219           0 :             luaL_checktype(L, 5, LUA_TTABLE);
     220           0 :             res_tb_idx = 5;
     221             : 
     222             : #if 0
     223             :             /* clear the Lua table */
     224             :             lua_pushnil(L);
     225             :             while (lua_next(L, res_tb_idx) != 0) {
     226             :                 lua_pop(L, 1);
     227             :                 lua_pushvalue(L, -1);
     228             :                 lua_pushnil(L);
     229             :                 lua_rawset(L, res_tb_idx);
     230             :             }
     231             : #endif
     232             : 
     233             :         } else {
     234           0 :             group_id =  luaL_checkint(L, 5);
     235           0 :             if (group_id < 0) {
     236           0 :                 group_id = 0;
     237             :             }
     238             :         }
     239             :     }
     240             : 
     241           0 :     re_comp.options = 0;
     242             : 
     243           0 :     flags = ngx_http_lua_ngx_re_parse_opts(L, &re_comp, &opts, 3);
     244             : 
     245           0 :     lmcf = ngx_http_get_module_main_conf(r, ngx_http_lua_module);
     246             : 
     247           0 :     if (flags & NGX_LUA_RE_COMPILE_ONCE) {
     248           0 :         pool = lmcf->pool;
     249             : 
     250             :         dd("server pool %p", lmcf->pool);
     251             : 
     252           0 :         lua_pushlightuserdata(L, &ngx_http_lua_regex_cache_key);
     253           0 :         lua_rawget(L, LUA_REGISTRYINDEX); /* table */
     254             : 
     255           0 :         lua_pushliteral(L, "m");
     256           0 :         lua_pushvalue(L, 2); /* table regex */
     257             : 
     258             :         dd("options size: %d", (int) sizeof(re_comp.options));
     259             : 
     260           0 :         lua_pushlstring(L, (char *) &re_comp.options, sizeof(re_comp.options));
     261             :                 /* table regex opts */
     262             : 
     263           0 :         lua_concat(L, 3); /* table key */
     264           0 :         lua_pushvalue(L, -1); /* table key key */
     265             : 
     266             :         dd("regex cache key: %.*s", (int) (pat.len + sizeof(re_comp.options)),
     267             :            lua_tostring(L, -1));
     268             : 
     269           0 :         lua_rawget(L, -3); /* table key re */
     270           0 :         re = lua_touserdata(L, -1);
     271             : 
     272           0 :         lua_pop(L, 1); /* table key */
     273             : 
     274           0 :         if (re) {
     275           0 :             ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
     276             :                            "lua regex cache hit for match regex \"%s\" with "
     277             :                            "options \"%s\"", pat.data, opts.data);
     278             : 
     279           0 :             lua_pop(L, 2);
     280             : 
     281             :             dd("restoring regex %p, ncaptures %d,  captures %p", re->regex,
     282             :                re->ncaptures, re->captures);
     283             : 
     284           0 :             re_comp.regex = re->regex;
     285           0 :             sd = re->regex_sd;
     286           0 :             re_comp.captures = re->ncaptures;
     287           0 :             cap = re->captures;
     288             : 
     289           0 :             if (flags & NGX_LUA_RE_MODE_DFA) {
     290           0 :                 ovecsize = 2;
     291             : 
     292             :             } else {
     293           0 :                 ovecsize = (re->ncaptures + 1) * 3;
     294             :             }
     295             : 
     296           0 :             goto exec;
     297             :         }
     298             : 
     299           0 :         ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
     300             :                        "lua regex cache miss for match regex \"%s\" "
     301             :                        "with options \"%s\"", pat.data, opts.data);
     302             : 
     303           0 :         if (lmcf->regex_cache_entries >= lmcf->regex_cache_max_entries) {
     304             : 
     305           0 :             if (lmcf->regex_cache_entries == lmcf->regex_cache_max_entries) {
     306           0 :                 ngx_log_error(NGX_LOG_WARN, r->connection->log, 0,
     307             :                               "lua exceeding regex cache max entries (%i)",
     308             :                               lmcf->regex_cache_max_entries);
     309             : 
     310           0 :                 lmcf->regex_cache_entries++;
     311             :             }
     312             : 
     313           0 :             pool = r->pool;
     314           0 :             flags &= ~NGX_LUA_RE_COMPILE_ONCE;
     315             :         }
     316             : 
     317             :     } else {
     318           0 :         pool = r->pool;
     319             :     }
     320             : 
     321             :     dd("pool %p, r pool %p", pool, r->pool);
     322             : 
     323           0 :     re_comp.pattern = pat;
     324           0 :     re_comp.err.len = NGX_MAX_CONF_ERRSTR;
     325           0 :     re_comp.err.data = errstr;
     326           0 :     re_comp.pool = pool;
     327             : 
     328           0 :     ngx_log_debug5(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
     329             :                    "lua compiling match regex \"%s\" with options \"%s\" "
     330             :                    "(compile once: %d) (dfa mode: %d) (jit mode: %d)",
     331             :                    pat.data, opts.data,
     332             :                    (flags & NGX_LUA_RE_COMPILE_ONCE) != 0,
     333             :                    (flags & NGX_LUA_RE_MODE_DFA) != 0,
     334             :                    (flags & NGX_LUA_RE_MODE_JIT) != 0);
     335             : 
     336           0 :     old_pool = ngx_http_lua_pcre_malloc_init(pool);
     337             : 
     338           0 :     rc = ngx_http_lua_regex_compile(&re_comp);
     339             : 
     340           0 :     ngx_http_lua_pcre_malloc_done(old_pool);
     341             : 
     342           0 :     if (rc != NGX_OK) {
     343             :         dd("compile failed");
     344             : 
     345           0 :         lua_pushnil(L);
     346           0 :         if (!wantcaps) {
     347           0 :             lua_pushnil(L);
     348             :         }
     349           0 :         lua_pushlstring(L, (char *) re_comp.err.data, re_comp.err.len);
     350           0 :         return wantcaps ? 2 : 3;
     351             :     }
     352             : 
     353             : #if (LUA_HAVE_PCRE_JIT)
     354             : 
     355           0 :     if (flags & NGX_LUA_RE_MODE_JIT) {
     356             : 
     357           0 :         old_pool = ngx_http_lua_pcre_malloc_init(pool);
     358             : 
     359           0 :         sd = pcre_study(re_comp.regex, PCRE_STUDY_JIT_COMPILE, &msg);
     360             : 
     361           0 :         if (sd && lmcf->jit_stack) {
     362           0 :             pcre_assign_jit_stack(sd, NULL, lmcf->jit_stack);
     363             :         }
     364             : 
     365           0 :         ngx_http_lua_pcre_malloc_done(old_pool);
     366             : 
     367             : #   if (NGX_DEBUG)
     368             :         dd("sd = %p", sd);
     369             : 
     370           0 :         if (msg != NULL) {
     371           0 :             ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
     372             :                            "pcre study failed with PCRE_STUDY_JIT_COMPILE: "
     373             :                            "%s (%p)", msg, sd);
     374             :         }
     375             : 
     376           0 :         if (sd != NULL) {
     377             :             int         jitted;
     378             : 
     379           0 :             old_pool = ngx_http_lua_pcre_malloc_init(pool);
     380             : 
     381           0 :             pcre_fullinfo(re_comp.regex, sd, PCRE_INFO_JIT, &jitted);
     382             : 
     383           0 :             ngx_http_lua_pcre_malloc_done(old_pool);
     384             : 
     385           0 :             ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
     386             :                            "pcre JIT compiling result: %d", jitted);
     387             :         }
     388             : #   endif /* !(NGX_DEBUG) */
     389             : 
     390             :     } else {
     391           0 :         old_pool = ngx_http_lua_pcre_malloc_init(pool);
     392             : 
     393           0 :         sd = pcre_study(re_comp.regex, 0, &msg);
     394             : 
     395           0 :         ngx_http_lua_pcre_malloc_done(old_pool);
     396             : 
     397             : #   if (NGX_DEBUG)
     398             :         dd("sd = %p", sd);
     399             : 
     400           0 :         if (msg != NULL) {
     401           0 :             ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
     402             :                            "pcre_study failed with PCRE_STUDY_JIT_COMPILE: "
     403             :                            "%s (%p)", msg, sd);
     404             :         }
     405             : #   endif /* NGX_DEBUG */
     406             :     }
     407             : 
     408             : #else  /* !(LUA_HAVE_PCRE_JIT) */
     409             : 
     410             :     if (flags & NGX_LUA_RE_MODE_JIT) {
     411             :         ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
     412             :                        "your pcre build does not have JIT support and "
     413             :                        "the \"j\" regex option is ignored");
     414             :     }
     415             : 
     416             : #endif /* LUA_HAVE_PCRE_JIT */
     417             : 
     418           0 :     if (sd && lmcf->regex_match_limit > 0) {
     419           0 :         sd->flags |= PCRE_EXTRA_MATCH_LIMIT;
     420           0 :         sd->match_limit = lmcf->regex_match_limit;
     421             :     }
     422             : 
     423             :     dd("compile done, captures %d", (int) re_comp.captures);
     424             : 
     425           0 :     if (flags & NGX_LUA_RE_MODE_DFA) {
     426           0 :         ovecsize = 2;
     427           0 :         re_comp.captures = 0;
     428             : 
     429             :     } else {
     430           0 :         ovecsize = (re_comp.captures + 1) * 3;
     431             :     }
     432             : 
     433             :     dd("allocating cap with size: %d", (int) ovecsize);
     434             : 
     435           0 :     cap = ngx_palloc(pool, ovecsize * sizeof(int));
     436             : 
     437           0 :     if (cap == NULL) {
     438           0 :         flags &= ~NGX_LUA_RE_COMPILE_ONCE;
     439           0 :         msg = "no memory";
     440           0 :         goto error;
     441             :     }
     442             : 
     443           0 :     if (flags & NGX_LUA_RE_COMPILE_ONCE) {
     444             : 
     445           0 :         ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
     446             :                        "lua saving compiled regex (%d captures) into the cache "
     447             :                        "(entries %i)", re_comp.captures,
     448             :                        lmcf->regex_cache_entries);
     449             : 
     450           0 :         re = ngx_palloc(pool, sizeof(ngx_http_lua_regex_t));
     451           0 :         if (re == NULL) {
     452           0 :             msg = "no memory";
     453           0 :             goto error;
     454             :         }
     455             : 
     456             :         dd("saving regex %p, ncaptures %d,  captures %p", re_comp.regex,
     457             :            re_comp.captures, cap);
     458             : 
     459           0 :         re->regex = re_comp.regex;
     460           0 :         re->regex_sd = sd;
     461           0 :         re->ncaptures = re_comp.captures;
     462           0 :         re->captures = cap;
     463           0 :         re->replace = NULL;
     464             : 
     465           0 :         lua_pushlightuserdata(L, re); /* table key value */
     466           0 :         lua_rawset(L, -3); /* table */
     467           0 :         lua_pop(L, 1);
     468             : 
     469           0 :         if (lmcf) {
     470           0 :             lmcf->regex_cache_entries++;
     471             :         }
     472             :     }
     473             : 
     474           0 : exec:
     475             : 
     476           0 :     if (pcre_fullinfo(re_comp.regex, NULL, PCRE_INFO_NAMECOUNT,
     477             :                       &name_count) != 0)
     478             :     {
     479           0 :         msg = "cannot acquire named subpattern count";
     480           0 :         goto error;
     481             :     }
     482             : 
     483           0 :     if (name_count > 0) {
     484           0 :         if (pcre_fullinfo(re_comp.regex, NULL, PCRE_INFO_NAMEENTRYSIZE,
     485             :                           &name_entry_size) != 0)
     486             :         {
     487           0 :             msg = "cannot acquire named subpattern entry size";
     488           0 :             goto error;
     489             :         }
     490             : 
     491           0 :         if (pcre_fullinfo(re_comp.regex, NULL, PCRE_INFO_NAMETABLE,
     492             :                           &name_table) != 0)
     493             :         {
     494           0 :             msg = "cannot acquire named subpattern table";
     495           0 :             goto error;
     496             :         }
     497             :     }
     498             : 
     499           0 :     if (flags & NGX_LUA_RE_NO_UTF8_CHECK) {
     500           0 :         exec_opts = PCRE_NO_UTF8_CHECK;
     501             : 
     502             :     } else {
     503           0 :         exec_opts = 0;
     504             :     }
     505             : 
     506           0 :     if (flags & NGX_LUA_RE_MODE_DFA) {
     507             : 
     508             : #if LUA_HAVE_PCRE_DFA
     509             : 
     510             :         int ws[NGX_LUA_RE_DFA_MODE_WORKSPACE_COUNT];
     511           0 :         rc = ngx_http_lua_regex_dfa_exec(re_comp.regex, sd, &subj,
     512             :                                          (int) pos, cap, ovecsize, ws,
     513             :                                          sizeof(ws)/sizeof(ws[0]), exec_opts);
     514             : 
     515             : #else /* LUA_HAVE_PCRE_DFA */
     516             : 
     517             :         msg = "at least pcre 6.0 is required for the DFA mode";
     518             :         goto error;
     519             : 
     520             : #endif /* LUA_HAVE_PCRE_DFA */
     521             : 
     522             :     } else {
     523           0 :         rc = ngx_http_lua_regex_exec(re_comp.regex, sd, &subj, (int) pos, cap,
     524             :                                      ovecsize, exec_opts);
     525             :     }
     526             : 
     527           0 :     if (rc == NGX_REGEX_NO_MATCHED) {
     528           0 :         ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
     529             :                        "regex \"%V\" not matched on string \"%V\" starting "
     530             :                        "from %i", &pat, &subj, pos);
     531             : 
     532           0 :         if (!(flags & NGX_LUA_RE_COMPILE_ONCE)) {
     533           0 :             if (sd) {
     534           0 :                 ngx_http_lua_regex_free_study_data(pool, sd);
     535             :             }
     536             : 
     537           0 :             ngx_pfree(pool, re_comp.regex);
     538           0 :             ngx_pfree(pool, cap);
     539             :         }
     540             : 
     541           0 :         lua_pushnil(L);
     542           0 :         return 1;
     543             :     }
     544             : 
     545           0 :     if (rc < 0) {
     546           0 :         msg = lua_pushfstring(L, ngx_regex_exec_n " failed: %d", (int) rc);
     547           0 :         goto error;
     548             :     }
     549             : 
     550           0 :     if (rc == 0) {
     551           0 :         if (flags & NGX_LUA_RE_MODE_DFA) {
     552           0 :             rc = 1;
     553             : 
     554             :         } else {
     555           0 :             msg = "capture size too small";
     556           0 :             goto error;
     557             :         }
     558             :     }
     559             : 
     560             :     dd("rc = %d", (int) rc);
     561             : 
     562           0 :     if (has_ctx) { /* having ctx table */
     563           0 :         pos = cap[1];
     564           0 :         lua_pushinteger(L, (lua_Integer) (pos + 1));
     565           0 :         lua_setfield(L, 4, "pos");
     566             :     }
     567             : 
     568           0 :     if (!wantcaps) {
     569           0 :         if (group_id > re_comp.captures) {
     570           0 :             lua_pushnil(L);
     571           0 :             lua_pushnil(L);
     572           0 :             lua_pushliteral(L, "nth out of bound");
     573           0 :             return 3;
     574             :         }
     575             : 
     576           0 :         if (group_id >= rc) {
     577           0 :             lua_pushnil(L);
     578           0 :             lua_pushnil(L);
     579           0 :             return 2;
     580             :         }
     581             : 
     582             :         {
     583             :             int     from, to;
     584             : 
     585           0 :             from = cap[group_id * 2] + 1;
     586           0 :             to = cap[group_id * 2 + 1];
     587           0 :             if (from < 0 || to < 0) {
     588           0 :                 lua_pushnil(L);
     589           0 :                 lua_pushnil(L);
     590           0 :                 return 2;
     591             :             }
     592             : 
     593           0 :             lua_pushinteger(L, from);
     594           0 :             lua_pushinteger(L, to);
     595           0 :             return 2;
     596             :         }
     597             :     }
     598             : 
     599           0 :     if (res_tb_idx == 0) {
     600           0 :         lua_createtable(L, re_comp.captures || 1 /* narr */,
     601             :                         name_count /* nrec */);
     602           0 :         res_tb_idx = lua_gettop(L);
     603             :     }
     604             : 
     605           0 :     for (i = 0, n = 0; i <= re_comp.captures; i++, n += 2) {
     606             :         dd("capture %d: %d %d", i, cap[n], cap[n + 1]);
     607           0 :         if (i >= rc || cap[n] < 0) {
     608           0 :             lua_pushboolean(L, 0);
     609             : 
     610             :         } else {
     611           0 :             lua_pushlstring(L, (char *) &subj.data[cap[n]],
     612           0 :                             cap[n + 1] - cap[n]);
     613             : 
     614             :             dd("pushing capture %s at %d", lua_tostring(L, -1), (int) i);
     615             :         }
     616             : 
     617           0 :         lua_rawseti(L, res_tb_idx, (int) i);
     618             :     }
     619             : 
     620           0 :     if (name_count > 0) {
     621           0 :         ngx_http_lua_re_collect_named_captures(L, res_tb_idx, name_table,
     622             :                                                name_count, name_entry_size,
     623             :                                                flags, &subj);
     624             :     }
     625             : 
     626           0 :     if (!(flags & NGX_LUA_RE_COMPILE_ONCE)) {
     627             : 
     628           0 :         if (sd) {
     629           0 :             ngx_http_lua_regex_free_study_data(pool, sd);
     630             :         }
     631             : 
     632           0 :         ngx_pfree(pool, re_comp.regex);
     633           0 :         ngx_pfree(pool, cap);
     634             :     }
     635             : 
     636           0 :     return 1;
     637             : 
     638           0 : error:
     639             : 
     640           0 :     if (!(flags & NGX_LUA_RE_COMPILE_ONCE)) {
     641           0 :         if (sd) {
     642           0 :             ngx_http_lua_regex_free_study_data(pool, sd);
     643             :         }
     644             : 
     645           0 :         if (re_comp.regex) {
     646           0 :             ngx_pfree(pool, re_comp.regex);
     647             :         }
     648             : 
     649           0 :         if (cap) {
     650           0 :             ngx_pfree(pool, cap);
     651             :         }
     652             :     }
     653             : 
     654           0 :     lua_pushnil(L);
     655           0 :     if (!wantcaps) {
     656           0 :         lua_pushnil(L);
     657             :     }
     658           0 :     lua_pushstring(L, msg);
     659           0 :     return wantcaps ? 2 : 3;
     660             : }
     661             : 
     662             : 
     663             : static int
     664           0 : ngx_http_lua_ngx_re_gmatch(lua_State *L)
     665             : {
     666             :     ngx_http_lua_main_conf_t    *lmcf;
     667             :     ngx_http_request_t          *r;
     668             :     ngx_str_t                    subj;
     669             :     ngx_str_t                    pat;
     670             :     ngx_str_t                    opts;
     671             :     int                          ovecsize;
     672             :     ngx_http_lua_regex_t        *re;
     673             :     ngx_http_lua_regex_ctx_t    *ctx;
     674             :     const char                  *msg;
     675             :     int                          nargs;
     676             :     ngx_int_t                    flags;
     677           0 :     int                         *cap = NULL;
     678             :     ngx_int_t                    rc;
     679             :     ngx_pool_t                  *pool, *old_pool;
     680             :     u_char                       errstr[NGX_MAX_CONF_ERRSTR + 1];
     681           0 :     pcre_extra                  *sd = NULL;
     682             :     ngx_http_cleanup_t          *cln;
     683             : 
     684             :     ngx_http_lua_regex_compile_t      re_comp;
     685             : 
     686           0 :     nargs = lua_gettop(L);
     687             : 
     688           0 :     if (nargs != 2 && nargs != 3) {
     689           0 :         return luaL_error(L, "expecting two or three arguments, but got %d",
     690             :                           nargs);
     691             :     }
     692             : 
     693           0 :     r = ngx_http_lua_get_req(L);
     694           0 :     if (r == NULL) {
     695           0 :         return luaL_error(L, "no request object found");
     696             :     }
     697             : 
     698           0 :     subj.data = (u_char *) luaL_checklstring(L, 1, &subj.len);
     699           0 :     pat.data = (u_char *) luaL_checklstring(L, 2, &pat.len);
     700             : 
     701           0 :     if (nargs == 3) {
     702           0 :         opts.data = (u_char *) luaL_checklstring(L, 3, &opts.len);
     703           0 :         lua_pop(L, 1);
     704             : 
     705             :     } else {
     706           0 :         opts.data = (u_char *) "";
     707           0 :         opts.len = 0;
     708             :     }
     709             : 
     710             :     /* stack: subj regex */
     711             : 
     712           0 :     re_comp.options = 0;
     713             : 
     714           0 :     flags = ngx_http_lua_ngx_re_parse_opts(L, &re_comp, &opts, 3);
     715             : 
     716           0 :     lmcf = ngx_http_get_module_main_conf(r, ngx_http_lua_module);
     717             : 
     718           0 :     if (flags & NGX_LUA_RE_COMPILE_ONCE) {
     719           0 :         pool = lmcf->pool;
     720             : 
     721             :         dd("server pool %p", lmcf->pool);
     722             : 
     723           0 :         lua_pushlightuserdata(L, &ngx_http_lua_regex_cache_key);
     724           0 :         lua_rawget(L, LUA_REGISTRYINDEX); /* table */
     725             : 
     726           0 :         lua_pushliteral(L, "m");
     727           0 :         lua_pushvalue(L, 2); /* table regex */
     728             : 
     729             :         dd("options size: %d", (int) sizeof(re_comp.options));
     730             : 
     731           0 :         lua_pushlstring(L, (char *) &re_comp.options,
     732             :                         sizeof(re_comp.options)); /* table regex opts */
     733             : 
     734           0 :         lua_concat(L, 3); /* table key */
     735           0 :         lua_pushvalue(L, -1); /* table key key */
     736             : 
     737             :         dd("regex cache key: %.*s", (int) (pat.len + sizeof(re_comp.options)),
     738             :            lua_tostring(L, -1));
     739             : 
     740           0 :         lua_rawget(L, -3); /* table key re */
     741           0 :         re = lua_touserdata(L, -1);
     742             : 
     743           0 :         lua_pop(L, 1); /* table key */
     744             : 
     745           0 :         if (re) {
     746           0 :             ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
     747             :                            "lua regex cache hit for match regex \"%s\" "
     748             :                            "with options \"%s\"", pat.data, opts.data);
     749             : 
     750           0 :             lua_pop(L, 2);
     751             : 
     752             :             dd("restoring regex %p, ncaptures %d,  captures %p", re->regex,
     753             :                re->ncaptures, re->captures);
     754             : 
     755           0 :             re_comp.regex = re->regex;
     756           0 :             sd = re->regex_sd;
     757           0 :             re_comp.captures = re->ncaptures;
     758           0 :             cap = re->captures;
     759             : 
     760           0 :             if (flags & NGX_LUA_RE_MODE_DFA) {
     761           0 :                 ovecsize = 2;
     762             : 
     763             :             } else {
     764           0 :                 ovecsize = (re->ncaptures + 1) * 3;
     765             :             }
     766             : 
     767           0 :             goto compiled;
     768             :         }
     769             : 
     770           0 :         ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
     771             :                        "lua regex cache miss for match regex \"%s\" "
     772             :                        "with options \"%s\"", pat.data, opts.data);
     773             : 
     774           0 :         if (lmcf->regex_cache_entries >= lmcf->regex_cache_max_entries) {
     775             : 
     776           0 :             if (lmcf->regex_cache_entries == lmcf->regex_cache_max_entries) {
     777           0 :                 ngx_log_error(NGX_LOG_WARN, r->connection->log, 0,
     778             :                               "lua exceeding regex cache max entries (%i)",
     779             :                               lmcf->regex_cache_max_entries);
     780             : 
     781           0 :                 lmcf->regex_cache_entries++;
     782             :             }
     783             : 
     784           0 :             pool = r->pool;
     785           0 :             flags &= ~NGX_LUA_RE_COMPILE_ONCE;
     786             :         }
     787             : 
     788             :     } else {
     789           0 :         pool = r->pool;
     790             :     }
     791             : 
     792           0 :     re_comp.pattern = pat;
     793           0 :     re_comp.err.len = NGX_MAX_CONF_ERRSTR;
     794           0 :     re_comp.err.data = errstr;
     795           0 :     re_comp.pool = pool;
     796             : 
     797           0 :     ngx_log_debug5(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
     798             :                    "lua compiling gmatch regex \"%s\" with options \"%s\" "
     799             :                    "(compile once: %d) (dfa mode: %d) (jit mode: %d)",
     800             :                    pat.data, opts.data,
     801             :                    (flags & NGX_LUA_RE_COMPILE_ONCE) != 0,
     802             :                    (flags & NGX_LUA_RE_MODE_DFA) != 0,
     803             :                    (flags & NGX_LUA_RE_MODE_JIT) != 0);
     804             : 
     805           0 :     old_pool = ngx_http_lua_pcre_malloc_init(pool);
     806             : 
     807           0 :     rc = ngx_http_lua_regex_compile(&re_comp);
     808             : 
     809           0 :     ngx_http_lua_pcre_malloc_done(old_pool);
     810             : 
     811           0 :     if (rc != NGX_OK) {
     812             :         dd("compile failed");
     813             : 
     814           0 :         lua_pushnil(L);
     815           0 :         lua_pushlstring(L, (char *) re_comp.err.data, re_comp.err.len);
     816           0 :         return 2;
     817             :     }
     818             : 
     819             : #if LUA_HAVE_PCRE_JIT
     820             : 
     821           0 :     if (flags & NGX_LUA_RE_MODE_JIT) {
     822             : 
     823           0 :         old_pool = ngx_http_lua_pcre_malloc_init(pool);
     824             : 
     825           0 :         sd = pcre_study(re_comp.regex, PCRE_STUDY_JIT_COMPILE, &msg);
     826             : 
     827           0 :         if (sd && lmcf->jit_stack) {
     828           0 :             pcre_assign_jit_stack(sd, NULL, lmcf->jit_stack);
     829             :         }
     830             : 
     831           0 :         ngx_http_lua_pcre_malloc_done(old_pool);
     832             : 
     833             : #   if (NGX_DEBUG)
     834             :         dd("sd = %p", sd);
     835             : 
     836           0 :         if (msg != NULL) {
     837           0 :             ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
     838             :                            "pcre_study failed with PCRE_STUDY_JIT_COMPILE: "
     839             :                            "%s (%p)", msg, sd);
     840             :         }
     841             : 
     842           0 :         if (sd != NULL) {
     843             :             int         jitted;
     844             : 
     845           0 :             old_pool = ngx_http_lua_pcre_malloc_init(pool);
     846             : 
     847           0 :             pcre_fullinfo(re_comp.regex, sd, PCRE_INFO_JIT, &jitted);
     848             : 
     849           0 :             ngx_http_lua_pcre_malloc_done(old_pool);
     850             : 
     851           0 :             ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
     852             :                            "pcre JIT compiling result: %d", jitted);
     853             :         }
     854             : #   endif /* NGX_DEBUG */
     855             : 
     856             :     } else {
     857             : 
     858           0 :         old_pool = ngx_http_lua_pcre_malloc_init(pool);
     859             : 
     860           0 :         sd = pcre_study(re_comp.regex, 0, &msg);
     861             : 
     862           0 :         ngx_http_lua_pcre_malloc_done(old_pool);
     863             : 
     864             : #   if (NGX_DEBUG)
     865             :         dd("sd = %p", sd);
     866             : 
     867           0 :         if (msg != NULL) {
     868           0 :             ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
     869             :                            "pcre study failed with PCRE_STUDY_JIT_COMPILE: "
     870             :                            "%s (%p)", msg, sd);
     871             :         }
     872             : #   endif /* NGX_DEBUG */
     873             :     }
     874             : 
     875             : #else  /* LUA_HAVE_PCRE_JIT */
     876             : 
     877             :     if (flags & NGX_LUA_RE_MODE_JIT) {
     878             :         ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
     879             :                        "your pcre build does not have JIT support and "
     880             :                        "the \"j\" regex option is ignored");
     881             :     }
     882             : 
     883             : #endif /* LUA_HAVE_PCRE_JIT */
     884             : 
     885           0 :     if (sd && lmcf->regex_match_limit > 0) {
     886           0 :         sd->flags |= PCRE_EXTRA_MATCH_LIMIT;
     887           0 :         sd->match_limit = lmcf->regex_match_limit;
     888             :     }
     889             : 
     890             :     dd("compile done, captures %d", re_comp.captures);
     891             : 
     892           0 :     if (flags & NGX_LUA_RE_MODE_DFA) {
     893           0 :         ovecsize = 2;
     894           0 :         re_comp.captures = 0;
     895             : 
     896             :     } else {
     897           0 :         ovecsize = (re_comp.captures + 1) * 3;
     898             :     }
     899             : 
     900           0 :     cap = ngx_palloc(pool, ovecsize * sizeof(int));
     901           0 :     if (cap == NULL) {
     902           0 :         flags &= ~NGX_LUA_RE_COMPILE_ONCE;
     903           0 :         msg = "no memory";
     904           0 :         goto error;
     905             :     }
     906             : 
     907           0 :     if (flags & NGX_LUA_RE_COMPILE_ONCE) {
     908             : 
     909           0 :         ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
     910             :                        "lua saving compiled regex (%d captures) into the cache "
     911             :                        "(entries %i)", re_comp.captures,
     912             :                        lmcf->regex_cache_entries);
     913             : 
     914           0 :         re = ngx_palloc(pool, sizeof(ngx_http_lua_regex_t));
     915           0 :         if (re == NULL) {
     916           0 :             msg = "no memory";
     917           0 :             goto error;
     918             :         }
     919             : 
     920             :         dd("saving regex %p, ncaptures %d,  captures %p", re_comp.regex,
     921             :            re_comp.captures, cap);
     922             : 
     923           0 :         re->regex = re_comp.regex;
     924           0 :         re->regex_sd = sd;
     925           0 :         re->ncaptures = re_comp.captures;
     926           0 :         re->captures = cap;
     927           0 :         re->replace = NULL;
     928             : 
     929           0 :         lua_pushlightuserdata(L, re); /* table key value */
     930           0 :         lua_rawset(L, -3); /* table */
     931           0 :         lua_pop(L, 1);
     932             : 
     933           0 :         if (lmcf) {
     934           0 :             lmcf->regex_cache_entries++;
     935             :         }
     936             :     }
     937             : 
     938           0 : compiled:
     939             : 
     940           0 :     lua_settop(L, 1);
     941             : 
     942           0 :     ctx = lua_newuserdata(L, sizeof(ngx_http_lua_regex_ctx_t));
     943             : 
     944           0 :     ctx->request = r;
     945           0 :     ctx->regex = re_comp.regex;
     946           0 :     ctx->regex_sd = sd;
     947           0 :     ctx->ncaptures = re_comp.captures;
     948           0 :     ctx->captures = cap;
     949           0 :     ctx->captures_len = ovecsize;
     950           0 :     ctx->flags = (uint8_t) flags;
     951             : 
     952           0 :     if (!(flags & NGX_LUA_RE_COMPILE_ONCE)) {
     953           0 :         lua_createtable(L, 0 /* narr */, 1 /* nrec */); /* metatable */
     954           0 :         lua_pushcfunction(L, ngx_http_lua_ngx_re_gmatch_gc);
     955           0 :         lua_setfield(L, -2, "__gc");
     956           0 :         lua_setmetatable(L, -2);
     957             : 
     958           0 :         cln = ngx_http_cleanup_add(r, 0);
     959           0 :         if (cln == NULL) {
     960           0 :             msg = "no memory";
     961           0 :             goto error;
     962             :         }
     963             : 
     964           0 :         cln->handler = ngx_http_lua_ngx_re_gmatch_cleanup;
     965           0 :         cln->data = ctx;
     966           0 :         ctx->cleanup = &cln->handler;
     967             : 
     968             :     } else {
     969           0 :         ctx->cleanup = NULL;
     970             :     }
     971             : 
     972           0 :     lua_pushinteger(L, 0);
     973             : 
     974             :     /* upvalues in order: subj ctx offset */
     975           0 :     lua_pushcclosure(L, ngx_http_lua_ngx_re_gmatch_iterator, 3);
     976             : 
     977           0 :     return 1;
     978             : 
     979           0 : error:
     980             : 
     981           0 :     if (!(flags & NGX_LUA_RE_COMPILE_ONCE)) {
     982           0 :         if (sd) {
     983           0 :             ngx_http_lua_regex_free_study_data(pool, sd);
     984             :         }
     985             : 
     986           0 :         if (re_comp.regex) {
     987           0 :             ngx_pfree(pool, re_comp.regex);
     988             :         }
     989             : 
     990           0 :         if (cap) {
     991           0 :             ngx_pfree(pool, cap);
     992             :         }
     993             :     }
     994             : 
     995           0 :     lua_pushnil(L);
     996           0 :     lua_pushstring(L, msg);
     997           0 :     return 2;
     998             : }
     999             : 
    1000             : 
    1001             : static int
    1002           0 : ngx_http_lua_ngx_re_gmatch_iterator(lua_State *L)
    1003             : {
    1004             :     ngx_http_lua_regex_ctx_t    *ctx;
    1005             :     ngx_http_request_t          *r;
    1006             :     int                         *cap;
    1007             :     ngx_int_t                    rc;
    1008             :     ngx_uint_t                   n;
    1009             :     int                          i;
    1010             :     ngx_str_t                    subj;
    1011             :     int                          offset;
    1012           0 :     const char                  *msg = NULL;
    1013           0 :     int                          name_entry_size = 0, name_count;
    1014           0 :     u_char                      *name_table = NULL;
    1015             :     int                          exec_opts;
    1016             : 
    1017             :     /* upvalues in order: subj ctx offset */
    1018             : 
    1019           0 :     subj.data = (u_char *) lua_tolstring(L, lua_upvalueindex(1), &subj.len);
    1020           0 :     ctx = (ngx_http_lua_regex_ctx_t *) lua_touserdata(L, lua_upvalueindex(2));
    1021           0 :     offset = (int) lua_tointeger(L, lua_upvalueindex(3));
    1022             : 
    1023           0 :     if (offset < 0) {
    1024           0 :         lua_pushnil(L);
    1025           0 :         return 1;
    1026             :     }
    1027             : 
    1028           0 :     cap = ctx->captures;
    1029             : 
    1030             :     dd("offset %d, r %p, subj %s", (int) offset, ctx->request, subj.data);
    1031             : 
    1032           0 :     r = ngx_http_lua_get_req(L);
    1033           0 :     if (r == NULL) {
    1034           0 :         return luaL_error(L, "no request object found");
    1035             :     }
    1036             : 
    1037           0 :     if (r != ctx->request || r->pool != ctx->request->pool) {
    1038           0 :         return luaL_error(L, "attempt to use ngx.re.gmatch iterator in a "
    1039             :                           "request that did not create it");
    1040             :     }
    1041             : 
    1042             :     dd("regex exec...");
    1043             : 
    1044           0 :     if (pcre_fullinfo(ctx->regex, NULL, PCRE_INFO_NAMECOUNT,
    1045             :                       &name_count) != 0)
    1046             :     {
    1047           0 :         msg = "cannot acquire named subpattern count";
    1048           0 :         goto error;
    1049             :     }
    1050             : 
    1051           0 :     if (name_count > 0) {
    1052           0 :         if (pcre_fullinfo(ctx->regex, NULL, PCRE_INFO_NAMEENTRYSIZE,
    1053             :                           &name_entry_size) != 0)
    1054             :         {
    1055           0 :             msg = "cannot acquire named subpattern entry size";
    1056           0 :             goto error;
    1057             :         }
    1058             : 
    1059           0 :         if (pcre_fullinfo(ctx->regex, NULL, PCRE_INFO_NAMETABLE,
    1060             :                           &name_table) != 0)
    1061             :         {
    1062           0 :             msg = "cannot acquire named subpattern table";
    1063           0 :             goto error;
    1064             :         }
    1065             :     }
    1066             : 
    1067           0 :     if (ctx->flags & NGX_LUA_RE_NO_UTF8_CHECK) {
    1068           0 :         exec_opts = PCRE_NO_UTF8_CHECK;
    1069             : 
    1070             :     } else {
    1071           0 :         exec_opts = 0;
    1072             :     }
    1073             : 
    1074           0 :     if (ctx->flags & NGX_LUA_RE_MODE_DFA) {
    1075             : 
    1076             : #if LUA_HAVE_PCRE_DFA
    1077             : 
    1078             :         int ws[NGX_LUA_RE_DFA_MODE_WORKSPACE_COUNT];
    1079             : 
    1080           0 :         rc = ngx_http_lua_regex_dfa_exec(ctx->regex, ctx->regex_sd, &subj,
    1081             :                                          offset, cap, ctx->captures_len, ws,
    1082             :                                          sizeof(ws)/sizeof(ws[0]), exec_opts);
    1083             : 
    1084             : #else /* LUA_HAVE_PCRE_DFA */
    1085             :         msg = "at least pcre 6.0 is required for the DFA mode";
    1086             :         goto error;
    1087             : 
    1088             : #endif /* LUA_HAVE_PCRE_DFA */
    1089             : 
    1090             :     } else {
    1091           0 :         rc = ngx_http_lua_regex_exec(ctx->regex, ctx->regex_sd, &subj,
    1092             :                                      offset, cap, ctx->captures_len,
    1093             :                                      exec_opts);
    1094             :     }
    1095             : 
    1096           0 :     if (rc == NGX_REGEX_NO_MATCHED) {
    1097             :         /* set upvalue "offset" to -1 */
    1098           0 :         lua_pushinteger(L, -1);
    1099           0 :         lua_replace(L, lua_upvalueindex(3));
    1100             : 
    1101           0 :         if (!(ctx->flags & NGX_LUA_RE_COMPILE_ONCE)) {
    1102           0 :             if (ctx->regex_sd) {
    1103           0 :                 ngx_http_lua_regex_free_study_data(r->pool, ctx->regex_sd);
    1104           0 :                 ctx->regex_sd = NULL;
    1105             :             }
    1106             : 
    1107           0 :             ngx_pfree(r->pool, cap);
    1108             :         }
    1109             : 
    1110           0 :         lua_pushnil(L);
    1111           0 :         return 1;
    1112             :     }
    1113             : 
    1114           0 :     if (rc < 0) {
    1115           0 :         msg = lua_pushfstring(L, ngx_regex_exec_n " failed: %d", (int) rc);
    1116           0 :         goto error;
    1117             :     }
    1118             : 
    1119           0 :     if (rc == 0) {
    1120           0 :         if (ctx->flags & NGX_LUA_RE_MODE_DFA) {
    1121           0 :             rc = 1;
    1122             : 
    1123             :         } else {
    1124           0 :             goto error;
    1125             :         }
    1126             :     }
    1127             : 
    1128             :     dd("rc = %d", (int) rc);
    1129             : 
    1130           0 :     lua_createtable(L, ctx->ncaptures || 1 /* narr */, name_count /* nrec */);
    1131             : 
    1132           0 :     for (i = 0, n = 0; i <= ctx->ncaptures; i++, n += 2) {
    1133             :         dd("capture %d: %d %d", i, cap[n], cap[n + 1]);
    1134           0 :         if (i >= rc || cap[n] < 0) {
    1135           0 :             lua_pushboolean(L, 0);
    1136             : 
    1137             :         } else {
    1138           0 :             lua_pushlstring(L, (char *) &subj.data[cap[n]],
    1139           0 :                             cap[n + 1] - cap[n]);
    1140             : 
    1141             :             dd("pushing capture %s at %d", lua_tostring(L, -1), (int) i);
    1142             :         }
    1143             : 
    1144           0 :         lua_rawseti(L, -2, (int) i);
    1145             :     }
    1146             : 
    1147           0 :     if (name_count > 0) {
    1148           0 :         ngx_http_lua_re_collect_named_captures(L, lua_gettop(L), name_table,
    1149             :                                                name_count, name_entry_size,
    1150           0 :                                                ctx->flags, &subj);
    1151             :     }
    1152             : 
    1153           0 :     offset = cap[1];
    1154           0 :     if (offset == cap[0]) {
    1155           0 :         offset++;
    1156             :     }
    1157             : 
    1158           0 :     if (offset > (ssize_t) subj.len) {
    1159           0 :         offset = -1;
    1160             : 
    1161           0 :         if (!(ctx->flags & NGX_LUA_RE_COMPILE_ONCE)) {
    1162           0 :             if (ctx->regex_sd) {
    1163           0 :                 ngx_http_lua_regex_free_study_data(r->pool, ctx->regex_sd);
    1164           0 :                 ctx->regex_sd = NULL;
    1165             :             }
    1166             : 
    1167           0 :             ngx_pfree(r->pool, cap);
    1168             :         }
    1169             :     }
    1170             : 
    1171           0 :     lua_pushinteger(L, offset);
    1172           0 :     lua_replace(L, lua_upvalueindex(3));
    1173             : 
    1174           0 :     return 1;
    1175             : 
    1176           0 : error:
    1177             : 
    1178           0 :     lua_pushinteger(L, -1);
    1179           0 :     lua_replace(L, lua_upvalueindex(3));
    1180             : 
    1181           0 :     if (!(ctx->flags & NGX_LUA_RE_COMPILE_ONCE)) {
    1182           0 :         if (ctx->regex_sd) {
    1183           0 :             ngx_http_lua_regex_free_study_data(r->pool, ctx->regex_sd);
    1184           0 :             ctx->regex_sd = NULL;
    1185             :         }
    1186             : 
    1187           0 :         ngx_pfree(r->pool, cap);
    1188             :     }
    1189             : 
    1190           0 :     lua_pushnil(L);
    1191           0 :     lua_pushstring(L, msg);
    1192           0 :     return 2;
    1193             : }
    1194             : 
    1195             : 
    1196             : static ngx_uint_t
    1197           0 : ngx_http_lua_ngx_re_parse_opts(lua_State *L, ngx_http_lua_regex_compile_t *re,
    1198             :     ngx_str_t *opts, int narg)
    1199             : {
    1200             :     u_char          *p;
    1201             :     const char      *msg;
    1202             :     ngx_uint_t       flags;
    1203             : 
    1204           0 :     flags = 0;
    1205           0 :     p = opts->data;
    1206             : 
    1207           0 :     while (*p != '\0') {
    1208           0 :         switch (*p) {
    1209           0 :             case 'i':
    1210           0 :                 re->options |= NGX_REGEX_CASELESS;
    1211           0 :                 break;
    1212             : 
    1213           0 :             case 's':
    1214           0 :                 re->options |= PCRE_DOTALL;
    1215           0 :                 break;
    1216             : 
    1217           0 :             case 'm':
    1218           0 :                 re->options |= PCRE_MULTILINE;
    1219           0 :                 break;
    1220             : 
    1221           0 :             case 'u':
    1222           0 :                 re->options |= PCRE_UTF8;
    1223           0 :                 break;
    1224             : 
    1225           0 :             case 'U':
    1226           0 :                 re->options |= PCRE_UTF8;
    1227           0 :                 flags |= NGX_LUA_RE_NO_UTF8_CHECK;
    1228           0 :                 break;
    1229             : 
    1230           0 :             case 'x':
    1231           0 :                 re->options |= PCRE_EXTENDED;
    1232           0 :                 break;
    1233             : 
    1234           0 :             case 'o':
    1235           0 :                 flags |= NGX_LUA_RE_COMPILE_ONCE;
    1236           0 :                 break;
    1237             : 
    1238           0 :             case 'j':
    1239           0 :                 flags |= NGX_LUA_RE_MODE_JIT;
    1240           0 :                 break;
    1241             : 
    1242           0 :             case 'd':
    1243           0 :                 flags |= NGX_LUA_RE_MODE_DFA;
    1244           0 :                 break;
    1245             : 
    1246           0 :             case 'a':
    1247           0 :                 re->options |= PCRE_ANCHORED;
    1248           0 :                 break;
    1249             : 
    1250             : #if (PCRE_MAJOR > 8) || (PCRE_MAJOR == 8 && PCRE_MINOR >= 12)
    1251           0 :             case 'D':
    1252           0 :                 re->options |= PCRE_DUPNAMES;
    1253           0 :                 flags |= NGX_LUA_RE_MODE_DUPNAMES;
    1254           0 :                 break;
    1255             : 
    1256           0 :             case 'J':
    1257           0 :                 re->options |= PCRE_JAVASCRIPT_COMPAT;
    1258           0 :                 break;
    1259             : #endif
    1260             : 
    1261           0 :             default:
    1262           0 :                 msg = lua_pushfstring(L, "unknown flag \"%c\" (flags \"%s\")",
    1263           0 :                                       *p, opts->data);
    1264           0 :                 return luaL_argerror(L, narg, msg);
    1265             :         }
    1266             : 
    1267           0 :         p++;
    1268             :     }
    1269             : 
    1270             :     /* pcre does not support JIT for DFA mode yet,
    1271             :      * so if DFA mode is specified, we turn off JIT automatically
    1272             :      * */
    1273           0 :     if ((flags & NGX_LUA_RE_MODE_JIT) && (flags & NGX_LUA_RE_MODE_DFA)) {
    1274           0 :         flags &= ~NGX_LUA_RE_MODE_JIT;
    1275             :     }
    1276             : 
    1277           0 :     return flags;
    1278             : }
    1279             : 
    1280             : 
    1281             : static int
    1282           0 : ngx_http_lua_ngx_re_sub(lua_State *L)
    1283             : {
    1284           0 :     return ngx_http_lua_ngx_re_sub_helper(L, 0 /* global */);
    1285             : }
    1286             : 
    1287             : 
    1288             : static int
    1289           0 : ngx_http_lua_ngx_re_gsub(lua_State *L)
    1290             : {
    1291           0 :     return ngx_http_lua_ngx_re_sub_helper(L, 1 /* global */);
    1292             : }
    1293             : 
    1294             : 
    1295             : static int
    1296           0 : ngx_http_lua_ngx_re_sub_helper(lua_State *L, unsigned global)
    1297             : {
    1298             :     ngx_http_lua_regex_t        *re;
    1299             :     ngx_http_request_t          *r;
    1300             :     ngx_str_t                    subj;
    1301             :     ngx_str_t                    pat;
    1302             :     ngx_str_t                    opts;
    1303             :     ngx_str_t                    tpl;
    1304             :     ngx_http_lua_main_conf_t    *lmcf;
    1305             :     ngx_pool_t                  *pool, *old_pool;
    1306             :     const char                  *msg;
    1307             :     ngx_int_t                    rc;
    1308             :     ngx_uint_t                   n;
    1309             :     ngx_int_t                    i;
    1310             :     int                          nargs;
    1311           0 :     int                         *cap = NULL;
    1312             :     int                          ovecsize;
    1313             :     int                          type;
    1314             :     unsigned                     func;
    1315             :     int                          offset;
    1316             :     int                          cp_offset;
    1317             :     size_t                       count;
    1318             :     luaL_Buffer                  luabuf;
    1319             :     ngx_int_t                    flags;
    1320             :     u_char                      *p;
    1321             :     u_char                       errstr[NGX_MAX_CONF_ERRSTR + 1];
    1322           0 :     pcre_extra                  *sd = NULL;
    1323           0 :     int                          name_entry_size = 0, name_count;
    1324           0 :     u_char                      *name_table = NULL;
    1325             :     int                          exec_opts;
    1326             : 
    1327             :     ngx_http_lua_regex_compile_t               re_comp;
    1328           0 :     ngx_http_lua_complex_value_t              *ctpl = NULL;
    1329             :     ngx_http_lua_compile_complex_value_t       ccv;
    1330             : 
    1331           0 :     nargs = lua_gettop(L);
    1332             : 
    1333           0 :     if (nargs != 3 && nargs != 4) {
    1334           0 :         return luaL_error(L, "expecting three or four arguments, but got %d",
    1335             :                           nargs);
    1336             :     }
    1337             : 
    1338           0 :     r = ngx_http_lua_get_req(L);
    1339           0 :     if (r == NULL) {
    1340           0 :         return luaL_error(L, "no request object found");
    1341             :     }
    1342             : 
    1343           0 :     subj.data = (u_char *) luaL_checklstring(L, 1, &subj.len);
    1344           0 :     pat.data = (u_char *) luaL_checklstring(L, 2, &pat.len);
    1345             : 
    1346           0 :     func = 0;
    1347             : 
    1348           0 :     type = lua_type(L, 3);
    1349           0 :     switch (type) {
    1350           0 :         case LUA_TFUNCTION:
    1351           0 :             func = 1;
    1352           0 :             tpl.len = 0;
    1353           0 :             tpl.data = (u_char *) "";
    1354           0 :             break;
    1355             : 
    1356           0 :         case LUA_TNUMBER:
    1357             :         case LUA_TSTRING:
    1358           0 :             tpl.data = (u_char *) lua_tolstring(L, 3, &tpl.len);
    1359           0 :             break;
    1360             : 
    1361           0 :         default:
    1362           0 :             msg = lua_pushfstring(L, "string, number, or function expected, "
    1363             :                                   "got %s", lua_typename(L, type));
    1364           0 :             return luaL_argerror(L, 3, msg);
    1365             :     }
    1366             : 
    1367           0 :     ngx_memzero(&re_comp, sizeof(ngx_http_lua_regex_compile_t));
    1368             : 
    1369           0 :     if (nargs == 4) {
    1370           0 :         opts.data = (u_char *) luaL_checklstring(L, 4, &opts.len);
    1371           0 :         lua_pop(L, 1);
    1372             : 
    1373             :     } else { /* nargs == 3 */
    1374           0 :         opts.data = (u_char *) "";
    1375           0 :         opts.len = 0;
    1376             :     }
    1377             : 
    1378             :     /* stack: subj regex repl */
    1379             : 
    1380           0 :     re_comp.options = 0;
    1381             : 
    1382           0 :     flags = ngx_http_lua_ngx_re_parse_opts(L, &re_comp, &opts, 4);
    1383             : 
    1384           0 :     lmcf = ngx_http_get_module_main_conf(r, ngx_http_lua_module);
    1385             : 
    1386           0 :     if (flags & NGX_LUA_RE_COMPILE_ONCE) {
    1387           0 :         pool = lmcf->pool;
    1388             : 
    1389             :         dd("server pool %p", lmcf->pool);
    1390             : 
    1391           0 :         lua_pushlightuserdata(L, &ngx_http_lua_regex_cache_key);
    1392           0 :         lua_rawget(L, LUA_REGISTRYINDEX); /* table */
    1393             : 
    1394           0 :         lua_pushliteral(L, "s");
    1395           0 :         lua_pushinteger(L, tpl.len);
    1396           0 :         lua_pushliteral(L, ":");
    1397           0 :         lua_pushvalue(L, 2);
    1398             : 
    1399           0 :         if (tpl.len != 0) {
    1400           0 :             lua_pushvalue(L, 3);
    1401             :         }
    1402             : 
    1403             :         dd("options size: %d", (int) sizeof(re_comp.options));
    1404             : 
    1405           0 :         lua_pushlstring(L, (char *) &re_comp.options, sizeof(re_comp.options));
    1406             :                 /* table regex opts */
    1407             : 
    1408           0 :         if (tpl.len == 0) {
    1409           0 :             lua_concat(L, 5); /* table key */
    1410             : 
    1411             :         } else {
    1412           0 :             lua_concat(L, 6); /* table key */
    1413             :         }
    1414             : 
    1415           0 :         lua_pushvalue(L, -1); /* table key key */
    1416             : 
    1417             :         dd("regex cache key: %.*s", (int) (pat.len + sizeof(re_comp.options)),
    1418             :            lua_tostring(L, -1));
    1419             : 
    1420           0 :         lua_rawget(L, -3); /* table key re */
    1421           0 :         re = lua_touserdata(L, -1);
    1422             : 
    1423           0 :         lua_pop(L, 1); /* table key */
    1424             : 
    1425           0 :         if (re) {
    1426           0 :             ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
    1427             :                            "lua regex cache hit for sub regex \"%s\" with "
    1428             :                            "options \"%s\" and replace \"%s\"",
    1429             :                            pat.data, opts.data,
    1430             :                            func ? (u_char *) "<func>" : tpl.data);
    1431             : 
    1432           0 :             lua_pop(L, 2);
    1433             : 
    1434             :             dd("restoring regex %p, ncaptures %d,  captures %p", re->regex,
    1435             :                re->ncaptures, re->captures);
    1436             : 
    1437           0 :             re_comp.regex = re->regex;
    1438           0 :             sd = re->regex_sd;
    1439           0 :             re_comp.captures = re->ncaptures;
    1440           0 :             cap = re->captures;
    1441           0 :             ctpl = re->replace;
    1442             : 
    1443           0 :             if (flags & NGX_LUA_RE_MODE_DFA) {
    1444           0 :                 ovecsize = 2;
    1445             : 
    1446             :             } else {
    1447           0 :                 ovecsize = (re->ncaptures + 1) * 3;
    1448             :             }
    1449             : 
    1450           0 :             goto exec;
    1451             :         }
    1452             : 
    1453           0 :         ngx_log_debug4(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
    1454             :                        "lua regex cache miss for %ssub regex \"%s\" with "
    1455             :                        "options \"%s\" and replace \"%s\"",
    1456             :                        global ? "g" : "", pat.data, opts.data,
    1457             :                        func ? (u_char *) "<func>" : tpl.data);
    1458             : 
    1459           0 :         if (lmcf->regex_cache_entries >= lmcf->regex_cache_max_entries) {
    1460             : 
    1461           0 :             if (lmcf->regex_cache_entries == lmcf->regex_cache_max_entries) {
    1462           0 :                 ngx_log_error(NGX_LOG_WARN, r->connection->log, 0,
    1463             :                               "lua exceeding regex cache max entries (%i)",
    1464             :                               lmcf->regex_cache_max_entries);
    1465             : 
    1466           0 :                 lmcf->regex_cache_entries++;
    1467             :             }
    1468             : 
    1469           0 :             pool = r->pool;
    1470           0 :             flags &= ~NGX_LUA_RE_COMPILE_ONCE;
    1471             :         }
    1472             : 
    1473             :     } else {
    1474           0 :         pool = r->pool;
    1475             :     }
    1476             : 
    1477           0 :     re_comp.pattern = pat;
    1478           0 :     re_comp.err.len = NGX_MAX_CONF_ERRSTR;
    1479           0 :     re_comp.err.data = errstr;
    1480           0 :     re_comp.pool = pool;
    1481             : 
    1482             :     dd("compiling regex");
    1483             : 
    1484           0 :     ngx_log_debug6(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
    1485             :                    "lua compiling %ssub regex \"%s\" with options \"%s\" "
    1486             :                    "(compile once: %d) (dfa mode: %d) (jit mode: %d)",
    1487             :                    global ? "g" : "", pat.data, opts.data,
    1488             :                    (flags & NGX_LUA_RE_COMPILE_ONCE) != 0,
    1489             :                    (flags & NGX_LUA_RE_MODE_DFA) != 0,
    1490             :                    (flags & NGX_LUA_RE_MODE_JIT) != 0);
    1491             : 
    1492           0 :     old_pool = ngx_http_lua_pcre_malloc_init(pool);
    1493             : 
    1494           0 :     rc = ngx_http_lua_regex_compile(&re_comp);
    1495             : 
    1496           0 :     ngx_http_lua_pcre_malloc_done(old_pool);
    1497             : 
    1498           0 :     if (rc != NGX_OK) {
    1499             :         dd("compile failed");
    1500             : 
    1501           0 :         lua_pushnil(L);
    1502           0 :         lua_pushnil(L);
    1503           0 :         lua_pushlstring(L, (char *) re_comp.err.data, re_comp.err.len);
    1504           0 :         return 3;
    1505             :     }
    1506             : 
    1507             : #if LUA_HAVE_PCRE_JIT
    1508             : 
    1509           0 :     if (flags & NGX_LUA_RE_MODE_JIT) {
    1510             : 
    1511           0 :         old_pool = ngx_http_lua_pcre_malloc_init(pool);
    1512             : 
    1513           0 :         sd = pcre_study(re_comp.regex, PCRE_STUDY_JIT_COMPILE, &msg);
    1514             : 
    1515           0 :         ngx_http_lua_pcre_malloc_done(old_pool);
    1516             : 
    1517             : #   if (NGX_DEBUG)
    1518             :         dd("sd = %p", sd);
    1519             : 
    1520           0 :         if (msg != NULL) {
    1521           0 :             ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
    1522             :                            "pcre study failed with PCRE_STUDY_JIT_COMPILE: "
    1523             :                            "%s (%p)", msg, sd);
    1524             :         }
    1525             : 
    1526           0 :         if (sd != NULL) {
    1527             :             int         jitted;
    1528             : 
    1529           0 :             old_pool = ngx_http_lua_pcre_malloc_init(pool);
    1530             : 
    1531           0 :             pcre_fullinfo(re_comp.regex, sd, PCRE_INFO_JIT, &jitted);
    1532             : 
    1533           0 :             ngx_http_lua_pcre_malloc_done(old_pool);
    1534             : 
    1535           0 :             ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
    1536             :                            "pcre JIT compiling result: %d", jitted);
    1537             :         }
    1538             : #   endif /* NGX_DEBUG */
    1539             : 
    1540             :     } else {
    1541             : 
    1542           0 :         old_pool = ngx_http_lua_pcre_malloc_init(pool);
    1543             : 
    1544           0 :         sd = pcre_study(re_comp.regex, 0, &msg);
    1545             : 
    1546           0 :         ngx_http_lua_pcre_malloc_done(old_pool);
    1547             : 
    1548             : #   if (NGX_DEBUG)
    1549             :         dd("sd = %p", sd);
    1550             : 
    1551           0 :         if (msg != NULL) {
    1552           0 :             ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
    1553             :                            "pcre_study failed with PCRE_STUDY_JIT_COMPILE: "
    1554             :                            "%s (%p)", msg, sd);
    1555             :         }
    1556             : #   endif /* NGX_DEBUG */
    1557             :     }
    1558             : 
    1559             : #else  /* LUA_HAVE_PCRE_JIT */
    1560             : 
    1561             :     if (flags & NGX_LUA_RE_MODE_JIT) {
    1562             :         ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
    1563             :                        "your pcre build does not have JIT support and "
    1564             :                        "the \"j\" regex option is ignored");
    1565             :     }
    1566             : 
    1567             : #endif /* LUA_HAVE_PCRE_JIT */
    1568             : 
    1569           0 :     if (sd && lmcf->regex_match_limit > 0) {
    1570           0 :         sd->flags |= PCRE_EXTRA_MATCH_LIMIT;
    1571           0 :         sd->match_limit = lmcf->regex_match_limit;
    1572             :     }
    1573             : 
    1574             :     dd("compile done, captures %d", re_comp.captures);
    1575             : 
    1576           0 :     if (flags & NGX_LUA_RE_MODE_DFA) {
    1577           0 :         ovecsize = 2;
    1578           0 :         re_comp.captures = 0;
    1579             : 
    1580             :     } else {
    1581           0 :         ovecsize = (re_comp.captures + 1) * 3;
    1582             :     }
    1583             : 
    1584           0 :     cap = ngx_palloc(pool, ovecsize * sizeof(int));
    1585           0 :     if (cap == NULL) {
    1586           0 :         flags &= ~NGX_LUA_RE_COMPILE_ONCE;
    1587           0 :         msg = "no memory";
    1588           0 :         goto error;
    1589             :     }
    1590             : 
    1591           0 :     if (func) {
    1592           0 :         ctpl = NULL;
    1593             : 
    1594             :     } else {
    1595           0 :         ctpl = ngx_palloc(pool, sizeof(ngx_http_lua_complex_value_t));
    1596           0 :         if (ctpl == NULL) {
    1597           0 :             flags &= ~NGX_LUA_RE_COMPILE_ONCE;
    1598           0 :             msg = "no memory";
    1599           0 :             goto error;
    1600             :         }
    1601             : 
    1602           0 :         if ((flags & NGX_LUA_RE_COMPILE_ONCE) && tpl.len != 0) {
    1603             :             /* copy the string buffer pointed to by tpl.data from Lua VM */
    1604           0 :             p = ngx_palloc(pool, tpl.len + 1);
    1605           0 :             if (p == NULL) {
    1606           0 :                 flags &= ~NGX_LUA_RE_COMPILE_ONCE;
    1607           0 :                 msg = "no memory";
    1608           0 :                 goto error;
    1609             :             }
    1610             : 
    1611           0 :             ngx_memcpy(p, tpl.data, tpl.len);
    1612           0 :             p[tpl.len] = '\0';
    1613             : 
    1614           0 :             tpl.data = p;
    1615             :         }
    1616             : 
    1617           0 :         ngx_memzero(&ccv, sizeof(ngx_http_lua_compile_complex_value_t));
    1618           0 :         ccv.pool = pool;
    1619           0 :         ccv.log = r->connection->log;
    1620           0 :         ccv.value = &tpl;
    1621           0 :         ccv.complex_value = ctpl;
    1622             : 
    1623           0 :         if (ngx_http_lua_compile_complex_value(&ccv) != NGX_OK) {
    1624           0 :             ngx_pfree(pool, cap);
    1625           0 :             ngx_pfree(pool, ctpl);
    1626             : 
    1627           0 :             if ((flags & NGX_LUA_RE_COMPILE_ONCE) && tpl.len != 0) {
    1628           0 :                 ngx_pfree(pool, tpl.data);
    1629             :             }
    1630             : 
    1631           0 :             if (sd) {
    1632           0 :                 ngx_http_lua_regex_free_study_data(pool, sd);
    1633             :             }
    1634             : 
    1635           0 :             ngx_pfree(pool, re_comp.regex);
    1636             : 
    1637           0 :             lua_pushnil(L);
    1638           0 :             lua_pushnil(L);
    1639           0 :             lua_pushliteral(L, "failed to compile the replacement template");
    1640           0 :             return 3;
    1641             :         }
    1642             :     }
    1643             : 
    1644           0 :     if (flags & NGX_LUA_RE_COMPILE_ONCE) {
    1645             : 
    1646           0 :         ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
    1647             :                        "lua saving compiled sub regex (%d captures) into "
    1648             :                        "the cache (entries %i)", re_comp.captures,
    1649             :                        lmcf->regex_cache_entries);
    1650             : 
    1651           0 :         re = ngx_palloc(pool, sizeof(ngx_http_lua_regex_t));
    1652           0 :         if (re == NULL) {
    1653           0 :             msg = "no memory";
    1654           0 :             goto error;
    1655             :         }
    1656             : 
    1657             :         dd("saving regex %p, ncaptures %d,  captures %p", re_comp.regex,
    1658             :            re_comp.captures, cap);
    1659             : 
    1660           0 :         re->regex = re_comp.regex;
    1661           0 :         re->regex_sd = sd;
    1662           0 :         re->ncaptures = re_comp.captures;
    1663           0 :         re->captures = cap;
    1664           0 :         re->replace = ctpl;
    1665             : 
    1666           0 :         lua_pushlightuserdata(L, re); /* table key value */
    1667           0 :         lua_rawset(L, -3); /* table */
    1668           0 :         lua_pop(L, 1);
    1669             : 
    1670           0 :         if (lmcf) {
    1671           0 :             lmcf->regex_cache_entries++;
    1672             :         }
    1673             :     }
    1674             : 
    1675           0 : exec:
    1676             : 
    1677           0 :     count = 0;
    1678           0 :     offset = 0;
    1679           0 :     cp_offset = 0;
    1680             : 
    1681           0 :     if (pcre_fullinfo(re_comp.regex, NULL, PCRE_INFO_NAMECOUNT,
    1682             :                       &name_count) != 0)
    1683             :     {
    1684           0 :         msg = "cannot acquire named subpattern count";
    1685           0 :         goto error;
    1686             :     }
    1687             : 
    1688           0 :     if (name_count > 0) {
    1689           0 :         if (pcre_fullinfo(re_comp.regex, NULL, PCRE_INFO_NAMEENTRYSIZE,
    1690             :                           &name_entry_size) != 0)
    1691             :         {
    1692           0 :             msg = "cannot acquire named subpattern entry size";
    1693           0 :             goto error;
    1694             :         }
    1695             : 
    1696           0 :         if (pcre_fullinfo(re_comp.regex, NULL, PCRE_INFO_NAMETABLE,
    1697             :                           &name_table) != 0)
    1698             :         {
    1699           0 :             msg = "cannot acquire named subpattern table";
    1700           0 :             goto error;
    1701             :         }
    1702             :     }
    1703             : 
    1704           0 :     if (flags & NGX_LUA_RE_NO_UTF8_CHECK) {
    1705           0 :         exec_opts = PCRE_NO_UTF8_CHECK;
    1706             : 
    1707             :     } else {
    1708           0 :         exec_opts = 0;
    1709             :     }
    1710             : 
    1711             :     for (;;) {
    1712           0 :         if (flags & NGX_LUA_RE_MODE_DFA) {
    1713             : 
    1714             : #if LUA_HAVE_PCRE_DFA
    1715             : 
    1716             :             int ws[NGX_LUA_RE_DFA_MODE_WORKSPACE_COUNT];
    1717           0 :             rc = ngx_http_lua_regex_dfa_exec(re_comp.regex, sd, &subj,
    1718             :                                              offset, cap, ovecsize, ws,
    1719             :                                              sizeof(ws)/sizeof(ws[0]),
    1720             :                                              exec_opts);
    1721             : 
    1722             : #else /* LUA_HAVE_PCRE_DFA */
    1723             : 
    1724             :             msg = "at least pcre 6.0 is required for the DFA mode";
    1725             :             goto error;
    1726             : 
    1727             : #endif /* LUA_HAVE_PCRE_DFA */
    1728             : 
    1729             :         } else {
    1730           0 :             rc = ngx_http_lua_regex_exec(re_comp.regex, sd, &subj, offset, cap,
    1731             :                                          ovecsize, exec_opts);
    1732             :         }
    1733             : 
    1734           0 :         if (rc == NGX_REGEX_NO_MATCHED) {
    1735           0 :             break;
    1736             :         }
    1737             : 
    1738           0 :         if (rc < 0) {
    1739           0 :             msg = lua_pushfstring(L, ngx_regex_exec_n " failed: %d",
    1740             :                                   (int) rc);
    1741           0 :             goto error;
    1742             :         }
    1743             : 
    1744           0 :         if (rc == 0) {
    1745           0 :             if (flags & NGX_LUA_RE_MODE_DFA) {
    1746           0 :                 rc = 1;
    1747             : 
    1748             :             } else {
    1749           0 :                 msg = "capture size too small";
    1750           0 :                 goto error;
    1751             :             }
    1752             :         }
    1753             : 
    1754             :         dd("rc = %d", (int) rc);
    1755             : 
    1756           0 :         count++;
    1757             : 
    1758           0 :         if (count == 1) {
    1759           0 :             luaL_buffinit(L, &luabuf);
    1760             :         }
    1761             : 
    1762           0 :         if (func) {
    1763           0 :             lua_pushvalue(L, 3);
    1764             : 
    1765           0 :             lua_createtable(L, re_comp.captures || 1 /* narr */,
    1766             :                             name_count /* nrec */);
    1767             : 
    1768           0 :             for (i = 0, n = 0; i <= re_comp.captures; i++, n += 2) {
    1769             :                 dd("capture %d: %d %d", (int) i, cap[n], cap[n + 1]);
    1770           0 :                 if (i >= rc || cap[n] < 0) {
    1771           0 :                     lua_pushboolean(L, 0);
    1772             : 
    1773             :                 } else {
    1774           0 :                     lua_pushlstring(L, (char *) &subj.data[cap[n]],
    1775           0 :                                     cap[n + 1] - cap[n]);
    1776             : 
    1777             :                     dd("pushing capture %s at %d", lua_tostring(L, -1),
    1778             :                        (int) i);
    1779             :                 }
    1780             : 
    1781           0 :                 lua_rawseti(L, -2, (int) i);
    1782             :             }
    1783             : 
    1784           0 :             if (name_count > 0) {
    1785           0 :                 ngx_http_lua_re_collect_named_captures(L, lua_gettop(L),
    1786             :                                                        name_table,
    1787             :                                                        name_count,
    1788             :                                                        name_entry_size,
    1789             :                                                        flags, &subj);
    1790             :             }
    1791             : 
    1792             :             dd("stack size at call: %d", lua_gettop(L));
    1793             : 
    1794           0 :             lua_call(L, 1 /* nargs */, 1 /* nresults */);
    1795           0 :             type = lua_type(L, -1);
    1796           0 :             switch (type) {
    1797           0 :                 case LUA_TNUMBER:
    1798             :                 case LUA_TSTRING:
    1799           0 :                     tpl.data = (u_char *) lua_tolstring(L, -1, &tpl.len);
    1800           0 :                     break;
    1801             : 
    1802           0 :                 default:
    1803           0 :                     msg = lua_pushfstring(L, "string or number expected to be "
    1804             :                                           "returned by the replace "
    1805             :                                           "function, got %s",
    1806             :                                           lua_typename(L, type));
    1807           0 :                     return luaL_argerror(L, 3, msg);
    1808             :             }
    1809             : 
    1810           0 :             lua_insert(L, 1);
    1811             : 
    1812           0 :             luaL_addlstring(&luabuf, (char *) &subj.data[cp_offset],
    1813           0 :                             cap[0] - cp_offset);
    1814             : 
    1815           0 :             luaL_addlstring(&luabuf, (char *) tpl.data, tpl.len);
    1816             : 
    1817           0 :             lua_remove(L, 1);
    1818             : 
    1819           0 :             cp_offset = cap[1];
    1820           0 :             offset = cp_offset;
    1821           0 :             if (offset == cap[0]) {
    1822           0 :                 offset++;
    1823           0 :                 if (offset > (ssize_t) subj.len) {
    1824           0 :                     break;
    1825             :                 }
    1826             :             }
    1827             : 
    1828           0 :             if (global) {
    1829           0 :                 continue;
    1830             :             }
    1831             : 
    1832           0 :             break;
    1833             :         }
    1834             : 
    1835           0 :         rc = ngx_http_lua_complex_value(r, &subj, cp_offset, rc, cap, ctpl,
    1836             :                                         &luabuf);
    1837             : 
    1838           0 :         if (rc != NGX_OK) {
    1839           0 :             msg = lua_pushfstring(L, "failed to eval the template for "
    1840             :                                   "replacement: \"%s\"", tpl.data);
    1841           0 :             goto error;
    1842             :         }
    1843             : 
    1844           0 :         cp_offset = cap[1];
    1845           0 :         offset = cp_offset;
    1846           0 :         if (offset == cap[0]) {
    1847           0 :             offset++;
    1848           0 :             if (offset > (ssize_t) subj.len) {
    1849           0 :                 break;
    1850             :             }
    1851             :         }
    1852             : 
    1853           0 :         if (global) {
    1854           0 :             continue;
    1855             :         }
    1856             : 
    1857           0 :         break;
    1858             :     }
    1859             : 
    1860           0 :     if (count == 0) {
    1861             :         dd("no match, just the original subject");
    1862           0 :         lua_settop(L, 1);
    1863             : 
    1864             :     } else {
    1865           0 :         if (offset < (int) subj.len) {
    1866             :             dd("adding trailer: %s (len %d)", &subj.data[cp_offset],
    1867             :                (int) (subj.len - cp_offset));
    1868             : 
    1869             : 
    1870           0 :             luaL_addlstring(&luabuf, (char *) &subj.data[cp_offset],
    1871           0 :                             subj.len - cp_offset);
    1872             :         }
    1873             : 
    1874           0 :         luaL_pushresult(&luabuf);
    1875             : 
    1876             :         dd("the dst string: %s", lua_tostring(L, -1));
    1877             :     }
    1878             : 
    1879           0 :     if (!(flags & NGX_LUA_RE_COMPILE_ONCE)) {
    1880           0 :         if (sd) {
    1881           0 :             ngx_http_lua_regex_free_study_data(pool, sd);
    1882             :         }
    1883             : 
    1884           0 :         if (re_comp.regex) {
    1885           0 :             ngx_pfree(pool, re_comp.regex);
    1886             :         }
    1887             : 
    1888           0 :         if (ctpl) {
    1889           0 :             ngx_pfree(pool, ctpl);
    1890             :         }
    1891             : 
    1892           0 :         if (cap) {
    1893           0 :             ngx_pfree(pool, cap);
    1894             :         }
    1895             :     }
    1896             : 
    1897           0 :     lua_pushinteger(L, count);
    1898           0 :     return 2;
    1899             : 
    1900           0 : error:
    1901             : 
    1902           0 :     if (!(flags & NGX_LUA_RE_COMPILE_ONCE)) {
    1903           0 :         if (sd) {
    1904           0 :             ngx_http_lua_regex_free_study_data(pool, sd);
    1905             :         }
    1906             : 
    1907           0 :         if (re_comp.regex) {
    1908           0 :             ngx_pfree(pool, re_comp.regex);
    1909             :         }
    1910             : 
    1911           0 :         if (ctpl) {
    1912           0 :             ngx_pfree(pool, ctpl);
    1913             :         }
    1914             : 
    1915           0 :         if (cap) {
    1916           0 :             ngx_pfree(pool, cap);
    1917             :         }
    1918             :     }
    1919             : 
    1920           0 :     lua_pushnil(L);
    1921           0 :     lua_pushnil(L);
    1922           0 :     lua_pushstring(L, msg);
    1923           0 :     return 3;
    1924             : }
    1925             : 
    1926             : 
    1927             : ngx_int_t
    1928           0 : ngx_http_lua_ffi_set_jit_stack_size(int size, u_char *errstr,
    1929             :     size_t *errstr_size)
    1930             : {
    1931             : #if LUA_HAVE_PCRE_JIT
    1932             : 
    1933             :     ngx_http_lua_main_conf_t    *lmcf;
    1934             :     ngx_pool_t                  *pool, *old_pool;
    1935             : 
    1936           0 :     lmcf = ngx_http_cycle_get_module_main_conf(ngx_cycle,
    1937             :                                                ngx_http_lua_module);
    1938             : 
    1939           0 :     if (size < NGX_LUA_RE_MIN_JIT_STACK_SIZE) {
    1940           0 :         size = NGX_LUA_RE_MIN_JIT_STACK_SIZE;
    1941             :     }
    1942             : 
    1943           0 :     pool = lmcf->pool;
    1944             : 
    1945             :     dd("server pool %p", lmcf->pool);
    1946             : 
    1947           0 :     if (lmcf->jit_stack) {
    1948           0 :         old_pool = ngx_http_lua_pcre_malloc_init(pool);
    1949             : 
    1950           0 :         pcre_jit_stack_free(lmcf->jit_stack);
    1951             : 
    1952           0 :         ngx_http_lua_pcre_malloc_done(old_pool);
    1953             :     }
    1954             : 
    1955           0 :     old_pool = ngx_http_lua_pcre_malloc_init(pool);
    1956             : 
    1957           0 :     lmcf->jit_stack = pcre_jit_stack_alloc(NGX_LUA_RE_MIN_JIT_STACK_SIZE,
    1958             :                                            size);
    1959             : 
    1960           0 :     ngx_http_lua_pcre_malloc_done(old_pool);
    1961             : 
    1962           0 :     if (lmcf->jit_stack == NULL) {
    1963           0 :         *errstr_size = ngx_snprintf(errstr, *errstr_size,
    1964             :                                     "pcre jit stack allocation failed")
    1965           0 :                        - errstr;
    1966           0 :         return NGX_ERROR;
    1967             :     }
    1968             : 
    1969           0 :     return NGX_OK;
    1970             : 
    1971             : #else  /* LUA_HAVE_PCRE_JIT */
    1972             : 
    1973             :     *errstr_size = ngx_snprintf(errstr, *errstr_size,
    1974             :                                 "no pcre jit support found") - errstr;
    1975             :     return NGX_ERROR;
    1976             : 
    1977             : #endif /* LUA_HAVE_PCRE_JIT */
    1978             : }
    1979             : 
    1980             : 
    1981             : void
    1982          18 : ngx_http_lua_inject_regex_api(lua_State *L)
    1983             : {
    1984             :     /* ngx.re */
    1985             : 
    1986          18 :     lua_createtable(L, 0, 5 /* nrec */);    /* .re */
    1987             : 
    1988          18 :     lua_pushcfunction(L, ngx_http_lua_ngx_re_find);
    1989          18 :     lua_setfield(L, -2, "find");
    1990             : 
    1991          18 :     lua_pushcfunction(L, ngx_http_lua_ngx_re_match);
    1992          18 :     lua_setfield(L, -2, "match");
    1993             : 
    1994          18 :     lua_pushcfunction(L, ngx_http_lua_ngx_re_gmatch);
    1995          18 :     lua_setfield(L, -2, "gmatch");
    1996             : 
    1997          18 :     lua_pushcfunction(L, ngx_http_lua_ngx_re_sub);
    1998          18 :     lua_setfield(L, -2, "sub");
    1999             : 
    2000          18 :     lua_pushcfunction(L, ngx_http_lua_ngx_re_gsub);
    2001          18 :     lua_setfield(L, -2, "gsub");
    2002             : 
    2003          18 :     lua_setfield(L, -2, "re");
    2004          18 : }
    2005             : 
    2006             : 
    2007             : static void
    2008           0 : ngx_http_lua_regex_free_study_data(ngx_pool_t *pool, pcre_extra *sd)
    2009             : {
    2010             :     ngx_pool_t              *old_pool;
    2011             : 
    2012           0 :     old_pool = ngx_http_lua_pcre_malloc_init(pool);
    2013             : 
    2014             : #if LUA_HAVE_PCRE_JIT
    2015           0 :     pcre_free_study(sd);
    2016             : #else
    2017             :     pcre_free(sd);
    2018             : #endif
    2019             : 
    2020           0 :     ngx_http_lua_pcre_malloc_done(old_pool);
    2021           0 : }
    2022             : 
    2023             : 
    2024             : static ngx_int_t
    2025           0 : ngx_http_lua_regex_compile(ngx_http_lua_regex_compile_t *rc)
    2026             : {
    2027             :     int           n, erroff;
    2028             :     char         *p;
    2029             :     const char   *errstr;
    2030             :     pcre         *re;
    2031             :     ngx_pool_t   *old_pool;
    2032             : 
    2033           0 :     old_pool = ngx_http_lua_pcre_malloc_init(rc->pool);
    2034             : 
    2035           0 :     re = pcre_compile((const char *) rc->pattern.data, (int) rc->options,
    2036             :                       &errstr, &erroff, NULL);
    2037             : 
    2038           0 :     ngx_http_lua_pcre_malloc_done(old_pool);
    2039             : 
    2040           0 :     if (re == NULL) {
    2041           0 :         if ((size_t) erroff == rc->pattern.len) {
    2042           0 :             rc->err.len = ngx_snprintf(rc->err.data, rc->err.len,
    2043             :                                        "pcre_compile() failed: %s in \"%V\"",
    2044             :                                       errstr, &rc->pattern)
    2045           0 :                          - rc->err.data;
    2046             : 
    2047             :         } else {
    2048           0 :             rc->err.len = ngx_snprintf(rc->err.data, rc->err.len,
    2049             :                                        "pcre_compile() failed: %s in \"%V\" "
    2050             :                                        "at \"%s\"", errstr, &rc->pattern,
    2051           0 :                                        rc->pattern.data + erroff)
    2052           0 :                          - rc->err.data;
    2053             :         }
    2054             : 
    2055           0 :         return NGX_ERROR;
    2056             :     }
    2057             : 
    2058           0 :     rc->regex = re;
    2059             : 
    2060             : #if 1
    2061           0 :     n = pcre_fullinfo(re, NULL, PCRE_INFO_CAPTURECOUNT, &rc->captures);
    2062           0 :     if (n < 0) {
    2063           0 :         p = "pcre_fullinfo(\"%V\", PCRE_INFO_CAPTURECOUNT) failed: %d";
    2064           0 :         goto failed;
    2065             :     }
    2066             : #endif
    2067             : 
    2068           0 :     return NGX_OK;
    2069             : 
    2070           0 : failed:
    2071             : 
    2072           0 :     rc->err.len = ngx_snprintf(rc->err.data, rc->err.len, p, &rc->pattern, n)
    2073           0 :                   - rc->err.data;
    2074           0 :     return NGX_OK;
    2075             : }
    2076             : 
    2077             : 
    2078             : static void
    2079           0 : ngx_http_lua_ngx_re_gmatch_cleanup(void *data)
    2080             : {
    2081           0 :     ngx_http_lua_regex_ctx_t    *ctx = data;
    2082             : 
    2083           0 :     if (ctx) {
    2084           0 :         if (ctx->regex_sd) {
    2085           0 :             ngx_http_lua_regex_free_study_data(ctx->request->pool,
    2086             :                                                ctx->regex_sd);
    2087           0 :             ctx->regex_sd = NULL;
    2088             :         }
    2089             : 
    2090           0 :         if (ctx->cleanup) {
    2091           0 :             *ctx->cleanup = NULL;
    2092           0 :             ctx->cleanup = NULL;
    2093             :         }
    2094             : 
    2095           0 :         ctx->request = NULL;
    2096             :     }
    2097             : 
    2098           0 :     return;
    2099             : }
    2100             : 
    2101             : 
    2102             : static int
    2103           0 : ngx_http_lua_ngx_re_gmatch_gc(lua_State *L)
    2104             : {
    2105             :     ngx_http_lua_regex_ctx_t    *ctx;
    2106             : 
    2107           0 :     ctx = lua_touserdata(L, 1);
    2108             : 
    2109           0 :     if (ctx && ctx->cleanup) {
    2110           0 :         ngx_http_lua_ngx_re_gmatch_cleanup(ctx);
    2111             :     }
    2112             : 
    2113           0 :     return 0;
    2114             : }
    2115             : 
    2116             : 
    2117             : static void
    2118           0 : ngx_http_lua_re_collect_named_captures(lua_State *L, int res_tb_idx,
    2119             :     u_char *name_table, int name_count, int name_entry_size, unsigned flags,
    2120             :     ngx_str_t *subj)
    2121             : {
    2122             :     int              i, n;
    2123             :     size_t           len;
    2124             :     u_char          *name_entry;
    2125             :     char            *name;
    2126             : 
    2127           0 :     for (i = 0; i < name_count; i++) {
    2128             :         dd("top: %d", lua_gettop(L));
    2129             : 
    2130           0 :         name_entry = &name_table[i * name_entry_size];
    2131           0 :         n = (name_entry[0] << 8) | name_entry[1];
    2132           0 :         name = (char *) &name_entry[2];
    2133             : 
    2134           0 :         lua_rawgeti(L, -1, n);
    2135           0 :         if (lua_isnil(L, -1)) {
    2136           0 :             lua_pop(L, 1);
    2137           0 :             continue;
    2138             :         }
    2139             : 
    2140           0 :         if (flags & NGX_LUA_RE_MODE_DUPNAMES) {
    2141             :             /* unmatched groups are not stored in tables in DUPNAMES mode */
    2142           0 :             if (!lua_toboolean(L, -1)) {
    2143           0 :                 lua_pop(L, 1);
    2144           0 :                 continue;
    2145             :             }
    2146             : 
    2147           0 :             lua_getfield(L, -2, name); /* big_tb cap small_tb */
    2148             : 
    2149           0 :             if (lua_isnil(L, -1)) {
    2150           0 :                 lua_pop(L, 1);
    2151             : 
    2152             :                 /* assuming named submatches are usually unique */
    2153           0 :                 lua_createtable(L, 1 /* narr */, 0 /* nrec */);
    2154           0 :                 lua_pushstring(L, name);
    2155           0 :                 lua_pushvalue(L, -2); /* big_tb cap small_tb key small_tb */
    2156           0 :                 lua_rawset(L, res_tb_idx); /* big_tb cap small_tb */
    2157           0 :                 len = 0;
    2158             : 
    2159             :             } else {
    2160           0 :                 len = lua_objlen(L, -1);
    2161             :             }
    2162             : 
    2163           0 :             lua_pushvalue(L, -2); /* big_tb cap small_tb cap */
    2164           0 :             lua_rawseti(L, -2, (int) len + 1); /* big_tb cap small_tb */
    2165           0 :             lua_pop(L, 2);
    2166             : 
    2167             :         } else {
    2168           0 :             lua_pushstring(L, name); /* big_tb cap key */
    2169           0 :             lua_pushvalue(L, -2); /* big_tb cap key cap */
    2170           0 :             lua_rawset(L, res_tb_idx); /* big_tb cap */
    2171           0 :             lua_pop(L, 1);
    2172             :         }
    2173             : 
    2174             :         dd("top 2: %d", lua_gettop(L));
    2175             :     }
    2176           0 : }
    2177             : 
    2178             : 
    2179             : #ifndef NGX_LUA_NO_FFI_API
    2180             : ngx_http_lua_regex_t *
    2181           0 : ngx_http_lua_ffi_compile_regex(const unsigned char *pat, size_t pat_len,
    2182             :     int flags, int pcre_opts, u_char *errstr,
    2183             :     size_t errstr_size)
    2184             : {
    2185           0 :     int                     *cap = NULL, ovecsize;
    2186             :     u_char                  *p;
    2187             :     ngx_int_t                rc;
    2188             :     const char              *msg;
    2189             :     ngx_pool_t              *pool, *old_pool;
    2190           0 :     pcre_extra              *sd = NULL;
    2191             :     ngx_http_lua_regex_t    *re;
    2192             : 
    2193             :     ngx_http_lua_main_conf_t         *lmcf;
    2194             :     ngx_http_lua_regex_compile_t      re_comp;
    2195             : 
    2196           0 :     pool = ngx_create_pool(512, ngx_cycle->log);
    2197           0 :     if (pool == NULL) {
    2198           0 :         msg = "no memory";
    2199           0 :         goto error;
    2200             :     }
    2201             : 
    2202           0 :     re = ngx_palloc(pool, sizeof(ngx_http_lua_regex_t));
    2203           0 :     if (re == NULL) {
    2204           0 :         ngx_destroy_pool(pool);
    2205           0 :         pool = NULL;
    2206           0 :         msg = "no memory";
    2207           0 :         goto error;
    2208             :     }
    2209             : 
    2210           0 :     re->pool = pool;
    2211             : 
    2212           0 :     re_comp.options      = pcre_opts;
    2213           0 :     re_comp.pattern.data = (u_char *) pat;
    2214           0 :     re_comp.pattern.len  = pat_len;
    2215           0 :     re_comp.err.len      = errstr_size - 1;
    2216           0 :     re_comp.err.data     = errstr;
    2217           0 :     re_comp.pool         = pool;
    2218             : 
    2219           0 :     old_pool = ngx_http_lua_pcre_malloc_init(pool);
    2220           0 :     rc = ngx_http_lua_regex_compile(&re_comp);
    2221           0 :     ngx_http_lua_pcre_malloc_done(old_pool);
    2222             : 
    2223           0 :     if (rc != NGX_OK) {
    2224           0 :         re_comp.err.data[re_comp.err.len] = '\0';
    2225           0 :         msg = (char *) re_comp.err.data;
    2226           0 :         goto error;
    2227             :     }
    2228             : 
    2229           0 :     lmcf = ngx_http_cycle_get_module_main_conf(ngx_cycle,
    2230             :                                                ngx_http_lua_module);
    2231             : 
    2232             : #if (LUA_HAVE_PCRE_JIT)
    2233             : 
    2234           0 :     if (flags & NGX_LUA_RE_MODE_JIT) {
    2235             : 
    2236           0 :         old_pool = ngx_http_lua_pcre_malloc_init(pool);
    2237           0 :         sd = pcre_study(re_comp.regex, PCRE_STUDY_JIT_COMPILE, &msg);
    2238           0 :         ngx_http_lua_pcre_malloc_done(old_pool);
    2239             : 
    2240             : #   if (NGX_DEBUG)
    2241           0 :         if (msg != NULL) {
    2242           0 :             ngx_log_debug2(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0,
    2243             :                            "pcre study failed with PCRE_STUDY_JIT_COMPILE: "
    2244             :                            "%s (%p)", msg, sd);
    2245             :         }
    2246             : 
    2247           0 :         if (sd != NULL) {
    2248             :             int         jitted;
    2249             : 
    2250           0 :             old_pool = ngx_http_lua_pcre_malloc_init(pool);
    2251             : 
    2252           0 :             pcre_fullinfo(re_comp.regex, sd, PCRE_INFO_JIT, &jitted);
    2253             : 
    2254           0 :             ngx_http_lua_pcre_malloc_done(old_pool);
    2255             : 
    2256           0 :             ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0,
    2257             :                            "pcre JIT compiling result: %d", jitted);
    2258             :         }
    2259             : #   endif /* !(NGX_DEBUG) */
    2260             : 
    2261             :     } else {
    2262           0 :         old_pool = ngx_http_lua_pcre_malloc_init(pool);
    2263           0 :         sd = pcre_study(re_comp.regex, 0, &msg);
    2264           0 :         ngx_http_lua_pcre_malloc_done(old_pool);
    2265             :     }
    2266             : 
    2267           0 :     if (sd && lmcf->jit_stack) {
    2268           0 :         pcre_assign_jit_stack(sd, NULL, lmcf->jit_stack);
    2269             :     }
    2270             : 
    2271             : #endif /* LUA_HAVE_PCRE_JIT */
    2272             : 
    2273           0 :     if (sd && lmcf && lmcf->regex_match_limit > 0) {
    2274           0 :         sd->flags |= PCRE_EXTRA_MATCH_LIMIT;
    2275           0 :         sd->match_limit = lmcf->regex_match_limit;
    2276             :     }
    2277             : 
    2278           0 :     if (flags & NGX_LUA_RE_MODE_DFA) {
    2279           0 :         ovecsize = 2;
    2280           0 :         re_comp.captures = 0;
    2281             : 
    2282             :     } else {
    2283           0 :         ovecsize = (re_comp.captures + 1) * 3;
    2284             :     }
    2285             : 
    2286             :     dd("allocating cap with size: %d", (int) ovecsize);
    2287             : 
    2288           0 :     cap = ngx_palloc(pool, ovecsize * sizeof(int));
    2289           0 :     if (cap == NULL) {
    2290           0 :         msg = "no memory";
    2291           0 :         goto error;
    2292             :     }
    2293             : 
    2294           0 :     if (pcre_fullinfo(re_comp.regex, NULL, PCRE_INFO_NAMECOUNT,
    2295           0 :                       &re->name_count) != 0)
    2296             :     {
    2297           0 :         msg = "cannot acquire named subpattern count";
    2298           0 :         goto error;
    2299             :     }
    2300             : 
    2301           0 :     if (re->name_count > 0) {
    2302           0 :         if (pcre_fullinfo(re_comp.regex, NULL, PCRE_INFO_NAMEENTRYSIZE,
    2303           0 :                           &re->name_entry_size) != 0)
    2304             :         {
    2305           0 :             msg = "cannot acquire named subpattern entry size";
    2306           0 :             goto error;
    2307             :         }
    2308             : 
    2309           0 :         if (pcre_fullinfo(re_comp.regex, NULL, PCRE_INFO_NAMETABLE,
    2310           0 :                           &re->name_table) != 0)
    2311             :         {
    2312           0 :             msg = "cannot acquire named subpattern table";
    2313           0 :             goto error;
    2314             :         }
    2315             :     }
    2316             : 
    2317           0 :     re->regex = re_comp.regex;
    2318           0 :     re->regex_sd = sd;
    2319           0 :     re->ncaptures = re_comp.captures;
    2320           0 :     re->captures = cap;
    2321           0 :     re->replace = NULL;
    2322             : 
    2323             :     /* only for (stap) debugging, the pointer might be invalid when the
    2324             :      * string is collected later on.... */
    2325           0 :     re->pattern = pat;
    2326             : 
    2327           0 :     return re;
    2328             : 
    2329           0 : error:
    2330             : 
    2331           0 :     p = ngx_snprintf(errstr, errstr_size - 1, "%s", msg);
    2332           0 :     *p = '\0';
    2333             : 
    2334           0 :     if (sd) {
    2335           0 :         ngx_http_lua_regex_free_study_data(pool, sd);
    2336             :     }
    2337             : 
    2338           0 :     if (pool) {
    2339           0 :         ngx_destroy_pool(pool);
    2340             :     }
    2341             : 
    2342           0 :     return NULL;
    2343             : }
    2344             : 
    2345             : 
    2346             : int
    2347           0 : ngx_http_lua_ffi_exec_regex(ngx_http_lua_regex_t *re, int flags,
    2348             :     const u_char *s, size_t len, int pos)
    2349             : {
    2350             :     int             rc, ovecsize, exec_opts, *cap;
    2351             :     ngx_str_t       subj;
    2352             :     pcre_extra     *sd;
    2353             : 
    2354           0 :     cap = re->captures;
    2355           0 :     sd = re->regex_sd;
    2356             : 
    2357           0 :     if (flags & NGX_LUA_RE_MODE_DFA) {
    2358           0 :         ovecsize = 2;
    2359           0 :         re->ncaptures = 0;
    2360             : 
    2361             :     } else {
    2362           0 :         ovecsize = (re->ncaptures + 1) * 3;
    2363             :     }
    2364             : 
    2365           0 :     if (flags & NGX_LUA_RE_NO_UTF8_CHECK) {
    2366           0 :         exec_opts = PCRE_NO_UTF8_CHECK;
    2367             : 
    2368             :     } else {
    2369           0 :         exec_opts = 0;
    2370             :     }
    2371             : 
    2372           0 :     subj.data = (u_char *) s;
    2373           0 :     subj.len = len;
    2374             : 
    2375           0 :     if (flags & NGX_LUA_RE_MODE_DFA) {
    2376             : 
    2377             : #if LUA_HAVE_PCRE_DFA
    2378             : 
    2379             :         int ws[NGX_LUA_RE_DFA_MODE_WORKSPACE_COUNT];
    2380           0 :         rc = ngx_http_lua_regex_dfa_exec(re->regex, sd, &subj,
    2381             :                                          (int) pos, cap, ovecsize, ws,
    2382             :                                          sizeof(ws)/sizeof(ws[0]), exec_opts);
    2383             : 
    2384             : #else
    2385             : 
    2386             :         return PCRE_ERROR_BADOPTION;
    2387             : 
    2388             : #endif /* LUA_HAVE_PCRE_DFA */
    2389             : 
    2390             :     } else {
    2391           0 :         rc = ngx_http_lua_regex_exec(re->regex, sd, &subj, (int) pos, cap,
    2392             :                                      ovecsize, exec_opts);
    2393             :     }
    2394             : 
    2395           0 :     return rc;
    2396             : }
    2397             : 
    2398             : 
    2399             : void
    2400           0 : ngx_http_lua_ffi_destroy_regex(ngx_http_lua_regex_t *re)
    2401             : {
    2402             :     ngx_pool_t                  *old_pool;
    2403             : 
    2404             :     dd("destroy regex called");
    2405             : 
    2406           0 :     if (re == NULL || re->pool == NULL) {
    2407           0 :         return;
    2408             :     }
    2409             : 
    2410           0 :     if (re->regex_sd) {
    2411           0 :         old_pool = ngx_http_lua_pcre_malloc_init(re->pool);
    2412             : #if LUA_HAVE_PCRE_JIT
    2413           0 :         pcre_free_study(re->regex_sd);
    2414             : #else
    2415             :         pcre_free(re->regex_sd);
    2416             : #endif
    2417           0 :         ngx_http_lua_pcre_malloc_done(old_pool);
    2418           0 :         re->regex_sd = NULL;
    2419             :     }
    2420             : 
    2421           0 :     ngx_destroy_pool(re->pool);
    2422             : }
    2423             : 
    2424             : 
    2425             : int
    2426           0 : ngx_http_lua_ffi_compile_replace_template(ngx_http_lua_regex_t *re,
    2427             :     const u_char *replace_data, size_t replace_len)
    2428             : {
    2429             :     ngx_int_t                                rc;
    2430             :     ngx_str_t                                tpl;
    2431             :     ngx_http_lua_complex_value_t            *ctpl;
    2432             :     ngx_http_lua_compile_complex_value_t     ccv;
    2433             : 
    2434           0 :     ctpl = ngx_palloc(re->pool, sizeof(ngx_http_lua_complex_value_t));
    2435           0 :     if (ctpl == NULL) {
    2436           0 :         return NGX_ERROR;
    2437             :     }
    2438             : 
    2439           0 :     if (replace_len != 0) {
    2440             :         /* copy the string buffer pointed to by tpl.data from Lua VM */
    2441           0 :         tpl.data = ngx_palloc(re->pool, replace_len + 1);
    2442           0 :         if (tpl.data == NULL) {
    2443           0 :             return NGX_ERROR;
    2444             :         }
    2445             : 
    2446           0 :         ngx_memcpy(tpl.data, replace_data, replace_len);
    2447           0 :         tpl.data[replace_len] = '\0';
    2448             : 
    2449             :     } else {
    2450           0 :         tpl.data = (u_char *) replace_data;
    2451             :     }
    2452             : 
    2453           0 :     tpl.len = replace_len;
    2454             : 
    2455           0 :     ngx_memzero(&ccv, sizeof(ngx_http_lua_compile_complex_value_t));
    2456           0 :     ccv.pool = re->pool;
    2457           0 :     ccv.log = ngx_cycle->log;
    2458           0 :     ccv.value = &tpl;
    2459           0 :     ccv.complex_value = ctpl;
    2460             : 
    2461           0 :     rc = ngx_http_lua_compile_complex_value(&ccv);
    2462             : 
    2463           0 :     re->replace = ctpl;
    2464             : 
    2465           0 :     return rc;
    2466             : }
    2467             : 
    2468             : 
    2469             : ngx_http_lua_script_engine_t *
    2470           0 : ngx_http_lua_ffi_create_script_engine(void)
    2471             : {
    2472           0 :     return ngx_calloc(sizeof(ngx_http_lua_script_engine_t), ngx_cycle->log);
    2473             : }
    2474             : 
    2475             : 
    2476             : void
    2477           0 : ngx_http_lua_ffi_init_script_engine(ngx_http_lua_script_engine_t *e,
    2478             :     const unsigned char *subj, ngx_http_lua_regex_t *compiled, int count)
    2479             : {
    2480           0 :     e->log = ngx_cycle->log;
    2481           0 :     e->ncaptures = count * 2;
    2482           0 :     e->captures = compiled->captures;
    2483           0 :     e->captures_data = (u_char *) subj;
    2484           0 : }
    2485             : 
    2486             : 
    2487             : void
    2488           0 : ngx_http_lua_ffi_destroy_script_engine(ngx_http_lua_script_engine_t *e)
    2489             : {
    2490           0 :     ngx_free(e);
    2491           0 : }
    2492             : 
    2493             : 
    2494             : size_t
    2495           0 : ngx_http_lua_ffi_script_eval_len(ngx_http_lua_script_engine_t *e,
    2496             :     ngx_http_lua_complex_value_t *val)
    2497             : {
    2498             :     size_t          len;
    2499             : 
    2500             :     ngx_http_lua_script_len_code_pt   lcode;
    2501             : 
    2502           0 :     e->ip = val->lengths;
    2503           0 :     len = 0;
    2504             : 
    2505           0 :     while (*(uintptr_t *) e->ip) {
    2506           0 :         lcode = *(ngx_http_lua_script_len_code_pt *) e->ip;
    2507           0 :         len += lcode(e);
    2508             :     }
    2509             : 
    2510           0 :     return len;
    2511             : }
    2512             : 
    2513             : 
    2514             : void
    2515           0 : ngx_http_lua_ffi_script_eval_data(ngx_http_lua_script_engine_t *e,
    2516             :     ngx_http_lua_complex_value_t *val, u_char *dst)
    2517             : {
    2518             :     ngx_http_lua_script_code_pt       code;
    2519             : 
    2520           0 :     e->ip = val->values;
    2521           0 :     e->pos = dst;
    2522             : 
    2523           0 :     while (*(uintptr_t *) e->ip) {
    2524           0 :         code = *(ngx_http_lua_script_code_pt *) e->ip;
    2525           0 :         code(e);
    2526             :     }
    2527           0 : }
    2528             : 
    2529             : 
    2530             : uint32_t
    2531           0 : ngx_http_lua_ffi_max_regex_cache_size(void)
    2532             : {
    2533             :     ngx_http_lua_main_conf_t    *lmcf;
    2534           0 :     lmcf = ngx_http_cycle_get_module_main_conf(ngx_cycle,
    2535             :                                                ngx_http_lua_module);
    2536           0 :     if (lmcf == NULL) {
    2537           0 :         return 0;
    2538             :     }
    2539           0 :     return (uint32_t) lmcf->regex_cache_max_entries;
    2540             : }
    2541             : #endif /* NGX_LUA_NO_FFI_API */
    2542             : 
    2543             : 
    2544             : #endif /* NGX_PCRE */
    2545             : 
    2546             : /* vi:set ft=c ts=4 sw=4 et fdm=marker: */

Generated by: LCOV version 1.13