Repository: aio-libs/aiohttp

Issue:
secure_proxy_ssl_header with gunicorn
## Long story short

I think it's not possible to set `secure_proxy_ssl_header` when deploying with gunicorn.

## Expected behaviour

gunicorn config or environment variable should allow me to set `secure_proxy_ssl_header='X-Forwarded-Proto'` so `request.scheme` is correct.

## Actual behaviour

No apparent way to set it.

## Steps to reproduce

Can give more detail if required.

## Your environment

Heroku, but should be the same with any other.



Discussion:
currently i'm using

```python
secure = 'https' in (request.scheme, request.headers.get('X-Forwarded-Proto'))
ws_scheme = 'wss' if secure else 'ws'
ws_url = f'{ws_scheme}://{request.host}/ws'
```

In addition to fixing `secure_proxy_ssl_header` it would be great if there was `request.secure: bool` to avoid the need for `== 'https'` etc.
do you want to work on this?
Can do, just a key word argument to Application should work. 

Resolving patch:
diff --git a/aiohttp/web.py b/aiohttp/web.py
--- a/aiohttp/web.py
+++ b/aiohttp/web.py
@@ -42,10 +42,15 @@
 
 
 class Application(MutableMapping):
-
-    def __init__(self, *, logger=web_logger, router=None, middlewares=(),
-                 handler_args=None, client_max_size=1024**2,
-                 loop=None, debug=...):
+    def __init__(self, *,
+                 logger=web_logger,
+                 router=None,
+                 middlewares=(),
+                 handler_args=None,
+                 client_max_size=1024**2,
+                 secure_proxy_ssl_header=None,
+                 loop=None,
+                 debug=...):
         if router is None:
             router = web_urldispatcher.UrlDispatcher()
         assert isinstance(router, AbstractRouter), router
@@ -55,7 +60,7 @@ def __init__(self, *, logger=web_logger, router=None, middlewares=(),
 
         self._debug = debug
         self._router = router
-        self._secure_proxy_ssl_header = None
+        self._secure_proxy_ssl_header = secure_proxy_ssl_header
         self._loop = loop
         self._handler_args = handler_args
         self.logger = logger
@@ -229,7 +234,8 @@ def make_handler(self, *, loop=None,
             for k, v in self._handler_args.items():
                 kwargs[k] = v
 
-        self._secure_proxy_ssl_header = secure_proxy_ssl_header
+        if secure_proxy_ssl_header:
+            self._secure_proxy_ssl_header = secure_proxy_ssl_header
         return Server(self._handle, request_factory=self._make_request,
                       loop=self.loop, **kwargs)
 
diff --git a/aiohttp/web_request.py b/aiohttp/web_request.py
--- a/aiohttp/web_request.py
+++ b/aiohttp/web_request.py
@@ -142,6 +142,14 @@ def scheme(self):
         """
         return self.url.scheme
 
+    @property
+    def secure(self):
+        """A bool indicating if the request is handled with SSL or
+        'secure_proxy_ssl_header' is matching
+
+        """
+        return self.url.scheme == 'https'
+
     @reify
     def _scheme(self):
         if self._transport.get_extra_info('sslcontext'):


Test patch:
diff --git a/tests/test_web_application.py b/tests/test_web_application.py
--- a/tests/test_web_application.py
+++ b/tests/test_web_application.py
@@ -206,9 +206,16 @@ def test_secure_proxy_ssl_header_default():
     assert app._secure_proxy_ssl_header is None
 
 
-@asyncio.coroutine
 def test_secure_proxy_ssl_header_non_default(loop):
     app = web.Application()
     hdr = ('X-Forwarded-Proto', 'https')
     app.make_handler(secure_proxy_ssl_header=hdr, loop=loop)
     assert app._secure_proxy_ssl_header is hdr
+
+
+def test_secure_proxy_ssl_header_init(loop):
+    hdr = ('X-Forwarded-Proto', 'https')
+    app = web.Application(secure_proxy_ssl_header=hdr)
+    assert app._secure_proxy_ssl_header is hdr
+    app.make_handler(loop=loop)
+    assert app._secure_proxy_ssl_header is hdr
diff --git a/tests/test_web_request.py b/tests/test_web_request.py
--- a/tests/test_web_request.py
+++ b/tests/test_web_request.py
@@ -223,11 +223,13 @@ def test___repr___non_ascii_path(make_request):
 def test_http_scheme(make_request):
     req = make_request('GET', '/')
     assert "http" == req.scheme
+    assert req.secure is False
 
 
 def test_https_scheme_by_ssl_transport(make_request):
     req = make_request('GET', '/', sslcontext=True)
     assert "https" == req.scheme
+    assert req.secure is True
 
 
 def test_https_scheme_by_secure_proxy_ssl_header(make_request):
@@ -235,6 +237,7 @@ def test_https_scheme_by_secure_proxy_ssl_header(make_request):
                        secure_proxy_ssl_header=('X-HEADER', '1'),
                        headers=CIMultiDict({'X-HEADER': '1'}))
     assert "https" == req.scheme
+    assert req.secure is True
 
 
 def test_https_scheme_by_secure_proxy_ssl_header_false_test(make_request):
@@ -242,6 +245,7 @@ def test_https_scheme_by_secure_proxy_ssl_header_false_test(make_request):
                        secure_proxy_ssl_header=('X-HEADER', '1'),
                        headers=CIMultiDict({'X-HEADER': '0'}))
     assert "http" == req.scheme
+    assert req.secure is False
 
 
 def test_raw_headers(make_request):