You are viewing a plain text version of this content. The canonical link for it is here.
Posted to cvs@httpd.apache.org by st...@apache.org on 2001/10/02 23:01:31 UTC

cvs commit: apache-1.3/src/modules/standard mod_mime.c mod_negotiation.c

stoddard    01/10/02 14:01:31

  Modified:    src      CHANGES
               src/modules/standard mod_mime.c mod_negotiation.c
  Log:
  Modified mod_mime and mod_negotiation to prevent mod_negotiation
  from serving any multiview variant containing one or more
  'unknown' filename extensions. In PR #8130, mod_negotiation was
  incorrectly serving index.html.zh.Big5 when better variants were
  available. The httpd.conf file on the failing server did not have
  an AddLanguage directive for .zh, which caused mod_mime to loose
  the file_type information it gleened from parsing the .html
  extension. The absence of any language preferences, either in
  the browser or configured on the server, caused mod_negotiation
  to consider all the variants equivalent. When that occurs,
  mod_negotiation picks the 'smallest' variant available, which
  just happened to be  index.html.zh.Big5.
  [Bill Stoddard, Bill Rowe] PR #8130
  
  PR: 8130
  
  Revision  Changes    Path
  1.1718    +14 -0     apache-1.3/src/CHANGES
  
  Index: CHANGES
  ===================================================================
  RCS file: /home/cvs/apache-1.3/src/CHANGES,v
  retrieving revision 1.1717
  retrieving revision 1.1718
  diff -u -r1.1717 -r1.1718
  --- CHANGES	2001/10/02 19:35:30	1.1717
  +++ CHANGES	2001/10/02 21:01:30	1.1718
  @@ -1,4 +1,18 @@
   Changes with Apache 1.3.21
  +  *) Modified mod_mime and mod_negotiation to prevent mod_negotiation 
  +     from serving any multiview variant containing one or more 
  +     'unknown' filename extensions. In PR #8130, mod_negotiation was 
  +     incorrectly serving index.html.zh.Big5 when better variants were 
  +     available. The httpd.conf file on the failing server did not have 
  +     an AddLanguage directive for .zh, which caused mod_mime to loose
  +     the file_type information it gleened from parsing the .html
  +     extension. The absence of any language preferences, either in
  +     the browser or configured on the server, caused mod_negotiation
  +     to consider all the variants equivalent. When that occurs, 
  +     mod_negotiation picks the 'smallest' variant available, which
  +     just happened to be  index.html.zh.Big5.
  +     [Bill Stoddard, Bill Rowe] PR #8130
  +
     *) Security: Close autoindex /?M=D directory listing hole reported
        in bugtraq id 3009.  In some configurations where multiviews and 
        indexes are enabled for a directory, requesting URI /?M=D could
  
  
  
  1.60      +34 -23    apache-1.3/src/modules/standard/mod_mime.c
  
  Index: mod_mime.c
  ===================================================================
  RCS file: /home/cvs/apache-1.3/src/modules/standard/mod_mime.c,v
  retrieving revision 1.59
  retrieving revision 1.60
  diff -u -r1.59 -r1.60
  --- mod_mime.c	2001/01/15 17:05:45	1.59
  +++ mod_mime.c	2001/10/02 21:01:31	1.60
  @@ -615,27 +615,38 @@
   
   static int find_ct(request_rec *r)
   {
  -    const char *fn = strrchr(r->filename, '/');
  -    mime_dir_config *conf =
  -    (mime_dir_config *) ap_get_module_config(r->per_dir_config, &mime_module);
  +    mime_dir_config *conf;
  +    array_header *exception_list;
  +    const char *fn;
       char *ext;
  -    const char *orighandler = r->handler;
       const char *type;
       const char *charset = NULL;
  +    int found_metadata = 0;
   
       if (S_ISDIR(r->finfo.st_mode)) {
           r->content_type = DIR_MAGIC_TYPE;
           return OK;
       }
   
  -    /* TM -- FIXME
  -     * if r->filename does not contain a '/', the following passes a null
  -     * pointer to getword, causing a SEGV ..
  -     */
  +    conf = (mime_dir_config *) ap_get_module_config(r->per_dir_config, 
  +                                                    &mime_module);
  +
  +    exception_list = ap_make_array(r->pool, 2, sizeof(char *));
   
  -    if (fn == NULL) {
  +    /* Always drop the leading element */
  +    fn = strrchr(r->filename, '/');
  +    if (fn == NULL)
   	fn = r->filename;
  -    }
  +    else
  +        ++fn;
  +
  +    /* The exception list keeps track of those filename components that
  +     * are not associated with extensions indicating metadata.
  +     * The base name is always the first exception (i.e., "txt.html" has
  +     * a basename of "txt" even though it might look like an extension).
  +     */
  +    ext = ap_getword(r->pool, &fn, '.');
  +    *((const char **) ap_push_array(exception_list)) = ext;
   
       /* Parse filename extensions, which can be in any order */
       while ((ext = ap_getword(r->pool, &fn, '.')) && *ext) {
  @@ -683,19 +694,19 @@
               found = 1;
           }
   
  -        /* This is to deal with cases such as foo.gif.bak, which we want
  -         * to not have a type. So if we find an unknown extension, we
  -         * zap the type/language/encoding and reset the handler
  -         */
  -
  -        if (!found) {
  -            r->content_type = NULL;
  -            r->content_language = NULL;
  -            r->content_languages = NULL;
  -            r->content_encoding = NULL;
  -            r->handler = orighandler;
  -	    charset = NULL;
  -	}
  +        if (found)
  +            found_metadata = 1;
  +        else
  +            *((const char **) ap_push_array(exception_list)) = ext;
  +    }
  +
  +    /* Need to see a notes entry on r for unrecognized elements.
  +     * Somebody better claim them! If we did absolutly nothing,
  +     * skip the notes to alert mod_negotiation we are clueless.
  +     */
  +    if (found_metadata) {
  +        ap_table_setn(r->notes, "ap-mime-exceptions-list",
  +                      (void *) exception_list);
       }
   
       if (r->content_type) {
  
  
  
  1.108     +50 -3     apache-1.3/src/modules/standard/mod_negotiation.c
  
  Index: mod_negotiation.c
  ===================================================================
  RCS file: /home/cvs/apache-1.3/src/modules/standard/mod_negotiation.c,v
  retrieving revision 1.107
  retrieving revision 1.108
  diff -u -r1.107 -r1.108
  --- mod_negotiation.c	2001/10/02 16:05:20	1.107
  +++ mod_negotiation.c	2001/10/02 21:01:31	1.108
  @@ -922,10 +922,10 @@
       forbidden.all = 1;
   
       while ((dir_entry = readdir(dirp))) {
  +        array_header *exception_list;
           request_rec *sub_req;
   
           /* Do we have a match? */
  -
           if (strncmp(dir_entry->d_name, filp, prefix_len)) {
               continue;
           }
  @@ -955,15 +955,62 @@
           else if (sub_req->status == HTTP_FORBIDDEN)
               forbidden.any = 1;
   
  -        if (sub_req->status != HTTP_OK || !sub_req->content_type) {
  +        /* 
  +         * mod_mime will _always_ provide us the base name in the
  +         * ap-mime-exception-list, if it processed anything.  If
  +         * this list is empty, give up immediately, there was
  +         * nothing interesting.  For example, looking at the files
  +         * readme.txt and readme.foo, we will throw away .foo if
  +         * it's an insignificant file (e.g. did not identify a 
  +         * language, charset, encoding, content type or handler,)
  +         */
  +        exception_list = 
  +            (array_header *) ap_table_get(sub_req->notes,
  +                                          "ap-mime-exceptions-list");
  +        if (!exception_list) {
               ap_destroy_sub_req(sub_req);
               continue;
           }
   
  +        /*
  +         * Simple enough for now, every unreconized bit better match
  +         * our base name.  When we break up our base name and allow
  +         * index.en to match index.html.en, this gets tricker.
  +         * XXX: index.html.foo won't be caught by testing index.html
  +         * since the exceptions result is index.foo - this should be
  +         * fixed as part of a new match-parts logic here.
  +         */
  +        {
  +            char *base = ap_array_pstrcat(sub_req->pool, exception_list, '.');
  +            int base_len = strlen(base);
  +            if (base_len > prefix_len 
  +#ifdef CASE_BLIND_FILESYSTEM
  +                || strncasecmp(base, filp, base_len)
  +#else
  +                || strncmp(base, filp, base_len)
  +#endif
  +                || (prefix_len > base_len && filp[base_len] != '.')) {
  +                /* 
  +                 * Something you don't know is, something you don't know...
  +                 */
  +                ap_destroy_sub_req(sub_req);
  +                continue;
  +            }
  +        }
  +
  +        /* 
  +         * ###: be warned, the _default_ content type is already
  +         * picked up here!  If we failed the subrequest, or don't 
  +         * know what we are serving, then continue.
  +         */
  +        if (sub_req->status != HTTP_OK || (!sub_req->content_type)) {
  +            ap_destroy_sub_req(sub_req);
  +            continue;
  +        }
  +
           /* If it's a map file, we use that instead of the map
            * we're building...
            */
  -
           if (((sub_req->content_type) &&
                !strcmp(sub_req->content_type, MAP_FILE_MAGIC_TYPE)) ||
               ((sub_req->handler) &&