[PATCH 4 of 4] PCRE2 library support

Maxim Dounin mdounin at mdounin.ru
Sun Dec 12 11:22:40 UTC 2021


# HG changeset patch
# User Maxim Dounin <mdounin at mdounin.ru>
# Date 1639235687 -10800
#      Sat Dec 11 18:14:47 2021 +0300
# Node ID dfd93beb55f7ea950efa80a580b3ffc571588d5b
# Parent  84fae18c1b1e9d5cfafe10e0e9754f1d7ba628e1
PCRE2 library support.

The PCRE2 library is now used by default if found, instead of the
original PCRE library.  If needed for some reason, this can be disabled
with the --without-pcre2 configure option.

To make it possible to specify paths to the library and include files
via --with-cc-opt / --with-ld-opt, the library is first tested without
any additional paths and options.  If this fails, the pcre2-config script
is used.

Similarly to the original PCRE library, it is now possible to build PCRE2
from sources with nginx configure, by using the --with-pcre= option.
It automatically detects if PCRE or PCRE2 sources are provided.

Note that compiling PCRE2 10.33 and later requires inttypes.h.  When
compiling on Windows with MSVC, inttypes.h is only available starting
with MSVC 2013.  In older versions some replacement needs to be provided
("echo '#include <stdint.h>' > pcre2-10.xx/src/inttypes.h" is good enough
for MSVC 2010).

The interface on nginx side remains unchanged.

diff --git a/auto/lib/pcre/conf b/auto/lib/pcre/conf
--- a/auto/lib/pcre/conf
+++ b/auto/lib/pcre/conf
@@ -5,29 +5,61 @@
 
 if [ $PCRE != NONE ]; then
 
-    have=NGX_PCRE . auto/have
+    if [ -f $PCRE/src/pcre2.h.generic ]; then
+
+        PCRE_LIBRARY=PCRE2
+
+        have=NGX_PCRE . auto/have
+        have=NGX_PCRE2 . auto/have
+
+        if [ "$NGX_PLATFORM" = win32 ]; then
+            have=PCRE2_STATIC . auto/have
+        fi
+
+        CORE_INCS="$CORE_INCS $PCRE/src/"
+        CORE_DEPS="$CORE_DEPS $PCRE/src/pcre2.h"
 
-    if [ "$NGX_PLATFORM" = win32 ]; then
-        have=PCRE_STATIC . auto/have
-    fi
+        case "$NGX_CC_NAME" in
+
+            msvc)
+                LINK_DEPS="$LINK_DEPS $PCRE/src/pcre2-8.lib"
+                CORE_LIBS="$CORE_LIBS $PCRE/src/pcre2-8.lib"
+            ;;
 
-    CORE_INCS="$CORE_INCS $PCRE"
-    CORE_DEPS="$CORE_DEPS $PCRE/pcre.h"
+            *)
+                LINK_DEPS="$LINK_DEPS $PCRE/.libs/libpcre2-8.a"
+                CORE_LIBS="$CORE_LIBS $PCRE/.libs/libpcre2-8.a"
+            ;;
 
-    case "$NGX_CC_NAME" in
+        esac
 
-        msvc | owc | bcc)
-            LINK_DEPS="$LINK_DEPS $PCRE/pcre.lib"
-            CORE_LIBS="$CORE_LIBS $PCRE/pcre.lib"
-        ;;
+    else
+
+        PCRE_LIBRARY=PCRE
+
+        have=NGX_PCRE . auto/have
+
+        if [ "$NGX_PLATFORM" = win32 ]; then
+            have=PCRE_STATIC . auto/have
+        fi
+
+        CORE_INCS="$CORE_INCS $PCRE"
+        CORE_DEPS="$CORE_DEPS $PCRE/pcre.h"
 
-        *)
-            LINK_DEPS="$LINK_DEPS $PCRE/.libs/libpcre.a"
-            CORE_LIBS="$CORE_LIBS $PCRE/.libs/libpcre.a"
-        ;;
+        case "$NGX_CC_NAME" in
+
+            msvc | owc | bcc)
+                LINK_DEPS="$LINK_DEPS $PCRE/pcre.lib"
+                CORE_LIBS="$CORE_LIBS $PCRE/pcre.lib"
+            ;;
 
-    esac
+            *)
+                LINK_DEPS="$LINK_DEPS $PCRE/.libs/libpcre.a"
+                CORE_LIBS="$CORE_LIBS $PCRE/.libs/libpcre.a"
+            ;;
 
+        esac
+    fi
 
     if [ $PCRE_JIT = YES ]; then
         have=NGX_HAVE_PCRE_JIT . auto/have
@@ -37,8 +69,48 @@ if [ $PCRE != NONE ]; then
 else
 
     if [ "$NGX_PLATFORM" != win32 ]; then
+        PCRE=NO
+    fi
 
-        PCRE=NO
+    if [ $PCRE = NO -a $PCRE2 != DISABLED ]; then
+
+        ngx_feature="PCRE2 library"
+        ngx_feature_name="NGX_PCRE2"
+        ngx_feature_run=no
+        ngx_feature_incs="#define PCRE2_CODE_UNIT_WIDTH 8
+                          #include <pcre2.h>"
+        ngx_feature_path=
+        ngx_feature_libs="-lpcre2-8"
+        ngx_feature_test="pcre2_code *re;
+                          re = pcre2_compile(NULL, 0, 0, NULL, NULL, NULL);
+                          if (re == NULL) return 1"
+        . auto/feature
+
+        if [ $ngx_found = no ]; then
+
+            # pcre2-config
+
+            ngx_pcre2_prefix=`pcre2-config --prefix 2>/dev/null`
+
+            if [ -n "$ngx_pcre2_prefix" ]; then
+                ngx_feature="PCRE2 library in $ngx_pcre2_prefix"
+                ngx_feature_path=`pcre2-config --cflags \
+                                  | sed -n -e 's/.*-I *\([^ ][^ ]*\).*/\1/p'`
+                ngx_feature_libs=`pcre2-config --libs8`
+                . auto/feature
+            fi
+        fi
+
+        if [ $ngx_found = yes ]; then
+            have=NGX_PCRE . auto/have
+            CORE_INCS="$CORE_INCS $ngx_feature_path"
+            CORE_LIBS="$CORE_LIBS $ngx_feature_libs"
+            PCRE=YES
+            PCRE_LIBRARY=PCRE2
+        fi
+    fi
+
+    if [ $PCRE = NO ]; then
 
         ngx_feature="PCRE library"
         ngx_feature_name="NGX_PCRE"
@@ -114,6 +186,7 @@ else
             CORE_INCS="$CORE_INCS $ngx_feature_path"
             CORE_LIBS="$CORE_LIBS $ngx_feature_libs"
             PCRE=YES
+            PCRE_LIBRARY=PCRE
         fi
 
         if [ $PCRE = YES ]; then
diff --git a/auto/lib/pcre/make b/auto/lib/pcre/make
--- a/auto/lib/pcre/make
+++ b/auto/lib/pcre/make
@@ -3,36 +3,138 @@
 # Copyright (C) Nginx, Inc.
 
 
-case "$NGX_CC_NAME" in
+if [ $PCRE_LIBRARY = PCRE2 ]; then
+
+    # PCRE2
+
+    if [ $NGX_CC_NAME = msvc ]; then
+
+        # With PCRE2, it is not possible to compile all sources.
+        # Since list of source files changes between versions, we
+        # test files which might not be present.
 
-    msvc)
-        ngx_makefile=makefile.msvc
-        ngx_opt="CPU_OPT=\"$CPU_OPT\" LIBC=$LIBC"
-        ngx_pcre="PCRE=\"$PCRE\""
-    ;;
+        ngx_pcre_srcs="pcre2_auto_possess.c \
+                       pcre2_chartables.c \
+                       pcre2_compile.c \
+                       pcre2_config.c \
+                       pcre2_context.c \
+                       pcre2_dfa_match.c \
+                       pcre2_error.c \
+                       pcre2_jit_compile.c \
+                       pcre2_maketables.c \
+                       pcre2_match.c \
+                       pcre2_match_data.c \
+                       pcre2_newline.c \
+                       pcre2_ord2utf.c \
+                       pcre2_pattern_info.c \
+                       pcre2_string_utils.c \
+                       pcre2_study.c \
+                       pcre2_substitute.c \
+                       pcre2_substring.c \
+                       pcre2_tables.c \
+                       pcre2_ucd.c \
+                       pcre2_valid_utf.c \
+                       pcre2_xclass.c"
+
+        ngx_pcre_test="pcre2_convert.c \
+                       pcre2_extuni.c \
+                       pcre2_find_bracket.c \
+                       pcre2_script_run.c \
+                       pcre2_serialize.c"
+
+        for ngx_src in $ngx_pcre_test
+        do
+            if [ -f $PCRE/src/$ngx_src ]; then
+                ngx_pcre_srcs="$ngx_pcre_srcs $ngx_src"
+            fi
+        done
 
-    owc)
-        ngx_makefile=makefile.owc
-        ngx_opt="CPU_OPT=\"$CPU_OPT\""
-        ngx_pcre=`echo PCRE=\"$PCRE\" | sed -e "s/\//$ngx_regex_dirsep/g"`
-    ;;
+        ngx_pcre_objs=`echo $ngx_pcre_srcs \
+            | sed -e "s#\([^ ]*\.\)c#\1$ngx_objext#g"`
+
+        ngx_pcre_srcs=`echo $ngx_pcre_srcs \
+            | sed -e "s/  *\([^ ][^ ]*\)/$ngx_regex_cont\1/g"`
+        ngx_pcre_objs=`echo $ngx_pcre_objs \
+            | sed -e "s/  *\([^ ][^ ]*\)/$ngx_regex_cont\1/g"`
+
+        cat << END                                            >> $NGX_MAKEFILE
+
+PCRE_CFLAGS =	-O2 -Ob1 -Oi -Gs $LIBC $CPU_OPT
+PCRE_FLAGS =	-DHAVE_CONFIG_H -DPCRE2_STATIC -DPCRE2_CODE_UNIT_WIDTH=8 \\
+		-DHAVE_MEMMOVE
+
+PCRE_SRCS =	 $ngx_pcre_srcs
+PCRE_OBJS =	 $ngx_pcre_objs
+
+$PCRE/src/pcre2.h:
+	cd $PCRE/src \\
+	&& copy /y config.h.generic config.h \\
+	&& copy /y pcre2.h.generic pcre2.h \\
+	&& copy /y pcre2_chartables.c.dist pcre2_chartables.c
 
-    bcc)
-        ngx_makefile=makefile.bcc
-        ngx_opt="-DCPU_OPT=\"$CPU_OPT\""
-        ngx_pcre=`echo \-DPCRE=\"$PCRE\" | sed -e "s/\//$ngx_regex_dirsep/g"`
-    ;;
+$PCRE/src/pcre2-8.lib:	$PCRE/src/pcre2.h $NGX_MAKEFILE
+	cd $PCRE/src \\
+	&& cl -nologo -c \$(PCRE_CFLAGS) -I . \$(PCRE_FLAGS) \$(PCRE_SRCS) \\
+	&& link -lib -out:pcre2-8.lib -verbose:lib \$(PCRE_OBJS)
+
+END
+
+    else
+
+        cat << END                                            >> $NGX_MAKEFILE
+
+$PCRE/src/pcre2.h:	$PCRE/Makefile
 
-    *)
-        ngx_makefile=
-    ;;
+$PCRE/Makefile:	$NGX_MAKEFILE
+	cd $PCRE \\
+	&& if [ -f Makefile ]; then \$(MAKE) distclean; fi \\
+	&& CC="\$(CC)" CFLAGS="$PCRE_OPT" \\
+	./configure --disable-shared $PCRE_CONF_OPT
 
-esac
+$PCRE/.libs/libpcre2-8.a:	$PCRE/Makefile
+	cd $PCRE \\
+	&& \$(MAKE) libpcre2-8.la
+
+END
+
+    fi
 
 
-if [ -n "$ngx_makefile" ]; then
+else
+
+    # PCRE
+
+    case "$NGX_CC_NAME" in
+
+        msvc)
+            ngx_makefile=makefile.msvc
+            ngx_opt="CPU_OPT=\"$CPU_OPT\" LIBC=$LIBC"
+            ngx_pcre="PCRE=\"$PCRE\""
+        ;;
+
+        owc)
+            ngx_makefile=makefile.owc
+            ngx_opt="CPU_OPT=\"$CPU_OPT\""
+            ngx_pcre=`echo PCRE=\"$PCRE\" | sed -e "s/\//$ngx_regex_dirsep/g"`
+        ;;
 
-    cat << END                                                >> $NGX_MAKEFILE
+        bcc)
+            ngx_makefile=makefile.bcc
+            ngx_opt="-DCPU_OPT=\"$CPU_OPT\""
+            ngx_pcre=`echo \-DPCRE=\"$PCRE\" \
+                | sed -e "s/\//$ngx_regex_dirsep/g"`
+        ;;
+
+        *)
+            ngx_makefile=
+        ;;
+
+    esac
+
+
+    if [ -n "$ngx_makefile" ]; then
+
+        cat << END                                            >> $NGX_MAKEFILE
 
 `echo "$PCRE/pcre.lib:	$PCRE/pcre.h $NGX_MAKEFILE"			\
 	| sed -e "s/\//$ngx_regex_dirsep/g"`
@@ -43,9 +145,9 @@ if [ -n "$ngx_makefile" ]; then
 
 END
 
-else
+    else
 
-    cat << END                                                >> $NGX_MAKEFILE
+        cat << END                                            >> $NGX_MAKEFILE
 
 $PCRE/pcre.h:	$PCRE/Makefile
 
@@ -61,4 +163,6 @@ else
 
 END
 
+    fi
+
 fi
diff --git a/auto/options b/auto/options
--- a/auto/options
+++ b/auto/options
@@ -146,6 +146,7 @@ PCRE=NONE
 PCRE_OPT=
 PCRE_CONF_OPT=
 PCRE_JIT=NO
+PCRE2=YES
 
 USE_OPENSSL=NO
 OPENSSL=NONE
@@ -357,6 +358,7 @@ use the \"--with-mail_ssl_module\" optio
         --with-pcre=*)                   PCRE="$value"              ;;
         --with-pcre-opt=*)               PCRE_OPT="$value"          ;;
         --with-pcre-jit)                 PCRE_JIT=YES               ;;
+        --without-pcre2)                 PCRE2=DISABLED             ;;
 
         --with-openssl=*)                OPENSSL="$value"           ;;
         --with-openssl-opt=*)            OPENSSL_OPT="$value"       ;;
@@ -573,6 +575,7 @@ cat << END
   --with-pcre=DIR                    set path to PCRE library sources
   --with-pcre-opt=OPTIONS            set additional build options for PCRE
   --with-pcre-jit                    build PCRE with JIT compilation support
+  --without-pcre2                    do not use PCRE2 library
 
   --with-zlib=DIR                    set path to zlib library sources
   --with-zlib-opt=OPTIONS            set additional build options for zlib
diff --git a/auto/summary b/auto/summary
--- a/auto/summary
+++ b/auto/summary
@@ -16,9 +16,9 @@ if [ $USE_PCRE = DISABLED ]; then
 
 else
     case $PCRE in
-        YES)   echo "  + using system PCRE library" ;;
+        YES)   echo "  + using system $PCRE_LIBRARY library" ;;
         NONE)  echo "  + PCRE library is not used" ;;
-        *)     echo "  + using PCRE library: $PCRE" ;;
+        *)     echo "  + using $PCRE_LIBRARY library: $PCRE" ;;
     esac
 fi
 
diff --git a/src/core/ngx_regex.c b/src/core/ngx_regex.c
--- a/src/core/ngx_regex.c
+++ b/src/core/ngx_regex.c
@@ -15,8 +15,16 @@ typedef struct {
 } ngx_regex_conf_t;
 
 
+static ngx_inline void ngx_regex_malloc_init(ngx_pool_t *pool);
+static ngx_inline void ngx_regex_malloc_done(void);
+
+#if (NGX_PCRE2)
+static void * ngx_libc_cdecl ngx_regex_malloc(size_t size, void *data);
+static void ngx_libc_cdecl ngx_regex_free(void *p, void *data);
+#else
 static void * ngx_libc_cdecl ngx_regex_malloc(size_t size);
 static void ngx_libc_cdecl ngx_regex_free(void *p);
+#endif
 static void ngx_regex_cleanup(void *data);
 
 static ngx_int_t ngx_regex_module_init(ngx_cycle_t *cycle);
@@ -64,15 +72,24 @@ ngx_module_t  ngx_regex_module = {
 };
 
 
-static ngx_pool_t  *ngx_regex_pool;
-static ngx_list_t  *ngx_regex_studies;
+static ngx_pool_t             *ngx_regex_pool;
+static ngx_list_t             *ngx_regex_studies;
+static ngx_uint_t              ngx_regex_direct_alloc;
+
+#if (NGX_PCRE2)
+static pcre2_compile_context  *ngx_regex_compile_context;
+static pcre2_match_data       *ngx_regex_match_data;
+static ngx_uint_t              ngx_regex_match_data_size;
+#endif
 
 
 void
 ngx_regex_init(void)
 {
+#if !(NGX_PCRE2)
     pcre_malloc = ngx_regex_malloc;
     pcre_free = ngx_regex_free;
+#endif
 }
 
 
@@ -80,6 +97,7 @@ static ngx_inline void
 ngx_regex_malloc_init(ngx_pool_t *pool)
 {
     ngx_regex_pool = pool;
+    ngx_regex_direct_alloc = (pool == NULL) ? 1 : 0;
 }
 
 
@@ -87,9 +105,146 @@ static ngx_inline void
 ngx_regex_malloc_done(void)
 {
     ngx_regex_pool = NULL;
+    ngx_regex_direct_alloc = 0;
 }
 
 
+#if (NGX_PCRE2)
+
+ngx_int_t
+ngx_regex_compile(ngx_regex_compile_t *rc)
+{
+    int                     n, errcode;
+    char                   *p;
+    u_char                  errstr[128];
+    size_t                  erroff;
+    pcre2_code             *re;
+    ngx_regex_elt_t        *elt;
+    pcre2_general_context  *gctx;
+    pcre2_compile_context  *cctx;
+
+    if (ngx_regex_compile_context == NULL) {
+        /*
+         * Allocte a compile context if not yet allocated.  This uses
+         * direct allocations from heap, so the result can be cached
+         * even at runtime.
+         */
+
+        ngx_regex_malloc_init(NULL);
+
+        gctx = pcre2_general_context_create(ngx_regex_malloc, ngx_regex_free,
+                                            NULL);
+        if (gctx == NULL) {
+            ngx_regex_malloc_done();
+            goto nomem;
+        }
+
+        cctx = pcre2_compile_context_create(gctx);
+        if (cctx == NULL) {
+            pcre2_general_context_free(gctx);
+            ngx_regex_malloc_done();
+            goto nomem;
+        }
+
+        ngx_regex_compile_context = cctx;
+
+        pcre2_general_context_free(gctx);
+        ngx_regex_malloc_done();
+    }
+
+    ngx_regex_malloc_init(rc->pool);
+
+    re = pcre2_compile(rc->pattern.data, rc->pattern.len,
+                       (uint32_t) rc->options, &errcode, &erroff,
+                       ngx_regex_compile_context);
+
+    /* ensure that there is no current pool */
+    ngx_regex_malloc_done();
+
+    if (re == NULL) {
+        pcre2_get_error_message(errcode, errstr, 128);
+
+        if ((size_t) erroff == rc->pattern.len) {
+            rc->err.len = ngx_snprintf(rc->err.data, rc->err.len,
+                              "pcre2_compile() failed: %s in \"%V\"",
+                               errstr, &rc->pattern)
+                          - rc->err.data;
+
+        } else {
+            rc->err.len = ngx_snprintf(rc->err.data, rc->err.len,
+                              "pcre2_compile() failed: %s in \"%V\" at \"%s\"",
+                               errstr, &rc->pattern, rc->pattern.data + erroff)
+                          - rc->err.data;
+        }
+
+        return NGX_ERROR;
+    }
+
+    rc->regex = re;
+
+    /* do not study at runtime */
+
+    if (ngx_regex_studies != NULL) {
+        elt = ngx_list_push(ngx_regex_studies);
+        if (elt == NULL) {
+            goto nomem;
+        }
+
+        elt->regex = rc->regex;
+        elt->name = rc->pattern.data;
+    }
+
+    n = pcre2_pattern_info(re, PCRE2_INFO_CAPTURECOUNT, &rc->captures);
+    if (n < 0) {
+        p = "pcre2_pattern_info(\"%V\", PCRE2_INFO_CAPTURECOUNT) failed: %d";
+        goto failed;
+    }
+
+    if (rc->captures == 0) {
+        return NGX_OK;
+    }
+
+    n = pcre2_pattern_info(re, PCRE2_INFO_NAMECOUNT, &rc->named_captures);
+    if (n < 0) {
+        p = "pcre2_pattern_info(\"%V\", PCRE2_INFO_NAMECOUNT) failed: %d";
+        goto failed;
+    }
+
+    if (rc->named_captures == 0) {
+        return NGX_OK;
+    }
+
+    n = pcre2_pattern_info(re, PCRE2_INFO_NAMEENTRYSIZE, &rc->name_size);
+    if (n < 0) {
+        p = "pcre2_pattern_info(\"%V\", PCRE2_INFO_NAMEENTRYSIZE) failed: %d";
+        goto failed;
+    }
+
+    n = pcre2_pattern_info(re, PCRE2_INFO_NAMETABLE, &rc->names);
+    if (n < 0) {
+        p = "pcre2_pattern_info(\"%V\", PCRE2_INFO_NAMETABLE) failed: %d";
+        goto failed;
+    }
+
+    return NGX_OK;
+
+failed:
+
+    rc->err.len = ngx_snprintf(rc->err.data, rc->err.len, p, &rc->pattern, n)
+                  - rc->err.data;
+    return NGX_ERROR;
+
+nomem:
+
+    rc->err.len = ngx_snprintf(rc->err.data, rc->err.len,
+                               "regex \"%V\" compilation failed: no memory",
+                               &rc->pattern)
+                  - rc->err.data;
+    return NGX_ERROR;
+}
+
+#else
+
 ngx_int_t
 ngx_regex_compile(ngx_regex_compile_t *rc)
 {
@@ -192,6 +347,74 @@ nomem:
     return NGX_ERROR;
 }
 
+#endif
+
+
+#if (NGX_PCRE2)
+
+ngx_int_t
+ngx_regex_exec(ngx_regex_t *re, ngx_str_t *s, int *captures, ngx_uint_t size)
+{
+    size_t      *ov;
+    ngx_int_t    rc;
+    ngx_uint_t   n, i;
+
+    /*
+     * The pcre2_match() function might allocate memory for backtracking
+     * frames, typical allocations are from 40k and above.  So the allocator
+     * is configured to do direct allocations from heap during matching.
+     */
+
+    ngx_regex_malloc_init(NULL);
+
+    if (ngx_regex_match_data == NULL
+        || size > ngx_regex_match_data_size)
+    {
+        /*
+         * Allocate a match data if not yet allocated or smaller than
+         * needed.
+         */
+
+        if (ngx_regex_match_data) {
+            pcre2_match_data_free(ngx_regex_match_data);
+        }
+
+        ngx_regex_match_data_size = size;
+        ngx_regex_match_data = pcre2_match_data_create(size / 3, NULL);
+
+        if (ngx_regex_match_data == NULL) {
+            rc = PCRE2_ERROR_NOMEMORY;
+            goto failed;
+        }
+    }
+
+    rc = pcre2_match(re, s->data, s->len, 0, 0, ngx_regex_match_data, NULL);
+
+    if (rc < 0) {
+        goto failed;
+    }
+
+    n = pcre2_get_ovector_count(ngx_regex_match_data);
+    ov = pcre2_get_ovector_pointer(ngx_regex_match_data);
+
+    if (n > size / 3) {
+        n = size / 3;
+    }
+
+    for (i = 0; i < n; i++) {
+        captures[i * 2] = ov[i * 2];
+        captures[i * 2 + 1] = ov[i * 2 + 1];
+    }
+
+failed:
+
+    ngx_regex_malloc_done();
+
+    return rc;
+}
+
+#endif
+
 
 ngx_int_t
 ngx_regex_exec_array(ngx_array_t *a, ngx_str_t *s, ngx_log_t *log)
@@ -226,6 +449,35 @@ ngx_regex_exec_array(ngx_array_t *a, ngx
 }
 
 
+#if (NGX_PCRE2)
+
+static void * ngx_libc_cdecl
+ngx_regex_malloc(size_t size, void *data)
+{
+    if (ngx_regex_pool) {
+        return ngx_palloc(ngx_regex_pool, size);
+    }
+
+    if (ngx_regex_direct_alloc) {
+        return ngx_alloc(size, ngx_cycle->log);
+    }
+
+    return NULL;
+}
+
+
+static void ngx_libc_cdecl
+ngx_regex_free(void *p, void *data)
+{
+    if (ngx_regex_direct_alloc) {
+        ngx_free(p);
+    }
+
+    return;
+}
+
+#else
+
 static void * ngx_libc_cdecl
 ngx_regex_malloc(size_t size)
 {
@@ -243,11 +495,13 @@ ngx_regex_free(void *p)
     return;
 }
 
+#endif
+
 
 static void
 ngx_regex_cleanup(void *data)
 {
-#if (NGX_HAVE_PCRE_JIT)
+#if (NGX_PCRE2 || NGX_HAVE_PCRE_JIT)
     ngx_regex_conf_t *rcf = data;
 
     ngx_uint_t        i;
@@ -272,12 +526,17 @@ ngx_regex_cleanup(void *data)
         /*
          * The PCRE JIT compiler uses mmap for its executable codes, so we
          * have to explicitly call the pcre_free_study() function to free
-         * this memory.
+         * this memory.  In PCRE2, we call the pcre2_code_free() function
+         * for the same reason.
          */
 
+#if (NGX_PCRE2)
+        pcre2_code_free(elts[i].regex);
+#else
         if (elts[i].regex->extra != NULL) {
             pcre_free_study(elts[i].regex->extra);
         }
+#endif
     }
 #endif
 
@@ -287,6 +546,26 @@ ngx_regex_cleanup(void *data)
      */
 
     ngx_regex_studies = NULL;
+
+#if (NGX_PCRE2)
+
+    /*
+     * Free compile context and match data.  If needed at runtime by
+     * the new cycle, these will be re-allocated.
+     */
+
+    if (ngx_regex_compile_context) {
+        pcre2_compile_context_free(ngx_regex_compile_context);
+        ngx_regex_compile_context = NULL;
+    }
+
+    if (ngx_regex_match_data) {
+        pcre2_match_data_free(ngx_regex_match_data);
+        ngx_regex_match_data = NULL;
+        ngx_regex_match_data_size = 0;
+    }
+
+#endif
 }
 
 
@@ -294,7 +573,9 @@ static ngx_int_t
 ngx_regex_module_init(ngx_cycle_t *cycle)
 {
     int                opt;
+#if !(NGX_PCRE2)
     const char        *errstr;
+#endif
     ngx_uint_t         i;
     ngx_list_part_t   *part;
     ngx_regex_elt_t   *elts;
@@ -327,6 +608,23 @@ ngx_regex_module_init(ngx_cycle_t *cycle
             i = 0;
         }
 
+#if (NGX_PCRE2)
+
+        if (opt) {
+            int  n;
+
+            n = pcre2_jit_compile(elts[i].regex, PCRE2_JIT_COMPLETE);
+
+            if (n != 0) {
+                ngx_log_error(NGX_LOG_INFO, cycle->log, 0,
+                              "pcre2_jit_compile() failed: %d in \"%s\", "
+                              "ignored",
+                              n, elts[i].name);
+            }
+        }
+
+#else
+
         elts[i].regex->extra = pcre_study(elts[i].regex->code, opt, &errstr);
 
         if (errstr != NULL) {
@@ -350,11 +648,15 @@ ngx_regex_module_init(ngx_cycle_t *cycle
             }
         }
 #endif
+#endif
     }
 
     ngx_regex_malloc_done();
 
     ngx_regex_studies = NULL;
+#if (NGX_PCRE2)
+    ngx_regex_compile_context = NULL;
+#endif
 
     return NGX_OK;
 }
@@ -412,7 +714,21 @@ ngx_regex_pcre_jit(ngx_conf_t *cf, void 
         return NGX_CONF_OK;
     }
 
-#if (NGX_HAVE_PCRE_JIT)
+#if (NGX_PCRE2)
+    {
+    int       r;
+    uint32_t  jit;
+
+    jit = 0;
+    r = pcre2_config(PCRE2_CONFIG_JIT, &jit);
+
+    if (r != 0 || jit != 1) {
+        ngx_conf_log_error(NGX_LOG_WARN, cf, 0,
+                           "PCRE2 library does not support JIT");
+        *fp = 0;
+    }
+    }
+#elif (NGX_HAVE_PCRE_JIT)
     {
     int  jit, r;
 
diff --git a/src/core/ngx_regex.h b/src/core/ngx_regex.h
--- a/src/core/ngx_regex.h
+++ b/src/core/ngx_regex.h
@@ -12,19 +12,31 @@
 #include <ngx_config.h>
 #include <ngx_core.h>
 
+
+#if (NGX_PCRE2)
+
+#define PCRE2_CODE_UNIT_WIDTH  8
+#include <pcre2.h>
+
+#define NGX_REGEX_NO_MATCHED   PCRE2_ERROR_NOMATCH   /* -1 */
+#define NGX_REGEX_CASELESS     PCRE2_CASELESS
+
+typedef pcre2_code  ngx_regex_t;
+
+#else
+
 #include <pcre.h>
 
-
-#define NGX_REGEX_NO_MATCHED  PCRE_ERROR_NOMATCH   /* -1 */
-
-#define NGX_REGEX_CASELESS    PCRE_CASELESS
-
+#define NGX_REGEX_NO_MATCHED   PCRE_ERROR_NOMATCH   /* -1 */
+#define NGX_REGEX_CASELESS     PCRE_CASELESS
 
 typedef struct {
     pcre        *code;
     pcre_extra  *extra;
 } ngx_regex_t;
 
+#endif
+
 
 typedef struct {
     ngx_str_t     pattern;
@@ -49,10 +61,20 @@ typedef struct {
 void ngx_regex_init(void);
 ngx_int_t ngx_regex_compile(ngx_regex_compile_t *rc);
 
+#if (NGX_PCRE2)
+
+ngx_int_t ngx_regex_exec(ngx_regex_t *re, ngx_str_t *s, int *captures,
+    ngx_uint_t size);
+#define ngx_regex_exec_n       "pcre2_match()"
+
+#else
+
 #define ngx_regex_exec(re, s, captures, size)                                \
     pcre_exec(re->code, re->extra, (const char *) (s)->data, (s)->len, 0, 0, \
               captures, size)
-#define ngx_regex_exec_n      "pcre_exec()"
+#define ngx_regex_exec_n       "pcre_exec()"
+
+#endif
 
 ngx_int_t ngx_regex_exec_array(ngx_array_t *a, ngx_str_t *s, ngx_log_t *log);
 



More information about the nginx-devel mailing list