xref: /unit/src/nxt_pcre2.c (revision 1721)
1*1721Saxel.duch@nginx.com /*
2*1721Saxel.duch@nginx.com  * Copyright (C) Axel Duch
3*1721Saxel.duch@nginx.com  * Copyright (C) NGINX, Inc.
4*1721Saxel.duch@nginx.com  */
5*1721Saxel.duch@nginx.com 
6*1721Saxel.duch@nginx.com #include <nxt_main.h>
7*1721Saxel.duch@nginx.com #include <nxt_regex.h>
8*1721Saxel.duch@nginx.com 
9*1721Saxel.duch@nginx.com #define PCRE2_CODE_UNIT_WIDTH 8
10*1721Saxel.duch@nginx.com #include <pcre2.h>
11*1721Saxel.duch@nginx.com 
12*1721Saxel.duch@nginx.com 
13*1721Saxel.duch@nginx.com static void *nxt_pcre2_malloc(PCRE2_SIZE size, void *memory_data);
14*1721Saxel.duch@nginx.com static void nxt_pcre2_free(void *p, void *memory_data);
15*1721Saxel.duch@nginx.com 
16*1721Saxel.duch@nginx.com 
17*1721Saxel.duch@nginx.com struct nxt_regex_s {
18*1721Saxel.duch@nginx.com     pcre2_code  *code;
19*1721Saxel.duch@nginx.com     nxt_str_t   pattern;
20*1721Saxel.duch@nginx.com };
21*1721Saxel.duch@nginx.com 
22*1721Saxel.duch@nginx.com 
23*1721Saxel.duch@nginx.com nxt_regex_t *
24*1721Saxel.duch@nginx.com nxt_regex_compile(nxt_mp_t *mp, nxt_str_t *source, nxt_regex_err_t *err)
25*1721Saxel.duch@nginx.com {
26*1721Saxel.duch@nginx.com     int                    errcode;
27*1721Saxel.duch@nginx.com     nxt_int_t              ret;
28*1721Saxel.duch@nginx.com     PCRE2_SIZE             erroffset;
29*1721Saxel.duch@nginx.com     nxt_regex_t            *re;
30*1721Saxel.duch@nginx.com     pcre2_general_context  *general_ctx;
31*1721Saxel.duch@nginx.com     pcre2_compile_context  *compile_ctx;
32*1721Saxel.duch@nginx.com 
33*1721Saxel.duch@nginx.com     static const u_char    alloc_error[] = "memory allocation failed";
34*1721Saxel.duch@nginx.com 
35*1721Saxel.duch@nginx.com     general_ctx = pcre2_general_context_create(nxt_pcre2_malloc,
36*1721Saxel.duch@nginx.com                                                nxt_pcre2_free, mp);
37*1721Saxel.duch@nginx.com     if (nxt_slow_path(general_ctx == NULL)) {
38*1721Saxel.duch@nginx.com         goto alloc_fail;
39*1721Saxel.duch@nginx.com     }
40*1721Saxel.duch@nginx.com 
41*1721Saxel.duch@nginx.com     compile_ctx = pcre2_compile_context_create(general_ctx);
42*1721Saxel.duch@nginx.com     if (nxt_slow_path(compile_ctx == NULL)) {
43*1721Saxel.duch@nginx.com         goto alloc_fail;
44*1721Saxel.duch@nginx.com     }
45*1721Saxel.duch@nginx.com 
46*1721Saxel.duch@nginx.com     re = nxt_mp_get(mp, sizeof(nxt_regex_t));
47*1721Saxel.duch@nginx.com     if (nxt_slow_path(re == NULL)) {
48*1721Saxel.duch@nginx.com         goto alloc_fail;
49*1721Saxel.duch@nginx.com     }
50*1721Saxel.duch@nginx.com 
51*1721Saxel.duch@nginx.com     if (nxt_slow_path(nxt_str_dup(mp, &re->pattern, source) == NULL)) {
52*1721Saxel.duch@nginx.com         goto alloc_fail;
53*1721Saxel.duch@nginx.com     }
54*1721Saxel.duch@nginx.com 
55*1721Saxel.duch@nginx.com     re->code = pcre2_compile((PCRE2_SPTR) source->start, source->length, 0,
56*1721Saxel.duch@nginx.com                              &errcode, &erroffset, compile_ctx);
57*1721Saxel.duch@nginx.com     if (nxt_slow_path(re->code == NULL)) {
58*1721Saxel.duch@nginx.com         err->offset = erroffset;
59*1721Saxel.duch@nginx.com 
60*1721Saxel.duch@nginx.com         ret = pcre2_get_error_message(errcode, (PCRE2_UCHAR *) err->msg,
61*1721Saxel.duch@nginx.com                                       ERR_BUF_SIZE);
62*1721Saxel.duch@nginx.com         if (ret < 0) {
63*1721Saxel.duch@nginx.com             (void) nxt_sprintf(err->msg, err->msg + ERR_BUF_SIZE,
64*1721Saxel.duch@nginx.com                                "compilation failed with unknown "
65*1721Saxel.duch@nginx.com                                "error code: %d%Z", errcode);
66*1721Saxel.duch@nginx.com         }
67*1721Saxel.duch@nginx.com 
68*1721Saxel.duch@nginx.com         return NULL;
69*1721Saxel.duch@nginx.com     }
70*1721Saxel.duch@nginx.com 
71*1721Saxel.duch@nginx.com #if 0
72*1721Saxel.duch@nginx.com     errcode = pcre2_jit_compile(re, PCRE2_JIT_COMPLETE);
73*1721Saxel.duch@nginx.com     if (nxt_slow_path(errcode != 0 && errcode != PCRE2_ERROR_JIT_BADOPTION)) {
74*1721Saxel.duch@nginx.com         ret = pcre2_get_error_message(errcode, (PCRE2_UCHAR *) err->msg,
75*1721Saxel.duch@nginx.com                                       ERR_BUF_SIZE);
76*1721Saxel.duch@nginx.com         if (ret < 0) {
77*1721Saxel.duch@nginx.com             (void) nxt_sprintf(err->msg, err->msg + ERR_BUF_SIZE,
78*1721Saxel.duch@nginx.com                                "JIT compilation failed with unknown "
79*1721Saxel.duch@nginx.com                                "error code: %d%Z", errcode);
80*1721Saxel.duch@nginx.com         }
81*1721Saxel.duch@nginx.com 
82*1721Saxel.duch@nginx.com         return NULL;
83*1721Saxel.duch@nginx.com     }
84*1721Saxel.duch@nginx.com #endif
85*1721Saxel.duch@nginx.com 
86*1721Saxel.duch@nginx.com     return re;
87*1721Saxel.duch@nginx.com 
88*1721Saxel.duch@nginx.com alloc_fail:
89*1721Saxel.duch@nginx.com 
90*1721Saxel.duch@nginx.com     err->offset = source->length;
91*1721Saxel.duch@nginx.com     nxt_memcpy(err->msg, alloc_error, sizeof(alloc_error));
92*1721Saxel.duch@nginx.com 
93*1721Saxel.duch@nginx.com     return NULL;
94*1721Saxel.duch@nginx.com }
95*1721Saxel.duch@nginx.com 
96*1721Saxel.duch@nginx.com 
97*1721Saxel.duch@nginx.com static void *
98*1721Saxel.duch@nginx.com nxt_pcre2_malloc(PCRE2_SIZE size, void *mp)
99*1721Saxel.duch@nginx.com {
100*1721Saxel.duch@nginx.com     return nxt_mp_get(mp, size);
101*1721Saxel.duch@nginx.com }
102*1721Saxel.duch@nginx.com 
103*1721Saxel.duch@nginx.com 
104*1721Saxel.duch@nginx.com static void
105*1721Saxel.duch@nginx.com nxt_pcre2_free(void *p, void *mp)
106*1721Saxel.duch@nginx.com {
107*1721Saxel.duch@nginx.com }
108*1721Saxel.duch@nginx.com 
109*1721Saxel.duch@nginx.com 
110*1721Saxel.duch@nginx.com nxt_regex_match_t *
111*1721Saxel.duch@nginx.com nxt_regex_match_create(nxt_mp_t *mp, size_t size)
112*1721Saxel.duch@nginx.com {
113*1721Saxel.duch@nginx.com     nxt_regex_match_t      *match;
114*1721Saxel.duch@nginx.com     pcre2_general_context  *ctx;
115*1721Saxel.duch@nginx.com 
116*1721Saxel.duch@nginx.com     ctx = pcre2_general_context_create(nxt_pcre2_malloc, nxt_pcre2_free, mp);
117*1721Saxel.duch@nginx.com     if (nxt_slow_path(ctx == NULL)) {
118*1721Saxel.duch@nginx.com         nxt_thread_log_alert("pcre2_general_context_create() failed");
119*1721Saxel.duch@nginx.com         return NULL;
120*1721Saxel.duch@nginx.com     }
121*1721Saxel.duch@nginx.com 
122*1721Saxel.duch@nginx.com     match = pcre2_match_data_create(size, ctx);
123*1721Saxel.duch@nginx.com     if (nxt_slow_path(match == NULL)) {
124*1721Saxel.duch@nginx.com         nxt_thread_log_alert("pcre2_match_data_create(%uz) failed", size);
125*1721Saxel.duch@nginx.com         return NULL;
126*1721Saxel.duch@nginx.com     }
127*1721Saxel.duch@nginx.com 
128*1721Saxel.duch@nginx.com     return match;
129*1721Saxel.duch@nginx.com }
130*1721Saxel.duch@nginx.com 
131*1721Saxel.duch@nginx.com 
132*1721Saxel.duch@nginx.com nxt_int_t
133*1721Saxel.duch@nginx.com nxt_regex_match(nxt_regex_t *re, u_char *subject, size_t length,
134*1721Saxel.duch@nginx.com     nxt_regex_match_t *match)
135*1721Saxel.duch@nginx.com {
136*1721Saxel.duch@nginx.com     nxt_int_t    ret;
137*1721Saxel.duch@nginx.com     PCRE2_UCHAR  errptr[ERR_BUF_SIZE];
138*1721Saxel.duch@nginx.com 
139*1721Saxel.duch@nginx.com     ret = pcre2_match(re->code, (PCRE2_SPTR) subject, length, 0, 0, match,
140*1721Saxel.duch@nginx.com                       NULL);
141*1721Saxel.duch@nginx.com 
142*1721Saxel.duch@nginx.com     if (nxt_slow_path(ret < PCRE2_ERROR_NOMATCH)) {
143*1721Saxel.duch@nginx.com 
144*1721Saxel.duch@nginx.com         if (pcre2_get_error_message(ret, errptr, ERR_BUF_SIZE) < 0) {
145*1721Saxel.duch@nginx.com             nxt_thread_log_error(NXT_LOG_ERR,
146*1721Saxel.duch@nginx.com                                  "pcre2_match() failed: %d on \"%*s\" "
147*1721Saxel.duch@nginx.com                                  "using \"%V\"", ret, subject, length, subject,
148*1721Saxel.duch@nginx.com                                  &re->pattern);
149*1721Saxel.duch@nginx.com 
150*1721Saxel.duch@nginx.com         } else {
151*1721Saxel.duch@nginx.com             nxt_thread_log_error(NXT_LOG_ERR,
152*1721Saxel.duch@nginx.com                                  "pcre2_match() failed: %s (%d) on \"%*s\" "
153*1721Saxel.duch@nginx.com                                  "using \"%V\"", errptr, ret, length, subject,
154*1721Saxel.duch@nginx.com                                  &re->pattern);
155*1721Saxel.duch@nginx.com         }
156*1721Saxel.duch@nginx.com 
157*1721Saxel.duch@nginx.com         return NXT_ERROR;
158*1721Saxel.duch@nginx.com     }
159*1721Saxel.duch@nginx.com 
160*1721Saxel.duch@nginx.com     return (ret != PCRE2_ERROR_NOMATCH);
161*1721Saxel.duch@nginx.com }
162