httpd-cvs mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From n.@apache.org
Subject cvs commit: httpd-2.0/modules/mappers mod_rewrite.c
Date Wed, 30 Jul 2003 17:19:36 GMT
nd          2003/07/30 10:19:36

  Modified:    modules/mappers mod_rewrite.c
  Log:
  cleanup RewriteCond evaluation.
  - avoid unnecessary memory operations
  - parse non-regex patterns at configuration time, which
  - gives the ability to throw a useful warning, where [NC] is not supported
  - and speeds up processing at runtime
  - allow [NC] for simple comparison pattern (=)
  - improve readability
  
  Revision  Changes    Path
  1.206     +138 -107  httpd-2.0/modules/mappers/mod_rewrite.c
  
  Index: mod_rewrite.c
  ===================================================================
  RCS file: /home/cvs/httpd-2.0/modules/mappers/mod_rewrite.c,v
  retrieving revision 1.205
  retrieving revision 1.206
  diff -u -r1.205 -r1.206
  --- mod_rewrite.c	30 Jul 2003 13:37:36 -0000	1.205
  +++ mod_rewrite.c	30 Jul 2003 17:19:36 -0000	1.206
  @@ -225,6 +225,7 @@
   #define LEFT_CURLY  '{'
   #define RIGHT_CURLY '}'
   
  +
   /*
    * +-------------------------------------------------------+
    * |                                                       |
  @@ -246,11 +247,26 @@
       char **argv;                   /* argv of the external rewrite map    */
   } rewritemap_entry;
   
  +/* special pattern types for RewriteCond */
  +typedef enum {
  +    CONDPAT_REGEX = 0,
  +    CONDPAT_FILE_EXISTS,
  +    CONDPAT_FILE_SIZE,
  +    CONDPAT_FILE_LINK,
  +    CONDPAT_FILE_DIR,
  +    CONDPAT_LU_URL,
  +    CONDPAT_LU_FILE,
  +    CONDPAT_STR_GT,
  +    CONDPAT_STR_LT,
  +    CONDPAT_STR_EQ
  +} pattern_type;
  +
   typedef struct {
  -    char    *input;                /* Input string of RewriteCond   */
  -    char    *pattern;              /* the RegExp pattern string     */
  -    regex_t *regexp;               /* the precompiled regexp        */
  -    int      flags;                /* Flags which control the match */
  +    char        *input;   /* Input string of RewriteCond   */
  +    char        *pattern; /* the RegExp pattern string     */
  +    regex_t     *regexp;  /* the precompiled regexp        */
  +    int          flags;   /* Flags which control the match */
  +    pattern_type ptype;   /* pattern type                  */
   } rewritecond_entry;
   
   typedef struct {
  @@ -2876,18 +2892,23 @@
           newcond = apr_array_push(dconf->rewriteconds);
       }
   
  -    /*  parse the argument line ourself */
  +    /* parse the argument line ourself
  +     * a1 .. a3 are substrings of str, which is a fresh copy
  +     * of the argument line. So we can use a1 .. a3 without
  +     * copying them again.
  +     */
       if (parseargline(str, &a1, &a2, &a3)) {
           return apr_pstrcat(cmd->pool, "RewriteCond: bad argument line '", str,
                              "'", NULL);
       }
   
  -    /*  arg1: the input string */
  -    newcond->input = apr_pstrdup(cmd->pool, a1);
  +    /* arg1: the input string */
  +    newcond->input = a1;
   
       /* arg3: optional flags field
  -       (this have to be first parsed, because we need to
  -        know if the regex should be compiled with ICASE!) */
  +     * (this has to be parsed first, because we need to
  +     *  know if the regex should be compiled with ICASE!)
  +     */
       newcond->flags = CONDFLAG_NONE;
       if (a3 != NULL) {
           if ((err = cmd_parseflagfield(cmd->pool, newcond, a3,
  @@ -2896,24 +2917,60 @@
           }
       }
   
  -    /*  arg2: the pattern
  -        try to compile the regexp to test if is ok */
  +    /* arg2: the pattern */
       if (*a2 == '!') {
           newcond->flags |= CONDFLAG_NOTMATCH;
           ++a2;
       }
   
  -    regexp = ap_pregcomp(cmd->pool, a2, REG_EXTENDED |
  -                                        ((newcond->flags & CONDFLAG_NOCASE)
  -                                         ? REG_ICASE : 0));
  -    if (!regexp) {
  -        return apr_pstrcat(cmd->pool,
  -                           "RewriteCond: cannot compile regular expression '",
  -                           a2, "'", NULL);
  +    /* determine the pattern type */
  +    newcond->ptype = 0;
  +    if (*a2 && a2[1]) {
  +        if (!a2[2] && *a2 == '-') {
  +            switch (a2[1]) {
  +            case 'f': newcond->ptype = CONDPAT_FILE_EXISTS; break;
  +            case 's': newcond->ptype = CONDPAT_FILE_SIZE;   break;
  +            case 'l': newcond->ptype = CONDPAT_FILE_LINK;   break;
  +            case 'd': newcond->ptype = CONDPAT_FILE_DIR;    break;
  +            case 'U': newcond->ptype = CONDPAT_LU_URL;      break;
  +            case 'F': newcond->ptype = CONDPAT_LU_FILE;     break;
  +            }
  +        }
  +        else {
  +            switch (*a2) {
  +            case '>': newcond->ptype = CONDPAT_STR_GT; break;
  +            case '<': newcond->ptype = CONDPAT_STR_LT; break;
  +            case '=': newcond->ptype = CONDPAT_STR_EQ;
  +                /* "" represents an empty string */
  +                if (*++a2 == '"' && a2[1] == '"' && !a2[2]) {
  +                    a2 += 2;
  +                }
  +                break;
  +            }
  +        }
  +    }
  +
  +    if (newcond->ptype && newcond->ptype != CONDPAT_STR_EQ &&
  +        (newcond->flags & CONDFLAG_NOCASE)) {
  +        ap_log_error(APLOG_MARK, APLOG_WARNING, 0, cmd->server,
  +                     "RewriteCond: NoCase option for non-regex pattern '%s' "
  +                     "is not supported and will be ignored.", a2);
  +        newcond->flags &= ~CONDFLAG_NOCASE;
       }
   
  -    newcond->pattern = apr_pstrdup(cmd->pool, a2);
  -    newcond->regexp  = regexp;
  +    newcond->pattern = a2;
  +
  +    if (!newcond->ptype) {
  +        regexp = ap_pregcomp(cmd->pool, a2,
  +                             REG_EXTENDED | ((newcond->flags & CONDFLAG_NOCASE)
  +                                             ? REG_ICASE : 0));
  +        if (!regexp) {
  +            return apr_pstrcat(cmd->pool, "RewriteCond: cannot compile regular "
  +                               "expression '", a2, "'", NULL);
  +        }
  +
  +        newcond->regexp  = regexp;
  +    }
   
       return NULL;
   }
  @@ -3194,137 +3251,111 @@
                                 char *perdir, backrefinfo *briRR,
                                 backrefinfo *briRC)
   {
  -    char *input;
  +    char *input = do_expand(r, p->input, briRR, briRC);
       apr_finfo_t sb;
       request_rec *rsub;
       regmatch_t regmatch[MAX_NMATCH];
  -    int rc;
  -
  -    /*
  -     *   Construct the string we match against
  -     */
  -
  -    input = do_expand(r, p->input, briRR, briRC);
  -
  -    /*
  -     *   Apply the patterns
  -     */
  +    int rc = 0;
   
  -    rc = 0;
  -    if (strcmp(p->pattern, "-f") == 0) {
  -        if (apr_stat(&sb, input, APR_FINFO_MIN, r->pool) == APR_SUCCESS) {
  -            if (sb.filetype == APR_REG) {
  -                rc = 1;
  -            }
  +    switch (p->ptype) {
  +    case CONDPAT_FILE_EXISTS:
  +        if (   apr_stat(&sb, input, APR_FINFO_MIN, r->pool) == APR_SUCCESS
  +            && sb.filetype == APR_REG) {
  +            rc = 1;
           }
  -    }
  -    else if (strcmp(p->pattern, "-s") == 0) {
  -        if (apr_stat(&sb, input, APR_FINFO_MIN, r->pool) == APR_SUCCESS) {
  -            if ((sb.filetype == APR_REG) && sb.size > 0) {
  -                rc = 1;
  -            }
  +        break;
  +
  +    case CONDPAT_FILE_SIZE:
  +        if (   apr_stat(&sb, input, APR_FINFO_MIN, r->pool) == APR_SUCCESS
  +            && sb.filetype == APR_REG && sb.size > 0) {
  +            rc = 1;
           }
  -    }
  -    else if (strcmp(p->pattern, "-l") == 0) {
  +        break;
  +
  +    case CONDPAT_FILE_LINK:
   #if !defined(OS2)
  -        if (apr_lstat(&sb, input, APR_FINFO_MIN, r->pool) == APR_SUCCESS) {
  -            if (sb.filetype == APR_LNK) {
  -                rc = 1;
  -            }
  +        if (   apr_lstat(&sb, input, APR_FINFO_MIN, r->pool) == APR_SUCCESS
  +            && sb.filetype == APR_LNK) {
  +            rc = 1;
           }
   #endif
  -    }
  -    else if (strcmp(p->pattern, "-d") == 0) {
  -        if (apr_stat(&sb, input, APR_FINFO_MIN, r->pool) == APR_SUCCESS) {
  -            if (sb.filetype == APR_DIR) {
  -                rc = 1;
  -            }
  +        break;
  +
  +    case CONDPAT_FILE_DIR:
  +        if (   apr_stat(&sb, input, APR_FINFO_MIN, r->pool) == APR_SUCCESS
  +            && sb.filetype == APR_DIR) {
  +            rc = 1;
           }
  -    }
  -    else if (strcmp(p->pattern, "-U") == 0) {
  -        /* avoid infinite subrequest recursion */
  -        if (strlen(input) > 0 && subreq_ok(r)) {
  +        break;
   
  -            /* run a URI-based subrequest */
  +    case CONDPAT_LU_URL:
  +        if (*input && subreq_ok(r)) {
               rsub = ap_sub_req_lookup_uri(input, r, NULL);
  -
  -            /* URI exists for any result up to 3xx, redirects allowed */
  -            if (rsub->status < 400)
  +            if (rsub->status < 400) {
                   rc = 1;
  -
  -            /* log it */
  +            }
               rewritelog(r, 5, "RewriteCond URI (-U) check: "
                          "path=%s -> status=%d", input, rsub->status);
  -
  -            /* cleanup by destroying the subrequest */
               ap_destroy_sub_req(rsub);
           }
  -    }
  -    else if (strcmp(p->pattern, "-F") == 0) {
  -        /* avoid infinite subrequest recursion */
  -        if (strlen(input) > 0 && subreq_ok(r)) {
  -
  -            /* process a file-based subrequest:
  -             * this differs from -U in that no path translation is done.
  -             */
  -            rsub = ap_sub_req_lookup_file(input, r, NULL);
  +        break;
   
  -            /* file exists for any result up to 2xx, no redirects */
  +    case CONDPAT_LU_FILE:
  +        if (*input && subreq_ok(r)) {
  +            rsub = ap_sub_req_lookup_file(input, r, NULL);
               if (rsub->status < 300 &&
                   /* double-check that file exists since default result is 200 */
                   apr_stat(&sb, rsub->filename, APR_FINFO_MIN,
                            r->pool) == APR_SUCCESS) {
                   rc = 1;
               }
  -
  -            /* log it */
               rewritelog(r, 5, "RewriteCond file (-F) check: path=%s "
                          "-> file=%s status=%d", input, rsub->filename,
                          rsub->status);
  -
  -            /* cleanup by destroying the subrequest */
               ap_destroy_sub_req(rsub);
           }
  -    }
  -    else if (strlen(p->pattern) > 1 && *(p->pattern) == '>') {
  -        rc = (compare_lexicography(input, p->pattern+1) == 1 ? 1 : 0);
  -    }
  -    else if (strlen(p->pattern) > 1 && *(p->pattern) == '<') {
  -        rc = (compare_lexicography(input, p->pattern+1) == -1 ? 1 : 0);
  -    }
  -    else if (strlen(p->pattern) > 1 && *(p->pattern) == '=') {
  -        if (strcmp(p->pattern+1, "\"\"") == 0) {
  -            rc = (*input == '\0');
  +        break;
  +
  +    case CONDPAT_STR_GT:
  +        rc = (compare_lexicography(input, p->pattern+1) == 1) ? 1 : 0;
  +        break;
  +
  +    case CONDPAT_STR_LT:
  +        rc = (compare_lexicography(input, p->pattern+1) == -1) ? 1 : 0;
  +        break;
  +
  +    case CONDPAT_STR_EQ:
  +        if (p->flags & CONDFLAG_NOCASE) {
  +            rc = !strcasecmp(input, p->pattern);
           }
           else {
  -            rc = (strcmp(input, p->pattern+1) == 0 ? 1 : 0);
  +            rc = !strcmp(input, p->pattern);
           }
  -    }
  -    else {
  +        break;
  +
  +    default:
           /* it is really a regexp pattern, so apply it */
  -        rc = (ap_regexec(p->regexp, input,
  -                         p->regexp->re_nsub+1, regmatch,0) == 0);
  +        rc = !ap_regexec(p->regexp, input, p->regexp->re_nsub+1, regmatch, 0);
   
  -        /* if it isn't a negated pattern and really matched
  -           we update the passed-through regex subst info structure */
  +        /* update briRC backref info */
           if (rc && !(p->flags & CONDFLAG_NOTMATCH)) {
  -            briRC->source = apr_pstrdup(r->pool, input);
  +            briRC->source = input;
               briRC->nsub   = p->regexp->re_nsub;
  -            memcpy((void *)(briRC->regmatch), (void *)(regmatch),
  -                   sizeof(regmatch));
  +            memcpy(briRC->regmatch, regmatch, sizeof(regmatch));
           }
  +        break;
       }
   
  -    /* if this is a non-matching regexp, just negate the result */
       if (p->flags & CONDFLAG_NOTMATCH) {
           rc = !rc;
       }
   
  -    rewritelog(r, 4, "RewriteCond: input='%s' pattern='%s%s' => %s",
  -               input, (p->flags & CONDFLAG_NOTMATCH ? "!" : ""),
  -               p->pattern, rc ? "matched" : "not-matched");
  +    rewritelog(r, 4, "RewriteCond: input='%s' pattern='%s%s%s'%s => %s",
  +               input, (p->flags & CONDFLAG_NOTMATCH) ? "!" : "",
  +               (p->ptype == CONDPAT_STR_EQ) ? "=" : "", p->pattern,
  +               (p->flags & CONDFLAG_NOCASE) ? " [NC]" : "",
  +               rc ? "matched" : "not-matched");
   
  -    /* end just return the result */
       return rc;
   }
   
  
  
  

Mime
View raw message