Repository: aio-libs/aiohttp

Issue:
Return no protocol instead of erroring when not agreeing on a protocol
sorry, my implementation of websocket subprotocols has a mistake, i.e. [the spec](https://tools.ietf.org/html/rfc6455#section-1.3) says:

> The server selects one or none of the acceptable protocols and echoes that value in its handshake to indicate that it has selected that protocol.

so instead of a Bad Request exception, we should send back _no `Sec-WebSocket-Protocol` header at all_ and leave it to the client to drop the connection or carry on without protocol (however dumb that sounds).



Discussion:

Resolving patch:
diff --git a/aiohttp/log.py b/aiohttp/log.py
--- a/aiohttp/log.py
+++ b/aiohttp/log.py
@@ -5,3 +5,4 @@
 client_log = logging.getLogger('aiohttp.client')
 internal_log = logging.getLogger('aiohttp.internal')
 server_log = logging.getLogger('aiohttp.server')
+websocket_log = logging.getLogger('aiohttp.websocket')
diff --git a/aiohttp/websocket.py b/aiohttp/websocket.py
--- a/aiohttp/websocket.py
+++ b/aiohttp/websocket.py
@@ -10,6 +10,7 @@
 import hashlib
 import struct
 from aiohttp import errors
+from aiohttp.log import websocket_log
 
 # Frame opcodes defined in the spec.
 OPCODE_CONTINUATION = 0x0
@@ -220,9 +221,9 @@ def do_handshake(method, headers, transport, protocols=()):
                 protocol = proto
                 break
         else:
-            raise errors.HttpBadRequest(
-                'Client protocols {!r} don’t overlap server-known ones {!r}'
-                .format(protocols, req_protocols))
+            websocket_log.warning(  # No overlap found: Return no protocol as per spec
+                'Client protocols %r don’t overlap server-known ones %r',
+                protocols, req_protocols)
 
     # check supported version
     version = headers.get('SEC-WEBSOCKET-VERSION')


Test patch:
diff --git a/tests/test_websocket.py b/tests/test_websocket.py
--- a/tests/test_websocket.py
+++ b/tests/test_websocket.py
@@ -471,12 +471,21 @@ def test_handshake_protocol_agreement(self):
 
         self.assertEqual(protocol, best_proto)
 
-    def test_handshake_protocol_unsupported(self):
+    @unittest.mock.patch('aiohttp.websocket.websocket_log.warning')
+    def test_handshake_protocol_unsupported(self, m_websocket_warn):
+        '''Tests if a protocol mismatch handshake warns and returns None'''
+        warn_called = False
+        def websocket_warn(msg, *fmts):
+            nonlocal warn_called
+            warn_called = True
+        m_websocket_warn.side_effect = websocket_warn
+
         proto = 'chat'
         self.headers.extend(self.gen_ws_headers('test')[0])
 
-        self.assertRaises(
-            errors.HttpBadRequest,
-            websocket.do_handshake,
+        _, _, _, _, protocol = websocket.do_handshake(
             self.message.method, self.message.headers, self.transport,
             protocols=[proto])
+
+        self.assertTrue(warn_called, 'protocol mismatch didn’t warn')
+        self.assertIsNone(protocol)
diff --git a/tests/test_wsgi.py b/tests/test_wsgi.py
--- a/tests/test_wsgi.py
+++ b/tests/test_wsgi.py
@@ -276,7 +276,6 @@ def wsgi_app(env, start):
 
     def test_dont_unquote_environ_path_info(self):
         path = '/path/some%20text'
-        print(path)
         self.message = protocol.RawRequestMessage(
             'GET', path, (1, 0), self.headers, True, 'deflate')
         environ = self._make_one()