From 931acbf5bcd550af8613d131f4ba49e22e909efb Mon Sep 17 00:00:00 2001
From: Maxim Dounin <mdounin@mdounin.ru>
Date: Sat, 25 Dec 2021 01:07:16 +0300
Subject: [PATCH] PCRE2 and PCRE binary compatibility.

With this change, dynamic modules using nginx regex interface can be used
regardless of the variant of the PCRE library nginx was compiled with.

If a module is compiled with different PCRE library variant, in case of
ngx_regex_exec() errors it will report wrong function name in error
messages.  This is believed to be tolerable, given that fixing this will
require interface changes.
---
 src/core/ngx_regex.c | 46 ++++++++++++++++++++++++++++++++++++++++----
 src/core/ngx_regex.h | 17 ++++++----------
 2 files changed, 48 insertions(+), 15 deletions(-)

diff --git a/src/core/ngx_regex.c b/src/core/ngx_regex.c
index 5ae4f780b..991728b27 100644
--- a/src/core/ngx_regex.c
+++ b/src/core/ngx_regex.c
@@ -118,6 +118,7 @@ ngx_regex_compile(ngx_regex_compile_t *rc)
     char                   *p;
     u_char                  errstr[128];
     size_t                  erroff;
+    uint32_t                options;
     pcre2_code             *re;
     ngx_regex_elt_t        *elt;
     pcre2_general_context  *gctx;
@@ -152,11 +153,24 @@ ngx_regex_compile(ngx_regex_compile_t *rc)
         ngx_regex_malloc_done();
     }
 
+    options = 0;
+
+    if (rc->options & NGX_REGEX_CASELESS) {
+        options |= PCRE2_CASELESS;
+    }
+
+    if (rc->options & ~NGX_REGEX_CASELESS) {
+        rc->err.len = ngx_snprintf(rc->err.data, rc->err.len,
+                            "regex \"%V\" compilation failed: invalid options",
+                            &rc->pattern)
+                      - rc->err.data;
+        return NGX_ERROR;
+    }
+
     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);
+    re = pcre2_compile(rc->pattern.data, rc->pattern.len, options,
+                       &errcode, &erroff, ngx_regex_compile_context);
 
     /* ensure that there is no current pool */
     ngx_regex_malloc_done();
@@ -252,11 +266,26 @@ ngx_regex_compile(ngx_regex_compile_t *rc)
     char             *p;
     pcre             *re;
     const char       *errstr;
+    ngx_uint_t        options;
     ngx_regex_elt_t  *elt;
 
+    options = 0;
+
+    if (rc->options & NGX_REGEX_CASELESS) {
+        options |= PCRE_CASELESS;
+    }
+
+    if (rc->options & ~NGX_REGEX_CASELESS) {
+        rc->err.len = ngx_snprintf(rc->err.data, rc->err.len,
+                            "regex \"%V\" compilation failed: invalid options",
+                            &rc->pattern)
+                      - rc->err.data;
+        return NGX_ERROR;
+    }
+
     ngx_regex_malloc_init(rc->pool);
 
-    re = pcre_compile((const char *) rc->pattern.data, (int) rc->options,
+    re = pcre_compile((const char *) rc->pattern.data, (int) options,
                       &errstr, &erroff, NULL);
 
     /* ensure that there is no current pool */
@@ -413,6 +442,15 @@ failed:
     return rc;
 }
 
+#else
+
+ngx_int_t
+ngx_regex_exec(ngx_regex_t *re, ngx_str_t *s, int *captures, ngx_uint_t size)
+{
+    return pcre_exec(re->code, re->extra, (const char *) s->data, s->len,
+                     0, 0, captures, size);
+}
+
 #endif
 
 
diff --git a/src/core/ngx_regex.h b/src/core/ngx_regex.h
index 70bd1db9f..74e694d2e 100644
--- a/src/core/ngx_regex.h
+++ b/src/core/ngx_regex.h
@@ -19,7 +19,6 @@
 #include <pcre2.h>
 
 #define NGX_REGEX_NO_MATCHED   PCRE2_ERROR_NOMATCH   /* -1 */
-#define NGX_REGEX_CASELESS     PCRE2_CASELESS
 
 typedef pcre2_code  ngx_regex_t;
 
@@ -28,7 +27,6 @@ typedef pcre2_code  ngx_regex_t;
 #include <pcre.h>
 
 #define NGX_REGEX_NO_MATCHED   PCRE_ERROR_NOMATCH    /* -1 */
-#define NGX_REGEX_CASELESS     PCRE_CASELESS
 
 typedef struct {
     pcre        *code;
@@ -38,10 +36,13 @@ typedef struct {
 #endif
 
 
+#define NGX_REGEX_CASELESS     0x00000001
+
+
 typedef struct {
     ngx_str_t     pattern;
     ngx_pool_t   *pool;
-    ngx_int_t     options;
+    ngx_uint_t    options;
 
     ngx_regex_t  *regex;
     int           captures;
@@ -61,19 +62,13 @@ 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);
+
+#if (NGX_PCRE2)
 #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()"
-
 #endif
 
 ngx_int_t ngx_regex_exec_array(ngx_array_t *a, ngx_str_t *s, ngx_log_t *log);