Commit d58cae85 authored by William A. Rowe Jr's avatar William A. Rowe Jr
Browse files

  Solve the major underlying problem of content negotation by passing
  mod_negotiation the 'unresolved' parts of the path in a ->notes
  array ap-mime-exceptions-list.

  If mod_mime is given index.html.bad.en it will add index and bad
  to the list (presuming html and en are both defined.)

  mod_negotiation will decide if index and bad are it's fault (the
  user requested index.html.bad[.*]) or if it's a messed up file
  (say .old, .junk, or .bak).

  The next patch to allow any-order negotiation should check each
  of these list elements, so that asking for index.bad in the prior
  example would succeed.  Right now that request would fail because
  .html was recognized, so it's not in the exceptions list.  This
  patch uses a simple strcmp to the given name.

  Also, this patch allows any mod_mime processed file to be served,
  even if the content type cannot be determined (think README.en).
  This is crippled by the client expect headers and omitting the
  default content type.

  PLEASE vet this code carefully.


git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@89912 13f79535-47bb-0310-9956-ffa450edef68
parent cf8e920c
Loading
Loading
Loading
Loading
+27 −21
Original line number Diff line number Diff line
@@ -245,7 +245,7 @@ static void *merge_mime_dir_configs(apr_pool_t *p, void *basev, void *addv)
                                 || add->encodings_remove)) {
            apr_hash_t *copyhash = new->extension_mappings;
            new->extension_mappings = apr_hash_make(p);
            /* XXX as slow as can be... just use an apr_hash_dup! */
            /* ### as slow as can be... just use an apr_hash_dup! */
            overlay_extension_mappings(p, copyhash, new->extension_mappings);
            new->copy_mappings = 1;
        }
@@ -788,22 +788,29 @@ static int find_ct(request_rec *r)
    const char *orighandler = r->handler;
    const char *type;
    const char *charset = NULL;
    apr_array_header_t *exception_list =
        apr_array_make(r->pool, 2, sizeof(char *));

    if (r->finfo.filetype == APR_DIR) {
        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 ..
    /* Always drop the leading element
     */

    if (fn == NULL) {
    if (fn == NULL)
	fn = r->filename;
    }
    else
        ++fn;

    /* always add a note that we have parsed exceptions,
     * the base name is the first exception.
     */
    ext= ap_getword(r->pool, &fn, '.');
    *((const char **) apr_array_push(exception_list)) = ext;

    /* Parse filename extensions, which can be in any order */
    /* Parse filename extensions which can be in any order 
     */
    while ((ext = ap_getword(r->pool, &fn, '.')) && *ext) {
        int found = 0;
        extension_info *exinfo;
@@ -848,7 +855,7 @@ static int find_ct(request_rec *r)
            if (!r->content_encoding)
                r->content_encoding = type;
            else
                /* XXX: should eliminate duplicate entities */
                /* XXX should eliminate duplicate entities */
                r->content_encoding = apr_pstrcat(r->pool, r->content_encoding,
                                                  ", ", type, NULL);
            found = 1;
@@ -861,20 +868,19 @@ static int find_ct(request_rec *r)
            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
         * XXX: This is an unexpected, unplesant surprize for some!
        /* Not good... nobody claims it.
         */

        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)
            *((const char **) apr_array_push(exception_list)) = ext;
    }

    /*
     * Need to set a notes entry on r for unrecognized elements.
     * Somebody better claim them!
     */
    if (exception_list->nelts) {
        apr_table_setn(r->notes, "ap-mime-exceptions-list", 
                       (void *)exception_list);
    }

    if (r->content_type) {
+31 −1
Original line number Diff line number Diff line
@@ -932,6 +932,7 @@ static int read_types_multi(negotiation_state *neg)
    }

    while (apr_dir_read(&dirent, APR_FINFO_DIRENT, dirp) == APR_SUCCESS) {
        apr_array_header_t *exception_list;
        request_rec *sub_req;
        
        /* Do we have a match? */
@@ -961,7 +962,36 @@ static int read_types_multi(negotiation_state *neg)
            sub_req->content_type = CGI_MAGIC_TYPE;
        }

        if (sub_req->status != HTTP_OK || !sub_req->content_type) {
        exception_list = 
            (apr_array_header_t *)apr_table_get(sub_req->notes, 
                                                "ap-mime-exceptions-list");
        if (exception_list) {
            /* Every last missing bit danged well better be in our table!
             * Simple enough for now, every unregonized 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.
             */
            char *base = apr_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;
            }
        }

        /* XXX If we successfully negotate ANYTHING, continue
         */
        if (sub_req->status != HTTP_OK ||
            (!sub_req->content_type && !exception_list)) {
            ap_destroy_sub_req(sub_req);
            continue;
        }