mod_autoindex.c revision b4c8a80f7dbfc9b56dbe03bdc28f0b5eb5f23697
587fec427c80b6c34dcf1d7570f891fcb652a7c5Lennart Poettering/* ====================================================================
587fec427c80b6c34dcf1d7570f891fcb652a7c5Lennart Poettering * Copyright (c) 1995-1999 The Apache Group. All rights reserved.
587fec427c80b6c34dcf1d7570f891fcb652a7c5Lennart Poettering * Redistribution and use in source and binary forms, with or without
587fec427c80b6c34dcf1d7570f891fcb652a7c5Lennart Poettering * modification, are permitted provided that the following conditions
587fec427c80b6c34dcf1d7570f891fcb652a7c5Lennart Poettering * 1. Redistributions of source code must retain the above copyright
587fec427c80b6c34dcf1d7570f891fcb652a7c5Lennart Poettering * notice, this list of conditions and the following disclaimer.
587fec427c80b6c34dcf1d7570f891fcb652a7c5Lennart Poettering * 2. Redistributions in binary form must reproduce the above copyright
587fec427c80b6c34dcf1d7570f891fcb652a7c5Lennart Poettering * notice, this list of conditions and the following disclaimer in
587fec427c80b6c34dcf1d7570f891fcb652a7c5Lennart Poettering * the documentation and/or other materials provided with the
587fec427c80b6c34dcf1d7570f891fcb652a7c5Lennart Poettering * distribution.
587fec427c80b6c34dcf1d7570f891fcb652a7c5Lennart Poettering * 3. All advertising materials mentioning features or use of this
587fec427c80b6c34dcf1d7570f891fcb652a7c5Lennart Poettering * software must display the following acknowledgment:
587fec427c80b6c34dcf1d7570f891fcb652a7c5Lennart Poettering * "This product includes software developed by the Apache Group
587fec427c80b6c34dcf1d7570f891fcb652a7c5Lennart Poettering * for use in the Apache HTTP server project (http://www.apache.org/)."
587fec427c80b6c34dcf1d7570f891fcb652a7c5Lennart Poettering * 4. The names "Apache Server" and "Apache Group" must not be used to
587fec427c80b6c34dcf1d7570f891fcb652a7c5Lennart Poettering * endorse or promote products derived from this software without
587fec427c80b6c34dcf1d7570f891fcb652a7c5Lennart Poettering * prior written permission. For written permission, please contact
587fec427c80b6c34dcf1d7570f891fcb652a7c5Lennart Poettering * apache@apache.org.
24882e06c135584f16f31ba8a00fecde8b7f6fadLennart Poettering * 5. Products derived from this software may not be called "Apache"
587fec427c80b6c34dcf1d7570f891fcb652a7c5Lennart Poettering * nor may "Apache" appear in their names without prior written
587fec427c80b6c34dcf1d7570f891fcb652a7c5Lennart Poettering * permission of the Apache Group.
587fec427c80b6c34dcf1d7570f891fcb652a7c5Lennart Poettering * 6. Redistributions of any form whatsoever must retain the following
587fec427c80b6c34dcf1d7570f891fcb652a7c5Lennart Poettering * acknowledgment:
587fec427c80b6c34dcf1d7570f891fcb652a7c5Lennart Poettering * "This product includes software developed by the Apache Group
587fec427c80b6c34dcf1d7570f891fcb652a7c5Lennart Poettering * for use in the Apache HTTP server project (http://www.apache.org/)."
587fec427c80b6c34dcf1d7570f891fcb652a7c5Lennart Poettering * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY
587fec427c80b6c34dcf1d7570f891fcb652a7c5Lennart Poettering * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
587fec427c80b6c34dcf1d7570f891fcb652a7c5Lennart Poettering * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
587fec427c80b6c34dcf1d7570f891fcb652a7c5Lennart Poettering * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE APACHE GROUP OR
587fec427c80b6c34dcf1d7570f891fcb652a7c5Lennart Poettering * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
587fec427c80b6c34dcf1d7570f891fcb652a7c5Lennart Poettering * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
587fec427c80b6c34dcf1d7570f891fcb652a7c5Lennart Poettering * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
587fec427c80b6c34dcf1d7570f891fcb652a7c5Lennart Poettering * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
587fec427c80b6c34dcf1d7570f891fcb652a7c5Lennart Poettering * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
587fec427c80b6c34dcf1d7570f891fcb652a7c5Lennart Poettering * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
587fec427c80b6c34dcf1d7570f891fcb652a7c5Lennart Poettering * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
587fec427c80b6c34dcf1d7570f891fcb652a7c5Lennart Poettering * OF THE POSSIBILITY OF SUCH DAMAGE.
587fec427c80b6c34dcf1d7570f891fcb652a7c5Lennart Poettering * ====================================================================
587fec427c80b6c34dcf1d7570f891fcb652a7c5Lennart Poettering * This software consists of voluntary contributions made by many
587fec427c80b6c34dcf1d7570f891fcb652a7c5Lennart Poettering * individuals on behalf of the Apache Group and was originally based
587fec427c80b6c34dcf1d7570f891fcb652a7c5Lennart Poettering * on public domain software written at the National Center for
587fec427c80b6c34dcf1d7570f891fcb652a7c5Lennart Poettering * Supercomputing Applications, University of Illinois, Urbana-Champaign.
587fec427c80b6c34dcf1d7570f891fcb652a7c5Lennart Poettering * For more information on the Apache Group and the Apache HTTP server
587fec427c80b6c34dcf1d7570f891fcb652a7c5Lennart Poettering * project, please see <http://www.apache.org/>.
587fec427c80b6c34dcf1d7570f891fcb652a7c5Lennart Poettering * mod_autoindex.c: Handles the on-the-fly html index generation
587fec427c80b6c34dcf1d7570f891fcb652a7c5Lennart Poettering * Adapted to Apache by rst.
587fec427c80b6c34dcf1d7570f891fcb652a7c5Lennart Poetteringmodule MODULE_VAR_EXPORT autoindex_module;
587fec427c80b6c34dcf1d7570f891fcb652a7c5Lennart Poettering/****************************************************************
587fec427c80b6c34dcf1d7570f891fcb652a7c5Lennart Poettering * Handling configuration directives...
587fec427c80b6c34dcf1d7570f891fcb652a7c5Lennart Poettering#define FANCY_INDEXING 1 /* Indexing options */
587fec427c80b6c34dcf1d7570f891fcb652a7c5Lennart Poettering * Define keys for sorting.
587fec427c80b6c34dcf1d7570f891fcb652a7c5Lennart Poettering#define K_NAME 'N' /* Sort by file name (default) */
587fec427c80b6c34dcf1d7570f891fcb652a7c5Lennart Poettering#define K_LAST_MOD 'M' /* Last modification date */
587fec427c80b6c34dcf1d7570f891fcb652a7c5Lennart Poettering#define K_SIZE 'S' /* Size (absolute, not as displayed) */
587fec427c80b6c34dcf1d7570f891fcb652a7c5Lennart Poettering * These are the dimensions of the default icons supplied with Apache.
587fec427c80b6c34dcf1d7570f891fcb652a7c5Lennart Poettering * Other default dimensions.
587fec427c80b6c34dcf1d7570f891fcb652a7c5Lennart Poetteringtypedef struct ai_desc_t {
587fec427c80b6c34dcf1d7570f891fcb652a7c5Lennart Poetteringstatic char c_by_encoding, c_by_type, c_by_path;
587fec427c80b6c34dcf1d7570f891fcb652a7c5Lennart Poettering * Return true if the specified string refers to the parent directory (i.e.,
587fec427c80b6c34dcf1d7570f891fcb652a7c5Lennart Poettering * matches ".." or "../"). Hopefully this one call is significantly less
587fec427c80b6c34dcf1d7570f891fcb652a7c5Lennart Poettering * expensive than multiple strcmp() calls.
587fec427c80b6c34dcf1d7570f891fcb652a7c5Lennart Poetteringstatic ap_inline int is_parent(const char *name)
587fec427c80b6c34dcf1d7570f891fcb652a7c5Lennart Poettering * Now, IFF the first two bytes are dots, and the third byte is either
587fec427c80b6c34dcf1d7570f891fcb652a7c5Lennart Poettering * EOS (\0) or a slash followed by EOS, we have a match.
587fec427c80b6c34dcf1d7570f891fcb652a7c5Lennart Poettering if (((name[0] == '.') && (name[1] == '.'))
587fec427c80b6c34dcf1d7570f891fcb652a7c5Lennart Poettering || ((name[2] == '/') && (name[3] == '\0')))) {
587fec427c80b6c34dcf1d7570f891fcb652a7c5Lennart Poettering * This routine puts the standard HTML header at the top of the index page.
587fec427c80b6c34dcf1d7570f891fcb652a7c5Lennart Poettering * We include the DOCTYPE because we may be using features therefrom (i.e.,
587fec427c80b6c34dcf1d7570f891fcb652a7c5Lennart Poettering * HEIGHT and WIDTH attributes on the icons if we're FancyIndexing).
587fec427c80b6c34dcf1d7570f891fcb652a7c5Lennart Poetteringstatic void emit_preamble(request_rec *r, char *title)
587fec427c80b6c34dcf1d7570f891fcb652a7c5Lennart Poettering "<HTML>\n <HEAD>\n <TITLE>Index of ", title,
72c0a2c255b172ebbb2a2b7dab7c9aec4c9582d9Lennart Poetteringstatic void push_item(ap_array_header_t *arr, char *type, char *to, char *path,
587fec427c80b6c34dcf1d7570f891fcb652a7c5Lennart Poettering struct item *p = (struct item *) ap_push_array(arr);
587fec427c80b6c34dcf1d7570f891fcb652a7c5Lennart Poettering p->data = data ? ap_pstrdup(arr->cont, data) : NULL;
587fec427c80b6c34dcf1d7570f891fcb652a7c5Lennart Poettering p->apply_path = ap_pstrcat(arr->cont, path, "*", NULL);
587fec427c80b6c34dcf1d7570f891fcb652a7c5Lennart Poettering if ((type == BY_PATH) && (!ap_is_matchexp(to))) {
587fec427c80b6c34dcf1d7570f891fcb652a7c5Lennart Poettering p->apply_to = ap_pstrcat(arr->cont, "*", to, NULL);
587fec427c80b6c34dcf1d7570f891fcb652a7c5Lennart Poetteringstatic const char *add_alt(cmd_parms *cmd, void *d, char *alt, char *to)
587fec427c80b6c34dcf1d7570f891fcb652a7c5Lennart Poettering push_item(((autoindex_config_rec *) d)->alt_list, cmd->info, to,
587fec427c80b6c34dcf1d7570f891fcb652a7c5Lennart Poetteringstatic const char *add_icon(cmd_parms *cmd, void *d, char *icon, char *to)
587fec427c80b6c34dcf1d7570f891fcb652a7c5Lennart Poettering char *iconbak = ap_pstrdup(cmd->pool, icon);
587fec427c80b6c34dcf1d7570f891fcb652a7c5Lennart Poettering return "missing closing paren";
587fec427c80b6c34dcf1d7570f891fcb652a7c5Lennart Poettering alt = ap_getword_nc(cmd->pool, &iconbak, ',');
587fec427c80b6c34dcf1d7570f891fcb652a7c5Lennart Poettering push_item(((autoindex_config_rec *) d)->icon_list, cmd->info, to,
587fec427c80b6c34dcf1d7570f891fcb652a7c5Lennart Poettering * Add description text for a filename pattern. If the pattern has
587fec427c80b6c34dcf1d7570f891fcb652a7c5Lennart Poettering * wildcards already (or we need to add them), add leading and
587fec427c80b6c34dcf1d7570f891fcb652a7c5Lennart Poettering * trailing wildcards to it to ensure substring processing. If the
587fec427c80b6c34dcf1d7570f891fcb652a7c5Lennart Poettering * pattern contains a '/' anywhere, force wildcard matching mode,
587fec427c80b6c34dcf1d7570f891fcb652a7c5Lennart Poettering * add a slash to the prefix so that "bar/bletch" won't be matched
587fec427c80b6c34dcf1d7570f891fcb652a7c5Lennart Poettering * by "foobar/bletch", and make a note that there's a delimiter;
587fec427c80b6c34dcf1d7570f891fcb652a7c5Lennart Poettering * the matching routine simplifies to just the actual filename
587fec427c80b6c34dcf1d7570f891fcb652a7c5Lennart Poettering * whenever it can. This allows definitions in parent directories
587fec427c80b6c34dcf1d7570f891fcb652a7c5Lennart Poettering * to be made for files in subordinate ones using relative paths.
587fec427c80b6c34dcf1d7570f891fcb652a7c5Lennart Poettering * Absent a strcasestr() function, we have to force wildcards on
587fec427c80b6c34dcf1d7570f891fcb652a7c5Lennart Poettering * systems for which "AAA" and "aaa" mean the same file.
587fec427c80b6c34dcf1d7570f891fcb652a7c5Lennart Poetteringstatic const char *add_desc(cmd_parms *cmd, void *d, char *desc, char *to)
587fec427c80b6c34dcf1d7570f891fcb652a7c5Lennart Poettering autoindex_config_rec *dcfg = (autoindex_config_rec *) d;
587fec427c80b6c34dcf1d7570f891fcb652a7c5Lennart Poettering desc_entry = (ai_desc_t *) ap_push_array(dcfg->desc_list);
587fec427c80b6c34dcf1d7570f891fcb652a7c5Lennart Poettering desc_entry->full_path = (strchr(to, '/') == NULL) ? 0 : 1;
587fec427c80b6c34dcf1d7570f891fcb652a7c5Lennart Poettering desc_entry->wildcards = (WILDCARDS_REQUIRED
587fec427c80b6c34dcf1d7570f891fcb652a7c5Lennart Poettering prefix = desc_entry->full_path ? "*/" : "*";
587fec427c80b6c34dcf1d7570f891fcb652a7c5Lennart Poettering desc_entry->pattern = ap_pstrcat(dcfg->desc_list->cont,
587fec427c80b6c34dcf1d7570f891fcb652a7c5Lennart Poettering desc_entry->pattern = ap_pstrdup(dcfg->desc_list->cont, to);
587fec427c80b6c34dcf1d7570f891fcb652a7c5Lennart Poettering desc_entry->description = ap_pstrdup(dcfg->desc_list->cont, desc);
587fec427c80b6c34dcf1d7570f891fcb652a7c5Lennart Poetteringstatic const char *add_ignore(cmd_parms *cmd, void *d, char *ext)
587fec427c80b6c34dcf1d7570f891fcb652a7c5Lennart Poettering push_item(((autoindex_config_rec *) d)->ign_list, 0, ext, cmd->path, NULL);
name);
return NULL;
name);
return NULL;
int curopts;
int newopts;
return NULL;
int opts;
int opts_add;
int opts_remove;
char action;
while (optstr[0]) {
int option = 0;
action = *(w++);
opts_add = 0;
opts_remove = 0;
opts_add = 0;
opts_remove = 0;
return NULL;
char *key)
return NULL;
{NULL}
return (void *) new;
return new;
struct ent {
char *name;
char *icon;
char *alt;
char *desc;
int ascending;
char key;
if (!*(p->apply_to)) {
return p->data;
return p->data;
else if (!path_only) {
if (!content_encoding) {
if (content_type
p->apply_to)) {
return p->data;
p->apply_to)) {
return p->data;
return NULL;
request_rec r;
* Look through the list of pattern/description pairs and return the first one
#ifdef CASE_BLIND_FILESYSTEM
#define MATCH_FLAGS 0
const char *filename_only;
const char *filename;
int found;
if (found) {
return NULL;
char *tt;
tt++;
char *ap;
ap++;
#ifndef CASE_BLIND_FILESYSTEM
int i, n, c, ch;
while (!feof(f)) {
char *title)
FILE *f;
* text/anything-else. The former is allowed to be processed for
emit_amble = 0;
emit_H1 = 0;
if (! suppress_amble) {
emit_amble = 0;
do_emit_plain(r, f);
emit_H1 = 0;
if (emit_amble) {
if (emit_H1) {
FILE *f;
int suppress_post = 0;
int suppress_sig = 0;
* text/anything-else. The former is allowed to be processed for
do_emit_plain(r, f);
if (!suppress_sig) {
if (!suppress_post) {
return NULL;
&& !r->content_encoding) {
return NULL;
return NULL;
for (x = 0, p = 0; titlebuf[x]; x++) {
if (!find[++p]) {
for (y = x; titlebuf[y]; y++) {
return NULL;
char direction)
struct ent *p;
return (NULL);
return (NULL);
if (p->lm < 0) {
p->lm = 0;
int autoindex_opts)
if (!desc[x]) {
maxsize = 0;
--maxsize;
maxsize = 0;
--maxsize;
return desc;
int reverse;
if (!nosort) {
char *tp;
int name_width;
char *name_scratch;
char *pad_scratch;
if (t > name_width) {
name_width = t;
d->icon_height,
d->icon_width
int nwidth;
ap_getparents(t);
t2 = t;
: d->default_icon),
NULL);
autoindex_opts), r);
int result = 0;
case K_LAST_MOD:
case K_SIZE:
case K_DESC:
if (result) {
return result;
char *title_endp;
DIR *d;
int num_ent = 0, x;
const char *qstring;
char keyid;
char direction;
return HTTP_FORBIDDEN;
if (r->header_only) {
if (p != NULL) {
head = p;
num_ent++;
if (num_ent > 0) {
p = head;
ar[x++] = p;
p = p->next;
(int (*)(const void *, const void *)) dsortf);
return DECLINED;
return index_directory(r, d);
return HTTP_FORBIDDEN;
{NULL}