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 <de...@daoine.org> on 2003/02/07 16:44:22 UTC

Re: [patch] IndexResults

On Mon, Jan 27, 2003 at 09:37:23AM +0000, Francis Daly wrote:
> On Sat, Jan 25, 2003 at 02:06:26PM -0800, Justin Erenkrantz wrote:

Newer version of the patch included below. Built and tested against
2.0.44, it applies and compiles (and works) against current HEAD too.

> But now that I actually write it down, it looks like it may not be much
> of a problem after all -- a better data structure makes a big difference

Looks like I was wrong in the first part, but not the second. I ran
into big problems trying to properly merge configurations, so tried a
simpler data structure -- 

typedef struct range_info {
    int code;
    int show;
    struct range_info *next;
} range_info;

range_info *range_allow[10];

where "code" is either the HTTP status, or a magic value meaning "this
range", and "show" is either "show" or "hide". 

> > But, we ought to keep the comparisons as integers.  This would be 
> > reasonably efficient to compare (tables are awful) and is directly 
> > proportional to the number of IndexResults directives you have.  I 
> > think it's a fair tradeoff with a much cleaner implementation.

Yup, that's there now. It turns out to be (worst case) proportional to
the number of IndexReults directives after the most recent range one
which corresponds to the range of this status.

(The code probably explains it much better than that sentence.)

> > The comparison would simply look like (pseudocode):
> > 
> > current = ranges[r->status % 100];
> > while (current) {
> >  if (r->status >= current.start && r->status <= current.end) {
> >    return 1;
> >  }
> >  current = current.next;
> > }
> > 
> > That's way more efficient than doing a sprintf.  Walk it twice for 
> > denials and approvals.

show_result() is now something like that, but only needs to be walked
once. It may have to walk the entire chain, though, since the chain isn't
ordered -- but it would be a strange config where any chain has more
than a handful of links.

The docs patch has changed too, since the order of arguments to the
directive now matters more than in the previous patch.

Any further comments are welcome,

	f
-- 
Francis Daly        deva@daoine.org

--- modules/generators/mod_autoindex.c	2003-01-06 15:24:29.000000000 +0000
+++ modules/generators/mod_autoindex.c	2003-02-06 21:57:48.000000000 +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);
@@ -582,6 +674,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,
@@ -594,7 +688,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));
@@ -617,6 +711,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;
 }
 
@@ -638,6 +741,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
@@ -799,6 +946,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
@@ -1320,7 +1484,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);
     }
--- docs/manual/mod/mod_autoindex.xml	2003-01-06 16:32:15.000000000 +0000
+++ docs/manual/mod/mod_autoindex.xml	2003-02-07 00:01:31.000000000 +0000
@@ -854,6 +854,41 @@ 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 version 2.0.45 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>
+    <example><title>Show unauthorized filenames, but no other 4xx ones</title>
+      IndexResults -4xx 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>