Skip to main content

uploadserver plus an in-browser previewer for developer files (Markdown, JSON, code, CSV, diffs, images). No build step; works offline on a LAN.

Project description

uploadserver-preview

An in-browser previewer bolted onto uploadserver. Browse a directory over HTTP and click a file to see it rendered instead of downloaded: Markdown as formatted prose, JSON as a collapsible tree, source code with syntax highlighting and line numbers, CSV/TSV as tables, unified diffs the way GitHub shows them, and images inline.

Everything renders client-side with vendored JavaScript — no build step, no CDN, no outbound network. It works on an air-gapped LAN, which is where a file server like this usually lives. Uploads and every other uploadserver feature (basic auth, TLS/mTLS, --directory, --theme, ...) are untouched.

Install

Published on PyPI as uploadserver-preview.

With uv (recommended — no separate install step):

uvx uploadserver-preview             # run once, in an ephemeral environment
uvx uploadserver-preview 9000 -d /srv

Or install it properly, with either uv or pip:

uv tool install uploadserver-preview
pip install uploadserver-preview

This pulls in uploadserver as a dependency. Python 3.9+.

Use

Exactly like uploadserver — same arguments, same behaviour, plus previews:

uploadserver-preview                 # serve ./ on :8000
uploadserver-preview 9000 -d /srv    # port 9000, serve /srv
uploadserver-preview --theme dark
uploadserver-preview --basic-auth me:secret
python -m uploadserver_preview 8080  # module form also works

Then open http://<host>:8000/, browse, and click a file. Each row shows a small type tag (md, json, py, csv, …); previewable files open in the viewer, anything else downloads. Every file also has a raw link.

Flags

All of uploadserver's flags are accepted (port, --directory/-d, --bind/-b, --theme, --allow-replace, --server-certificate/-c, --client-certificate, --basic-auth, --basic-auth-upload, --cgi), plus:

Flag Effect
--no-preview Disable the previewer; behave like plain uploadserver.

--cgi also disables the previewer (CGI mode is left to stock uploadserver).

What it renders

Type Extensions Rendered as
Markdown .md .markdown .mdown .mkd Sanitized HTML prose; fenced code highlighted
JSON .json .geojson .ipynb Collapsible tree (falls back to highlighted source if invalid)
Config .yaml .yml .toml .ini .cfg .conf Highlighted source (comments preserved)
Code .py .js .ts .tsx .rs .go .java .c .cpp .rb .php .lua .sql .sh and more Highlighted, line-numbered
Tables .csv .tsv Sortable-width HTML table with row numbers
Diffs .diff .patch Line-by-line diff view
Images .png .jpg .jpeg .gif .webp .bmp .ico .avif .svg Inline, with dimensions
Markup .html .htm .xml .xhtml Source only — never executed

Unrecognized extensions are shown as text when they look textual, and flagged as binary otherwise. Text rendering is capped at 3 MB and tables at 5,000 rows to keep the browser responsive; the raw link always serves the full file.

How it works

uploadserver exposes its request handler as a module-level name that serve_forever() resolves at call time. This package subclasses that handler and swaps it in before serving, so uploads and auth keep working while a few extra routes are added:

  • A browser navigating to a previewable file's own URL (detected via Sec-Fetch-Dest: document) gets the explorer shell instead of raw bytes; the client then fetches the file same-origin, dispatches on extension, and renders it. curl/wget, fetch(), iframes — and anything with ?raw — keep getting the raw file, so scripted downloads behave like stock uploadserver.
  • GET /__view__?path=… returns a small static viewer shell (kept for old links). The server never reflects path into HTML.
  • GET /__preview_asset__/<name> serves the vendored JS/CSS by basename from a fixed whitelist (traversal-proof).
  • Directory listings are replaced with a richer, themed listing that adds view and raw links and the type tags.

Everything else — raw files, /upload, redirects — falls through to uploadserver unchanged.

Security notes

  • Uploaded content is untrusted. Markdown is sanitized with DOMPurify before it touches the DOM. Code, JSON, YAML, CSV, and diffs are escaped or inserted as text. HTML/SVG/XML files are shown as source and never executed; images are loaded via <img>, where scripts do not run.
  • A strict Content-Security-Policy is sent on preview pages: script-src 'self' (all JS is external — there are no inline scripts), default-src 'self', object-src 'none'. Inline styles are permitted because the JSON component and highlight/diff themes rely on them.
  • Preview routes and assets are behind the same basic auth as the rest of the server, so nothing is exposed before authentication.
  • This is still a simple file server. Don't expose it to the public internet without auth + TLS, exactly as with stock uploadserver.

Offline / vendored assets

All rendering libraries live under uploadserver_preview/assets/ and are served locally, so the previewer needs no internet access. Bundled: highlight.js (common languages + Dockerfile), marked, DOMPurify, PapaParse, diff2html (core), and @andypf/json-viewer. See LICENSE for their licenses.

Limitations

  • No preview for PDF or Office documents (they open via the raw link, and modern browsers render PDFs natively).
  • Diffs are colored by line; intra-line syntax highlighting inside diffs is omitted to keep the bundle small.
  • CGI mode (--cgi) is served by stock uploadserver without previews.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

uploadserver_preview-0.1.13.tar.gz (160.8 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

uploadserver_preview-0.1.13-py3-none-any.whl (164.4 kB view details)

Uploaded Python 3

File details

Details for the file uploadserver_preview-0.1.13.tar.gz.

File metadata

  • Download URL: uploadserver_preview-0.1.13.tar.gz
  • Upload date:
  • Size: 160.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.11.28 {"installer":{"name":"uv","version":"0.11.28","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for uploadserver_preview-0.1.13.tar.gz
Algorithm Hash digest
SHA256 110d4391fda89209dadfcbd9a8a2294181f945350c1c0143b96c41f9c81505f1
MD5 614ab9a29a848d90f5df7641396b8943
BLAKE2b-256 77742c81cfbafe90bdcde2481cf83e1c3c535b1e6ab94e4c6f311db605debe21

See more details on using hashes here.

File details

Details for the file uploadserver_preview-0.1.13-py3-none-any.whl.

File metadata

  • Download URL: uploadserver_preview-0.1.13-py3-none-any.whl
  • Upload date:
  • Size: 164.4 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.11.28 {"installer":{"name":"uv","version":"0.11.28","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for uploadserver_preview-0.1.13-py3-none-any.whl
Algorithm Hash digest
SHA256 495e0e7237b7dd96dd95424bd5ddc97e4714a0cc5f3022f7afd4eea8dcb07cf0
MD5 f92c9f3aa91003e719320e6fcc2a12c8
BLAKE2b-256 193c69b537dc144c7e240c0f19a9ea04b42865946a21b3e6a2516dc113da4257

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page