def _get_environ(self, request, body, content_length): # Resolve the path info. path_info = request.match_info["path_info"] script_name = request.rel_url.path[:len(request.rel_url.path) - len(path_info)] # Special case: If the app was mounted on the root, then the script name will # currently be set to "/", which is illegal in the WSGI spec. The script name # could also end with a slash if the WSGIHandler was mounted as a route # manually with a trailing slash before the path_info. In either case, we # correct this according to the WSGI spec by transferring the trailing slash # from script_name to the start of path_info. if script_name.endswith("/"): script_name = script_name[:-1] path_info = "/" + path_info # Parse the connection info. server_name, server_port = parse_sockname( request.transport.get_extra_info("sockname")) remote_addr, remote_port = parse_sockname( request.transport.get_extra_info("peername")) # Detect the URL scheme. url_scheme = self._url_scheme if url_scheme is None: url_scheme = "http" if request.transport.get_extra_info( "sslcontext") is None else "https" # Create the environ. environ = { "REQUEST_METHOD": request.method, "SCRIPT_NAME": script_name, "PATH_INFO": path_info, "QUERY_STRING": request.rel_url.query_string, "CONTENT_TYPE": request.headers.get("Content-Type", ""), "CONTENT_LENGTH": str(content_length), "SERVER_NAME": server_name, "SERVER_PORT": server_port, "REMOTE_ADDR": remote_addr, "REMOTE_HOST": remote_addr, "REMOTE_PORT": remote_port, "SERVER_PROTOCOL": "HTTP/{}.{}".format(*request.version), "wsgi.version": (1, 0), "wsgi.url_scheme": url_scheme, "wsgi.input": body, "wsgi.errors": self._stderr, "wsgi.multithread": True, "wsgi.multiprocess": False, "wsgi.run_once": False, "asyncio.loop": self._loop, "asyncio.executor": self._executor, "aiohttp.request": request, } # Add in additional HTTP headers. for header_name in request.headers: header_name = header_name.upper() if not (is_hop_by_hop(header_name)) and header_name not in ( "CONTENT-LENGTH", "CONTENT-TYPE"): header_value = ",".join(request.headers.getall(header_name)) environ["HTTP_" + header_name.replace("-", "_")] = header_value # All done! return environ
def _get_environ(self, request): # Resolve the path info. path_info = request.match_info["path_info"] script_name = request.path[:len(request.path)-len(path_info)] # Special case: If the app was mounted on the root, then the script name will # currently be set to "/", which is illegal in the WSGI spec. The script name # could also end with a slash if the WSGIHandler was mounted as a route # manually with a trailing slash before the path_info. In either case, we # correct this according to the WSGI spec by transferring the trailing slash # from script_name to the start of path_info. if script_name.endswith("/"): script_name = script_name[:-1] path_info = "/" + path_info # Read the body. body = (yield from request.read()) # Parse the connection info. server_name, server_port = parse_sockname(request.transport.get_extra_info("sockname")) remote_addr, remote_port = parse_sockname(request.transport.get_extra_info("peername")) # Detect the URL scheme. url_scheme = self._url_scheme if url_scheme is None: url_scheme = "http" if request.transport.get_extra_info("sslcontext") is None else "https" # Create the environ. environ = { "REQUEST_METHOD": request.method, "SCRIPT_NAME": quote(script_name), # WSGI spec expects URL-quoted path components. "PATH_INFO": quote(path_info), # WSGI spec expects URL-quoted path components. "QUERY_STRING": request.query_string, "CONTENT_TYPE": request.headers.get("Content-Type", ""), "CONTENT_LENGTH": str(len(body)), "SERVER_NAME": server_name, "SERVER_PORT": server_port, "REMOTE_ADDR": remote_addr, "REMOTE_HOST": remote_addr, "REMOTE_PORT": remote_port, "SERVER_PROTOCOL": "HTTP/{}.{}".format(*request.version), "wsgi.version": (1, 0), "wsgi.url_scheme": url_scheme, "wsgi.input": io.BytesIO(body), "wsgi.errors": self._stderr, "wsgi.multithread": True, "wsgi.multiprocess": False, "wsgi.run_once": False, } # Add in additional HTTP headers. for header_name in request.headers: header_name = header_name.upper() if not(is_hop_by_hop(header_name)) and not header_name in ("CONTENT-LENGTH", "CONTENT-TYPE"): header_value = ",".join(request.headers.getall(header_name)) environ["HTTP_" + header_name.replace("-", "_")] = header_value # All done! return environ
def _get_environ(self, request): # Resolve the path info. path_info = request.path if path_info.startswith(self._script_name): path_info = path_info[len(self._script_name):] # Read the body. body = (yield from request.read()) # Parse the connection info. server_name, server_port = parse_sockname( request.transport.get_extra_info("sockname")) remote_addr, remote_port = parse_sockname( request.transport.get_extra_info("peername")) # Detect the URL scheme. url_scheme = self._url_scheme if url_scheme is None: url_scheme = "http" if request.transport.get_extra_info( "sslcontext") is None else "https" # Create the environ. environ = { "REQUEST_METHOD": request.method, "SCRIPT_NAME": self._script_name, "PATH_INFO": path_info, "QUERY_STRING": request.query_string, "CONTENT_TYPE": request.headers.get("Content-Type", ""), "CONTENT_LENGTH": str(len(body)), "SERVER_NAME": server_name, "SERVER_PORT": server_port, "REMOTE_ADDR": remote_addr, "REMOTE_HOST": remote_addr, "REMOTE_PORT": remote_port, "SERVER_PROTOCOL": "HTTP/{}.{}".format(*request.version), "wsgi.version": (1, 0), "wsgi.url_scheme": url_scheme, "wsgi.input": io.BytesIO(body), "wsgi.errors": self._stderr, "wsgi.multithread": True, "wsgi.multiprocess": False, "wsgi.run_once": False, } # Add in additional HTTP headers. for header_name in request.headers: header_name = header_name.upper() if not (is_hop_by_hop(header_name)) and not header_name in ( "CONTENT-LENGTH", "CONTENT-TYPE"): header_value = ",".join(request.headers.getall(header_name)) environ["HTTP_" + header_name.replace("-", "_")] = header_value # All done! return environ
def start_server( application, loop, executor, *, # Server config. host=None, port=8080, # Unix server config. unix_socket=None, unix_socket_perms=0o600, # Shared server config. backlog=1024, # aiohttp config. static=(), # Aiohttp config. script_name="", **kwargs): app = Application() # Add static routes. for static_item in static: assert "=" in static_item, "{!r} should have format 'path=directory'" static_item = static_item.split("=", 1) path, dirname = static_item app.router.add_static(format_path(path), dirname) # Add the wsgi application. This has to be last. app.router.add_route( "*", "{}{{path_info:.*}}".format(format_path(script_name)), WSGIHandler(application, loop=loop, executor=executor, **kwargs).handle_request, ) # HACK: Access logging is broken in aiohtp for unix sockets. handler = app.make_handler( access_log=access_logger if unix_socket is None else None) # Set up the server. shared_server_kwargs = { "backlog": backlog, } if unix_socket is not None: server = yield from loop.create_unix_server(handler, path=unix_socket, **shared_server_kwargs) else: server = yield from loop.create_server(handler, host=host, port=port, **shared_server_kwargs) # Set socket permissions. if unix_socket is not None: os.chmod(unix_socket, unix_socket_perms) # Report. server_uri = " ".join( "http://{}:{}".format(*parse_sockname(socket.getsockname())) for socket in server.sockets) logger.info("Serving on %s", server_uri) # All done! return app, handler, server, server_uri
def _get_environ(self, request): # Resolve the path info. path_info = request.match_info["path_info"] script_name = request.path[:len(request.path)-len(path_info)] # Read the body. body = (yield from request.read()) # Parse the connection info. server_name, server_port = parse_sockname(request.transport.get_extra_info("sockname")) remote_addr, remote_port = parse_sockname(request.transport.get_extra_info("peername")) # Detect the URL scheme. url_scheme = self._url_scheme if url_scheme is None: url_scheme = "http" if request.transport.get_extra_info("sslcontext") is None else "https" # Create the environ. environ = { "REQUEST_METHOD": request.method, "SCRIPT_NAME": script_name, "PATH_INFO": path_info, "QUERY_STRING": request.query_string, "CONTENT_TYPE": request.headers.get("Content-Type", ""), "CONTENT_LENGTH": str(len(body)), "SERVER_NAME": server_name, "SERVER_PORT": server_port, "REMOTE_ADDR": remote_addr, "REMOTE_HOST": remote_addr, "REMOTE_PORT": remote_port, "SERVER_PROTOCOL": "HTTP/{}.{}".format(*request.version), "wsgi.version": (1, 0), "wsgi.url_scheme": url_scheme, "wsgi.input": io.BytesIO(body), "wsgi.errors": self._stderr, "wsgi.multithread": True, "wsgi.multiprocess": False, "wsgi.run_once": False, } # Add in additional HTTP headers. for header_name in request.headers: header_name = header_name.upper() if not(is_hop_by_hop(header_name)) and not header_name in ("CONTENT-LENGTH", "CONTENT-TYPE"): header_value = ",".join(request.headers.getall(header_name)) environ["HTTP_" + header_name.replace("-", "_")] = header_value # All done! return environ
def configure_server( application, *, # Server config. host="0.0.0.0", port=8080, # Unix server config. unix_socket=None, unix_socket_perms=0o600, # aiohttp config. static=(), # Asyncio config. loop=None, # Handler config. **kwargs): loop = loop or asyncio.get_event_loop() # Create the WSGI handler. wsgi_middleware = middleware.wsgi(application, loop=loop, **kwargs) # Wrap the application in an executor. app = Application( loop=loop, middlewares=[wsgi_middleware], ) # Add static routes. if isinstance(static, Mapping): static = static.items() for path, dirname in static: app.router.add_static(path, dirname) # Set up the server. if unix_socket is not None: server_future = loop.create_unix_server( app.make_handler(), path=unix_socket, ) else: server_future = loop.create_server( app.make_handler(), host=host, port=port, ) server = loop.run_until_complete(server_future) app.logger.info("Serving on http://%s:%s", *parse_sockname(server.sockets[0].getsockname())) # Set socket permissions. if unix_socket is not None: os.chmod(unix_socket, unix_socket_perms) # All done! return server, app
def _serve(self, *args): with serve("-q", *args) as (loop, server): host, port = parse_sockname(server.sockets[0].getsockname()) if host == "unix": connector = aiohttp.UnixConnector(path=port, loop=loop) else: connector = aiohttp.TCPConnector(loop=loop) session = loop.run_until_complete(create_client_session(connector=connector, loop=loop)) try: yield TestClient(self, loop, host, port, session) finally: loop.run_until_complete(session.close()) connector.close()
def _run_server(self, *args, **kwargs): with run_server(*args, **kwargs) as (loop, site): host, port = parse_sockname(site._server.sockets[0].getsockname()) if host == "unix": connector = aiohttp.UnixConnector(path=port, loop=loop) else: connector = aiohttp.TCPConnector(loop=loop) session = aiohttp.ClientSession(connector=connector, loop=loop) try: yield TestClient(self, loop, host, port, session) finally: loop.run_until_complete(session.close()) connector.close()
def close_server(app, handler, server, server_uri, *, shutdown_timeout=60.0): # Clean up unix sockets. for socket in server.sockets: host, port = parse_sockname(socket.getsockname()) if host == "unix": os.unlink(port) # Close the server. logger.debug("Shutting down server on %s", server_uri) server.close() yield from server.wait_closed() # Shut down app. logger.debug("Shutting down app on %s", server_uri) yield from app.shutdown() yield from handler.shutdown(shutdown_timeout) yield from app.cleanup()
def run_server( application, *, # asyncio config. threads=4, # Server config. host=None, port=8080, # Unix server config. unix_socket=None, unix_socket_perms=0o600, # Shared server config. backlog=1024, # aiohttp config. static=(), static_cors=None, script_name="", shutdown_timeout=60.0, **kwargs): # Set up async context. loop = asyncio.new_event_loop() asyncio.set_event_loop(loop) assert threads >= 1, "threads should be >= 1" executor = ThreadPoolExecutor(threads) # Create aiohttp app. app = Application() # Add static routes. static = [(format_path(path), dirname) for path, dirname in static] for path, dirname in static: app.router.add_static(path, dirname) # Add the wsgi application. This has to be last. app.router.add_route( "*", "{}{{path_info:.*}}".format(format_path(script_name)), WSGIHandler(application, loop=loop, executor=executor, **kwargs).handle_request, ) # Configure middleware. if static_cors: app.middlewares.append( static_cors_middleware( static=static, static_cors=static_cors, )) # Start the app runner. runner = AppRunner(app) loop.run_until_complete(runner.setup()) # Set up the server. if unix_socket is not None: site = UnixSite(runner, path=unix_socket, backlog=backlog, shutdown_timeout=shutdown_timeout) else: site = TCPSite(runner, host=host, port=port, backlog=backlog, shutdown_timeout=shutdown_timeout) loop.run_until_complete(site.start()) # Set socket permissions. if unix_socket is not None: os.chmod(unix_socket, unix_socket_perms) # Report. server_uri = " ".join( "http://{}:{}".format(*parse_sockname(socket.getsockname())) for socket in site._server.sockets) logger.info("Serving on %s", server_uri) try: yield loop, site finally: # Clean up unix sockets. for socket in site._server.sockets: host, port = parse_sockname(socket.getsockname()) if host == "unix": os.unlink(port) # Close the server. logger.debug("Shutting down server on %s", server_uri) loop.run_until_complete(site.stop()) # Shut down app. logger.debug("Shutting down app on %s", server_uri) loop.run_until_complete(runner.cleanup()) # Shut down executor. logger.debug("Shutting down executor on %s", server_uri) executor.shutdown() # Shut down loop. logger.debug("Shutting down loop on %s", server_uri) loop.close() asyncio.set_event_loop(None) # All done! logger.info("Stopped serving on %s", server_uri)
def configure_server(application, *, # Server config. host = "0.0.0.0", port = 8080, # Unix server config. unix_socket = None, unix_socket_perms = 0o600, # Prexisting socket config. socket = None, # Shared server config. backlog = 1024, # aiohttp config. routes = (), static = (), on_finish = (), # Asyncio config. loop = None, # Handler config. script_name = "", **kwargs ): loop = loop or asyncio.get_event_loop() app = Application( loop = loop, ) # Add routes. for method, path, handler in routes: app.router.add_route(method, path, handler) # Add static routes. if isinstance(static, Mapping): static = static.items() for path, dirname in static: app.router.add_static(path, dirname) # Add on finish callbacks. for on_finish_callback in on_finish: app.register_on_finish(on_finish_callback) # Add the wsgi application. This has to be last. app.router.add_route("*", "{}{{path_info:.*}}".format(script_name), WSGIHandler(application, **kwargs).handle_request) # Set up the server. shared_server_kwargs = { "backlog": backlog, } if unix_socket is not None: server_future = loop.create_unix_server(app.make_handler(), path = unix_socket, **shared_server_kwargs ) elif socket is not None: server_future = loop.create_server(app.make_handler(), sock = socket, **shared_server_kwargs ) else: server_future = loop.create_server(app.make_handler(), host = host, port = port, **shared_server_kwargs ) server = loop.run_until_complete(server_future) app.logger.info("Serving on http://%s:%s", *parse_sockname(server.sockets[0].getsockname())) # Set socket permissions. if unix_socket is not None: os.chmod(unix_socket, unix_socket_perms) # All done! return server, app
def configure_server(application, *, # Server config. host = "0.0.0.0", port = 8080, # Unix server config. unix_socket = None, unix_socket_perms = 0o600, # Prexisting socket config. socket = None, # Shared server config. backlog = 1024, # aiohttp config. routes = (), static = (), on_finish = (), # Asyncio config. loop = None, # Handler config. script_name = "", **kwargs ): loop = loop or asyncio.get_event_loop() app = Application( loop = loop, ) # Add routes. for method, path, handler in routes: app.router.add_route(method, path, handler) # Add static routes. if isinstance(static, Mapping): static = static.items() for path, dirname in static: app.router.add_static(path, dirname) # Add on finish callbacks. for on_finish_callback in on_finish: app.on_shutdown.append(on_finish_callback) # The WSGI spec says that script name should not end with a slash. However, # aiohttp wants all route paths to start with a forward slash. This means # we need a special case for mounting on the root. if script_name.endswith("/"): # pragma: no cover raise ValueError("Script name should not end with /") if script_name == "": script_name = "/" if not script_name.startswith("/"): # pragma: no cover raise ValueError("Script name should start with /") # Add the wsgi application. This has to be last. app.router.add_route("*", "{}{{path_info:.*}}".format(script_name), WSGIHandler(application, loop=loop, **kwargs).handle_request) # Set up the server. shared_server_kwargs = { "backlog": backlog, } if unix_socket is not None: server_future = loop.create_unix_server(app.make_handler(), path = unix_socket, **shared_server_kwargs ) elif socket is not None: server_future = loop.create_server(app.make_handler(), sock = socket, **shared_server_kwargs ) else: server_future = loop.create_server(app.make_handler(), host = host, port = port, **shared_server_kwargs ) server = loop.run_until_complete(server_future) app.logger.info("Serving on http://%s:%s", *parse_sockname(server.sockets[0].getsockname())) # Set socket permissions. if unix_socket is not None: os.chmod(unix_socket, unix_socket_perms) # All done! return server, app
def configure_server( application, *, # Server config. host="0.0.0.0", port=8080, # Unix server config. unix_socket=None, unix_socket_perms=0o600, # Prexisting socket config. socket=None, # Shared server config. backlog=1024, # aiohttp config. routes=(), static=(), on_finish=(), # Asyncio config. loop=None, # Handler config. script_name="", **kwargs): loop = loop or asyncio.get_event_loop() app = Application(loop=loop, ) # Add routes. for method, path, handler in routes: app.router.add_route(method, path, handler) # Add static routes. if isinstance(static, Mapping): static = static.items() for path, dirname in static: app.router.add_static(path, dirname) # Add on finish callbacks. for on_finish_callback in on_finish: app.register_on_finish(on_finish_callback) # The WSGI spec says that script name should not end with a slash. However, # aiohttp wants all route paths to start with a forward slash. This means # we need a special case for mounting on the root. if script_name.endswith("/"): # pragma: no cover raise ValueError("Script name should not end with /") if script_name == "": script_name = "/" if not script_name.startswith("/"): # pragma: no cover raise ValueError("Script name should start with /") # Add the wsgi application. This has to be last. app.router.add_route("*", "{}{{path_info:.*}}".format(script_name), WSGIHandler(application, **kwargs).handle_request) # Set up the server. shared_server_kwargs = { "backlog": backlog, } if unix_socket is not None: server_future = loop.create_unix_server(app.make_handler(), path=unix_socket, **shared_server_kwargs) elif socket is not None: server_future = loop.create_server(app.make_handler(), sock=socket, **shared_server_kwargs) else: server_future = loop.create_server(app.make_handler(), host=host, port=port, **shared_server_kwargs) server = loop.run_until_complete(server_future) app.logger.info("Serving on http://%s:%s", *parse_sockname(server.sockets[0].getsockname())) # Set socket permissions. if unix_socket is not None: os.chmod(unix_socket, unix_socket_perms) # All done! return server, app