Python's http.server extended to include a file upload page
python3 -m pip install --user uploadserver
python3 -m uploadserver
Accepts the same options as http.server, plus a couple extras (documented below).
After the server starts, the upload page is at /upload. For example, if the server is running at http://localhost:8000/ go to http://localhost:8000/upload .
Warning: This is an upload server, and running it will allow uploads. Uploaded files will replace existing files with the same name.
Now supports uploading multiple files at once! Select multiple files in the web page's file selector, or upload with cURL:
curl -X POST http://127.0.0.1:8000/upload -F '[email protected]' -F '[email protected]'
Run with a simple token.
python3 -m uploadserver -t helloworld
Now you can upload a file with the token. For example:
curl -X POST http://127.0.0.1:8000/upload -F '[email protected]' -F 'token=helloworld'
Uploads without the token will be rejected. Tokens can be stolen if sent in plain HTTP, so this option is best used with HTTPS.
Note: The server cannot check the token until after a file has been transferred, due to the way HTML form uploads are formatted, which creates a DoS vulnerability. If this is a concern, use mTLS for client authentication instead of relying on tokens.
Run with a file listing multiple tokens.
python3 -m uploadserver -t tokenlist.txt --tokenlist
Uploads will be moved into a sub-folder whose name is the same as the token, so the token should acceptable as a filesystem folder name - E.g. a UUID. Uploads without a valid token will be rejected and the temporarily uploaded file will be deleted.
Run with a storage limit preventing DoS for other services.
python3 -m uploadserver --quota 100 # in MB, default is 100
If an upload causes the destination folder to exceede the quota capacity, that file will be deleted.
In any case, if an upload causes the destination filesystem to fill, that file will be deleted.
The upload page supports a dark mode for showing white text on black background. If no option is specified, the color scheme is chosen from the client’s browser’s preference (which typically matches their operating system’s setting, if light or dark mode is supported by the OS). To enforce the light or dark theme, the CLI parameter --theme
can be used:
python3 -m uploadserver --theme light
or
python3 -m uploadserver --theme dark
Run with HTTPS and without client authentication:
# Generate self-signed server certificate
openssl req -x509 -out server.pem -keyout server.pem -newkey rsa:2048 -nodes -sha256 -subj '/CN=server'
# The server root should not contain the certificate, for security reasons
cd server-root
python3 -m uploadserver --server-certificate server.pem
# Connect as a client
curl -X POST https://localhost:8000/upload --insecure -F [email protected]
Run with HTTPS and with client authentication:
# Generate self-signed server certificate
openssl req -x509 -out server.pem -keyout server.pem -newkey rsa:2048 -nodes -sha256 -subj '/CN=server'
# Generate self-signed client certificate
openssl req -x509 -out client.pem -keyout client.pem -newkey rsa:2048 -nodes -sha256 -subj '/CN=client'
# Extract public key from self-signed client certificate
openssl x509 -in client.pem -out client.crt
# The server root should not contain the certificates, for security reasons
cd server-root
python3 -m uploadserver --server-certificate server.pem --client-certificate client.crt
# Connect as a client
curl -X POST https://localhost:8000/upload --insecure --cert client.pem -F [email protected]
Note: This uses a self-signed server certificate which clients such as web browser and cURL will warn about. Most browsers will allow you to proceed after adding an exception, and cURL will work if given the -k/--insecure option. Using your own certificate from a certificate authority will avoid these warnings.
- By default, uploaded files which have the same name as an existing file are renamed. To restore the previous behavior of overwriting them, pass
--allowreplace
. - File uploads with no files in them are rejected with 400 Bad Request instead of 500 Internal Server Error, with a more informative error message.
- Handling of large uploads has been improved. Theoretically this should not cause any breaking changes, but filesystems are black magic and should be viewed with suspicion.
- If
serve_forever
is called directly, such as by an extension, thetheme
field is now required on the arguments object. This change will not affect users who run this module unmodified.
- File uploads now respect the
--directory
option. Not doing so was a bug, and a security risk (since it could to the server root containing the server's certificate without the user realizing). - The
--token
option, if supplied, must be given a value. Not requiring a value was a bug, and a security risk (since a user could specify the token option but forget to provide a token). - Some internal refactoring was done to support creating extensions. This does not affect command line use.
- File field in upload form renamed from
file_1
tofiles
, to reflect support for multiple file upload. Scripts using cURL will need to be upadted with the new field name. - Successful uploads now respond with 204 No Content instead of 200 OK, so that cURL will not default to printing the upload page at the terminal.
Much of main()
was copied from Python's http.server
.
Thanks to lishoujun for sending the first pull request! (Added the token option.)
Thanks to NteRySin for several improvements including mTLS support and refactoring to support use by other modules.
Thanks to marvinruder for work on the upload progress indicator, theme option, and pre-validation of tokens before upload.
Thanks to shuangye for finding an easy way to handle large file uploads, and improved handling of filename collisions.