# PCRE names its libraries differently for debug vs. release builds.
# We can't query our own CMAKE_BUILD_TYPE at configure time.
# If the debug version exists in PREFIX/lib, default to that one.
-IF(EXISTS "${CMAKE_INSTALL_PREFIX}/lib/pcred.lib")
+IF(EXISTS "${CMAKE_INSTALL_PREFIX}/lib/pcre2-8d.lib")
+ SET(default_pcre_libraries ${CMAKE_INSTALL_PREFIX}/lib/pcre2-8d.lib)
+ SET(default_pcre_cflags "-DHAVE_PCRE2")
+ELSEIF(EXISTS "${CMAKE_INSTALL_PREFIX}/lib/pcre2-8.lib")
+ SET(default_pcre_libraries ${CMAKE_INSTALL_PREFIX}/lib/pcre2-8.lib)
+ SET(default_pcre_cflags "-DHAVE_PCRE2")
+ELSEIF(EXISTS "${CMAKE_INSTALL_PREFIX}/lib/pcred.lib")
SET(default_pcre_libraries ${CMAKE_INSTALL_PREFIX}/lib/pcred.lib)
ELSE()
SET(default_pcre_libraries ${CMAKE_INSTALL_PREFIX}/lib/pcre.lib)
SET(APR_LIBRARIES ${default_apr_libraries} CACHE STRING "APR libraries to link with")
SET(NGHTTP2_INCLUDE_DIR "${CMAKE_INSTALL_PREFIX}/include" CACHE STRING "Directory with NGHTTP2 include files within nghttp2 subdirectory")
SET(NGHTTP2_LIBRARIES ${default_nghttp2_libraries} CACHE STRING "NGHTTP2 libraries to link with")
+SET(PCRE_CFLAGS "${default_pcre_cflags}" CACHE STRING "PCRE flags for util_pcre.c compilation")
SET(PCRE_INCLUDE_DIR "${CMAKE_INSTALL_PREFIX}/include" CACHE STRING "Directory with PCRE include files")
SET(PCRE_LIBRARIES ${default_pcre_libraries} CACHE STRING "PCRE libraries to link with")
SET(LIBXML2_ICONV_INCLUDE_DIR "" CACHE STRING "Directory with iconv include files for libxml2")
SET(install_bin_pdb ${install_bin_pdb} $<TARGET_PDB_FILE:libhttpd>)
TARGET_LINK_LIBRARIES(libhttpd ${EXTRA_LIBS} ${APR_LIBRARIES} ${PCRE_LIBRARIES} ${HTTPD_SYSTEM_LIBS})
DEFINE_WITH_BLANKS(define_long_name "LONG_NAME" "Apache HTTP Server Core")
-SET_TARGET_PROPERTIES(libhttpd PROPERTIES COMPILE_FLAGS "-DAP_DECLARE_EXPORT ${define_long_name} -DBIN_NAME=libhttpd.dll ${EXTRA_COMPILE_FLAGS}")
+SET_TARGET_PROPERTIES(libhttpd PROPERTIES COMPILE_FLAGS "-DAP_DECLARE_EXPORT ${define_long_name} ${PCRE_CFLAGS} -DBIN_NAME=libhttpd.dll ${EXTRA_COMPILE_FLAGS}")
ADD_DEPENDENCIES(libhttpd test_char_header)
########### HTTPD EXECUTABLES ##########
PATCHES ACCEPTED TO BACKPORT FROM TRUNK:
[ start all new proposals below, under PATCHES PROPOSED. ]
- *) Support PCRE2 (10.x) in place of PCRE (8.x).
- Submitted by: wrowe, Petr Pisar [ppisar redhat.com], rjung
- trunk patches:
- http://svn.apache.org/r1773454
- http://svn.apache.org/r1773741
- http://svn.apache.org/r1773742
- http://svn.apache.org/r1773839
- http://svn.apache.org/r1773870
- http://svn.apache.org/r1773882
- http://svn.apache.org/r1814662
- http://svn.apache.org/r1881478
- summarized/conflicts resolved:
- https://gist.github.com/wrowe/73f655d13bbe0f12030aa4557e804d8a
- +1: wrowe, rpluem, ylavic
- wrowe notes that the current code drops optimizations, owing to the fact
- that the ovector is a required allocation and is no longer allocated on
- the stack, by design. The correct fix is an apr userdata allocation on
- the appropriate pool, which would be thread-safe, but the actual API of
- ap_regexec[_len]() offers us no pool and isn't suitable for httpd-2.4.x.
- At this time, PCRE 8.45 is EOL and will not receive security updates,
- and taking ovector and other arrays off the stack was in direct reaction
- to the patterns of abuse of previous pcre exploits. So this patch doesn't
- wait for httpd-2.4 to be retired, it will need to be adopted without the
- existing optimiation.
- jorton: Adding ap_pregexec/_len which pass a pool would also work
- for internal users of this api; not sure if performance
- impact is significant from using malloc here.
- ylavic: A follow up backport (based on this one) using thread locals to
- reuse ap_regex*() contexts: https://github.com/apache/httpd/pull/289
- Proposed for backport below, in place of or after this one.
- rpluem: +1 on PR 289 as well.
-
*) Support PCRE2 with buffers reuse through Thread Local Storage.
trunk patches:
http://svn.apache.org/r1897240
2.4.x patches:
https://github.com/apache/httpd/pull/289.diff
(PR: https://github.com/apache/httpd/pull/289)
- +1: ylavic, rpluem, covener, steffenal
+ +1: ylavic, rpluem, covener, steffenal, wrowe
ylavic: This backport proposal inludes the PCRE2 backport already accepted,
we can apply this one instead or the original one first and then
this one (I'd have to rebase the github PR first).
AC_ARG_WITH(pcre,
APACHE_HELP_STRING(--with-pcre=PATH,Use external PCRE library))
-
-AC_PATH_PROG(PCRE_CONFIG, pcre-config, false)
-if test -d "$with_pcre" && test -x "$with_pcre/bin/pcre-config"; then
- PCRE_CONFIG=$with_pcre/bin/pcre-config
-elif test -x "$with_pcre"; then
- PCRE_CONFIG=$with_pcre
+if test "x$with_pcre" = "x" || test "$with_pcre" = "yes"; then
+ with_pcre="$PATH"
+else if which $with_pcre 2>/dev/null; then :; else
+ with_pcre="$with_pcre/bin:$with_pcre"
+fi
fi
-if test "$PCRE_CONFIG" != "false"; then
+AC_CHECK_TARGET_TOOLS(PCRE_CONFIG, [pcre2-config pcre-config],
+ [`which $with_pcre 2>/dev/null`], $with_pcre)
+
+if test "x$PCRE_CONFIG" != "x"; then
if $PCRE_CONFIG --version >/dev/null 2>&1; then :; else
- AC_MSG_ERROR([Did not find pcre-config script at $PCRE_CONFIG])
+ AC_MSG_ERROR([Did not find working script at $PCRE_CONFIG])
fi
case `$PCRE_CONFIG --version` in
+ [1[0-9].*])
+ AC_DEFINE(HAVE_PCRE2, 1, [Detected PCRE2])
+ ;;
[[1-5].*])
AC_MSG_ERROR([Need at least pcre version 6.0])
;;
esac
AC_MSG_NOTICE([Using external PCRE library from $PCRE_CONFIG])
APR_ADDTO(PCRE_INCLUDES, [`$PCRE_CONFIG --cflags`])
- APR_ADDTO(PCRE_LIBS, [`$PCRE_CONFIG --libs`])
+ APR_ADDTO(PCRE_LIBS, [`$PCRE_CONFIG --libs8 2>/dev/null || $PCRE_CONFIG --libs`])
else
- AC_MSG_ERROR([pcre-config for libpcre not found. PCRE is required and available from http://pcre.org/])
+ AC_MSG_ERROR([pcre(2)-config for libpcre not found. PCRE is required and available from http://pcre.org/])
fi
APACHE_SUBST(PCRE_LIBS)
dnl Add in path to PCRE includes
APR_ADDTO(INCLUDES, $PCRE_INCLUDES)
+save_CPPFLAGS="$CPPFLAGS"
+CPPFLAGS="$CPPFLAGS $PCRE_INCLUDES"
+AC_EGREP_CPP(yes,
+[
+#ifdef HAVE_PCRE2
+yes
+#else
+#include <pcre.h>
+#ifdef PCRE_DUPNAMES
+yes
+#endif
+#endif
+],pcre_have_dupnames=yes,pcre_have_dupnames=no)
+if test "$pcre_have_dupnames" != "yes"; then
+ AC_MSG_ERROR([pcre version does not support PCRE_DUPNAMES])
+fi
+CPPFLAGS="$save_CPPFLAGS"
+
AC_MSG_NOTICE([])
AC_MSG_NOTICE([Applying OS-specific hints for httpd...])
AC_MSG_NOTICE([])
#include "httpd.h"
#include "apr_strings.h"
#include "apr_tables.h"
+
+#ifdef HAVE_PCRE2
+#define PCRE2_CODE_UNIT_WIDTH 8
+#include "pcre2.h"
+#define PCREn(x) PCRE2_ ## x
+#else
#include "pcre.h"
+#define PCREn(x) PCRE_ ## x
+#endif
/* PCRE_DUPNAMES is only present since version 6.7 of PCRE */
-#ifndef PCRE_DUPNAMES
+#if !defined(PCRE_DUPNAMES) && !defined(HAVE_PCRE2)
#error PCRE Version 6.7 or later required!
#else
AP_DECLARE(void) ap_regfree(ap_regex_t *preg)
{
+#ifdef HAVE_PCRE2
+ pcre2_code_free(preg->re_pcre);
+#else
(pcre_free)(preg->re_pcre);
+#endif
}
*/
AP_DECLARE(int) ap_regcomp(ap_regex_t * preg, const char *pattern, int cflags)
{
+#ifdef HAVE_PCRE2
+ uint32_t capcount;
+ size_t erroffset;
+#else
const char *errorptr;
int erroffset;
+#endif
int errcode = 0;
- int options = PCRE_DUPNAMES;
+ int options = PCREn(DUPNAMES);
if ((cflags & AP_REG_NO_DEFAULT) == 0)
cflags |= default_cflags;
if ((cflags & AP_REG_ICASE) != 0)
- options |= PCRE_CASELESS;
+ options |= PCREn(CASELESS);
if ((cflags & AP_REG_NEWLINE) != 0)
- options |= PCRE_MULTILINE;
+ options |= PCREn(MULTILINE);
if ((cflags & AP_REG_DOTALL) != 0)
- options |= PCRE_DOTALL;
+ options |= PCREn(DOTALL);
if ((cflags & AP_REG_DOLLAR_ENDONLY) != 0)
- options |= PCRE_DOLLAR_ENDONLY;
+ options |= PCREn(DOLLAR_ENDONLY);
- preg->re_pcre =
- pcre_compile2(pattern, options, &errcode, &errorptr, &erroffset, NULL);
- preg->re_erroffset = erroffset;
+#ifdef HAVE_PCRE2
+ preg->re_pcre = pcre2_compile((const unsigned char *)pattern,
+ PCRE2_ZERO_TERMINATED, options, &errcode,
+ &erroffset, NULL);
+#else
+ preg->re_pcre = pcre_compile2(pattern, options, &errcode,
+ &errorptr, &erroffset, NULL);
+#endif
+ preg->re_erroffset = erroffset;
if (preg->re_pcre == NULL) {
- /*
- * There doesn't seem to be constants defined for compile time error
- * codes. 21 is "failed to get memory" according to pcreapi(3).
- */
+ /* Internal ERR21 is "failed to get memory" according to pcreapi(3) */
if (errcode == 21)
return AP_REG_ESPACE;
return AP_REG_INVARG;
}
+#ifdef HAVE_PCRE2
+ pcre2_pattern_info((const pcre2_code *)preg->re_pcre,
+ PCRE2_INFO_CAPTURECOUNT, &capcount);
+ preg->re_nsub = capcount;
+#else
pcre_fullinfo((const pcre *)preg->re_pcre, NULL,
- PCRE_INFO_CAPTURECOUNT, &(preg->re_nsub));
+ PCRE_INFO_CAPTURECOUNT, &(preg->re_nsub));
+#endif
return 0;
}
{
int rc;
int options = 0;
- int *ovector = NULL;
+ apr_size_t nlim;
+#ifdef HAVE_PCRE2
+ pcre2_match_data *matchdata;
+ size_t *ovector;
+#else
int small_ovector[POSIX_MALLOC_THRESHOLD * 3];
int allocated_ovector = 0;
+ int *ovector = NULL;
+#endif
if ((eflags & AP_REG_NOTBOL) != 0)
- options |= PCRE_NOTBOL;
+ options |= PCREn(NOTBOL);
if ((eflags & AP_REG_NOTEOL) != 0)
- options |= PCRE_NOTEOL;
-
- ((ap_regex_t *)preg)->re_erroffset = (apr_size_t)(-1); /* Only has meaning after compile */
-
+ options |= PCREn(NOTEOL);
+
+#ifdef HAVE_PCRE2
+ /* TODO: create a generic TLS matchdata buffer of some nmatch limit,
+ * e.g. 10 matches, to avoid a malloc-per-call. If it must be alloced,
+ * implement a general context using palloc and no free implementation.
+ */
+ nlim = ((apr_size_t)preg->re_nsub + 1) > nmatch
+ ? ((apr_size_t)preg->re_nsub + 1) : nmatch;
+ matchdata = pcre2_match_data_create(nlim, NULL);
+ if (matchdata == NULL)
+ return AP_REG_ESPACE;
+ ovector = pcre2_get_ovector_pointer(matchdata);
+ rc = pcre2_match((const pcre2_code *)preg->re_pcre,
+ (const unsigned char *)buff, len,
+ 0, options, matchdata, NULL);
+ if (rc == 0)
+ rc = nlim; /* All captured slots were filled in */
+#else
if (nmatch > 0) {
if (nmatch <= POSIX_MALLOC_THRESHOLD) {
ovector = &(small_ovector[0]);
allocated_ovector = 1;
}
}
-
rc = pcre_exec((const pcre *)preg->re_pcre, NULL, buff, (int)len,
0, options, ovector, nmatch * 3);
-
if (rc == 0)
rc = nmatch; /* All captured slots were filled in */
+#endif
if (rc >= 0) {
apr_size_t i;
- for (i = 0; i < (apr_size_t)rc; i++) {
+ nlim = (apr_size_t)rc < nmatch ? (apr_size_t)rc : nmatch;
+ for (i = 0; i < nlim; i++) {
pmatch[i].rm_so = ovector[i * 2];
pmatch[i].rm_eo = ovector[i * 2 + 1];
}
- if (allocated_ovector)
- free(ovector);
for (; i < nmatch; i++)
pmatch[i].rm_so = pmatch[i].rm_eo = -1;
- return 0;
}
+#ifdef HAVE_PCRE2
+ pcre2_match_data_free(matchdata);
+#else
+ if (allocated_ovector)
+ free(ovector);
+#endif
+
+ if (rc >= 0) {
+ return 0;
+ }
else {
- if (allocated_ovector)
- free(ovector);
+#ifdef HAVE_PCRE2
+ if (rc <= PCRE2_ERROR_UTF8_ERR1 && rc >= PCRE2_ERROR_UTF8_ERR21)
+ return AP_REG_INVARG;
+#endif
switch (rc) {
- case PCRE_ERROR_NOMATCH:
+ case PCREn(ERROR_NOMATCH):
return AP_REG_NOMATCH;
- case PCRE_ERROR_NULL:
+ case PCREn(ERROR_NULL):
return AP_REG_INVARG;
- case PCRE_ERROR_BADOPTION:
+ case PCREn(ERROR_BADOPTION):
return AP_REG_INVARG;
- case PCRE_ERROR_BADMAGIC:
+ case PCREn(ERROR_BADMAGIC):
return AP_REG_INVARG;
- case PCRE_ERROR_UNKNOWN_NODE:
- return AP_REG_ASSERT;
- case PCRE_ERROR_NOMEMORY:
+ case PCREn(ERROR_NOMEMORY):
return AP_REG_ESPACE;
-#ifdef PCRE_ERROR_MATCHLIMIT
- case PCRE_ERROR_MATCHLIMIT:
+#if defined(HAVE_PCRE2) || defined(PCRE_ERROR_MATCHLIMIT)
+ case PCREn(ERROR_MATCHLIMIT):
return AP_REG_ESPACE;
#endif
-#ifdef PCRE_ERROR_BADUTF8
- case PCRE_ERROR_BADUTF8:
+#if defined(PCRE_ERROR_UNKNOWN_NODE)
+ case PCRE_ERROR_UNKNOWN_NODE:
+ return AP_REG_ASSERT;
+#endif
+#if defined(PCRE_ERROR_BADUTF8)
+ case PCREn(ERROR_BADUTF8):
return AP_REG_INVARG;
#endif
-#ifdef PCRE_ERROR_BADUTF8_OFFSET
- case PCRE_ERROR_BADUTF8_OFFSET:
+#if defined(PCRE_ERROR_BADUTF8_OFFSET)
+ case PCREn(ERROR_BADUTF8_OFFSET):
return AP_REG_INVARG;
#endif
default:
apr_array_header_t *names, const char *prefix,
int upper)
{
+ char *nametable;
+
+#ifdef HAVE_PCRE2
+ uint32_t namecount;
+ uint32_t nameentrysize;
+ uint32_t i;
+ pcre2_pattern_info((const pcre2_code *)preg->re_pcre,
+ PCRE2_INFO_NAMECOUNT, &namecount);
+ pcre2_pattern_info((const pcre2_code *)preg->re_pcre,
+ PCRE2_INFO_NAMEENTRYSIZE, &nameentrysize);
+ pcre2_pattern_info((const pcre2_code *)preg->re_pcre,
+ PCRE2_INFO_NAMETABLE, &nametable);
+#else
int namecount;
int nameentrysize;
int i;
- char *nametable;
-
pcre_fullinfo((const pcre *)preg->re_pcre, NULL,
- PCRE_INFO_NAMECOUNT, &namecount);
+ PCRE_INFO_NAMECOUNT, &namecount);
pcre_fullinfo((const pcre *)preg->re_pcre, NULL,
- PCRE_INFO_NAMEENTRYSIZE, &nameentrysize);
+ PCRE_INFO_NAMEENTRYSIZE, &nameentrysize);
pcre_fullinfo((const pcre *)preg->re_pcre, NULL,
- PCRE_INFO_NAMETABLE, &nametable);
+ PCRE_INFO_NAMETABLE, &nametable);
+#endif
for (i = 0; i < namecount; i++) {
const char *offset = nametable + i * nameentrysize;