title: how to implement a websocket aware reverse-proxy with aiohttp (python 3.6)
body: <p>I am trying to implement an application specific reverse-proxy for jupyter notebooks using aiohttp. It works fine for http requests, but the websocket forwarding does not work. Requests from the browser arrive and get forwarded, but there are no responses from jupyter forthcoming. I assume my websocket client code somehow does not react to incoming messages from jupyter.</p>
  
  <p>The only indication on the jupyter side that something is amiss are messages like this:</p>
  
  <pre><code>WebSocket ping timeout after 90009 ms.
  </code></pre>
  
  <p>so here is my attempt at writing the proxy</p>
  
  <pre class="lang-py prettyprint-override"><code>from aiohttp import web
  from aiohttp import client
  import aiohttp
  import logging
  import pprint
  
  logging.basicConfig(level=logging.INFO)
  logger = logging.getLogger(__name__)
  
  
  baseUrl = 'http://0.0.0.0:8888'
  mountPoint = '/fakeUuid'
  
  async def handler(req):
      proxyPath = req.match_info.get('proxyPath','no proxyPath placeholder defined')
      reqH = req.headers.copy()
      if reqH['connection'] == 'Upgrade' and reqH['upgrade'] == 'websocket' and req.method == 'GET':
  
        ws_server = web.WebSocketResponse()
        await ws_server.prepare(req)
        logger.info('##### WS_SERVER %s' % pprint.pformat(ws_server))
  
        client_session = aiohttp.ClientSession()
        async with client_session.ws_connect(baseUrl+req.path_qs,
          headers = { 'cookie': reqH['cookie'] },
        ) as ws_client:
          logger.info('##### WS_CLIENT %s' % pprint.pformat(ws_client))
  
          async for server_msg in ws_server:
            logger.info('&gt;&gt;&gt; msg from browser: %s',pprint.pformat(server_msg))
            if server_msg.type == aiohttp.WSMsgType.TEXT:
              await ws_client.send_str(server_msg.data)
            else:
              await ws_client.send_bytes(server_msg.data)
  
          async for client_msg in ws_client:
            logger.info('&gt;&gt;&gt; msg from jupyter: %s',pprint.pformat(client_msg))
            if client_msg.tp == aiohttp.WSMsgType.TEXT:
              await ws_server.send_str(client_msg.data)
            else:
              await ws_server.send_bytes(client_msg.data)
  
          return ws_server
      else:
        async with client.request(
            req.method,baseUrl+mountPoint+proxyPath,
            headers = reqH,
            allow_redirects=False,
            data = await req.read()
        ) as res:
            headers = res.headers.copy()
            body = await res.read()
            return web.Response(
              headers = headers,
              status = res.status,
              body = body
            )
        return ws_server
  
  app = web.Application()
  app.router.add_route('*',mountPoint + '{proxyPath:.*}', handler)
  web.run_app(app,port=3984)
  </code></pre>