#!/usr/bin/env python3 """Simple server written using an event loop.""" import email.message import os import sys assert sys.version >= '3.3', 'Please use Python 3.3 or higher.' import tulip import tulip.http class HttpServer(tulip.http.ServerHttpProtocol): def handle_request(self, request_info, message): print('method = {!r}; path = {!r}; version = {!r}'.format( request_info.method, request_info.uri, request_info.version)) path = request_info.uri if (not (path.isprintable() and path.startswith('/')) or '/.' in path): print('bad path', repr(path)) path = None else: path = '.' + path if not os.path.exists(path): print('no file', repr(path)) path = None else: isdir = os.path.isdir(path) if not path: raise tulip.http.HttpStatusException(404) headers = email.message.Message() for hdr, val in message.headers: print(hdr, val) headers.add_header(hdr, val) if isdir and not path.endswith('/'): path = path + '/' raise tulip.http.HttpStatusException( 302, headers=(('URI', path), ('Location', path))) response = tulip.http.Response(self.transport, 200) response.add_header('Transfer-Encoding', 'chunked') # content encoding accept_encoding = headers.get('accept-encoding', '').lower() if 'deflate' in accept_encoding: response.add_header('Content-Encoding', 'deflate') response.add_compression_filter('deflate') elif 'gzip' in accept_encoding: response.add_header('Content-Encoding', 'gzip') response.add_compression_filter('gzip') response.add_chunking_filter(1025) if isdir: response.add_header('Content-type', 'text/html') response.send_headers() response.write(b'') else: response.add_header('Content-type', 'text/plain') response.send_headers() try: with open(path, 'rb') as fp: chunk = fp.read(8196) while chunk: if not response.write(chunk): break chunk = fp.read(8196) except OSError: response.write(b'Cannot open') response.write_eof() self.close() def main(): host = '127.0.0.1' port = 8080 if sys.argv[1:]: host = sys.argv[1] if sys.argv[2:]: port = int(sys.argv[2]) elif ':' in host: host, port = host.split(':', 1) port = int(port) loop = tulip.get_event_loop() f = loop.start_serving(lambda: HttpServer(debug=True), host, port) x = loop.run_until_complete(f) print('serving on', x.getsockname()) loop.run_forever() if __name__ == '__main__': main()