sanic: Breaking change in Websocket 6.0 release

Hi,

Just pipenv installed sanic and it pulled down the new websocket 6.0 release. Making a simple websocket server will now throw a AttributeError on connection of a websocket client.

Here’s a simple websocket sanic app along with the stack trace.

from sanic import Sanic

app = Sanic()

@app.websocket('/feed')
async def feed(request, ws):
    while True:
        data = 'hello!'
        print('Sending: ' + data)
        await ws.send(data)
        data = await ws.recv()
        print('Received: ' + data)

if __name__ == "__main__":
    app.run(host="0.0.0.0", port=8000)

Here’s the stack trace produced:

[2018-07-18 11:39:04 +0100] [63160] [INFO] Goin' Fast @ http://0.0.0.0:8000
[2018-07-18 11:39:04 +0100] [63160] [INFO] Starting worker [63160]
[2018-07-18 11:39:06 +0100] [63160] [ERROR] Traceback (most recent call last):
  File "venv/lib/python3.7/site-packages/sanic/app.py", line 556, in handle_request
    response = await response
  File "venv/lib/python3.7/site-packages/sanic/app.py", line 259, in websocket_handler
    ws = await protocol.websocket_handshake(request, subprotocols)
  File "venv/lib/python3.7/site-packages/sanic/websocket.py", line 63, in websocket_handshake
    key = handshake.check_request(get_header)
  File "venv/lib/python3.7/site-packages/websockets/handshake.py", line 83, in check_request
    connection = parse_connection(headers.get('Connection', ''))
AttributeError: 'function' object has no attribute 'get'

[2018-07-18 11:39:06 +0100] - (sanic.access)[INFO][1:2]: GET ws://0.0.0.0:8000/feed  500 144

About this issue

  • Original URL
  • State: closed
  • Created 6 years ago
  • Comments: 20 (12 by maintainers)

Commits related to this issue

Most upvoted comments

I was able to get sanic master + websockets 6 to allow websocket connections with some small tweaks to sanic/websockets.py.

Looks like this has already been picked up by someone on master, though on the latest 7.0 release those checks are missing.

So this might be worth cherry picking those requirements into a point release to prevent those newly pip installing from getting a version of sanic with broken websockets, until sanic is updated to play nice with websockets>=6.0.

@ahopkins Im replying to your comment in this thread: https://github.com/channelcat/sanic/issues/1245#issuecomment-413761378 @garyo you may be interested in this too. I have the same issue at my workplace. I use sanic in some projects, but its my own custom version, based on Sanic master with a bunch of patches applied.

Inspired by this, a few weeks ago I created a new project. https://github.com/ashleysommer/pynecktie

PyNecktie is serious Sanic for serious business. It literally just relies on Sanic master, and inherits and extends every class with new names to make it look like its not Sanic. It has its own small test suite to ensure it is working correctly. Its aimed at devs who want to pitch this tool to their boss for use in an upcoming project, while hopefully avoiding the stigma of Sanic. It advertises it self as a “High Performance Python 3 Microservices Framework” rather than a HTTP server in an attempt to appeal to a non-tech-savvy audience. The project is still in its infancy, I did have it pinned to sanic@0.7.0 but but yesterday I rebased it to sanic@master, and fixed a bunch of issues. I intend to have a professional-looking website/homepage for the project, hosted docs, and do releases regularly, whenever new features or fixes are added to Sanic.

Equally, ran across some more things that may help others. pytest-sanic also has a related issue around Sanic’s websockets. Which requires to have websockets<5 instead of websockets<=6.

websockets 4.x also uses async in its code which also makes it incompatible with Python 3.7’s upgrade of async to a keyword. So currently I’m running this setup:

# Pipfile
[[source]]
url = "https://pypi.org/simple"
verify_ssl = true
name = "pypi"

[packages]
sanic = "*"
websockets = "<5.0"  # Sanic breaks on 6.0, pytest-sanic breaks on 5.0

[dev-packages]
pytest-sanic = "*"

[requires]
python_version = "3.6"  # websockets 4.0 uses async keyword from python 3.7