Blame server/util_pcre.c

Packit 90a5c9
/* Licensed to the Apache Software Foundation (ASF) under one or more
Packit 90a5c9
 * contributor license agreements.  See the NOTICE file distributed with
Packit 90a5c9
 * this work for additional information regarding copyright ownership.
Packit 90a5c9
 * The ASF licenses this file to You under the Apache License, Version 2.0
Packit 90a5c9
 * (the "License"); you may not use this file except in compliance with
Packit 90a5c9
 * the License.  You may obtain a copy of the License at
Packit 90a5c9
 *
Packit 90a5c9
 *     http://www.apache.org/licenses/LICENSE-2.0
Packit 90a5c9
 *
Packit 90a5c9
 * Unless required by applicable law or agreed to in writing, software
Packit 90a5c9
 * distributed under the License is distributed on an "AS IS" BASIS,
Packit 90a5c9
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
Packit 90a5c9
 * See the License for the specific language governing permissions and
Packit 90a5c9
 * limitations under the License.
Packit 90a5c9
 */
Packit 90a5c9
Packit 90a5c9
/* This code is based on pcreposix.c from the PCRE Library distribution,
Packit 90a5c9
 * as originally written by Philip Hazel <ph10@cam.ac.uk>, and forked by
Packit 90a5c9
 * the Apache HTTP Server project to provide POSIX-style regex function
Packit 90a5c9
 * wrappers around underlying PCRE library functions for httpd.
Packit 90a5c9
 * 
Packit 90a5c9
 * The original source file pcreposix.c is copyright and licensed as follows;
Packit 90a5c9
Packit 90a5c9
           Copyright (c) 1997-2004 University of Cambridge
Packit 90a5c9
Packit 90a5c9
-----------------------------------------------------------------------------
Packit 90a5c9
Redistribution and use in source and binary forms, with or without
Packit 90a5c9
modification, are permitted provided that the following conditions are met:
Packit 90a5c9
Packit 90a5c9
    * Redistributions of source code must retain the above copyright notice,
Packit 90a5c9
      this list of conditions and the following disclaimer.
Packit 90a5c9
Packit 90a5c9
    * Redistributions in binary form must reproduce the above copyright
Packit 90a5c9
      notice, this list of conditions and the following disclaimer in the
Packit 90a5c9
      documentation and/or other materials provided with the distribution.
Packit 90a5c9
Packit 90a5c9
    * Neither the name of the University of Cambridge nor the names of its
Packit 90a5c9
      contributors may be used to endorse or promote products derived from
Packit 90a5c9
      this software without specific prior written permission.
Packit 90a5c9
Packit 90a5c9
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
Packit 90a5c9
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
Packit 90a5c9
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
Packit 90a5c9
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
Packit 90a5c9
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
Packit 90a5c9
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
Packit 90a5c9
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
Packit 90a5c9
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
Packit 90a5c9
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
Packit 90a5c9
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
Packit 90a5c9
POSSIBILITY OF SUCH DAMAGE.
Packit 90a5c9
-----------------------------------------------------------------------------
Packit 90a5c9
*/
Packit 90a5c9
Packit 90a5c9
#include "httpd.h"
Packit 90a5c9
#include "apr_strings.h"
Packit 90a5c9
#include "apr_tables.h"
Packit 90a5c9
#include "pcre.h"
Packit 90a5c9
Packit 90a5c9
#define APR_WANT_STRFUNC
Packit 90a5c9
#include "apr_want.h"
Packit 90a5c9
Packit 90a5c9
#ifndef POSIX_MALLOC_THRESHOLD
Packit 90a5c9
#define POSIX_MALLOC_THRESHOLD (10)
Packit 90a5c9
#endif
Packit 90a5c9
Packit 90a5c9
/* Table of error strings corresponding to POSIX error codes; must be
Packit 90a5c9
 * kept in synch with include/ap_regex.h's AP_REG_E* definitions.
Packit 90a5c9
 */
Packit 90a5c9
Packit 90a5c9
static const char *const pstring[] = {
Packit 90a5c9
    "",                         /* Dummy for value 0 */
Packit 90a5c9
    "internal error",           /* AP_REG_ASSERT */
Packit 90a5c9
    "failed to get memory",     /* AP_REG_ESPACE */
Packit 90a5c9
    "bad argument",             /* AP_REG_INVARG */
Packit 90a5c9
    "match failed"              /* AP_REG_NOMATCH */
Packit 90a5c9
};
Packit 90a5c9
Packit 90a5c9
AP_DECLARE(apr_size_t) ap_regerror(int errcode, const ap_regex_t *preg,
Packit 90a5c9
                                   char *errbuf, apr_size_t errbuf_size)
Packit 90a5c9
{
Packit 90a5c9
    const char *message, *addmessage;
Packit 90a5c9
    apr_size_t length, addlength;
Packit 90a5c9
Packit 90a5c9
    message = (errcode >= (int)(sizeof(pstring) / sizeof(char *))) ?
Packit 90a5c9
              "unknown error code" : pstring[errcode];
Packit 90a5c9
    length = strlen(message) + 1;
Packit 90a5c9
Packit 90a5c9
    addmessage = " at offset ";
Packit 90a5c9
    addlength = (preg != NULL && (int)preg->re_erroffset != -1) ?
Packit 90a5c9
                strlen(addmessage) + 6 : 0;
Packit 90a5c9
Packit 90a5c9
    if (errbuf_size > 0) {
Packit 90a5c9
        if (addlength > 0 && errbuf_size >= length + addlength)
Packit 90a5c9
            apr_snprintf(errbuf, errbuf_size, "%s%s%-6d", message, addmessage,
Packit 90a5c9
                         (int)preg->re_erroffset);
Packit 90a5c9
        else
Packit 90a5c9
            apr_cpystrn(errbuf, message, errbuf_size);
Packit 90a5c9
    }
Packit 90a5c9
Packit 90a5c9
    return length + addlength;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
Packit 90a5c9
Packit 90a5c9
Packit 90a5c9
/*************************************************
Packit 90a5c9
 *           Free store held by a regex          *
Packit 90a5c9
 *************************************************/
Packit 90a5c9
Packit 90a5c9
AP_DECLARE(void) ap_regfree(ap_regex_t *preg)
Packit 90a5c9
{
Packit 90a5c9
    (pcre_free)(preg->re_pcre);
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
Packit 90a5c9
Packit 90a5c9
Packit 90a5c9
/*************************************************
Packit 90a5c9
 *            Compile a regular expression       *
Packit 90a5c9
 *************************************************/
Packit 90a5c9
Packit 90a5c9
static int default_cflags = AP_REG_DOLLAR_ENDONLY;
Packit 90a5c9
Packit 90a5c9
AP_DECLARE(int) ap_regcomp_get_default_cflags(void)
Packit 90a5c9
{
Packit 90a5c9
    return default_cflags;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
AP_DECLARE(void) ap_regcomp_set_default_cflags(int cflags)
Packit 90a5c9
{
Packit 90a5c9
    default_cflags = cflags;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
AP_DECLARE(int) ap_regcomp_default_cflag_by_name(const char *name)
Packit 90a5c9
{
Packit 90a5c9
    int cflag = 0;
Packit 90a5c9
Packit 90a5c9
    if (ap_cstr_casecmp(name, "ICASE") == 0) {
Packit 90a5c9
        cflag = AP_REG_ICASE;
Packit 90a5c9
    }
Packit 90a5c9
    else if (ap_cstr_casecmp(name, "DOTALL") == 0) {
Packit 90a5c9
        cflag = AP_REG_DOTALL;
Packit 90a5c9
    }
Packit 90a5c9
    else if (ap_cstr_casecmp(name, "DOLLAR_ENDONLY") == 0) {
Packit 90a5c9
        cflag = AP_REG_DOLLAR_ENDONLY;
Packit 90a5c9
    }
Packit 90a5c9
    else if (ap_cstr_casecmp(name, "EXTENDED") == 0) {
Packit 90a5c9
        cflag = AP_REG_EXTENDED;
Packit 90a5c9
    }
Packit 90a5c9
Packit 90a5c9
    return cflag;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
/*
Packit 90a5c9
 * Arguments:
Packit 90a5c9
 *  preg        points to a structure for recording the compiled expression
Packit 90a5c9
 *  pattern     the pattern to compile
Packit 90a5c9
 *  cflags      compilation flags
Packit 90a5c9
 *
Packit 90a5c9
 * Returns:      0 on success
Packit 90a5c9
 *               various non-zero codes on failure
Packit 90a5c9
*/
Packit 90a5c9
AP_DECLARE(int) ap_regcomp(ap_regex_t * preg, const char *pattern, int cflags)
Packit 90a5c9
{
Packit 90a5c9
    const char *errorptr;
Packit 90a5c9
    int erroffset;
Packit 90a5c9
    int errcode = 0;
Packit 90a5c9
    int options = PCRE_DUPNAMES;
Packit 90a5c9
Packit 90a5c9
    cflags |= default_cflags;
Packit 90a5c9
    if ((cflags & AP_REG_ICASE) != 0)
Packit 90a5c9
        options |= PCRE_CASELESS;
Packit 90a5c9
    if ((cflags & AP_REG_NEWLINE) != 0)
Packit 90a5c9
        options |= PCRE_MULTILINE;
Packit 90a5c9
    if ((cflags & AP_REG_DOTALL) != 0)
Packit 90a5c9
        options |= PCRE_DOTALL;
Packit 90a5c9
    if ((cflags & AP_REG_DOLLAR_ENDONLY) != 0)
Packit 90a5c9
        options |= PCRE_DOLLAR_ENDONLY;
Packit 90a5c9
Packit 90a5c9
    preg->re_pcre =
Packit 90a5c9
        pcre_compile2(pattern, options, &errcode, &errorptr, &erroffset, NULL);
Packit 90a5c9
    preg->re_erroffset = erroffset;
Packit 90a5c9
Packit 90a5c9
    if (preg->re_pcre == NULL) {
Packit 90a5c9
        /*
Packit 90a5c9
         * There doesn't seem to be constants defined for compile time error
Packit 90a5c9
         * codes. 21 is "failed to get memory" according to pcreapi(3).
Packit 90a5c9
         */
Packit 90a5c9
        if (errcode == 21)
Packit 90a5c9
            return AP_REG_ESPACE;
Packit 90a5c9
        return AP_REG_INVARG;
Packit 90a5c9
    }
Packit 90a5c9
Packit 90a5c9
    pcre_fullinfo((const pcre *)preg->re_pcre, NULL,
Packit 90a5c9
                   PCRE_INFO_CAPTURECOUNT, &(preg->re_nsub));
Packit 90a5c9
    return 0;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
Packit 90a5c9
Packit 90a5c9
Packit 90a5c9
/*************************************************
Packit 90a5c9
 *              Match a regular expression       *
Packit 90a5c9
 *************************************************/
Packit 90a5c9
Packit 90a5c9
/* Unfortunately, PCRE requires 3 ints of working space for each captured
Packit 90a5c9
 * substring, so we have to get and release working store instead of just using
Packit 90a5c9
 * the POSIX structures as was done in earlier releases when PCRE needed only 2
Packit 90a5c9
 * ints. However, if the number of possible capturing brackets is small, use a
Packit 90a5c9
 * block of store on the stack, to reduce the use of malloc/free. The threshold
Packit 90a5c9
 * is in a macro that can be changed at configure time.
Packit 90a5c9
 */
Packit 90a5c9
AP_DECLARE(int) ap_regexec(const ap_regex_t *preg, const char *string,
Packit 90a5c9
                           apr_size_t nmatch, ap_regmatch_t *pmatch,
Packit 90a5c9
                           int eflags)
Packit 90a5c9
{
Packit 90a5c9
    return ap_regexec_len(preg, string, strlen(string), nmatch, pmatch,
Packit 90a5c9
                          eflags);
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
AP_DECLARE(int) ap_regexec_len(const ap_regex_t *preg, const char *buff,
Packit 90a5c9
                               apr_size_t len, apr_size_t nmatch,
Packit 90a5c9
                               ap_regmatch_t *pmatch, int eflags)
Packit 90a5c9
{
Packit 90a5c9
    int rc;
Packit 90a5c9
    int options = 0;
Packit 90a5c9
    int *ovector = NULL;
Packit 90a5c9
    int small_ovector[POSIX_MALLOC_THRESHOLD * 3];
Packit 90a5c9
    int allocated_ovector = 0;
Packit 90a5c9
Packit 90a5c9
    if ((eflags & AP_REG_NOTBOL) != 0)
Packit 90a5c9
        options |= PCRE_NOTBOL;
Packit 90a5c9
    if ((eflags & AP_REG_NOTEOL) != 0)
Packit 90a5c9
        options |= PCRE_NOTEOL;
Packit 90a5c9
Packit 90a5c9
    ((ap_regex_t *)preg)->re_erroffset = (apr_size_t)(-1);    /* Only has meaning after compile */
Packit 90a5c9
Packit 90a5c9
    if (nmatch > 0) {
Packit 90a5c9
        if (nmatch <= POSIX_MALLOC_THRESHOLD) {
Packit 90a5c9
            ovector = &(small_ovector[0]);
Packit 90a5c9
        }
Packit 90a5c9
        else {
Packit 90a5c9
            ovector = (int *)malloc(sizeof(int) * nmatch * 3);
Packit 90a5c9
            if (ovector == NULL)
Packit 90a5c9
                return AP_REG_ESPACE;
Packit 90a5c9
            allocated_ovector = 1;
Packit 90a5c9
        }
Packit 90a5c9
    }
Packit 90a5c9
Packit 90a5c9
    rc = pcre_exec((const pcre *)preg->re_pcre, NULL, buff, (int)len,
Packit 90a5c9
                   0, options, ovector, nmatch * 3);
Packit 90a5c9
Packit 90a5c9
    if (rc == 0)
Packit 90a5c9
        rc = nmatch;            /* All captured slots were filled in */
Packit 90a5c9
Packit 90a5c9
    if (rc >= 0) {
Packit 90a5c9
        apr_size_t i;
Packit 90a5c9
        for (i = 0; i < (apr_size_t)rc; i++) {
Packit 90a5c9
            pmatch[i].rm_so = ovector[i * 2];
Packit 90a5c9
            pmatch[i].rm_eo = ovector[i * 2 + 1];
Packit 90a5c9
        }
Packit 90a5c9
        if (allocated_ovector)
Packit 90a5c9
            free(ovector);
Packit 90a5c9
        for (; i < nmatch; i++)
Packit 90a5c9
            pmatch[i].rm_so = pmatch[i].rm_eo = -1;
Packit 90a5c9
        return 0;
Packit 90a5c9
    }
Packit 90a5c9
Packit 90a5c9
    else {
Packit 90a5c9
        if (allocated_ovector)
Packit 90a5c9
            free(ovector);
Packit 90a5c9
        switch (rc) {
Packit 90a5c9
        case PCRE_ERROR_NOMATCH:
Packit 90a5c9
            return AP_REG_NOMATCH;
Packit 90a5c9
        case PCRE_ERROR_NULL:
Packit 90a5c9
            return AP_REG_INVARG;
Packit 90a5c9
        case PCRE_ERROR_BADOPTION:
Packit 90a5c9
            return AP_REG_INVARG;
Packit 90a5c9
        case PCRE_ERROR_BADMAGIC:
Packit 90a5c9
            return AP_REG_INVARG;
Packit 90a5c9
        case PCRE_ERROR_UNKNOWN_NODE:
Packit 90a5c9
            return AP_REG_ASSERT;
Packit 90a5c9
        case PCRE_ERROR_NOMEMORY:
Packit 90a5c9
            return AP_REG_ESPACE;
Packit 90a5c9
#ifdef PCRE_ERROR_MATCHLIMIT
Packit 90a5c9
        case PCRE_ERROR_MATCHLIMIT:
Packit 90a5c9
            return AP_REG_ESPACE;
Packit 90a5c9
#endif
Packit 90a5c9
#ifdef PCRE_ERROR_BADUTF8
Packit 90a5c9
        case PCRE_ERROR_BADUTF8:
Packit 90a5c9
            return AP_REG_INVARG;
Packit 90a5c9
#endif
Packit 90a5c9
#ifdef PCRE_ERROR_BADUTF8_OFFSET
Packit 90a5c9
        case PCRE_ERROR_BADUTF8_OFFSET:
Packit 90a5c9
            return AP_REG_INVARG;
Packit 90a5c9
#endif
Packit 90a5c9
        default:
Packit 90a5c9
            return AP_REG_ASSERT;
Packit 90a5c9
        }
Packit 90a5c9
    }
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
AP_DECLARE(int) ap_regname(const ap_regex_t *preg,
Packit 90a5c9
                           apr_array_header_t *names, const char *prefix,
Packit 90a5c9
                           int upper)
Packit 90a5c9
{
Packit 90a5c9
    int namecount;
Packit 90a5c9
    int nameentrysize;
Packit 90a5c9
    int i;
Packit 90a5c9
    char *nametable;
Packit 90a5c9
Packit 90a5c9
    pcre_fullinfo((const pcre *)preg->re_pcre, NULL,
Packit 90a5c9
                       PCRE_INFO_NAMECOUNT, &namecount);
Packit 90a5c9
    pcre_fullinfo((const pcre *)preg->re_pcre, NULL,
Packit 90a5c9
                       PCRE_INFO_NAMEENTRYSIZE, &nameentrysize);
Packit 90a5c9
    pcre_fullinfo((const pcre *)preg->re_pcre, NULL,
Packit 90a5c9
                       PCRE_INFO_NAMETABLE, &nametable);
Packit 90a5c9
Packit 90a5c9
    for (i = 0; i < namecount; i++) {
Packit 90a5c9
        const char *offset = nametable + i * nameentrysize;
Packit 90a5c9
        int capture = ((offset[0] << 8) + offset[1]);
Packit 90a5c9
        while (names->nelts <= capture) {
Packit 90a5c9
            apr_array_push(names);
Packit 90a5c9
        }
Packit 90a5c9
        if (upper || prefix) {
Packit 90a5c9
            char *name = ((char **) names->elts)[capture] =
Packit 90a5c9
                    prefix ? apr_pstrcat(names->pool, prefix, offset + 2,
Packit 90a5c9
                            NULL) :
Packit 90a5c9
                            apr_pstrdup(names->pool, offset + 2);
Packit 90a5c9
            if (upper) {
Packit 90a5c9
                ap_str_toupper(name);
Packit 90a5c9
            }
Packit 90a5c9
        }
Packit 90a5c9
        else {
Packit 90a5c9
            ((const char **)names->elts)[capture] = offset + 2;
Packit 90a5c9
        }
Packit 90a5c9
    }
Packit 90a5c9
Packit 90a5c9
    return namecount;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
/* End of pcreposix.c */