You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@httpd.apache.org by Francis Daly <fr...@daoine.org> on 2003/05/13 20:32:09 UTC

[PATCH] IndexResults for mod_autoindex

Hi there,

included is a patch against current CVS which adds "IndexResults" as an
option.  It controls which files get listed in a mod_autoindex-generated
page.

Specifically, it can be set to allow URLs for which the requestor is not
(yet) authenticated be listed.

Further patches to hide the file size and modify time; and to change
the icon displayed to an "unauthorized" one; will follow if this is
considered useful.

All the best,

	f
-- 
Francis Daly        francis@daoine.org

Index: docs/manual/mod/mod_autoindex.xml
===================================================================
RCS file: /home/cvspublic/httpd-2.0/docs/manual/mod/mod_autoindex.xml,v
retrieving revision 1.15
diff -u -p -r1.15 mod_autoindex.xml
--- docs/manual/mod/mod_autoindex.xml	11 Apr 2003 01:25:52 -0000	1.15
+++ docs/manual/mod/mod_autoindex.xml	13 May 2003 18:07:15 -0000
@@ -854,6 +854,38 @@ Name|Date|Size|Description</syntax>
 </directivesynopsis>
 
 <directivesynopsis>
+<name>IndexResults</name>
+<description>Changes the list of files to show in a directory index,
+based on the HTTP status</description>
+<syntax>IndexResults <var>[-]code</var> [<var>[-]code</var>] ...</syntax>
+<default>IndexResults 3xx</default>
+<contextlist><context>server config</context><context>virtual host</context>
+<context>directory</context><context>.htaccess</context>
+</contextlist>
+<override>Indexes</override>
+<compatibility>Available in Apache 2.1 and later</compatibility>
+
+<usage>
+    <p>The <directive>IndexResults</directive> directive changes the
+    list of files to show in a directory index. <var>code</var>
+    is a HTTP status (from 100 to 999)(like <code>401</code>, for
+    "unauthorized"), or a range (from 1xx to 9xx)(like <code>4xx</code>,
+    meaning "all 400-series statuses") for additional files to list.
+    Prefix <var>code</var> with a minus (-) to explicitly hide that
+    status or range. Multiple IndexResults arguments or directives are 
+    processed in order, which means a range always overrides an
+    earlier status. The <code>2xx</code> ("successful") range is
+    always present. By default, the list contains the <code>3xx</code>
+    range ("redirection"), but that can be explicitly overridden by a
+    <code>-3xx</code> if that is really wanted.</p>
+
+    <example><title>Show unauthorized filenames</title>
+      IndexResults 401
+    </example>
+</usage>
+</directivesynopsis>
+
+<directivesynopsis>
 <name>ReadmeName</name>
 <description>Name of the file that will be inserted at the end
 of the index listing</description>
Index: modules/generators/mod_autoindex.c
===================================================================
RCS file: /home/cvspublic/httpd-2.0/modules/generators/mod_autoindex.c,v
retrieving revision 1.119
diff -u -p -r1.119 mod_autoindex.c
--- modules/generators/mod_autoindex.c	2 Mar 2003 18:06:16 -0000	1.119
+++ modules/generators/mod_autoindex.c	13 May 2003 18:07:16 -0000
@@ -155,6 +155,17 @@ typedef struct ai_desc_t {
     int wildcards;
 } ai_desc_t;
 
+/* range_info is for IndexResults */
+typedef struct range_info {
+    int code;
+    int show;
+    struct range_info *next;
+} range_info;
+
+#define AI_FULL_RANGE 99
+/* int that is never otherwise valid in range_info.code */
+
+
 typedef struct autoindex_config_struct {
 
     char *default_icon;
@@ -177,6 +188,8 @@ typedef struct autoindex_config_struct {
     apr_array_header_t *hdr_list;
     apr_array_header_t *rdme_list;
 
+    range_info *range_allow[10];
+
 } autoindex_config_rec;
 
 static char c_by_encoding, c_by_type, c_by_path;
@@ -321,6 +334,85 @@ static const char *add_desc(cmd_parms *c
     return NULL;
 }
 
+void range_allow_modify(range_info *given[], apr_pool_t *p, 
+                        const int entry, const int show)
+{
+    /* 
+     * given - (pointer to) an array of 10 pointers to range_info. writeable.
+     * p     - pool out of which new range_info's can be allocated
+     * show is - 1 => show 
+     *         - 0 => hide
+     *         entry is - < 10 => that full range
+     *                  - else => that single value
+     */
+
+    range_info *current;
+    range_info *prev = NULL;
+
+    if (entry < 10) {
+        /* replace current with the new full range */
+        if (!given[entry]) {
+             given[entry] = apr_palloc(p, sizeof(range_info));
+        }
+        given[entry]->code = AI_FULL_RANGE;
+        given[entry]->show = show;
+        given[entry]->next = NULL;
+        return;
+    }
+
+    current = given[entry/100];
+    /* move to the end of the chain; stop if this entry is already present */
+    while (current) {
+        if (entry == current->code) {
+            current->show = show;
+            return;
+        }
+        prev = current;
+        current = current->next;
+    }
+
+    current = apr_palloc(p, sizeof(range_info));
+    if (prev) {
+        prev->next = current;
+    } else {
+        given[entry/100] = current;
+    }
+
+    current->code = entry;
+    current->show = show;
+    current->next = NULL;
+    return;
+}
+
+static const char *set_results(cmd_parms *cmd, void *d, const char *name)
+{
+    autoindex_config_rec *dr = d;
+    int entry;
+    int show = 1;
+    if (name[0] == '-') {
+        show = 0;
+        name++;
+    }
+
+    /* verify that the form is valid */
+    if (name[0] == '\0' || name[1] == '\0' || name[2] == '\0' ||
+            name[3] != '\0') {
+        return "Value (after leading minus) must be three characters long";
+    }
+
+    /* verify that the value is valid */
+    if ((name[0] < '1' || name[0] > '9')
+            || !((isdigit(name[1]) && isdigit(name[2]))
+                || (name[1] == 'x' && name[2] == 'x'))) {
+        return "Value must be [-]### or [-]#xx, where # is a digit";
+    }
+
+    entry = atoi(name);
+    range_allow_modify(dr->range_allow, cmd->pool, entry, show);
+    return NULL;
+}
+
+
 static const char *add_ignore(cmd_parms *cmd, void *d, const char *ext)
 {
     push_item(((autoindex_config_rec *) d)->ign_list, 0, ext, cmd->path, NULL);
@@ -585,6 +677,8 @@ static const command_rec autoindex_cmds[
                     "one or more file extensions"),
     AP_INIT_ITERATE2("AddDescription", add_desc, BY_PATH, DIR_CMD_PERMS,
                      "Descriptive text followed by one or more filenames"),
+    AP_INIT_ITERATE("IndexResults", set_results, NULL, DIR_CMD_PERMS,
+                    "one or more http status codes"),
     AP_INIT_TAKE1("HeaderName", add_header, NULL, DIR_CMD_PERMS,
                   "a filename"),
     AP_INIT_TAKE1("ReadmeName", add_readme, NULL, DIR_CMD_PERMS,
@@ -598,7 +692,7 @@ static const command_rec autoindex_cmds[
     {NULL}
 };
 
-static void *create_autoindex_config(apr_pool_t *p, char *dummy)
+static void *create_autoindex_config(apr_pool_t *p, char *dir)
 {
     autoindex_config_rec *new =
     (autoindex_config_rec *) apr_pcalloc(p, sizeof(autoindex_config_rec));
@@ -621,6 +715,15 @@ static void *create_autoindex_config(apr
     new->default_keyid = '\0';
     new->default_direction = '\0';
 
+    /* new->range_allow is already initialised as 10 NULL pointers */
+    /* include, effectively, a global "IndexResults 3xx" */
+    if (dir == NULL) {
+        new->range_allow[3] = apr_palloc(p, sizeof(range_info));
+        new->range_allow[3]->code = AI_FULL_RANGE;
+        new->range_allow[3]->show = 1;
+        new->range_allow[3]->next = NULL;
+    }
+
     return (void *) new;
 }
 
@@ -642,6 +745,50 @@ static void *merge_autoindex_configs(apr
     new->desc_list = apr_array_append(p, add->desc_list, base->desc_list);
     new->icon_list = apr_array_append(p, add->icon_list, base->icon_list);
     new->rdme_list = apr_array_append(p, add->rdme_list, base->rdme_list);
+    {
+        int i;
+        range_info *mod;
+        range_info *old;
+        range_info *copy;
+        for (i=0; i<10; i++) {
+            mod = add->range_allow[i];
+
+            /* if there is no change at all to i this time, use base */
+            if (!mod || mod->code == 0) {
+                new->range_allow[i] = base->range_allow[i];
+                continue;
+            }
+
+            /* else if the change involves a range, use add */
+            if (mod->code == AI_FULL_RANGE) {
+                new->range_allow[i] = add->range_allow[i];
+                continue;
+            }   
+
+            /* else deep-copy base, then merge the changes */
+            old = base->range_allow[i];
+            if (old && old->code) {
+                copy = apr_palloc(p, sizeof(range_info));
+                new->range_allow[i] = copy;
+                while (old && old->code) {
+                    copy->code = old->code;
+                    copy->show = old->show;
+                    old = old->next;
+                    if (old) {
+                        copy->next = apr_palloc(p, sizeof(range_info));
+                        copy = copy->next;
+                    } else {
+                        copy->next = NULL;
+                    }
+                }
+            }
+            while (mod && mod->code) {
+                range_allow_modify(new->range_allow, p, mod->code, mod->show);
+                mod = mod->next;
+            }
+        }
+    }
+
     if (add->opts & NO_OPTIONS) {
         /*
          * If the current directory says 'no options' then we also
@@ -803,6 +950,24 @@ static char *find_default_item(char *bog
 #define find_default_icon(d,n) find_default_item(n, d->icon_list)
 #define find_default_alt(d,n) find_default_item(n, d->alt_list)
 
+static int show_result(autoindex_config_rec *d, int status)
+{
+    range_info *current;
+    int show = 0;  /* default don't show */
+
+    current = d->range_allow[status / 100];
+    while (current) {
+        if (current->code == status) {
+            return current->show;
+        }
+        if (current->code == AI_FULL_RANGE) {
+            show = current->show;
+        } 
+        current = current->next;
+    }
+    return show;
+}
+
 /*
  * Look through the list of pattern/description pairs and return the first one
  * if any) that matches the filename in the request.  If multiple patterns
@@ -1324,7 +1489,7 @@ static struct ent *make_autoindex_entry(
 
     if ((rr->finfo.filetype != APR_DIR && rr->finfo.filetype != APR_REG)
         || !(rr->status == OK || ap_is_HTTP_SUCCESS(rr->status)
-                              || ap_is_HTTP_REDIRECT(rr->status))) {
+                              || show_result(d, rr->status))) {
         ap_destroy_sub_req(rr);
         return (NULL);
     }