<H2>Autoindex Request Query Arguments</H2>
-The column sorting headers are self-referencing hyperlinks that add the following
-query options, they may be added to any request for the directory resource, where
-They have no effect if the <A HREF="#indexoptions">IndexOptions</A> directive's
-<SAMP>SuppressColumnSorting</SAMP> option is in effect. In the list below,
-<EM>S</EM> is the desired sort order, either <SAMP>A</SAMP> for ascending or
-<SAMP>D</SAMP> for descending sequence.
+<P>Apache 2.0.23 reorganized the Query Arguments for Column Sorting, and introduced
+an entire group of new query options. To effectively eliminate all client control
+over the output, the <SAMP><A HREF="#indexoptions:ignoreclient">IndexOptions
+IgnoreClient</A></SAMP> option was introduced.</P>
+
+<P>The column sorting headers themselves are self-referencing hyperlinks that add the
+sort query options shown below. Any option below may be added to any request for the
+directory resource.
<ul>
-<li><SAMP>N=<EM>S</EM></SAMP> sorts the directory by file name
-<li><SAMP>M=<EM>S</EM></SAMP> sorts the directory by last-modified date, then file name
-<li><SAMP>S=<EM>S</EM></SAMP> sorts the directory by size, then file name
-<li><SAMP>D=<EM>S</EM></SAMP> sorts the directory by description, then file name
+<li><SAMP>C=N</SAMP> sorts the directory by file name
+<li><SAMP>C=M</SAMP> sorts the directory by last-modified date, then file name
+<li><SAMP>C=S</SAMP> sorts the directory by size, then file name
+<li><SAMP>C=D</SAMP> sorts the directory by description, then file name<br />
+
+<li><SAMP>O=A</SAMP> sorts the listing in Ascending Order
+<li><SAMP>O=D</SAMP> sorts the listing in Descending Order<br />
+
+<li><SAMP>F=0</SAMP> formats the listing as a simple list (not FancyIndexed)
+<li><SAMP>F=1</SAMP> formats the listing as a FancyIndexed list
+<li><SAMP>F=2</SAMP> formats the listing as an HTMLTable FancyIndexed list<br />
+
+<li><SAMP>V=0</SAMP> disables version sorting
+<li><SAMP>V=0</SAMP> enables version sorting<br />
+
+<li><SAMP>P=<EM>pattern</EM></SAMP> lists only files matching the given <EM>pattern</EM>
</ul>
+<P>Note that the 'P'attern query argument is tested <em>after</em> the usual IndexIgnore
+directives are processed, and all file names are still subjected to the same critera
+as any other autoindex listing. The Query Arguments parser in mod_autoindex will stop
+abruptly when an unrecognized option is encountered. The Query Arguments must be well
+formed, according to the table above.</P>
+
+<P>The simple example below, which can be clipped and saved in a header.html file,
+illustrates these query options. Note that the unknown "X" argument, for the
+submit button, is listed last to assure the arguments are all parsed before
+mod_autoindex encounters the X=Go input.</P>
+
+<pre><FORM METHOD="GET">
+ Show me a <SELECT NAME="F">
+ <OPTION VALUE="0"> Plain list
+ <OPTION VALUE="1" SELECTED> Fancy list
+ <OPTION VALUE="2"> Table list
+ </SELECT>
+ Sorted by <SELECT NAME="C">
+ <OPTION VALUE="N" SELECTED> Name
+ <OPTION VALUE="M"> Date Modified
+ <OPTION VALUE="S"> Size
+ <OPTION VALUE="D"> Description
+ </SELECT>
+ <SELECT NAME="O">
+ <OPTION VALUE="A" SELECTED> Ascending
+ <OPTION VALUE="D"> Descending
+ </SELECT>
+ <SELECT NAME="V">
+ <OPTION VALUE="0" SELECTED> in Normal order
+ <OPTION VALUE="1"> in Version order
+ </SELECT>
+ Matching <INPUT TYPE="text" NAME="P" VALUE="*">
+ <INPUT TYPE="submit" NAME="X" VALUE="Go">
+</FORM>
+</pre>
<H2>Directives</H2>
necessary if file names or description text will alternate between left-to-right
and right-to-left reading order, as can happen on WinNT or other utf-8
enabled platforms.
+<DT><A NAME="indexoptions:iconsarelinks">IconsAreLinks</A>
+<DD>
+<!--%plaintext <?INDEX {\tt IconsAreLinks} index option> -->
+This makes the icons part of the anchor for the filename, for
+fancy indexing.
<DT><A NAME="indexoptions:iconheight">IconHeight[=pixels] (<EM>Apache 1.3 and later</EM>)</A>
<DD>
<!--%plaintext <?INDEX {\tt IconHeight} index option> -->
images have been loaded. If no value is given for the option, it
defaults to the standard height of the icons supplied with the Apache
software.
-<DT><A NAME="indexoptions:iconsarelinks">IconsAreLinks</A>
-<DD>
-<!--%plaintext <?INDEX {\tt IconsAreLinks} index option> -->
-This makes the icons part of the anchor for the filename, for
-fancy indexing.
<DT><A NAME="indexoptions:iconwidth">IconWidth[=pixels] (<EM>Apache 1.3 and later</EM>)</A>
<DD>
<!--%plaintext <?INDEX {\tt IconWidth} index option> -->
images have been loaded. If no value is given for the option, it
defaults to the standard width of the icons supplied with the Apache
software.
+<DT><A NAME="indexoptions:ignoreclient">IgnoreClient</A>
+<DD>
+<!--%plaintext <?INDEX {\tt IgnoreClient} index option> -->
+This option causes mod_autoindex to ignore all query variables from the
+client, including sort order (implies <EM><A
+ HREF="#indexoptions:suppresscolumnsorting">SuppressColumnSorting</A></EM>.)
<DT><A NAME="indexoptions:namewidth">NameWidth=[<EM>n</EM> | *] (<EM>Apache 1.3.2 and later</EM>)</A>
<DD>
The NameWidth keyword allows you to specify the width of the
If specified, Apache will not make the column headings in a FancyIndexed
directory listing into links for sorting. The default behaviour is
for them to be links; selecting the column heading will sort the directory
-listing by the values in that column.
+listing by the values in that column. <STRONG>Prior to Apache 2.0.23, this
+also disabled parsing the Query Arguments for the sort string.</STRONG>
+That behavior is now controled by <A HREF="#indexoptions:ignoreclient"
+ >IndexOptions IgnoreClient</A> in Apache 2.0.23.
<DT><A NAME="indexoptions:suppressdescription">SuppressDescription</A>
<DD>
<!--%plaintext <?INDEX {\tt SuppressDescription} index option> -->
#define TRACK_MODIFIED 0x1000
#define FANCY_INDEXING 0x2000
#define TABLE_INDEXING 0x4000
+#define IGNORE_CLIENT 0x8000
#define K_NOADJUST 0
#define K_ADJUST 1
#define K_LAST_MOD 'M' /* Last modification date */
#define K_SIZE 'S' /* Size (absolute, not as displayed) */
#define K_DESC 'D' /* Description */
+#define K_VALID "NMSD" /* String containing _all_ valid K_ opts */
#define D_ASCENDING 'A'
#define D_DESCENDING 'D'
+#define D_VALID "AD" /* String containing _all_ valid D_ opts */
/*
* These are the dimensions of the default icons supplied with Apache.
typedef struct autoindex_config_struct {
char *default_icon;
- int opts;
- int incremented_opts;
- int decremented_opts;
+ apr_int32_t opts;
+ apr_int32_t incremented_opts;
+ apr_int32_t decremented_opts;
int name_width;
int name_adjust;
int desc_width;
static const char *add_opts(cmd_parms *cmd, void *d, const char *optstr)
{
char *w;
- int opts;
- int opts_add;
- int opts_remove;
+ apr_int32_t opts;
+ apr_int32_t opts_add;
+ apr_int32_t opts_remove;
char action;
autoindex_config_rec *d_cfg = (autoindex_config_rec *) d;
else if (!strcasecmp(w, "IconsAreLinks")) {
option = ICONS_ARE_LINKS;
}
+ else if (!strcasecmp(w, "IgnoreClient")) {
+ option = IGNORE_CLIENT;
+ }
else if (!strcasecmp(w, "ScanHTMLTitles")) {
option = SCAN_HTML_TITLES;
}
+ else if (!strcasecmp(w, "SuppressColumnSorting")) {
+ option = SUPPRESS_COLSORT;
+ }
+ else if (!strcasecmp(w, "SuppressDescription")) {
+ option = SUPPRESS_DESC;
+ }
+ else if (!strcasecmp(w, "SuppressHTMLPreamble")) {
+ option = SUPPRESS_PREAMBLE;
+ }
else if (!strcasecmp(w, "SuppressIcon")) {
option = SUPPRESS_ICON;
}
else if (!strcasecmp(w, "SuppressSize")) {
option = SUPPRESS_SIZE;
}
- else if (!strcasecmp(w, "SuppressDescription")) {
- option = SUPPRESS_DESC;
- }
- else if (!strcasecmp(w, "SuppressHTMLPreamble")) {
- option = SUPPRESS_PREAMBLE;
- }
- else if (!strcasecmp(w, "SuppressColumnSorting")) {
- option = SUPPRESS_COLSORT;
- }
else if (!strcasecmp(w, "SuppressRules")) {
option = SUPPRESS_RULES;
}
AP_INIT_ITERATE2("AddAltByEncoding", add_alt, BY_ENCODING, DIR_CMD_PERMS,
"alternate descriptive text followed by one or more content encodings"),
AP_INIT_RAW_ARGS("IndexOptions", add_opts, NULL, DIR_CMD_PERMS,
- "one or more index options"),
+ "one or more index options [+|-][]"),
AP_INIT_TAKE2("IndexOrderDefault", set_default_order, NULL, DIR_CMD_PERMS,
"{Ascending,Descending} {Name,Size,Description,Date}"),
AP_INIT_ITERATE("IndexIgnore", add_ignore, NULL, DIR_CMD_PERMS,
new->name_width = add->name_width;
new->name_adjust = add->name_adjust;
}
+
/*
* Likewise for DescriptionWidth.
*/
return NULL;
}
-static struct ent *make_parent_entry(int autoindex_opts,
+static struct ent *make_parent_entry(apr_int32_t autoindex_opts,
autoindex_config_rec *d,
request_rec *r, char keyid,
char direction)
int autoindex_opts,
autoindex_config_rec *d,
request_rec *r, char keyid,
- char direction)
+ char direction,
+ const char *pattern)
{
request_rec *rr;
struct ent *p;
|| ((dirent->name[1] == '.') && !dirent->name[2])))
return (NULL);
+#ifndef CASE_BLIND_FILESYSTEM
+ if (pattern && (apr_fnmatch(pattern, dirent->name,
+ FNM_NOESCAPE | FNM_PERIOD)
+ != APR_SUCCESS))
+ return (NULL);
+#else /* !CASE_BLIND_FILESYSTEM */
+ /*
+ * On some platforms, the match must be case-blind. This is really
+ * a factor of the filesystem involved, but we can't detect that
+ * reliably - so we have to granularise at the OS level.
+ */
+ if (pattern && (apr_fnmatch(pattern, dirent->name,
+ FNM_NOESCAPE | FNM_PERIOD | FNM_CASE_BLIND)
+ != APR_SUCCESS))
+ return (NULL);
+#endif /* !CASE_BLIND_FILESYSTEM */
+
if (ignore_entry(d, ap_make_full_path(r->pool, r->filename, dirent->name)))
return (NULL);
- if (!(rr = ap_sub_req_lookup_dirent(dirent, r, NULL)))
+ if (!(rr = ap_sub_req_lookup_dirent(dirent, r, NULL))) {
return (NULL);
+ }
if ((rr->finfo.filetype != APR_DIR && rr->finfo.filetype != APR_REG)
|| !(rr->status == OK || ap_is_HTTP_SUCCESS(rr->status)
p->isdir = 0;
p->key = apr_toupper(keyid);
p->ascending = (apr_toupper(direction) == D_ASCENDING);
- p->version_sort = autoindex_opts & VERSION_SORT;
+ p->version_sort = !!(autoindex_opts & VERSION_SORT);
if (autoindex_opts & (FANCY_INDEXING | TABLE_INDEXING))
{
}
static char *terminate_description(autoindex_config_rec *d, char *desc,
- int autoindex_opts, int desc_width)
+ apr_int32_t autoindex_opts, int desc_width)
{
int maxsize = desc_width;
register int x;
* current request, the link changes its meaning to reverse the order when
* selected again. Non-active fields always start in ascending order.
*/
-static void emit_link(request_rec *r, char *anchor, char fname, char curkey,
- char curdirection, int nosort)
+static void emit_link(request_rec *r, const char *anchor, char column,
+ char curkey, char curdirection,
+ const char *colargs, int nosort)
{
- char qvalue[5];
+ char qvalue[9];
int reverse;
if (!nosort) {
+ reverse = ((curkey == column) && (curdirection == D_ASCENDING));
qvalue[0] = '?';
- qvalue[1] = fname;
+ qvalue[1] = 'C';
qvalue[2] = '=';
- qvalue[4] = '\0';
- reverse = ((curkey == fname) && (curdirection == D_ASCENDING));
- qvalue[3] = reverse ? D_DESCENDING : D_ASCENDING;
- ap_rvputs(r, "<a href=\"", qvalue, "\">", anchor, "</a>", NULL);
+ qvalue[3] = column;
+ qvalue[4] = '&';
+ qvalue[5] = 'O';
+ qvalue[6] = '=';
+ qvalue[7] = reverse ? D_DESCENDING : D_ASCENDING;
+ qvalue[8] = '\0';
+ ap_rvputs(r, "<a href=\"", qvalue, colargs ? colargs : "",
+ "\">", anchor, "</a>", NULL);
}
else {
ap_rputs(anchor, r);
static void output_directories(struct ent **ar, int n,
autoindex_config_rec *d, request_rec *r,
- int autoindex_opts, char keyid, char direction)
+ apr_int32_t autoindex_opts, char keyid,
+ char direction, const char *colargs)
{
int x;
apr_size_t rv;
char *name = r->uri;
char *tp;
- int static_columns = (autoindex_opts & SUPPRESS_COLSORT);
+ int static_columns = !!(autoindex_opts & SUPPRESS_COLSORT);
apr_pool_t *scratch;
int name_width;
int desc_width;
++cols;
}
ap_rputs("<th>", r);
- emit_link(r, "Name", K_NAME, keyid, direction, static_columns);
+ emit_link(r, "Name", K_NAME, keyid, direction,
+ colargs, static_columns);
if (!(autoindex_opts & SUPPRESS_LAST_MOD)) {
ap_rputs("</th><th>", r);
- emit_link(r, "Last modified", K_LAST_MOD, keyid, direction, static_columns);
+ emit_link(r, "Last modified", K_LAST_MOD, keyid, direction,
+ colargs, static_columns);
++cols;
}
if (!(autoindex_opts & SUPPRESS_SIZE)) {
ap_rputs("</th><th>", r);
- emit_link(r, "Size", K_SIZE, keyid, direction, static_columns);
+ emit_link(r, "Size", K_SIZE, keyid, direction,
+ colargs, static_columns);
++cols;
}
if (!(autoindex_opts & SUPPRESS_DESC)) {
ap_rputs("</th><th>", r);
- emit_link(r, "Description", K_DESC, keyid, direction, static_columns);
+ emit_link(r, "Description", K_DESC, keyid, direction,
+ colargs, static_columns);
++cols;
}
if (!(autoindex_opts & SUPPRESS_RULES))
else
ap_rputs(" ", r);
}
- emit_link(r, "Name", K_NAME, keyid, direction, static_columns);
+ emit_link(r, "Name", K_NAME, keyid, direction,
+ colargs, static_columns);
ap_rputs(pad_scratch + 4, r);
/*
* Emit the guaranteed-at-least-one-space-between-columns byte.
ap_rputs(" ", r);
if (!(autoindex_opts & SUPPRESS_LAST_MOD)) {
emit_link(r, "Last modified", K_LAST_MOD, keyid, direction,
- static_columns);
+ colargs, static_columns);
ap_rputs(" ", r);
}
if (!(autoindex_opts & SUPPRESS_SIZE)) {
- emit_link(r, "Size", K_SIZE, keyid, direction, static_columns);
+ emit_link(r, "Size", K_SIZE, keyid, direction,
+ colargs, static_columns);
ap_rputs(" ", r);
}
if (!(autoindex_opts & SUPPRESS_DESC)) {
emit_link(r, "Description", K_DESC, keyid, direction,
- static_columns);
+ colargs, static_columns);
}
if (!(autoindex_opts & SUPPRESS_RULES))
ap_rputs("<hr />", r);
char *title_name = ap_escape_html(r->pool, r->uri);
char *title_endp;
char *name = r->filename;
+ char *pstring = NULL;
apr_finfo_t dirent;
apr_dir_t *thedir;
apr_status_t status;
struct ent *head, *p;
struct ent **ar = NULL;
const char *qstring;
- int autoindex_opts = autoindex_conf->opts;
+ apr_int32_t autoindex_opts = autoindex_conf->opts;
char keyid;
char direction;
+ char *colargs;
if ((status = apr_dir_open(&thedir, name, r->pool)) != APR_SUCCESS) {
ap_log_rerror(APLOG_MARK, APLOG_ERR, status, r,
direction = autoindex_conf->default_direction
? autoindex_conf->default_direction : D_ASCENDING;
- /* Spew HTML preamble */
+ /*
+ * Figure out what sort of indexing (if any) we're supposed to use.
+ *
+ * If no QUERY_STRING was specified or client query strings have been
+ * explicitly disabled.
+ * If we are ignoring the client, suppress column sorting as well.
+ */
+ if (autoindex_opts & IGNORE_CLIENT) {
+ qstring = NULL;
+ autoindex_opts |= SUPPRESS_COLSORT;
+ colargs = "";
+ }
+ else {
+ char fval[5], vval[5], *ppre = "";
+ fval[0] = '\0'; vval[0] = '\0';
+ qstring = r->args;
+ while (qstring && *qstring) {
+ if (qstring[0] == 'C' && qstring[1] == '='
+ && qstring[2] && strchr(K_VALID, qstring[2])
+ && (qstring[3] == '&' || !qstring[3])) {
+ keyid = qstring[2];
+ qstring += qstring[3] ? 4 : 3;
+ }
+ else if (qstring[0] == 'O' && qstring[1] == '='
+ && ((qstring[2] == D_ASCENDING)
+ || (qstring[2] == D_DESCENDING))
+ && (qstring[3] == '&' || !qstring[3])) {
+ direction = qstring[2];
+ qstring += qstring[3] ? 4 : 3;
+ }
+ else if (qstring[0] == 'F' && qstring[1] == '='
+ && qstring[2] && strchr("012", qstring[2])
+ && (qstring[3] == '&' || !qstring[3])) {
+ if (qstring[2] == '0')
+ autoindex_opts &= ~(FANCY_INDEXING | TABLE_INDEXING);
+ else if (qstring[2] == '1')
+ autoindex_opts = (autoindex_opts | FANCY_INDEXING)
+ & ~TABLE_INDEXING;
+ else if (qstring[2] == '2')
+ autoindex_opts |= FANCY_INDEXING | TABLE_INDEXING;
+ strcpy(fval, "&F= ");
+ fval[3] = qstring[2];
+ qstring += qstring[3] ? 4 : 3;
+ }
+ else if (qstring[0] == 'V' && qstring[1] == '='
+ && (qstring[2] == '0' || qstring[2] == '1')
+ && (qstring[3] == '&' || !qstring[3])) {
+ if (qstring[2] == '0')
+ autoindex_opts &= ~VERSION_SORT;
+ else if (qstring[2] == '1')
+ autoindex_opts |= VERSION_SORT;
+ strcpy(fval, "&V= ");
+ vval[3] = qstring[2];
+ qstring += qstring[3] ? 4 : 3;
+ }
+ else if (qstring[0] == 'P' && qstring[1] == '=') {
+ char *eos = strchr(qstring, '&');
+ if (eos) {
+ pstring = apr_pstrndup(r->pool, qstring + 2,
+ eos - qstring - 2);
+ qstring = eos + 1;
+ }
+ else {
+ pstring = apr_pstrdup(r->pool, qstring + 2);
+ qstring = NULL;
+ }
+ if (*pstring)
+ ppre = "&P=";
+ else
+ pstring = NULL;
+ }
+ else /* Syntax error? Ignore the remainder! */
+ qstring = NULL;
+ }
+ colargs = apr_pstrcat(r->pool, fval, vval, ppre, pstring, NULL);
+ }
+
+ /* Spew HTML preamble */
title_endp = title_name + strlen(title_name) - 1;
while (title_endp > title_name && *title_endp == '/') {
emit_head(r, find_header(autoindex_conf, r),
autoindex_opts & SUPPRESS_PREAMBLE, title_name);
- /*
- * Figure out what sort of indexing (if any) we're supposed to use.
- *
- * If no QUERY_STRING was specified or column sorting has been
- * explicitly disabled, we use the default specified by the
- * IndexOrderDefault directive (if there is one); otherwise,
- * we fall back to ascending by name.
- */
- if (!(autoindex_opts & SUPPRESS_COLSORT))
- qstring = r->args;
- else
- qstring = NULL;
-
- /*
- * If there is no specific ordering defined for this directory,
- * take the defaults above.
- */
- if ((qstring != NULL) && (*qstring != '\0')) {
- keyid = *qstring;
- ap_getword(r->pool, &qstring, '=');
- if (qstring != '\0') {
- direction = *qstring;
- }
- }
-
/*
* Since we don't know how many dir. entries there are, put them into a
* linked list and then arrayificate them so qsort can use them.
num_ent++;
}
while (apr_dir_read(&dirent, APR_FINFO_DIRENT, thedir) == APR_SUCCESS) {
- p = make_autoindex_entry(&dirent, autoindex_opts,
- autoindex_conf, r, keyid, direction);
+ p = make_autoindex_entry(&dirent, autoindex_opts, autoindex_conf, r,
+ keyid, direction, pstring);
if (p != NULL) {
p->next = head;
head = p;
qsort((void *) ar, num_ent, sizeof(struct ent *),
(int (*)(const void *, const void *)) dsortf);
}
- output_directories(ar, num_ent, autoindex_conf, r, autoindex_opts, keyid,
- direction);
+ output_directories(ar, num_ent, autoindex_conf, r, autoindex_opts,
+ keyid, direction, colargs);
apr_dir_close(thedir);
emit_tail(r, find_readme(autoindex_conf, r),