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: */
|