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