Beispiel #1
0
def _do_start_ssl_proxy(port: int, target: PortOrUrl, target_ssl=False):
    import pproxy

    from localstack.services.generic_proxy import GenericProxy

    if ":" not in str(target):
        target = "127.0.0.1:%s" % target
    LOG.debug("Starting SSL proxy server %s -> %s", port, target)

    # create server and remote connection
    server = pproxy.Server("secure+tunnel://0.0.0.0:%s" % port)
    target_proto = "ssl+tunnel" if target_ssl else "tunnel"
    remote = pproxy.Connection("%s://%s" % (target_proto, target))
    args = dict(rserver=[remote], verbose=print)

    # set SSL contexts
    _, cert_file_name, key_file_name = GenericProxy.create_ssl_cert()
    for context in pproxy.server.sslcontexts:
        context.load_cert_chain(cert_file_name, key_file_name)

    loop = ensure_event_loop()
    handler = loop.run_until_complete(server.start_server(args))
    try:
        loop.run_forever()
    except KeyboardInterrupt:
        print("exit!")

    handler.close()
    loop.run_until_complete(handler.wait_closed())
    loop.run_until_complete(loop.shutdown_asyncgens())
    loop.close()
Beispiel #2
0
 def run_app_sync(*args, loop=None, shutdown_event=None):
     kwargs = {}
     config = Config()
     cert_file_name, key_file_name = ssl_creds or (None, None)
     if cert_file_name:
         kwargs["certfile"] = cert_file_name
         config.certfile = cert_file_name
     if key_file_name:
         kwargs["keyfile"] = key_file_name
         config.keyfile = key_file_name
     setup_quart_logging()
     config.bind = ["%s:%s" % (bind_address, port)]
     loop = loop or ensure_event_loop()
     run_kwargs = {}
     if shutdown_event:
         run_kwargs["shutdown_trigger"] = shutdown_event.wait
     try:
         try:
             return loop.run_until_complete(serve(app, config,
                                                  **run_kwargs))
         except Exception as e:
             LOG.info(
                 "Error running server event loop on port %s: %s %s",
                 port,
                 e,
                 traceback.format_exc(),
             )
             if "SSL" in str(e):
                 c_exists = os.path.exists(cert_file_name)
                 k_exists = os.path.exists(key_file_name)
                 c_size = len(load_file(cert_file_name)) if c_exists else 0
                 k_size = len(load_file(key_file_name)) if k_exists else 0
                 LOG.warning(
                     "Unable to create SSL context. Cert files exist: %s %s (%sB), %s %s (%sB)",
                     cert_file_name,
                     c_exists,
                     c_size,
                     key_file_name,
                     k_exists,
                     k_size,
                 )
             raise
     finally:
         try:
             _cancel_all_tasks(loop)
             loop.run_until_complete(loop.shutdown_asyncgens())
         finally:
             asyncio.set_event_loop(None)
             loop.close()
 def run_proxy(self, *args):
     self.loop = ensure_event_loop()
     self.shutdown_event = asyncio.Event()
     run_app_sync(loop=self.loop, shutdown_event=self.shutdown_event)
def run_server(port,
               bind_address,
               handler=None,
               asynchronous=True,
               ssl_creds=None):

    ensure_event_loop()
    app = Quart(__name__)
    app.config[
        "MAX_CONTENT_LENGTH"] = 256 * 1024 * 1024  # 256 MB request payload limit

    @app.route("/", methods=HTTP_METHODS, defaults={"path": ""})
    @app.route("/<path:path>", methods=HTTP_METHODS)
    async def index(path=None):
        response = await make_response("{}")
        if handler:
            data = await request.get_data()
            try:
                result = await run_sync(handler, request, data)
                if isinstance(result, Exception):
                    raise result
            except Exception as e:
                LOG.warning(
                    "Error in proxy handler for request %s %s: %s %s" %
                    (request.method, request.url, e, traceback.format_exc()))
                response.status_code = 500
                if isinstance(e, HTTPErrorResponse):
                    response.status_code = e.code or response.status_code
                return response
            if result is not None:
                # check if this is an async generator (for HTTP2 push event responses)
                async_gen = get_async_generator_result(result)
                if async_gen:
                    return async_gen
                # prepare and return regular response
                is_chunked = uses_chunked_encoding(result)
                result_content = result.content or ""
                response = await make_response(result_content)
                response.status_code = result.status_code
                if is_chunked:
                    response.headers.pop("Content-Length", None)
                result.headers.pop("Server", None)
                result.headers.pop("Date", None)
                headers = {
                    k: str(v).replace("\n", r"\n")
                    for k, v in result.headers.items()
                }
                response.headers.update(headers)
                # set multi-value headers
                multi_value_headers = getattr(result, "multi_value_headers",
                                              {})
                for key, values in multi_value_headers.items():
                    for value in values:
                        response.headers.add_header(key, value)
                # set default headers, if required
                if not is_chunked and request.method not in [
                        "OPTIONS", "HEAD"
                ]:
                    response_data = await response.get_data()
                    response.headers["Content-Length"] = str(
                        len(response_data or ""))
                if "Connection" not in response.headers:
                    response.headers["Connection"] = "close"
                # fix headers for OPTIONS requests (possible fix for Firefox requests)
                if request.method == "OPTIONS":
                    response.headers.pop("Content-Type", None)
                    if not response.headers.get("Cache-Control"):
                        response.headers["Cache-Control"] = "no-cache"
        return response

    def run_app_sync(*args, loop=None, shutdown_event=None):
        kwargs = {}
        config = Config()
        cert_file_name, key_file_name = ssl_creds or (None, None)
        if cert_file_name:
            kwargs["certfile"] = cert_file_name
            config.certfile = cert_file_name
        if key_file_name:
            kwargs["keyfile"] = key_file_name
            config.keyfile = key_file_name
        setup_quart_logging()
        config.bind = ["%s:%s" % (bind_address, port)]
        loop = loop or ensure_event_loop()
        run_kwargs = {}
        if shutdown_event:
            run_kwargs["shutdown_trigger"] = shutdown_event.wait
        try:
            try:
                return loop.run_until_complete(serve(app, config,
                                                     **run_kwargs))
            except Exception as e:
                LOG.info("Error running server event loop on port %s: %s %s" %
                         (port, e, traceback.format_exc()))
                if "SSL" in str(e):
                    c_exists = os.path.exists(cert_file_name)
                    k_exists = os.path.exists(key_file_name)
                    c_size = len(load_file(cert_file_name)) if c_exists else 0
                    k_size = len(load_file(key_file_name)) if k_exists else 0
                    LOG.warning(
                        "Unable to create SSL context. Cert files exist: %s %s (%sB), %s %s (%sB)"
                        % (
                            cert_file_name,
                            c_exists,
                            c_size,
                            key_file_name,
                            k_exists,
                            k_size,
                        ))
                raise
        finally:
            try:
                _cancel_all_tasks(loop)
                loop.run_until_complete(loop.shutdown_asyncgens())
            finally:
                asyncio.set_event_loop(None)
                loop.close()

    class ProxyThread(FuncThread):
        def __init__(self):
            FuncThread.__init__(self, self.run_proxy, None)
            self.shutdown_event = None
            self.loop = None

        def run_proxy(self, *args):
            self.loop = ensure_event_loop()
            self.shutdown_event = asyncio.Event()
            run_app_sync(loop=self.loop, shutdown_event=self.shutdown_event)

        def stop(self, quiet=None):
            event = self.shutdown_event

            async def set_event():
                event.set()

            run_coroutine(set_event(), self.loop)
            super().stop(quiet)

    def run_in_thread():
        thread = ProxyThread()
        thread.start()
        TMP_THREADS.append(thread)
        return thread

    if asynchronous:
        return run_in_thread()

    return run_app_sync()
Beispiel #5
0
def run_server(port, handler=None, asynchronous=True, ssl_creds=None):

    ensure_event_loop()
    app = Quart(__name__)
    app.config[
        'MAX_CONTENT_LENGTH'] = 256 * 1024 * 1024  # 256 MB request payload limit

    @app.route('/', methods=HTTP_METHODS, defaults={'path': ''})
    @app.route('/<path:path>', methods=HTTP_METHODS)
    async def index(path=None):
        response = await make_response('{}')
        if handler:
            data = await request.get_data()
            try:
                result = await run_sync(handler, request, data)
            except Exception as e:
                LOG.warning(
                    'Error in proxy handler for request %s %s: %s %s' %
                    (request.method, request.url, e, traceback.format_exc()))
                response.status_code = 500
                return response
            if result is not None:
                is_chunked = uses_chunked_encoding(result)
                result_content = result.content or ''
                response = await make_response(result_content)
                response.status_code = result.status_code
                if is_chunked:
                    response.headers.pop('Content-Length', None)
                result.headers.pop('Server', None)
                result.headers.pop('Date', None)
                response.headers.update(dict(result.headers))
                # set multi-value headers
                multi_value_headers = getattr(result, 'multi_value_headers',
                                              {})
                for key, values in multi_value_headers.items():
                    for value in values:
                        response.headers.add_header(key, value)
                # set default headers, if required
                if 'Content-Length' not in response.headers and not is_chunked:
                    response.headers['Content-Length'] = str(
                        len(result_content) if result_content else 0)
                if 'Connection' not in response.headers:
                    response.headers['Connection'] = 'close'
        return response

    def run_app_sync(*args, loop=None, shutdown_event=None):
        kwargs = {}
        config = Config()
        cert_file_name, key_file_name = ssl_creds or (None, None)
        if cert_file_name:
            kwargs['certfile'] = cert_file_name
            config.certfile = cert_file_name
        if key_file_name:
            kwargs['keyfile'] = key_file_name
            config.keyfile = key_file_name
        setup_quart_logging()
        config.bind = ['0.0.0.0:%s' % port]
        loop = loop or ensure_event_loop()
        run_kwargs = {}
        if shutdown_event:
            run_kwargs['shutdown_trigger'] = shutdown_event.wait
        try:
            try:
                return loop.run_until_complete(serve(app, config,
                                                     **run_kwargs))
            except Exception as e:
                LOG.info('Error running server event loop on port %s: %s %s' %
                         (port, e, traceback.format_exc()))
                if 'SSL' in str(e):
                    c_exists = os.path.exists(cert_file_name)
                    k_exists = os.path.exists(key_file_name)
                    c_size = len(load_file(cert_file_name)) if c_exists else 0
                    k_size = len(load_file(key_file_name)) if k_exists else 0
                    LOG.warning(
                        'Unable to create SSL context. Cert files exist: %s %s (%sB), %s %s (%sB)'
                        % (cert_file_name, c_exists, c_size, key_file_name,
                           k_exists, k_size))
                raise
        finally:
            try:
                _cancel_all_tasks(loop)
                loop.run_until_complete(loop.shutdown_asyncgens())
            finally:
                asyncio.set_event_loop(None)
                loop.close()

    class ProxyThread(FuncThread):
        def __init__(self):
            FuncThread.__init__(self, self.run_proxy, None)

        def run_proxy(self, *args):
            loop = ensure_event_loop()
            self.shutdown_event = asyncio.Event()
            run_app_sync(loop=loop, shutdown_event=self.shutdown_event)

        def stop(self, quiet=None):
            self.shutdown_event.set()

    def run_in_thread():
        thread = ProxyThread()
        thread.start()
        TMP_THREADS.append(thread)
        return thread

    if asynchronous:
        return run_in_thread()

    return run_app_sync()