You are viewing a plain text version of this content. The canonical link for it is here.
Posted to cvs@httpd.apache.org by nd...@apache.org on 2003/05/19 04:35:32 UTC

cvs commit: apache-1.3/src/modules/standard mod_rewrite.c mod_rewrite.h

nd          2003/05/18 19:35:32

  Modified:    src      CHANGES
               src/modules/standard mod_rewrite.c mod_rewrite.h
  Log:
  Fix mod_rewrite's abs_URI handling.
  - uris were partially not correctly escaped (in particular:
    ldap, news, mailto)
  - not all uri schemes contain an authority component (//)
  - add nntp:// scheme
  - don't add a query string (and drop r->args) if it's not
    http or mailto scheme
  - be more efficient (think so)
  
  Reviewed by: Justin Erenkrantz, Brian Pane
  
  Revision  Changes    Path
  1.1893    +5 -1      apache-1.3/src/CHANGES
  
  Index: CHANGES
  ===================================================================
  RCS file: /home/cvs/apache-1.3/src/CHANGES,v
  retrieving revision 1.1892
  retrieving revision 1.1893
  diff -u -r1.1892 -r1.1893
  --- CHANGES	13 May 2003 23:25:36 -0000	1.1892
  +++ CHANGES	19 May 2003 02:35:30 -0000	1.1893
  @@ -1,6 +1,10 @@
   Changes with Apache 1.3.28
   
  -  *) Use appropriate language code for Czech (cs) and Traditional Chinese
  +  *) Fix mod_rewrite's handling of absolute URIs. The escaping routines
  +     now work scheme dependent and the query string will only be
  +     appended if supported by the particular scheme.  [Andr� Malo]
  +
  +  *) Use appropriate language codes for Czech (cs) and Traditional Chinese
        (zh-tw) in default config files. PR 9427.  [Andr� Malo]
   
     *) Don't block synchronous signals (e.g., SIGSEGV) while waiting for
  
  
  
  1.187     +174 -84   apache-1.3/src/modules/standard/mod_rewrite.c
  
  Index: mod_rewrite.c
  ===================================================================
  RCS file: /home/cvs/apache-1.3/src/modules/standard/mod_rewrite.c,v
  retrieving revision 1.186
  retrieving revision 1.187
  diff -u -r1.186 -r1.187
  --- mod_rewrite.c	2 Apr 2003 21:11:41 -0000	1.186
  +++ mod_rewrite.c	19 May 2003 02:35:31 -0000	1.187
  @@ -1037,7 +1037,6 @@
       const char *thisurl;
       char buf[512];
       char docroot[512];
  -    char *cp, *cp2;
       const char *ccp;
       unsigned int port;
       int rulestatus;
  @@ -1126,6 +1125,7 @@
        */
       rulestatus = apply_rewrite_list(r, conf->rewriterules, NULL);
       if (rulestatus) {
  +        unsigned skip;
   
           if (strlen(r->filename) > 6 &&
               strncmp(r->filename, "proxy:", 6) == 0) {
  @@ -1163,40 +1163,21 @@
                          r->filename);
               return OK;
           }
  -        else if (is_absolute_uri(r->filename)) {
  +        else if ((skip = is_absolute_uri(r->filename)) > 0) {
               /* it was finally rewritten to a remote URL */
   
  -            /* skip 'scheme:' */
  -            for (cp = r->filename; *cp != ':' && *cp != '\0'; cp++)
  -                ;
  -            /* skip '://' */
  -            cp += 3;
  -            /* skip host part */
  -            for ( ; *cp != '/' && *cp != '\0'; cp++)
  -                ;
  -            if (*cp != '\0') {
  -                if (rulestatus != ACTION_NOESCAPE) {
  -                    rewritelog(r, 1, "escaping %s for redirect", r->filename);
  -                    cp2 = ap_escape_uri(r->pool, cp);
  -                }
  -                else {
  -                    cp2 = ap_pstrdup(r->pool, cp);
  -                }
  -                *cp = '\0';
  -                r->filename = ap_pstrcat(r->pool, r->filename, cp2, NULL);
  +            if (rulestatus != ACTION_NOESCAPE) {
  +                rewritelog(r, 1, "escaping %s for redirect", r->filename);
  +                r->filename = escape_absolute_uri(r->pool, r->filename, skip);
               }
   
               /* append the QUERY_STRING part */
  -            if (r->args != NULL) {
  -                char *args;
  -                if (rulestatus == ACTION_NOESCAPE) {
  -                    args = r->args;
  -                }
  -                else {
  -                    args = ap_escape_uri(r->pool, r->args);
  -                }
  -                r->filename = ap_pstrcat(r->pool, r->filename, "?", 
  -                                         args, NULL);
  +            if (r->args) {
  +                r->filename = ap_pstrcat(r->pool, r->filename, "?",
  +                                         (rulestatus == ACTION_NOESCAPE)
  +                                           ? r->args
  +                                           : ap_escape_uri(r->pool, r->args),
  +                                         NULL);
               }
   
               /* determine HTTP redirect response code */
  @@ -1408,6 +1389,7 @@
        */
       rulestatus = apply_rewrite_list(r, dconf->rewriterules, dconf->directory);
       if (rulestatus) {
  +        unsigned skip;
   
           if (strlen(r->filename) > 6 &&
               strncmp(r->filename, "proxy:", 6) == 0) {
  @@ -1431,7 +1413,7 @@
                          "%s [OK]", dconf->directory, r->filename);
               return OK;
           }
  -        else if (is_absolute_uri(r->filename)) {
  +        else if ((skip = is_absolute_uri(r->filename)) > 0) {
               /* it was finally rewritten to a remote URL */
   
               /* because we are in a per-dir context
  @@ -1439,11 +1421,9 @@
                * if there is a base-URL available
                */
               if (dconf->baseurl != NULL) {
  -                /* skip 'scheme:' */
  -                for (cp = r->filename; *cp != ':' && *cp != '\0'; cp++)
  -                    ;
  -                /* skip '://' */
  -                cp += 3;
  +                /* skip 'scheme://' */
  +                cp = r->filename + skip;
  +
                   if ((cp = strchr(cp, '/')) != NULL && *(++cp)) {
                       rewritelog(r, 2,
                                  "[per-dir %s] trying to replace "
  @@ -1486,39 +1466,19 @@
               }
   
               /* now prepare the redirect... */
  -
  -            /* skip 'scheme:' */
  -            for (cp = r->filename; *cp != ':' && *cp != '\0'; cp++)
  -                ;
  -            /* skip '://' */
  -            cp += 3;
  -            /* skip host part */
  -            for ( ; *cp != '/' && *cp != '\0'; cp++)
  -                ;
  -            if (*cp != '\0') {
  -                if (rulestatus != ACTION_NOESCAPE) {
  -                    rewritelog(r, 1, "[per-dir %s] escaping %s for redirect",
  -                               dconf->directory, r->filename);
  -                    cp2 = ap_escape_uri(r->pool, cp);
  -                }
  -                else {
  -                    cp2 = ap_pstrdup(r->pool, cp);
  -                }
  -                *cp = '\0';
  -                r->filename = ap_pstrcat(r->pool, r->filename, cp2, NULL);
  +            if (rulestatus != ACTION_NOESCAPE) {
  +                rewritelog(r, 1, "[per-dir %s] escaping %s for redirect",
  +                           dconf->directory, r->filename);
  +                r->filename = escape_absolute_uri(r->pool, r->filename, skip);
               }
   
               /* append the QUERY_STRING part */
  -            if (r->args != NULL) {
  -                char *args;
  -                if (rulestatus == ACTION_NOESCAPE) {
  -                    args = r->args;
  -                }
  -                else {
  -                    args = ap_escape_uri(r->pool, r->args);
  -                }
  -                r->filename = ap_pstrcat(r->pool, r->filename, "?", 
  -                                         args, NULL);
  +            if (r->args) {
  +                r->filename = ap_pstrcat(r->pool, r->filename, "?",
  +                                         (rulestatus == ACTION_NOESCAPE)
  +                                           ? r->args
  +                                           : ap_escape_uri(r->pool, r->args),
  +                                         NULL);
               }
   
               /* determine HTTP redirect response code */
  @@ -2534,6 +2494,16 @@
       char *q;
       char *olduri;
   
  +    /* don't touch, unless it's an http or mailto URL.
  +     * See RFC 1738 and RFC 2368.
  +     */
  +    if (   is_absolute_uri(r->filename)
  +        && strncasecmp(r->filename, "http", 4)
  +        && strncasecmp(r->filename, "mailto", 6)) {
  +        r->args = NULL; /* forget the query that's still flying around */
  +        return;
  +    }
  +
       q = strchr(r->filename, '?');
       if (q != NULL) {
           olduri = ap_pstrdup(r->pool, r->filename);
  @@ -2557,6 +2527,7 @@
                          r->filename, r->args);
           }
       }
  +
       return;
   }
   
  @@ -2682,29 +2653,148 @@
   }
   
   
  -/*
  -**
  -**  return non-zero if the URI is absolute (includes a scheme etc.)
  -**
  -*/
  -
  -static int is_absolute_uri(char *uri)
  +/* return number of chars of the scheme (incl. '://')
  + * if the URI is absolute (includes a scheme etc.)
  + * otherwise 0.
  + *
  + * NOTE: If you add new schemes here, please have a
  + *       look at escape_absolute_uri and splitout_queryargs.
  + *       Not every scheme takes query strings and some schemes
  + *       may be handled in a special way.
  + *
  + * XXX: we should consider a scheme registry, perhaps with
  + *      appropriate escape callbacks to allow other modules
  + *      to extend mod_rewrite at runtime.
  + */
  +static unsigned is_absolute_uri(char *uri)
   {
  -    int i = strlen(uri);
  -    if (   (i > 7 && strncasecmp(uri, "http://",   7) == 0)
  -        || (i > 8 && strncasecmp(uri, "https://",  8) == 0)
  -        || (i > 9 && strncasecmp(uri, "gopher://", 9) == 0)
  -        || (i > 6 && strncasecmp(uri, "ftp://",    6) == 0)
  -        || (i > 5 && strncasecmp(uri, "ldap:",     5) == 0)
  -        || (i > 5 && strncasecmp(uri, "news:",     5) == 0)
  -        || (i > 7 && strncasecmp(uri, "mailto:",   7) == 0) ) {
  -	return 1;
  +    /* fast exit */
  +    if (*uri == '/' || strlen(uri) <= 5) {
  +        return 0;
       }
  -    else {
  -	return 0;
  +
  +    switch (*uri++) {
  +    case 'f':
  +    case 'F':
  +        if (!strncasecmp(uri, "tp://", 5)) {        /* ftp://    */
  +            return 6;
  +        }
  +        break;
  +
  +    case 'g':
  +    case 'G':
  +        if (!strncasecmp(uri, "opher://", 8)) {     /* gopher:// */
  +            return 9;
  +        }
  +        break;
  +
  +    case 'h':
  +    case 'H':
  +        if (!strncasecmp(uri, "ttp://", 6)) {       /* http://   */
  +            return 7;
  +        }
  +        else if (!strncasecmp(uri, "ttps://", 7)) { /* https://  */
  +            return 8;
  +        }
  +        break;
  +
  +    case 'l':
  +    case 'L':
  +        if (!strncasecmp(uri, "dap://", 6)) {       /* ldap://   */
  +            return 7;
  +        }
  +        break;
  +
  +    case 'm':
  +    case 'M':
  +        if (!strncasecmp(uri, "ailto:", 6)) {       /* mailto:   */
  +            return 7;
  +        }
  +        break;
  +
  +    case 'n':
  +    case 'N':
  +        if (!strncasecmp(uri, "ews:", 4)) {         /* news:     */
  +            return 5;
  +        }
  +        else if (!strncasecmp(uri, "ntp://", 6)) {  /* nntp://   */
  +            return 7;
  +        }
  +        break;
       }
  +
  +    return 0;
   }
   
  +
  +/* escape absolute uri, which may or may not be path oriented.
  + * So let's handle them differently.
  + */
  +static char *escape_absolute_uri(ap_pool *p, char *uri, unsigned scheme)
  +{
  +    char *cp;
  +
  +    /* be safe.
  +     * NULL should indicate elsewhere, that something's wrong
  +     */
  +    if (!scheme || strlen(uri) < scheme) {
  +        return NULL;
  +    }
  +
  +    cp = uri + scheme;
  +
  +    /* scheme with authority part? */
  +    if (cp[-1] == '/') {
  +        /* skip host part */
  +        while (*cp && *cp != '/') {
  +            ++cp;
  +        }
  +
  +        /* nothing after the hostpart. ready! */
  +        if (!*cp || !*++cp) {
  +            return ap_pstrdup(p, uri);
  +        }
  +
  +        /* remember the hostname stuff */
  +        scheme = cp - uri;
  +
  +        /* special thing for ldap.
  +         * The parts are separated by question marks. From RFC 2255:
  +         *     ldapurl = scheme "://" [hostport] ["/"
  +         *               [dn ["?" [attributes] ["?" [scope]
  +         *               ["?" [filter] ["?" extensions]]]]]]
  +         */
  +        if (!strncasecmp(uri, "ldap", 4)) {
  +            char *token[5];
  +            int c = 0;
  +
  +            token[0] = cp = ap_pstrdup(p, cp);
  +            while (*cp && c < 5) {
  +                if (*cp == '?') {
  +                    token[++c] = cp + 1;
  +                    *cp = '\0';
  +                }
  +                ++cp;
  +            }
  +
  +            return ap_pstrcat(p, ap_pstrndup(p, uri, scheme),
  +                                         ap_escape_uri(p, token[0]),
  +                              (c >= 1) ? "?" : NULL,
  +                              (c >= 1) ? ap_escape_uri(p, token[1]) : NULL,
  +                              (c >= 2) ? "?" : NULL,
  +                              (c >= 2) ? ap_escape_uri(p, token[2]) : NULL,
  +                              (c >= 3) ? "?" : NULL,
  +                              (c >= 3) ? ap_escape_uri(p, token[3]) : NULL,
  +                              (c >= 4) ? "?" : NULL,
  +                              (c >= 4) ? ap_escape_uri(p, token[4]) : NULL,
  +                              NULL);
  +        }
  +    }
  +
  +    /* Nothing special here. Apply normal escaping. */
  +    return ap_pstrcat(p, ap_pstrndup(p, uri, scheme),
  +                      ap_escape_uri(p, cp), NULL);
  +}
   
   /*
   **
  
  
  
  1.86      +2 -1      apache-1.3/src/modules/standard/mod_rewrite.h
  
  Index: mod_rewrite.h
  ===================================================================
  RCS file: /home/cvs/apache-1.3/src/modules/standard/mod_rewrite.h,v
  retrieving revision 1.85
  retrieving revision 1.86
  diff -u -r1.85 -r1.86
  --- mod_rewrite.h	2 Apr 2003 21:01:09 -0000	1.85
  +++ mod_rewrite.h	19 May 2003 02:35:31 -0000	1.86
  @@ -440,7 +440,8 @@
   static void  splitout_queryargs(request_rec *r, int qsappend);
   static void  fully_qualify_uri(request_rec *r);
   static void  reduce_uri(request_rec *r);
  -static int   is_absolute_uri(char *uri);
  +static unsigned is_absolute_uri(char *uri);
  +static char *escape_absolute_uri(ap_pool *p, char *uri, unsigned scheme);
   static char *expand_tildepaths(request_rec *r, char *uri);
   
       /* rewrite map support functions */