xref: /f-stack/app/nginx-1.16.1/src/core/ngx_regex.c (revision 3da8d17d)
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 {
13     ngx_flag_t  pcre_jit;
14 } ngx_regex_conf_t;
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"),
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 
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 
52 ngx_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 
68 static ngx_pool_t  *ngx_pcre_pool;
69 static ngx_list_t  *ngx_pcre_studies;
70 
71 
72 void
ngx_regex_init(void)73 ngx_regex_init(void)
74 {
75     pcre_malloc = ngx_regex_malloc;
76     pcre_free = ngx_regex_free;
77 }
78 
79 
80 static ngx_inline void
ngx_regex_malloc_init(ngx_pool_t * pool)81 ngx_regex_malloc_init(ngx_pool_t *pool)
82 {
83     ngx_pcre_pool = pool;
84 }
85 
86 
87 static ngx_inline void
ngx_regex_malloc_done(void)88 ngx_regex_malloc_done(void)
89 {
90     ngx_pcre_pool = NULL;
91 }
92 
93 
94 ngx_int_t
ngx_regex_compile(ngx_regex_compile_t * rc)95 ngx_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 
181 failed:
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 
187 nomem:
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 
197 ngx_int_t
ngx_regex_exec_array(ngx_array_t * a,ngx_str_t * s,ngx_log_t * log)198 ngx_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 
230 static void * ngx_libc_cdecl
ngx_regex_malloc(size_t size)231 ngx_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 
244 static void ngx_libc_cdecl
ngx_regex_free(void * p)245 ngx_regex_free(void *p)
246 {
247     return;
248 }
249 
250 
251 #if (NGX_HAVE_PCRE_JIT)
252 
253 static void
ngx_pcre_free_studies(void * data)254 ngx_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 
286 static ngx_int_t
ngx_regex_module_init(ngx_cycle_t * cycle)287 ngx_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 
374 static void *
ngx_regex_create_conf(ngx_cycle_t * cycle)375 ngx_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 
395 static char *
ngx_regex_init_conf(ngx_cycle_t * cycle,void * conf)396 ngx_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 
406 static char *
ngx_regex_pcre_jit(ngx_conf_t * cf,void * post,void * data)407 ngx_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