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