In #6778 we found that AWS forwards HTTP headers to Lambdas from clients without modifying their casing. Since users are relying on this behavior, it effectively renders a web server that lowercases headers unusable as proxy for localstack. In general, I think there is a case to be made that web servers should not manipulate the casing of request headers, so that they can function as application-layer proxy to backends that make assumptions about header casing.

The issue of header casing for HTTP/1.1 in hypercorn was addressed with https://github.com/pgjones/hypercorn/issues/66, but later reverted with https://github.com/pgjones/hypercorn/issues/77. Apparently the relevant ASGI spec is being discussed here https://github.com/django/asgiref/issues/246 where I think we should make that case.

If this is a fundamental limitation of ASGI and we cannot get this into hypercorn, then we will be forced to either
- apologize to lambda users and tell them that they need to re-write their lambda code in a way that treats headers in a case-insensitive way
- fork hypercorn and maintain our own version
- use another webserver that does not manipulate HTTP headers, or at least allows access to the raw headers in some way
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):