Groonga 3.0.9 Source Code Document
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
ngx_regex.c
Go to the documentation of this file.
1 
2 /*
3  * Copyright (C) Igor Sysoev
4  * Copyright (C) Nginx, Inc.
5  */
6 
7 
8 #include <ngx_config.h>
9 #include <ngx_core.h>
10 
11 
12 typedef struct {
15 
16 
17 static void * ngx_libc_cdecl ngx_regex_malloc(size_t size);
18 static void ngx_libc_cdecl ngx_regex_free(void *p);
19 #if (NGX_HAVE_PCRE_JIT)
20 static void ngx_pcre_free_studies(void *data);
21 #endif
22 
23 static ngx_int_t ngx_regex_module_init(ngx_cycle_t *cycle);
24 
25 static void *ngx_regex_create_conf(ngx_cycle_t *cycle);
26 static char *ngx_regex_init_conf(ngx_cycle_t *cycle, void *conf);
27 
28 static char *ngx_regex_pcre_jit(ngx_conf_t *cf, void *post, void *data);
29 static ngx_conf_post_t ngx_regex_pcre_jit_post = { ngx_regex_pcre_jit };
30 
31 
32 static ngx_command_t ngx_regex_commands[] = {
33 
34  { ngx_string("pcre_jit"),
37  0,
38  offsetof(ngx_regex_conf_t, pcre_jit),
39  &ngx_regex_pcre_jit_post },
40 
42 };
43 
44 
45 static ngx_core_module_t ngx_regex_module_ctx = {
46  ngx_string("regex"),
47  ngx_regex_create_conf,
48  ngx_regex_init_conf
49 };
50 
51 
54  &ngx_regex_module_ctx, /* module context */
55  ngx_regex_commands, /* module directives */
56  NGX_CORE_MODULE, /* module type */
57  NULL, /* init master */
58  ngx_regex_module_init, /* init module */
59  NULL, /* init process */
60  NULL, /* init thread */
61  NULL, /* exit thread */
62  NULL, /* exit process */
63  NULL, /* exit master */
65 };
66 
67 
68 static ngx_pool_t *ngx_pcre_pool;
69 static ngx_list_t *ngx_pcre_studies;
70 
71 
72 void
74 {
75  pcre_malloc = ngx_regex_malloc;
76  pcre_free = ngx_regex_free;
77 }
78 
79 
80 static ngx_inline void
81 ngx_regex_malloc_init(ngx_pool_t *pool)
82 {
83 #if (NGX_THREADS)
84  ngx_core_tls_t *tls;
85 
86  if (ngx_threaded) {
87  tls = ngx_thread_get_tls(ngx_core_tls_key);
88  tls->pool = pool;
89  return;
90  }
91 
92 #endif
93 
94  ngx_pcre_pool = pool;
95 }
96 
97 
98 static ngx_inline void
99 ngx_regex_malloc_done(void)
100 {
101 #if (NGX_THREADS)
102  ngx_core_tls_t *tls;
103 
104  if (ngx_threaded) {
105  tls = ngx_thread_get_tls(ngx_core_tls_key);
106  tls->pool = NULL;
107  return;
108  }
109 
110 #endif
111 
112  ngx_pcre_pool = NULL;
113 }
114 
115 
116 ngx_int_t
118 {
119  int n, erroff;
120  char *p;
121  pcre *re;
122  const char *errstr;
123  ngx_regex_elt_t *elt;
124 
125  ngx_regex_malloc_init(rc->pool);
126 
127  re = pcre_compile((const char *) rc->pattern.data, (int) rc->options,
128  &errstr, &erroff, NULL);
129 
130  /* ensure that there is no current pool */
131  ngx_regex_malloc_done();
132 
133  if (re == NULL) {
134  if ((size_t) erroff == rc->pattern.len) {
135  rc->err.len = ngx_snprintf(rc->err.data, rc->err.len,
136  "pcre_compile() failed: %s in \"%V\"",
137  errstr, &rc->pattern)
138  - rc->err.data;
139 
140  } else {
141  rc->err.len = ngx_snprintf(rc->err.data, rc->err.len,
142  "pcre_compile() failed: %s in \"%V\" at \"%s\"",
143  errstr, &rc->pattern, rc->pattern.data + erroff)
144  - rc->err.data;
145  }
146 
147  return NGX_ERROR;
148  }
149 
150  rc->regex = ngx_pcalloc(rc->pool, sizeof(ngx_regex_t));
151  if (rc->regex == NULL) {
152  return NGX_ERROR;
153  }
154 
155  rc->regex->code = re;
156 
157  /* do not study at runtime */
158 
159  if (ngx_pcre_studies != NULL) {
160  elt = ngx_list_push(ngx_pcre_studies);
161  if (elt == NULL) {
162  return NGX_ERROR;
163  }
164 
165  elt->regex = rc->regex;
166  elt->name = rc->pattern.data;
167  }
168 
169  n = pcre_fullinfo(re, NULL, PCRE_INFO_CAPTURECOUNT, &rc->captures);
170  if (n < 0) {
171  p = "pcre_fullinfo(\"%V\", PCRE_INFO_CAPTURECOUNT) failed: %d";
172  goto failed;
173  }
174 
175  if (rc->captures == 0) {
176  return NGX_OK;
177  }
178 
179  n = pcre_fullinfo(re, NULL, PCRE_INFO_NAMECOUNT, &rc->named_captures);
180  if (n < 0) {
181  p = "pcre_fullinfo(\"%V\", PCRE_INFO_NAMECOUNT) failed: %d";
182  goto failed;
183  }
184 
185  if (rc->named_captures == 0) {
186  return NGX_OK;
187  }
188 
189  n = pcre_fullinfo(re, NULL, PCRE_INFO_NAMEENTRYSIZE, &rc->name_size);
190  if (n < 0) {
191  p = "pcre_fullinfo(\"%V\", PCRE_INFO_NAMEENTRYSIZE) failed: %d";
192  goto failed;
193  }
194 
195  n = pcre_fullinfo(re, NULL, PCRE_INFO_NAMETABLE, &rc->names);
196  if (n < 0) {
197  p = "pcre_fullinfo(\"%V\", PCRE_INFO_NAMETABLE) failed: %d";
198  goto failed;
199  }
200 
201  return NGX_OK;
202 
203 failed:
204 
205  rc->err.len = ngx_snprintf(rc->err.data, rc->err.len, p, &rc->pattern, n)
206  - rc->err.data;
207  return NGX_OK;
208 }
209 
210 
211 ngx_int_t
213 {
214  ngx_int_t n;
215  ngx_uint_t i;
216  ngx_regex_elt_t *re;
217 
218  re = a->elts;
219 
220  for (i = 0; i < a->nelts; i++) {
221 
222  n = ngx_regex_exec(re[i].regex, s, NULL, 0);
223 
224  if (n == NGX_REGEX_NO_MATCHED) {
225  continue;
226  }
227 
228  if (n < 0) {
230  ngx_regex_exec_n " failed: %i on \"%V\" using \"%s\"",
231  n, s, re[i].name);
232  return NGX_ERROR;
233  }
234 
235  /* match */
236 
237  return NGX_OK;
238  }
239 
240  return NGX_DECLINED;
241 }
242 
243 
244 static void * ngx_libc_cdecl
245 ngx_regex_malloc(size_t size)
246 {
247  ngx_pool_t *pool;
248 #if (NGX_THREADS)
249  ngx_core_tls_t *tls;
250 
251  if (ngx_threaded) {
252  tls = ngx_thread_get_tls(ngx_core_tls_key);
253  pool = tls->pool;
254 
255  } else {
256  pool = ngx_pcre_pool;
257  }
258 
259 #else
260 
261  pool = ngx_pcre_pool;
262 
263 #endif
264 
265  if (pool) {
266  return ngx_palloc(pool, size);
267  }
268 
269  return NULL;
270 }
271 
272 
273 static void ngx_libc_cdecl
274 ngx_regex_free(void *p)
275 {
276  return;
277 }
278 
279 
280 #if (NGX_HAVE_PCRE_JIT)
281 
282 static void
283 ngx_pcre_free_studies(void *data)
284 {
285  ngx_list_t *studies = data;
286 
287  ngx_uint_t i;
288  ngx_list_part_t *part;
289  ngx_regex_elt_t *elts;
290 
291  part = &studies->part;
292  elts = part->elts;
293 
294  for (i = 0 ; /* void */ ; i++) {
295 
296  if (i >= part->nelts) {
297  if (part->next == NULL) {
298  break;
299  }
300 
301  part = part->next;
302  elts = part->elts;
303  i = 0;
304  }
305 
306  if (elts[i].regex->extra != NULL) {
307  pcre_free_study(elts[i].regex->extra);
308  }
309  }
310 }
311 
312 #endif
313 
314 
315 static ngx_int_t
316 ngx_regex_module_init(ngx_cycle_t *cycle)
317 {
318  int opt;
319  const char *errstr;
320  ngx_uint_t i;
321  ngx_list_part_t *part;
322  ngx_regex_elt_t *elts;
323 
324  opt = 0;
325 
326 #if (NGX_HAVE_PCRE_JIT)
327  {
328  ngx_regex_conf_t *rcf;
329  ngx_pool_cleanup_t *cln;
330 
331  rcf = (ngx_regex_conf_t *) ngx_get_conf(cycle->conf_ctx, ngx_regex_module);
332 
333  if (rcf->pcre_jit) {
334  opt = PCRE_STUDY_JIT_COMPILE;
335 
336  /*
337  * The PCRE JIT compiler uses mmap for its executable codes, so we
338  * have to explicitly call the pcre_free_study() function to free
339  * this memory.
340  */
341 
342  cln = ngx_pool_cleanup_add(cycle->pool, 0);
343  if (cln == NULL) {
344  return NGX_ERROR;
345  }
346 
347  cln->handler = ngx_pcre_free_studies;
348  cln->data = ngx_pcre_studies;
349  }
350  }
351 #endif
352 
353  ngx_regex_malloc_init(cycle->pool);
354 
355  part = &ngx_pcre_studies->part;
356  elts = part->elts;
357 
358  for (i = 0 ; /* void */ ; i++) {
359 
360  if (i >= part->nelts) {
361  if (part->next == NULL) {
362  break;
363  }
364 
365  part = part->next;
366  elts = part->elts;
367  i = 0;
368  }
369 
370  elts[i].regex->extra = pcre_study(elts[i].regex->code, opt, &errstr);
371 
372  if (errstr != NULL) {
373  ngx_log_error(NGX_LOG_ALERT, cycle->log, 0,
374  "pcre_study() failed: %s in \"%s\"",
375  errstr, elts[i].name);
376  }
377 
378 #if (NGX_HAVE_PCRE_JIT)
379  if (opt & PCRE_STUDY_JIT_COMPILE) {
380  int jit, n;
381 
382  jit = 0;
383  n = pcre_fullinfo(elts[i].regex->code, elts[i].regex->extra,
384  PCRE_INFO_JIT, &jit);
385 
386  if (n != 0 || jit != 1) {
387  ngx_log_error(NGX_LOG_INFO, cycle->log, 0,
388  "JIT compiler does not support pattern: \"%s\"",
389  elts[i].name);
390  }
391  }
392 #endif
393  }
394 
395  ngx_regex_malloc_done();
396 
397  ngx_pcre_studies = NULL;
398 
399  return NGX_OK;
400 }
401 
402 
403 static void *
404 ngx_regex_create_conf(ngx_cycle_t *cycle)
405 {
406  ngx_regex_conf_t *rcf;
407 
408  rcf = ngx_pcalloc(cycle->pool, sizeof(ngx_regex_conf_t));
409  if (rcf == NULL) {
410  return NULL;
411  }
412 
413  rcf->pcre_jit = NGX_CONF_UNSET;
414 
415  ngx_pcre_studies = ngx_list_create(cycle->pool, 8, sizeof(ngx_regex_elt_t));
416  if (ngx_pcre_studies == NULL) {
417  return NULL;
418  }
419 
420  return rcf;
421 }
422 
423 
424 static char *
425 ngx_regex_init_conf(ngx_cycle_t *cycle, void *conf)
426 {
427  ngx_regex_conf_t *rcf = conf;
428 
429  ngx_conf_init_value(rcf->pcre_jit, 0);
430 
431  return NGX_CONF_OK;
432 }
433 
434 
435 static char *
436 ngx_regex_pcre_jit(ngx_conf_t *cf, void *post, void *data)
437 {
438  ngx_flag_t *fp = data;
439 
440  if (*fp == 0) {
441  return NGX_CONF_OK;
442  }
443 
444 #if (NGX_HAVE_PCRE_JIT)
445  {
446  int jit, r;
447 
448  jit = 0;
449  r = pcre_config(PCRE_CONFIG_JIT, &jit);
450 
451  if (r != 0 || jit != 1) {
453  "PCRE library does not support JIT");
454  *fp = 0;
455  }
456  }
457 #else
459  "nginx was built without PCRE JIT support");
460  *fp = 0;
461 #endif
462 
463  return NGX_CONF_OK;
464 }