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