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