Repository: adamchainz/apig-wsgi

Issue:
ELB Health Checks not handled 
Hello!

Thank you for your tool it's great.

We have  a little issue when using a lambda as an ELB target when we turn on health check because the event looks like this:

```
{
    "requestContext": {
        "elb": {
            "targetGroupArn": "arn:aws:elasticloadbalancing:region:123456789012:targetgroup/my-target-group/6d0ecf831eec9f09"
        }
    },
    "httpMethod": "GET",  
    "path": "/",  
    "queryStringParameters": {},  
    "headers": {
        "user-agent": "ELB-HealthChecker/2.0"
    },  
    "body": "",  
    "isBase64Encoded": false
}
```
source: https://docs.aws.amazon.com/elasticloadbalancing/latest/application/lambda-functions.html#enable-health-checks-lambda

This has almost no headers leading to this error

```
  File "/var/task/flask/app.py", line 2306, in wsgi_app
    ctx = self.request_context(environ)
  File "/var/task/flask/app.py", line 2223, in request_context
    return RequestContext(self, environ)
  File "/var/task/flask/ctx.py", line 284, in __init__
    self.url_adapter = app.create_url_adapter(self.request)
  File "/var/task/flask/app.py", line 2040, in create_url_adapter
    subdomain=subdomain)
  File "/var/task/werkzeug/routing.py", line 1502, in bind_to_environ
    wsgi_server_name = get_host(environ).lower()
  File "/var/task/werkzeug/wsgi.py", line 168, in get_host
    rv = environ["SERVER_NAME"]
```

i found with some testing that i can patch the event like this to make it work:

```
def elb_health_check_patcher(handler):
    @wraps(handler)
    def wrapper(event, context):
        user_agent = event.get('headers', {}).get('user-agent')
        if user_agent == "ELB-HealthChecker/2.0":
            event['headers']['x-forwarded-proto'] = 'http'
            event['headers']['host'] = 'elb-health-check'

        return handler(event, context)

    return wrapper

handler = elb_health_check_patcher(make_lambda_handler(my_app))
```

I may propose a PR soon if you're open to :)

Discussion:
adamchainz: Thanks, this looks good. Can you please add a note to the changelog?

Also please report this as a bug to AWS on your support - HTTP 1.1 requests must have a Host header!
lindycoder: Here's a version with updated defaults, i'll fixup if you like it
lindycoder: Fixup/Rebase completed and i also reworded the commit and PR to match the new reality.

Sorry for the 9001 pushes, should be ready for review now :)
lindycoder: Error seems environment related, how do you retrigger a build?   
adamchainz: I pushed some fixes to the wording and you've pushed on top of them.
lindycoder: Oh i'm very sorry.   

I didn't know you could push to my branch
lindycoder: Seems we lost the `http` for `wsgi.url_scheme` want me to add it back?
adamchainz: Nope I got it :)

Patch:
diff --git a/HISTORY.rst b/HISTORY.rst
index 048a4ab..8eb3af1 100644
--- a/HISTORY.rst
+++ b/HISTORY.rst
@@ -1,6 +1,12 @@
 History
 =======
 
+* Add defaults for ``SERVER_HOST``, ``SERVER_PORT`` and ``wsgi.url_scheme``.
+  This enables responding to `ELB health check events
+  <https://docs.aws.amazon.com/elasticloadbalancing/latest/application/lambda-functions.html#enable-health-checks-lambda>`__,
+  which don't contain the relevant headers
+  (`Issue #155 <https://github.com/adamchainz/apig-wsgi/pull/155>`__).
+
 2.6.0 (2020-03-07)
 ------------------
 
diff --git a/src/apig_wsgi.py b/src/apig_wsgi.py
index 4c7a17a..c12b638 100644
--- a/src/apig_wsgi.py
+++ b/src/apig_wsgi.py
@@ -62,12 +62,15 @@ def get_environ(event, context, binary_support):
         "REQUEST_METHOD": method,
         "SCRIPT_NAME": "",
         "SERVER_PROTOCOL": "HTTP/1.1",
+        "SERVER_NAME": "",
+        "SERVER_PORT": "",
         "wsgi.errors": sys.stderr,
         "wsgi.input": BytesIO(body),
         "wsgi.multiprocess": False,
         "wsgi.multithread": False,
         "wsgi.run_once": False,
         "wsgi.version": (1, 0),
+        "wsgi.url_scheme": "http",
     }
 
     # Multi-value query strings need explicit activation on ALB


Test patch:
diff --git a/tests/test_apig_wsgi.py b/tests/test_apig_wsgi.py
index 2e091a8..8339a89 100644
--- a/tests/test_apig_wsgi.py
+++ b/tests/test_apig_wsgi.py
@@ -472,6 +472,29 @@ def test_full_event(simple_app):
     assert simple_app.environ["apig_wsgi.full_event"] == event
 
 
+def test_elb_health_check(simple_app):
+    """
+    Check compatibility with health check events as per:
+    https://docs.aws.amazon.com/elasticloadbalancing/latest/application/lambda-functions.html#enable-health-checks-lambda  # noqa: B950
+    """
+    event = {
+        "requestContext": {"elb": {"targetGroupArn": "..."}},
+        "httpMethod": "GET",
+        "path": "/",
+        "queryStringParameters": {},
+        "headers": {"user-agent": "ELB-HealthChecker/2.0"},
+        "body": "",
+        "isBase64Encoded": False,
+    }
+
+    simple_app.handler(event, None)
+
+    environ = simple_app.environ
+    assert environ["SERVER_NAME"] == ""
+    assert environ["SERVER_PORT"] == ""
+    assert environ["wsgi.url_scheme"] == "http"
+
+
 def test_context(simple_app):
     context = ContextStub(aws_request_id="test-request-id")