Commit 1d2261ff authored by Brian Pane's avatar Brian Pane
Browse files

Performance fix: When a BrowserMatch or SetEnvIf pattern doesn't

actually require regular expression parsing, use a fast string search
instead.


git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@95027 13f79535-47bb-0310-9956-ffa450edef68
parent 606428ce
Loading
Loading
Loading
Loading
+77 −1
Changes for modules/metadata/mod_setenvif.c: 77 added lines, 1 removed line.
Original line number Diff line number Diff line
@@ -123,6 +123,7 @@

#include "apr.h"
#include "apr_strings.h"
#include "apr_strmatch.h"

#define APR_WANT_STRFUNC
#include "apr_want.h"
@@ -149,6 +150,7 @@ typedef struct {
    regex_t *pnamereg;          /* compiled header name regex */
    char *regex;                /* regex to match against */
    regex_t *preg;              /* compiled regex */
    const apr_strmatch_pattern *pattern; /* non-regex pattern to match */
    apr_table_t *features;      /* env vars to set (or unset) */
    enum special special_type;  /* is it a "special" header ? */
    int icase;                  /* ignoring case? */
@@ -219,10 +221,68 @@ static int is_header_regex(apr_pool_t *p, const char* name)
    }
    return 0;
}

/* If the input string does not take advantage of regular
 * expression metacharacters, return a pointer to an equivalent
 * string that can be searched using apr_strmatch().  (The
 * returned string will often be the input string.  But if
 * the input string contains escaped characters, the returned
 * string will be a copy with the escapes removed.)
 */
static const char *non_regex_pattern(apr_pool_t *p, const char *s)
{
    const char *src = s;
    int escapes_found = 0;
    int in_escape = 0;

    while (*src) {
        if (in_escape) {
            in_escape = 0;
        }
        else {
            switch (*src) {
            case '^':
            case '.':
            case '$':
            case '|':
            case '(':
            case ')':
            case '[':
            case ']':
            case '*':
            case '+':
            case '?':
            case '{':
            case '}':
                return NULL;
            case '\\':
                in_escape = 1;
                escapes_found = 1;
            }
        }
        src++;
    }
    if (!escapes_found) {
        return s;
    }
    else {
        char *unescaped = (char *)apr_palloc(p, src - s + 1);
        char *dst = unescaped;
        src = s;
        do {
            if (*src == '\\') {
                src++;
            }
        } while ((*dst++ = *src++));
        return unescaped;
    }
}

static const char *add_setenvif_core(cmd_parms *cmd, void *mconfig,
				     char *fname, const char *args)
{
    char *regex;
    const char *simple_pattern;
    const char *feature;
    sei_cfg_rec *sconf;
    sei_entry *new;
@@ -279,6 +339,16 @@ static const char *add_setenvif_core(cmd_parms *cmd, void *mconfig,
	new->name = fname;
	new->regex = regex;
	new->icase = icase;
        if ((simple_pattern = non_regex_pattern(cmd->pool, regex))) {
            new->pattern = apr_strmatch_precompile(cmd->pool,
                                                   simple_pattern, 1);
            if (new->pattern == NULL) {
                return apr_pstrcat(cmd->pool, cmd->cmd->name,
                                   " pattern could not be compiled.", NULL);
            }
            new->preg = NULL;
        }
        else {
            new->preg = ap_pregcomp(cmd->pool, regex,
                                    (REG_EXTENDED | REG_NOSUB
                                     | (icase ? REG_ICASE : 0)));
@@ -286,6 +356,8 @@ static const char *add_setenvif_core(cmd_parms *cmd, void *mconfig,
                return apr_pstrcat(cmd->pool, cmd->cmd->name,
                                   " regex could not be compiled.", NULL);
            }
            new->pattern = NULL;
        }
	new->features = apr_table_make(cmd->pool, 2);

	if (!strcasecmp(fname, "remote_addr")) {
@@ -408,6 +480,7 @@ static int match_headers(request_rec *r)
    sei_entry *entries;
    const apr_table_entry_t *elts;
    const char *val;
    apr_size_t val_len = 0;
    int i, j;
    char *last_name;

@@ -477,6 +550,7 @@ static int match_headers(request_rec *r)
                    }
                }
	    }
            val_len = val ? strlen(val) : 0;
        }

	/*
@@ -487,9 +561,11 @@ static int match_headers(request_rec *r)
	 */
        if (val == NULL) {
            val = "";
            val_len = 0;
        }

        if (!ap_regexec(b->preg, val, 0, NULL, 0)) {
        if (b->pattern ? apr_strmatch(b->pattern, val, val_len) :
            !ap_regexec(b->preg, val, 0, NULL, 0)) {
	    const apr_array_header_t *arr = apr_table_elts(b->features);
            elts = (const apr_table_entry_t *) arr->elts;