Skip to main content

HTTPdis

A small synchronous HTTP dispatcher for Python services: named and regex routes, JSON/form payloads, responses, static files and Basic authentication. Used by dwho, Covenant and Auton. HTTPdis is a reference to the TARDIS in Doctor Who, matching the naming of Sonicprobe, dwho and Auton. This is independent software, not an official product.

When to use it

HTTPdis is useful for maintaining and extending services already built around its request handlers and lifecycle hooks. It uses the Python standard HTTP server and sonicprobe workers; it is not an ASGI server. For an unrelated new application, compare the maintenance cost of this custom stack with a maintained web framework.

Installation

python -m pip install httpdis

The declared range remains Python 2.7 and Python 3.5+. Legacy installations require compatible dependency versions. On Python 3.13+, legacy-cgi and legacycrypt replace removed standard-library APIs while preserving multipart and password-file interfaces. Static MIME detection requires libmagic. See the CI matrix for actual tested interpreters and the tests for the covered behaviors.

Minimal JSON service

from httpdis.ext import httpdis_json as server

def health(request):
    return {'status': 'ok'}

server.register(health, 'GET', name='health')
options = {'listen_addr': '127.0.0.1', 'listen_port': 8080, 'max_workers': 2}
server.init(options)
server.run(options)
curl http://127.0.0.1:8080/health

Handlers receive a request with get_path(), query_params(), payload_params(), get_headers() and get_server_vars(). They may return data or an HttpResponse / HttpResponseJson to control status and headers. register supports method lists, compiled regular expressions and safe_init, at_start, at_stop hooks. Routes and options are process-global; use a separate process for independent apps.

Request body limits

Since HTTPdis 0.6.28, register(..., max_body_size=...) sets the body limit for a named or regex route. It applies to POST, PUT and PATCH before reading or parsing the body; oversized requests return HTTP 413.

server.register(action_handler, 'POST', name='v1/actions', max_body_size=1024)
server.register(notification_handler, 'POST', name='v1/notifications',
                max_body_size=64 * 1024)

Define your handlers before registering them. The value is a non-negative integer number of bytes. 0 allows only an empty body; None or an omitted argument uses the current global max_body_size option (1 MiB by default). A route value replaces the global default and may be smaller or larger. It does not change other routes or the global option. Negative values, booleans, floats and strings are rejected during registration.

Existing registrations and positional arguments remain compatible. JSON services using httpdis.ext.httpdis_json.register share the same option. GET/HEAD/DELETE continue to use the query handler; this option does not change their behavior.

Authentication and deployment

Configure auth_basic_file with a trusted htpasswd file and auth_basic with the realm. Set to_auth=True on protected routes, or use a username list such as to_auth=['alice']. A protected route without configured authentication now returns 401 rather than allowing the request. Invalid credentials are rejected; request credentials are isolated between threads. Existing {SHA} and system crypt hashes remain readable for compatibility; legacy SHA-1/DES hashes are not recommendations for new password storage. Basic credentials require HTTPS in transit.

Bind to loopback or a private interface behind a reverse proxy providing TLS, request timeouts, connection limits and access controls. This release does not claim complete HTTP parser hardening for hostile public traffic. Configure max_body_size to limit request bodies. Chunked request bodies are not supported. Internal exceptions are logged server-side and return a generic 500 to clients.

Static files

A static route uses static=True and root='/srv/public'. Regex routes can use replacement to map URLs to filenames. Resolved symlinks outside the root are rejected. Treat the static directory as administrator-controlled; these checks are not a filesystem sandbox against concurrent hostile filesystem modifications. Invalid If-Modified-Since values are ignored. Files are buffered in memory, so serve large downloads through the reverse proxy.

Compatibility fixes

  • Correct UTF-8 response byte lengths and duplicate Content-Type/Length headers.
  • Correct Basic authentication on Python 3 and username-list registration.
  • Keep credentials isolated across request threads and reject malformed headers.
  • Reject missing authentication on protected routes and truncated request bodies.
  • Resolve static paths before checking containment; tolerate invalid dates.
  • Keep removed CGI/crypt functionality available through compatibility packages.

The dependency loop with sonicprobe is retained because sonicprobe's historical HTTP JSON module re-exports HTTPdis. A future major release should untangle it.

Development and publication

python -m pip install -e . mock
python -m unittest discover -s tests -v
python -m pip install build twine
python -m build
python -m twine check --strict dist/*

Update VERSION, RELEASE and setup.yml together. After tests and distribution validation succeed, the master publication workflow creates vX.Y.Z and uploads via Trusted Publishing (decryptus/httpdis, pypi.yml, environment pypi). Already-tagged versions are not replaced by ordinary master commits.

License: GPL-3.0-or-later. Original authors and Wazo/Proformatique copyrights are preserved in the source files.

See the September 2026 code and architecture review (French).

Metadata

Release files for httpdis 0.6.28

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for httpdis 0.6.28
File Size Uploaded
httpdis-0.6.28.tar.gz 34.3 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for httpdis 0.6.28
File Interpreter ABI Platform
httpdis-0.6.28-py2.py3-none-any.whl Python 2, Python 3 none any Details

Total release size: 63.0 kB

Release files / httpdis-0.6.28.tar.gz

Download URL httpdis-0.6.28.tar.gz
Size 34.3 kB
Tags Source
SHA-256 checksum
How to use checksums
3ed496b49275493a58eaf132b5d4af504cab001f238e6c6bcf89ef70748d6da9
BLAKE2b-256 checksum
How to use checksums
75b28c36df1fd97a6237b41bf168997b52bda19bf171c85458bd1176f57d43a9
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 23, 2026.

Transparency log

Release files / httpdis-0.6.28-py2.py3-none-any.whl

Download URL httpdis-0.6.28-py2.py3-none-any.whl
Size 28.7 kB
Tags Python 2 Python 3
SHA-256 checksum
How to use checksums
7014964fdaa8cc97db8de1b42658597e9fbaeded46686d7124887543fe7d873a
BLAKE2b-256 checksum
How to use checksums
fb2500d525c82fc6c99e49b8859b800d3df11b3dc95a42c808d6d6067ac8acfd
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 23, 2026.

Transparency log

Release history Release notifications | RSS feed

0.6.31

2 release files

0.6.30

2 release files

0.6.29

2 release files

This release

0.6.28 This release

2 release files

0.6.27

2 release files

0.6.26

2 release files

0.6.22

2 release files

0.6.21

2 release files

0.6.20

2 release files

0.6.19

2 release files

0.6.18

2 release files

0.6.14

2 release files

0.6.13

2 release files

0.6.12

2 release files

0.6.11

2 release files

0.6.10

2 release files

0.6.9

2 release files

0.6.8

2 release files

0.6.7

2 release files

0.6.6

2 release files

0.6.5

2 release files

0.6.4

2 release files

0.6.2

2 release files

0.6.1

2 release files

0.5.17

1 release file

0.5.16

1 release file

0.5.15

1 release file

0.5.14

1 release file

0.5.13

1 release file

0.5.12

1 release file

0.5.11

1 release file

0.5.10

1 release file

0.5.9

1 release file

0.5.8

1 release file

0.5.7

1 release file

0.5.6

1 release file

0.5.5

1 release file

0.5.4

1 release file

0.5.3

1 release file

0.5.2

1 release file

0.5

1 release file

0.0.4

1 release file

0.0.3

1 release file

0.0.2

1 release file

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page