I have a python websocket server and a nodejs client and I am not able to implement the websocket's Protocol Handshake.
Code of python server
The following minimal websocket server makes use of Flask-sockets
(which uses gevent-websocket
). File name is ws_server.py
:
#!/usr/bin/python3
# -*- coding: utf-8 -*-
from flask import Flask, request, Response
from flask_sockets import Sockets
app = Flask(__name__)
sockets = Sockets(app)
@sockets.route('/')
def echo_socket(ws):
# print("type request: ",type(request))
# print("dir request: ", dir(request))
print("request.headers: ", request.headers)
# print("type ws: ",type(ws))
# print("dir ws: ",dir(ws))
if hasattr(request, "Sec-Websocket-Protocol"):
print(request.headers["Sec-Websocket-Protocol"])
else:
print("INFO: No protocol specified")
if request.headers["Sec-Websocket-Protocol"] == "aProtocol":
print("INFO: protocol is OK")
else:
print("INFO: protocol not accepted: closing connection")
ws.close()
while not ws.closed:
message = ws.receive()
if message:
print("received: "+message)
ws.send(message)
if ws.closed:
print("INFO: connection has been closed")
if __name__ == "__main__":
from gevent import pywsgi
from geventwebsocket.handler import WebSocketHandler
server = pywsgi.WSGIServer(('', 5001), app, handler_class=WebSocketHandler)
server.serve_forever()
Code of nodejs client
The following minimal websocket client makes use of websocket
library.
File name is app.js
:
'use strict'
var WebSocketClient = require('websocket').client;
var client = new WebSocketClient();
function connectToServer(uri,protocol){
client.on('connectFailed', function (error) {
console.log('Connect Error: ' + error.toString());
});
client.on('connect', function (connection) {
console.log('WebSocket Client Connected');
connection.on('error', function (error) {
console.log("Connection Error: " + error.toString());
});
connection.on('close', function () {
console.log('echo-protocol Connection Closed');
});
connection.on('ping', () => {
connection.pong();
});
connection.on('message', function (message) {
if (message.type === 'utf8') {
console.log("Received message is: '" + message.utf8Data + "'");
}
});
console.log("sending SOMETHING");
connection.sendUTF("SOMETHING");
});
client.connect(uri, protocol);
}
const wsHostAndPort = process.env.WSHSTPRT || "ws://echo.websocket.org:80";
const wsProtocol = process.env.WSPRTCL || []; // [] for no protocol
console.log("connecting to: ",wsHostAndPort,"with protocol",wsProtocol);
connectToServer(wsHostAndPort,wsProtocol);
Connection from nodejs as client
Start python ws server:
$ python3 ws_server.py
Connect from nodejs ws client:
$ WSHSTPRT=ws://localhost:5001/ WSPRTCL="aProtocol" node app.js
Output of client terminal is
connecting to: ws://localhost:5001/ with protocol aProtocol
Connect Error: Error: Expected a Sec-WebSocket-Protocol header.
Output of server terminal is:
request.headers: Upgrade: websocket
Connection: Upgrade
Sec-Websocket-Version: 13
Sec-Websocket-Key: +QjH5xejDI+OQZQ0OZcWEQ==
Host: localhost:5001
Sec-Websocket-Protocol: aProtocol
INFO: No protocol specified
INFO: protocol is OK
INFO: connection has been closed
It seems to me that the python server needs to set a header named
"Sec-WebSocket-Protocol"
with the same value it has received from the
client. But I don't know how to do it. I have searched the internet
(mainly the flask-sockets
and gevent-websockets
forums and issue
trackers) without any luck so far.
I tried another simple client, websocat
. I invoked it like this:
$ websocat ws://localhost:5001 --protocol aProtocol
I interactively prompted some messages, and they were echoed correctly by the python server.
It works because, i think, websocat
(unlike nodejs' websocket
) does
not expect a "Sec-WebSocket-Protocol header" in the handshake with the
server.
But I need to use the nodejs client which expects the header.
So my question is: how can I incorporate the "Sec-WebSocket-Protocol"
header in the python server handshake response?