async def METHOD_NAME(self, req):
    # based on https://github.com/oetiker/aio-reverse-proxy/blob/master/paraview-proxy.py
    ws_server = aiohttp.web.WebSocketResponse()
    await ws_server.prepare(req)
    async with self.session.ws_connect(
        self.next_url + "/ws", headers=req.headers
    ) as ws_client:
        async def ws_forward(ws_from, ws_to):
            async for msg in ws_from:
                if ws_to.closed:
                    await ws_to.close(code=ws_to.close_code, message=msg.extra)
                    return
                if msg.type == aiohttp.WSMsgType.TEXT:
                    await ws_to.send_str(msg.data)
                elif msg.type == aiohttp.WSMsgType.BINARY:
                    await ws_to.send_bytes(msg.data)
                elif msg.type == aiohttp.WSMsgType.PING:
                    await ws_to.ping()
                elif msg.type == aiohttp.WSMsgType.PONG:
                    await ws_to.pong()
                else:
                    raise ValueError(f'unexpected message type: {msg}')
        # keep forwarding websocket data in both directions
        await asyncio.wait(
            [
                ws_forward(ws_server, ws_client),
                ws_forward(ws_client, ws_server)
            ],
            return_when=asyncio.FIRST_COMPLETED)
    return ws_server