xref: /unit/src/nxt_pcre2.c (revision 1857)
11721Saxel.duch@nginx.com /*
21721Saxel.duch@nginx.com  * Copyright (C) Axel Duch
31721Saxel.duch@nginx.com  * Copyright (C) NGINX, Inc.
41721Saxel.duch@nginx.com  */
51721Saxel.duch@nginx.com 
61721Saxel.duch@nginx.com #include <nxt_main.h>
71721Saxel.duch@nginx.com #include <nxt_regex.h>
81721Saxel.duch@nginx.com 
91721Saxel.duch@nginx.com #define PCRE2_CODE_UNIT_WIDTH 8
101721Saxel.duch@nginx.com #include <pcre2.h>
111721Saxel.duch@nginx.com 
121721Saxel.duch@nginx.com 
131721Saxel.duch@nginx.com static void *nxt_pcre2_malloc(PCRE2_SIZE size, void *memory_data);
141721Saxel.duch@nginx.com static void nxt_pcre2_free(void *p, void *memory_data);
151721Saxel.duch@nginx.com 
161721Saxel.duch@nginx.com 
171721Saxel.duch@nginx.com struct nxt_regex_s {
181721Saxel.duch@nginx.com     pcre2_code  *code;
191721Saxel.duch@nginx.com     nxt_str_t   pattern;
201721Saxel.duch@nginx.com };
211721Saxel.duch@nginx.com 
221721Saxel.duch@nginx.com 
231721Saxel.duch@nginx.com nxt_regex_t *
241721Saxel.duch@nginx.com nxt_regex_compile(nxt_mp_t *mp, nxt_str_t *source, nxt_regex_err_t *err)
251721Saxel.duch@nginx.com {
261721Saxel.duch@nginx.com     int                    errcode;
271721Saxel.duch@nginx.com     nxt_int_t              ret;
281721Saxel.duch@nginx.com     PCRE2_SIZE             erroffset;
291721Saxel.duch@nginx.com     nxt_regex_t            *re;
301721Saxel.duch@nginx.com     pcre2_general_context  *general_ctx;
311721Saxel.duch@nginx.com     pcre2_compile_context  *compile_ctx;
321721Saxel.duch@nginx.com 
331721Saxel.duch@nginx.com     static const u_char    alloc_error[] = "memory allocation failed";
341721Saxel.duch@nginx.com 
351721Saxel.duch@nginx.com     general_ctx = pcre2_general_context_create(nxt_pcre2_malloc,
361721Saxel.duch@nginx.com                                                nxt_pcre2_free, mp);
371721Saxel.duch@nginx.com     if (nxt_slow_path(general_ctx == NULL)) {
381721Saxel.duch@nginx.com         goto alloc_fail;
391721Saxel.duch@nginx.com     }
401721Saxel.duch@nginx.com 
411721Saxel.duch@nginx.com     compile_ctx = pcre2_compile_context_create(general_ctx);
421721Saxel.duch@nginx.com     if (nxt_slow_path(compile_ctx == NULL)) {
431721Saxel.duch@nginx.com         goto alloc_fail;
441721Saxel.duch@nginx.com     }
451721Saxel.duch@nginx.com 
461721Saxel.duch@nginx.com     re = nxt_mp_get(mp, sizeof(nxt_regex_t));
471721Saxel.duch@nginx.com     if (nxt_slow_path(re == NULL)) {
481721Saxel.duch@nginx.com         goto alloc_fail;
491721Saxel.duch@nginx.com     }
501721Saxel.duch@nginx.com 
511721Saxel.duch@nginx.com     if (nxt_slow_path(nxt_str_dup(mp, &re->pattern, source) == NULL)) {
521721Saxel.duch@nginx.com         goto alloc_fail;
531721Saxel.duch@nginx.com     }
541721Saxel.duch@nginx.com 
551721Saxel.duch@nginx.com     re->code = pcre2_compile((PCRE2_SPTR) source->start, source->length, 0,
561721Saxel.duch@nginx.com                              &errcode, &erroffset, compile_ctx);
571721Saxel.duch@nginx.com     if (nxt_slow_path(re->code == NULL)) {
581721Saxel.duch@nginx.com         err->offset = erroffset;
591721Saxel.duch@nginx.com 
601721Saxel.duch@nginx.com         ret = pcre2_get_error_message(errcode, (PCRE2_UCHAR *) err->msg,
611721Saxel.duch@nginx.com                                       ERR_BUF_SIZE);
621721Saxel.duch@nginx.com         if (ret < 0) {
631721Saxel.duch@nginx.com             (void) nxt_sprintf(err->msg, err->msg + ERR_BUF_SIZE,
641721Saxel.duch@nginx.com                                "compilation failed with unknown "
651721Saxel.duch@nginx.com                                "error code: %d%Z", errcode);
661721Saxel.duch@nginx.com         }
671721Saxel.duch@nginx.com 
681721Saxel.duch@nginx.com         return NULL;
691721Saxel.duch@nginx.com     }
701721Saxel.duch@nginx.com 
711721Saxel.duch@nginx.com #if 0
721721Saxel.duch@nginx.com     errcode = pcre2_jit_compile(re, PCRE2_JIT_COMPLETE);
731721Saxel.duch@nginx.com     if (nxt_slow_path(errcode != 0 && errcode != PCRE2_ERROR_JIT_BADOPTION)) {
741721Saxel.duch@nginx.com         ret = pcre2_get_error_message(errcode, (PCRE2_UCHAR *) err->msg,
751721Saxel.duch@nginx.com                                       ERR_BUF_SIZE);
761721Saxel.duch@nginx.com         if (ret < 0) {
771721Saxel.duch@nginx.com             (void) nxt_sprintf(err->msg, err->msg + ERR_BUF_SIZE,
781721Saxel.duch@nginx.com                                "JIT compilation failed with unknown "
791721Saxel.duch@nginx.com                                "error code: %d%Z", errcode);
801721Saxel.duch@nginx.com         }
811721Saxel.duch@nginx.com 
821721Saxel.duch@nginx.com         return NULL;
831721Saxel.duch@nginx.com     }
841721Saxel.duch@nginx.com #endif
851721Saxel.duch@nginx.com 
861721Saxel.duch@nginx.com     return re;
871721Saxel.duch@nginx.com 
881721Saxel.duch@nginx.com alloc_fail:
891721Saxel.duch@nginx.com 
901721Saxel.duch@nginx.com     err->offset = source->length;
911721Saxel.duch@nginx.com     nxt_memcpy(err->msg, alloc_error, sizeof(alloc_error));
921721Saxel.duch@nginx.com 
931721Saxel.duch@nginx.com     return NULL;
941721Saxel.duch@nginx.com }
951721Saxel.duch@nginx.com 
961721Saxel.duch@nginx.com 
971721Saxel.duch@nginx.com static void *
981721Saxel.duch@nginx.com nxt_pcre2_malloc(PCRE2_SIZE size, void *mp)
991721Saxel.duch@nginx.com {
1001721Saxel.duch@nginx.com     return nxt_mp_get(mp, size);
1011721Saxel.duch@nginx.com }
1021721Saxel.duch@nginx.com 
1031721Saxel.duch@nginx.com 
1041721Saxel.duch@nginx.com static void
1051721Saxel.duch@nginx.com nxt_pcre2_free(void *p, void *mp)
1061721Saxel.duch@nginx.com {
1071721Saxel.duch@nginx.com }
1081721Saxel.duch@nginx.com 
1091721Saxel.duch@nginx.com 
1101721Saxel.duch@nginx.com nxt_regex_match_t *
1111721Saxel.duch@nginx.com nxt_regex_match_create(nxt_mp_t *mp, size_t size)
1121721Saxel.duch@nginx.com {
1131721Saxel.duch@nginx.com     nxt_regex_match_t      *match;
1141721Saxel.duch@nginx.com     pcre2_general_context  *ctx;
1151721Saxel.duch@nginx.com 
1161721Saxel.duch@nginx.com     ctx = pcre2_general_context_create(nxt_pcre2_malloc, nxt_pcre2_free, mp);
1171721Saxel.duch@nginx.com     if (nxt_slow_path(ctx == NULL)) {
1181721Saxel.duch@nginx.com         nxt_thread_log_alert("pcre2_general_context_create() failed");
1191721Saxel.duch@nginx.com         return NULL;
1201721Saxel.duch@nginx.com     }
1211721Saxel.duch@nginx.com 
1221721Saxel.duch@nginx.com     match = pcre2_match_data_create(size, ctx);
1231721Saxel.duch@nginx.com     if (nxt_slow_path(match == NULL)) {
1241721Saxel.duch@nginx.com         nxt_thread_log_alert("pcre2_match_data_create(%uz) failed", size);
1251721Saxel.duch@nginx.com         return NULL;
1261721Saxel.duch@nginx.com     }
1271721Saxel.duch@nginx.com 
1281721Saxel.duch@nginx.com     return match;
1291721Saxel.duch@nginx.com }
1301721Saxel.duch@nginx.com 
1311721Saxel.duch@nginx.com 
1321721Saxel.duch@nginx.com nxt_int_t
1331721Saxel.duch@nginx.com nxt_regex_match(nxt_regex_t *re, u_char *subject, size_t length,
1341721Saxel.duch@nginx.com     nxt_regex_match_t *match)
1351721Saxel.duch@nginx.com {
1361721Saxel.duch@nginx.com     nxt_int_t    ret;
1371721Saxel.duch@nginx.com     PCRE2_UCHAR  errptr[ERR_BUF_SIZE];
1381721Saxel.duch@nginx.com 
1391721Saxel.duch@nginx.com     ret = pcre2_match(re->code, (PCRE2_SPTR) subject, length, 0, 0, match,
1401721Saxel.duch@nginx.com                       NULL);
1411721Saxel.duch@nginx.com 
1421721Saxel.duch@nginx.com     if (nxt_slow_path(ret < PCRE2_ERROR_NOMATCH)) {
1431721Saxel.duch@nginx.com 
1441721Saxel.duch@nginx.com         if (pcre2_get_error_message(ret, errptr, ERR_BUF_SIZE) < 0) {
1451721Saxel.duch@nginx.com             nxt_thread_log_error(NXT_LOG_ERR,
1461721Saxel.duch@nginx.com                                  "pcre2_match() failed: %d on \"%*s\" "
147*1857Sz.hong@f5.com                                  "using \"%V\"", ret, length, subject,
1481721Saxel.duch@nginx.com                                  &re->pattern);
1491721Saxel.duch@nginx.com 
1501721Saxel.duch@nginx.com         } else {
1511721Saxel.duch@nginx.com             nxt_thread_log_error(NXT_LOG_ERR,
1521721Saxel.duch@nginx.com                                  "pcre2_match() failed: %s (%d) on \"%*s\" "
1531721Saxel.duch@nginx.com                                  "using \"%V\"", errptr, ret, length, subject,
1541721Saxel.duch@nginx.com                                  &re->pattern);
1551721Saxel.duch@nginx.com         }
1561721Saxel.duch@nginx.com 
1571721Saxel.duch@nginx.com         return NXT_ERROR;
1581721Saxel.duch@nginx.com     }
1591721Saxel.duch@nginx.com 
1601721Saxel.duch@nginx.com     return (ret != PCRE2_ERROR_NOMATCH);
1611721Saxel.duch@nginx.com }
162