From: William A. Rowe Jr Date: Fri, 3 Aug 2001 22:57:47 +0000 (+0000) Subject: Solve the major underlying problem of content negotation by passing X-Git-Tag: 2.0.23~68 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=d640fd47fe7a10aac598cd5881fe98c934c0552f;p=apache 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 --- diff --git a/modules/http/mod_mime.c b/modules/http/mod_mime.c index 4e4c5b2e04..6eba10c32a 100644 --- a/modules/http/mod_mime.c +++ b/modules/http/mod_mime.c @@ -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) + *((const char **) apr_array_push(exception_list)) = ext; + } - if (!found) { - r->content_type = NULL; - r->content_language = NULL; - r->content_languages = NULL; - r->content_encoding = NULL; - r->handler = orighandler; - charset = NULL; - } + /* + * 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) { diff --git a/modules/mappers/mod_negotiation.c b/modules/mappers/mod_negotiation.c index a54e259668..4d972b6935 100644 --- a/modules/mappers/mod_negotiation.c +++ b/modules/mappers/mod_negotiation.c @@ -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; }