Closed makinapower closed 5 years ago
It seems that you have an incorrect response from the server and HTTP parser of websockets fails on it. Can you put a print in the http.py code of websockets :
print(status_line)
version, status_code, reason = status_line[:-2].split(b' ', 2)
around line 125 And give me the output if there is not sensitive data.
I do not think we have the same http.py My http.py file is located in /usr/lib/python3/dist-packages/websockets/
I do not see where to place the print
` """ The :mod:
websockets.http` module provides HTTP parsing functions. They're
merely adequate for the WebSocket handshake messages.
These functions cannot be imported from :mod:websockets
; they must be
imported from :mod:websockets.http
.
"""
import asyncio import email.parser import io import sys
from .version import version as websockets_version
all = ['read_request', 'read_response', 'USER_AGENT']
MAX_HEADERS = 256 MAX_LINE = 4096
USER_AGENT = ' '.join(( 'Python/{}'.format(sys.version[:3]), 'websockets/{}'.format(websockets_version), ))
@asyncio.coroutine
def read_request(stream):
"""
Read an HTTP/1.1 request from stream
.
Return ``(path, headers)`` where ``path`` is a :class:`str` and
``headers`` is a :class:`~email.message.Message`. ``path`` isn't
URL-decoded.
Raise an exception if the request isn't well formatted.
The request is assumed not to contain a body.
"""
request_line, headers = yield from read_message(stream)
method, path, version = request_line[:-2].decode().split(None, 2)
if method != 'GET':
raise ValueError("Unsupported method")
if version != 'HTTP/1.1':
raise ValueError("Unsupported HTTP version")
return path, headers
@asyncio.coroutine
def read_response(stream):
"""
Read an HTTP/1.1 response from stream
.
Return ``(status, headers)`` where ``status`` is a :class:`int` and
``headers`` is a :class:`~email.message.Message`.
Raise an exception if the request isn't well formatted.
The response is assumed not to contain a body.
"""
status_line, headers = yield from read_message(stream)
version, status, reason = status_line[:-2].decode().split(None, 2)
if version != 'HTTP/1.1':
raise ValueError("Unsupported HTTP version")
return int(status), headers
@asyncio.coroutine
def read_message(stream):
"""
Read an HTTP message from stream
.
Return ``(start_line, headers)`` where ``start_line`` is :class:`bytes`
and ``headers`` is a :class:`~email.message.Message`.
The message is assumed not to contain a body.
"""
start_line = yield from read_line(stream)
header_lines = io.BytesIO()
for num in range(MAX_HEADERS):
header_line = yield from read_line(stream)
header_lines.write(header_line)
if header_line == b'\r\n':
break
else:
raise ValueError("Too many headers")
header_lines.seek(0)
headers = email.parser.BytesHeaderParser().parse(header_lines)
return start_line, headers
@asyncio.coroutine
def read_line(stream):
"""
Read a single line from stream
.
"""
line = yield from stream.readline()
if len(line) > MAX_LINE:
raise ValueError("Line too long")
if not line.endswith(b'\r\n'):
raise ValueError("Line without CRLF")
return line
`
yes it's the same. Put the print(status_line) in function read_response
before
version, status, reason = status_line[:-2].decode().split(None, 2)
Ok Thanks, here is the return:
send: b'GET /mediation/client?mac=001133445566&appli=1 HTTP/1.1\r\nAccept-Encoding: identity\r\nHost: mediation.tydom.com:443\r\nSec-WebSocket-Version: 13\r\nUpgrade: websocket\r\nAccept: /\r\nConnection: Upgrade\r\nSec-WebSocket-Key: NAnGaovSf7qCLcGM/GL48A==\r\n\r\n'
reply: 'HTTP/1.1 401 \r\n'
header: X-Content-Type-Options header: X-XSS-Protection header: Cache-Control header: Pragma header: Expires header: X-Frame-Options header: Set-Cookie header: WWW-Authenticate header: Content-Length header: Date b'HTTP/1.1 101 \r\n'
Traceback (most recent call last):
File "/usr/lib/python3/dist-packages/websockets/client.py", line 79, in handshake
status_code, headers = yield from read_response(self.reader)
File "/usr/lib/python3/dist-packages/websockets/http.py", line 67, in read_response
version, status, reason = status_line[:-2].decode().split(None, 2)
ValueError: not enough values to unpack (expected 3, got 2)
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
File "main.py", line 172, in
it's stange, it seems status_line[:-2].decode().split(None, 2) returns 2 elements instead of 3 But you have the correct printed value b'HTTP/1.1 101 \r\n' Which version of websockets do you have ? I've got 7.0
I got it :
in http.py change
status_line[:-2].decode().split(None, 2)
with
status_line[:-2].split(b' ', 2)
Seems that your websockets version is buggy.
See : https://github.com/aaugustin/websockets/commit/2e7fd48e19731aa1fe8e5af57825b5a7f43a972c
So try to update you websockets module to last version if possible.
Thanks cth35 My version of websockets is 3.2 (installed directly from Debian package) and I have another error with status_line[:-2].split(b' ', 2) I will try the update the websockets module for python 3 and will keep you informed.
send: b'GET /mediation/client?Mac=001122334455&appli=1 HTTP/1.1\r\nAccept-Encoding: identity\r\nSec-WebSocket-Version: 13\r\nSec-WebSocket-Key: UuLApq3Ah2yAp09Sv7Pu+A==\r\nHost: mediation.tydom.com:443\r\nConnection: Upgrade\r\nAccept: /\r\nUpgrade: websocket\r\n\r\n' reply: 'HTTP/1.1 401 \r\n' header: X-Content-Type-Options header: X-XSS-Protection header: Cache-Control header: Pragma header: Expires header: X-Frame-Options header: Set-Cookie header: WWW-Authenticate header: Content-Length header: Date b'HTTP/1.1 101 \r\n' Traceback (most recent call last): File "/usr/lib/python3/dist-packages/websockets/client.py", line 79, in handshake status_code, headers = yield from read_response(self.reader) File "/usr/lib/python3/dist-packages/websockets/http.py", line 70, in read_response raise ValueError("Unsupported HTTP version") ValueError: Unsupported HTTP version
Well done ! I have remove the debian package installed the websockets module via pip3:
pip3 install websockets. and It works ! Good Jobs and thanks again !
Cool ! You're welcome. If you develop on this code feel free to commit or to share what you did.
Hello and thanks for your work. I can not get the script working I am under debian 9 and I installed the package python3-websockets and uses python 3.5. I checked the credential, everything seems ok...
Thanks.
makina@JEEDOM:~/tydom_python$` python3.5 main.py
send: b'GET /mediation/client?mac=001122334455&appli=1 HTTP/1.1\r\nAccept-Encoding: identity\r\nSec-WebSocket-Version: 13\r\nUpgrade: websocket\r\nSec-WebSocket-Key: szgD00Pl4jejePGM8N4DAA==\r\nHost: mediation.tydom.com:443\r\nConnection: Upgrade\r\nAccept: /\r\n\r\n' reply: 'HTTP/1.1 401 \r\n' header: X-Content-Type-Options header: X-XSS-Protection header: Cache-Control header: Pragma header: Expires header: X-Frame-Options header: Set-Cookie header: WWW-Authenticate header: Content-Length header: Date Traceback (most recent call last): File "/usr/lib/python3/dist-packages/websockets/client.py", line 79, in handshake status_code, headers = yield from read_response(self.reader) File "/usr/lib/python3/dist-packages/websockets/http.py", line 66, in read_response version, status, reason = status_line[:-2].decode().split(None, 2) ValueError: not enough values to unpack (expected 3, got 2)
The above exception was the direct cause of the following exception:
Traceback (most recent call last): File "main.py", line 172, in
asyncio.get_event_loop().run_until_complete(hello())
File "/usr/lib/python3.5/asyncio/base_events.py", line 466, in run_until_complete
return future.result()
File "/usr/lib/python3.5/asyncio/futures.py", line 293, in result
raise self._exception
File "/usr/lib/python3.5/asyncio/tasks.py", line 239, in _step
result = coro.send(None)
File "main.py", line 164, in hello
async with websockets.client.connect('wss://mediation.tydom.com:443/mediation/client?mac={}&appli=1'.format(mac), extra_headers=websocketHeaders) as websocket:
File "/usr/lib/python3/dist-packages/websockets/py35/client.py", line 12, in aenter
self.websocket = await self
File "/usr/lib/python3/dist-packages/websockets/py35/client.py", line 19, in await
return (yield from self.client)
File "/usr/lib/python3/dist-packages/websockets/client.py", line 165, in connect
extra_headers=extra_headers)
File "/usr/lib/python3/dist-packages/websockets/client.py", line 81, in handshake
raise InvalidHandshake("Malformed HTTP message") from exc
websockets.exceptions.InvalidHandshake: Malformed HTTP message