]> granicus.if.org Git - apache/commitdiff
Solve the major underlying problem of content negotation by passing
authorWilliam A. Rowe Jr <wrowe@apache.org>
Fri, 3 Aug 2001 22:57:47 +0000 (22:57 +0000)
committerWilliam A. Rowe Jr <wrowe@apache.org>
Fri, 3 Aug 2001 22:57:47 +0000 (22:57 +0000)
  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

modules/http/mod_mime.c
modules/mappers/mod_negotiation.c

index 4e4c5b2e04596ae535a33bb867daa6b5653323ad..6eba10c32a648dfdd9ed01418df12d3764ccc14d 100644 (file)
@@ -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) {
index a54e25966837fdf3a5d9e8d8d76e6907913fa1f0..4d972b69351472cd3baf0739219155bbed96c00a 100644 (file)
@@ -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;
         }