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