Commit 6b470f3d authored by hydrargyrum's avatar hydrargyrum

httpshare: share a directory via HTTP, like Python "http.server" but supports "Range" headers

parent bf4350da
#!/usr/bin/env python3
# license: WTFPLv2
"""
Shares a directory on HTTP like "python3 -m http.server" but is capable of
handling "Range" header, making it suitable for seeking randomly in medias.
"""
import argparse
from pathlib import Path
from socketserver import ThreadingMixIn
from urllib.parse import quote
from wsgiref.simple_server import WSGIServer
from bottle import route, run, abort, static_file, WSGIRefServer, redirect
DIR = """<!DOCTYPE html>
<html>
<body>
<ul>
{0}
</ul>
</body>
</html>
"""
@route('/')
@route('/<path:path>')
def anything(path='/'):
try:
target = ROOT.joinpath(path.lstrip('/')).resolve(True)
relative = target.relative_to(ROOT)
except (FileNotFoundError, ValueError) as exc:
abort(403)
if target.is_dir():
if not path.endswith('/'):
redirect(f'{path}/')
parts = [
f'<li><a href="{quote(sub.name)}{"/" if sub.is_dir() else ""}">'
f'{sub.name}{"/" if sub.is_dir() else ""}</a></li>'
for sub in sorted(target.iterdir())
]
return DIR.format('\n'.join(parts))
elif target.is_file():
return static_file(str(relative), str(ROOT))
abort(404)
class ThreadedServer(ThreadingMixIn, WSGIServer):
pass
parser = argparse.ArgumentParser()
parser.add_argument('--bind', '-b', default='', metavar='ADDRESS',
help='Specify alternate bind address '
'[default: all interfaces]')
parser.add_argument('--directory', '-d', default=Path.cwd(), type=Path,
help='Specify alternative directory '
'[default:current directory]')
parser.add_argument('port', action='store',
default=8000, type=int,
nargs='?',
help='Specify alternate port [default: 8000]')
args = parser.parse_args()
ROOT = args.directory
run(server=WSGIRefServer(host=args.bind, port=args.port, server_class=ThreadedServer))
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment