Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

4 Commits
 
 
 
 
 
 
 
 

Repository files navigation

dirlister

An Apache directory index that renders symlinks as symlinks.

dirlister.py generates a directory listing for a filesystem subtree, rendering symbolic links explicitly as name -> target, distinguishing dir / file / broken / outside targets, and refusing to follow links whose target escapes the served root.

Pure stdlib, no third-party dependencies.

Features

  • Shows each symlink as name -> target, with the target colour-coded by kind (directory, file, broken, or pointing outside the served root).
  • Both the link name and its target are navigable when the target resolves inside the served root; escaping or broken targets are shown but not linked.
  • Symlinks may climb with .. as long as they resolve back inside the document root; anything that escapes is labelled outside and not followed.
  • VersionSort + case-insensitive ordering (so file-2 sorts before file-10).
  • Per-type icons ported from mod_autoindex AddIcon, served from Apache's standard /icons/ alias.
  • Hides dotfiles and other ignored names (mirrors IndexIgnore).

Configuration

Set via environment (Apache SetEnv) or by editing the constants at the top of the script:

Variable Default Purpose
DIRLISTER_ROOT auto Filesystem root this lister may expose.
DIRLISTER_URL_PREFIX auto URL prefix that maps to DIRLISTER_ROOT.
DIRLISTER_ICON_BASE /icons/ URL prefix for icon images (set "" to disable).
DIRLISTER_DEBUG unset Set to "1" to emit request/config diagnostics.

When neither DIRLISTER_ROOT nor DIRLISTER_URL_PREFIX is set, the pair is detected per request from Apache's CONTEXT_DOCUMENT_ROOT / CONTEXT_PREFIX, which name whichever Alias the requested URL fell under. A path served straight out of the document root reports the document root and an empty prefix, so the default behaviour is unchanged — but a directory reached through an Alias also resolves correctly, with no configuration. Set the variables explicitly only to serve a subtree narrower than the Alias target.

ALLOW_ESCAPING_LINKS (a constant in the script, default False) controls whether links whose target lies outside the served root are made followable or merely labelled.

Deployment

Deploy as a CGI script under mod_cgid / mod_cgi — the __main__ block bridges the WSGI app to CGI via wsgiref — or import the application callable directly under mod_wsgi.

Example: CGI directory index (recommended)

Run the lister as a CGI script and wire it in as the DirectoryIndex, so it replaces mod_autoindex for any directory without an index file:

# These belong at server scope (load once).
LoadModule cgid_module modules/mod_cgid.so

<VirtualHost *:80>
    ServerName  files.example.com
    DocumentRoot /srv/www

    # Make the lister runnable as CGI at a stable URL.
    ScriptAlias /dirlister.cgi /usr/local/lib/dirlister/dirlister.py

    # Confine the lister to the document root.
    SetEnv DIRLISTER_ROOT /srv/www

    <Directory /srv/www>
        # Replace the built-in autoindex; FollowSymLinks lets Apache serve
        # the symlinked content the lister links to.
        Options -Indexes +FollowSymLinks

        # A directory request with no index file is internally redirected to
        # the lister; the original directory path arrives in REDIRECT_URL.
        DirectoryIndex /dirlister.cgi

        Require all granted
    </Directory>
</VirtualHost>

Example: listing an Aliased prefix

An Alias maps a URL prefix onto a directory that need not sit under the document root, so the URL path cannot be appended to DocumentRoot to find the directory. The lister reads the alias from CONTEXT_DOCUMENT_ROOT / CONTEXT_PREFIX, so this needs no extra configuration:

<VirtualHost *:443>
    ServerName  files.example.com
    DocumentRoot /var/www/htdocs

    ScriptAlias /dirlister.cgi /usr/local/lib/dirlister/dirlister.py

    # /lts/dists/ is served from a directory named lts
    Alias /lts/dists /var/www/htdocs/lts

    <Directory /var/www/htdocs/lts>
        Options -Indexes +FollowSymLinks
        DirectoryIndex /dirlister.cgi
        Require all granted
    </Directory>
</VirtualHost>

Note that a DirectoryIndex request reaches the lister through an internal redirect, which re-runs the configuration against /dirlister.cgi. Two consequences are worth knowing:

  • The unprefixed CONTEXT_* variables then describe the lister's own ScriptAlias, not the listed directory. The originals survive as REDIRECT_CONTEXT_*, which is what the lister reads when it sees REDIRECT_URL.
  • SetEnv DIRLISTER_ROOT placed inside a <Directory> or <Location> block likewise arrives as REDIRECT_DIRLISTER_ROOT. The lister accepts either spelling, so per-directory SetEnv works — but only a vhost-scope SetEnv arrives unprefixed, and it applies to every path in the vhost.

Set DIRLISTER_DEBUG to 1 to dump the request variables actually received and see which ones carry the alias, rather than guessing.

Example: mod_wsgi

Point WSGIScriptAlias at the file and mod_wsgi imports application directly. Mount it on the prefix you want listed (it only handles directory requests; let Apache serve files normally):

LoadModule wsgi_module modules/mod_wsgi.so

<VirtualHost *:80>
    ServerName  files.example.com
    DocumentRoot /srv/www

    SetEnv DIRLISTER_ROOT /srv/www
    WSGIScriptAlias /browse /usr/local/lib/dirlister/dirlister.py

    <Directory /usr/local/lib/dirlister>
        Require all granted
    </Directory>
</VirtualHost>

The serving root is resolved per request, so it works correctly under both CGI (which sets DOCUMENT_ROOT as a real env var) and mod_wsgi (which exposes SetEnv values and DOCUMENT_ROOT in the WSGI environ instead).

Security

  • The serving root is resolved per request, so a single mod_wsgi worker never pins every request to a stale root.
  • Every requested path and every symlink target is run through os.path.realpath and checked for containment within the served root, so .. traversal and symlink escapes are refused.
  • DIRLISTER_DEBUG is gated on the exact string "1", so the natural "off" values ("0", "false") do not accidentally enable the diagnostics dump (which leaks paths and the environment — never enable it in production).
  • Malformed or unreadable paths return 400 / 403 / 404 rather than surfacing a 500 / traceback.
  • Symlink targets are only made navigable when they resolve inside the root.

License

See LICENSE.

About

Prettier directory listing CGI script for apache

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages