summaryrefslogtreecommitdiffhomepage
path: root/src/nxt_pcre2.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/nxt_pcre2.c')
-rw-r--r--src/nxt_pcre2.c161
1 files changed, 161 insertions, 0 deletions
diff --git a/src/nxt_pcre2.c b/src/nxt_pcre2.c
new file mode 100644
index 00000000..22c4d2d4
--- /dev/null
+++ b/src/nxt_pcre2.c
@@ -0,0 +1,161 @@
+/*
+ * Copyright (C) Axel Duch
+ * Copyright (C) NGINX, Inc.
+ */
+
+#include <nxt_main.h>
+#include <nxt_regex.h>
+
+#define PCRE2_CODE_UNIT_WIDTH 8
+#include <pcre2.h>
+
+
+static void *nxt_pcre2_malloc(PCRE2_SIZE size, void *memory_data);
+static void nxt_pcre2_free(void *p, void *memory_data);
+
+
+struct nxt_regex_s {
+ pcre2_code *code;
+ nxt_str_t pattern;
+};
+
+
+nxt_regex_t *
+nxt_regex_compile(nxt_mp_t *mp, nxt_str_t *source, nxt_regex_err_t *err)
+{
+ int errcode;
+ nxt_int_t ret;
+ PCRE2_SIZE erroffset;
+ nxt_regex_t *re;
+ pcre2_general_context *general_ctx;
+ pcre2_compile_context *compile_ctx;
+
+ static const u_char alloc_error[] = "memory allocation failed";
+
+ general_ctx = pcre2_general_context_create(nxt_pcre2_malloc,
+ nxt_pcre2_free, mp);
+ if (nxt_slow_path(general_ctx == NULL)) {
+ goto alloc_fail;
+ }
+
+ compile_ctx = pcre2_compile_context_create(general_ctx);
+ if (nxt_slow_path(compile_ctx == NULL)) {
+ goto alloc_fail;
+ }
+
+ re = nxt_mp_get(mp, sizeof(nxt_regex_t));
+ if (nxt_slow_path(re == NULL)) {
+ goto alloc_fail;
+ }
+
+ if (nxt_slow_path(nxt_str_dup(mp, &re->pattern, source) == NULL)) {
+ goto alloc_fail;
+ }
+
+ re->code = pcre2_compile((PCRE2_SPTR) source->start, source->length, 0,
+ &errcode, &erroffset, compile_ctx);
+ if (nxt_slow_path(re->code == NULL)) {
+ err->offset = erroffset;
+
+ ret = pcre2_get_error_message(errcode, (PCRE2_UCHAR *) err->msg,
+ ERR_BUF_SIZE);
+ if (ret < 0) {
+ (void) nxt_sprintf(err->msg, err->msg + ERR_BUF_SIZE,
+ "compilation failed with unknown "
+ "error code: %d%Z", errcode);
+ }
+
+ return NULL;
+ }
+
+#if 0
+ errcode = pcre2_jit_compile(re, PCRE2_JIT_COMPLETE);
+ if (nxt_slow_path(errcode != 0 && errcode != PCRE2_ERROR_JIT_BADOPTION)) {
+ ret = pcre2_get_error_message(errcode, (PCRE2_UCHAR *) err->msg,
+ ERR_BUF_SIZE);
+ if (ret < 0) {
+ (void) nxt_sprintf(err->msg, err->msg + ERR_BUF_SIZE,
+ "JIT compilation failed with unknown "
+ "error code: %d%Z", errcode);
+ }
+
+ return NULL;
+ }
+#endif
+
+ return re;
+
+alloc_fail:
+
+ err->offset = source->length;
+ nxt_memcpy(err->msg, alloc_error, sizeof(alloc_error));
+
+ return NULL;
+}
+
+
+static void *
+nxt_pcre2_malloc(PCRE2_SIZE size, void *mp)
+{
+ return nxt_mp_get(mp, size);
+}
+
+
+static void
+nxt_pcre2_free(void *p, void *mp)
+{
+}
+
+
+nxt_regex_match_t *
+nxt_regex_match_create(nxt_mp_t *mp, size_t size)
+{
+ nxt_regex_match_t *match;
+ pcre2_general_context *ctx;
+
+ ctx = pcre2_general_context_create(nxt_pcre2_malloc, nxt_pcre2_free, mp);
+ if (nxt_slow_path(ctx == NULL)) {
+ nxt_thread_log_alert("pcre2_general_context_create() failed");
+ return NULL;
+ }
+
+ match = pcre2_match_data_create(size, ctx);
+ if (nxt_slow_path(match == NULL)) {
+ nxt_thread_log_alert("pcre2_match_data_create(%uz) failed", size);
+ return NULL;
+ }
+
+ return match;
+}
+
+
+nxt_int_t
+nxt_regex_match(nxt_regex_t *re, u_char *subject, size_t length,
+ nxt_regex_match_t *match)
+{
+ nxt_int_t ret;
+ PCRE2_UCHAR errptr[ERR_BUF_SIZE];
+
+ ret = pcre2_match(re->code, (PCRE2_SPTR) subject, length, 0, 0, match,
+ NULL);
+
+ if (nxt_slow_path(ret < PCRE2_ERROR_NOMATCH)) {
+
+ if (pcre2_get_error_message(ret, errptr, ERR_BUF_SIZE) < 0) {
+ nxt_thread_log_error(NXT_LOG_ERR,
+ "pcre2_match() failed: %d on \"%*s\" "
+ "using \"%V\"", ret, subject, length, subject,
+ &re->pattern);
+
+ } else {
+ nxt_thread_log_error(NXT_LOG_ERR,
+ "pcre2_match() failed: %s (%d) on \"%*s\" "
+ "using \"%V\"", errptr, ret, length, subject,
+ &re->pattern);
+ }
+
+ return NXT_ERROR;
+ }
+
+ return (ret != PCRE2_ERROR_NOMATCH);
+}