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
return async_gen
                
                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)
                
                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)
                
                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"
                
                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):