websockets: worse

This commit is contained in:
Thomas Farstrike
2025-05-18 17:09:34 +02:00
parent 25a7aa37b5
commit f41a0c1f16
+71 -51
View File
@@ -2,6 +2,7 @@ import socket
import ssl
import ubinascii
from websocket import websocket
import time
# Connect to Wi-Fi (disabled as per your code)
if False:
@@ -13,8 +14,15 @@ if False:
print('Connected:', wlan.ifconfig())
# Resolve hostname
# Option 1: echo.websocket.events (unreliable)
host = 'echo.websocket.events'
port = 443
handshake_path = '/'
# Option 2: ws.postman-echo.com (recommended for testing)
# host = 'ws.postman-echo.com'
# port = 443
# handshake_path = '/raw'
try:
addr_info = socket.getaddrinfo(host, port)[0][-1]
print('Resolved address:', addr_info)
@@ -41,17 +49,21 @@ except Exception as e:
sock.close()
raise
# Set socket to non-blocking
ssl_sock.setblocking(False)
print('Socket set to non-blocking')
# Perform WebSocket handshake
key = ubinascii.b2a_base64(b'random_bytes_here').strip()
handshake = (
'GET / HTTP/1.1\r\n'
'GET {} HTTP/1.1\r\n'
'Host: {}\r\n'
'Upgrade: websocket\r\n'
'Connection: Upgrade\r\n'
'Sec-WebSocket-Key: {}\r\n'
'Sec-WebSocket-Version: 13\r\n'
'\r\n'
).format(host, key.decode())
).format(handshake_path, host, key.decode())
# Send handshake request
try:
@@ -63,12 +75,10 @@ except Exception as e:
ssl_sock.close()
raise
# Read HTTP response until \r\n\r\n
# Read HTTP response until \r\n\r\n (minimize reading)
response_bytes = bytearray()
max_read = 1024 # Maximum bytes to read
read_timeout = 2 # Reduced timeout (seconds)
import time
max_read = 1024
read_timeout = 2
start_time = time.time()
while len(response_bytes) < max_read:
try:
@@ -79,9 +89,29 @@ while len(response_bytes) < max_read:
print('Received chunk, length:', len(chunk), 'bytes:', chunk)
response_bytes.extend(chunk)
print('Total bytes received:', len(response_bytes))
# Check for end of HTTP headers (\r\n\r\n)
if b'\r\n\r\n' in response_bytes:
print('End of HTTP headers detected')
# Decode and verify HTTP response immediately
http_end = response_bytes.find(b'\r\n\r\n') + 4
if http_end < 4:
ssl_sock.close()
raise Exception('Invalid HTTP response: no headers found')
http_response_bytes = response_bytes[:http_end]
try:
response = http_response_bytes.decode('utf-8')
print('Decoded HTTP response:', response)
except UnicodeError as e:
print('UnicodeError during decode:', e)
printable = ''.join(c if 32 <= ord(c) < 127 else '.' for c in http_response_bytes.decode('latin-1'))
print('Printable characters:', printable)
ssl_sock.close()
raise Exception('Failed to decode HTTP response')
if '101 Switching Protocols' not in response:
print('Handshake response:', response)
ssl_sock.close()
raise Exception('Handshake failed')
# Stop reading to leave WebSocket frame in socket buffer
print('Stopping read to preserve WebSocket frame')
break
except Exception as e:
print('Error reading chunk:', e)
@@ -90,51 +120,41 @@ while len(response_bytes) < max_read:
print('Read timeout reached')
break
# Inspect raw bytes
print('Raw response bytes:', response_bytes)
print('Raw response hex:', response_bytes.hex())
# Split HTTP response from any subsequent data
http_end = response_bytes.find(b'\r\n\r\n') + 4
if http_end < 4:
ssl_sock.close()
raise Exception('Invalid HTTP response: no headers found')
http_response_bytes = response_bytes[:http_end]
extra_bytes = response_bytes[http_end:] if http_end < len(response_bytes) else b''
print('HTTP response bytes:', http_response_bytes)
print('Extra bytes (if any):', extra_bytes)
# Decode HTTP response
try:
response = http_response_bytes.decode('utf-8')
print('Decoded HTTP response:', response)
except UnicodeError as e:
print('UnicodeError during decode:', e)
# Dump printable characters as fallback
printable = ''.join(c if 32 <= ord(c) < 127 else '.' for c in http_response_bytes.decode('latin-1'))
print('Printable characters:', printable)
ssl_sock.close()
raise Exception('Failed to decode HTTP response')
# Check for valid WebSocket handshake
if '101 Switching Protocols' not in response:
print('Handshake response:', response)
ssl_sock.close()
raise Exception('Handshake failed')
# Push back extra bytes (WebSocket frame) to the socket
if extra_bytes:
print('Note: Extra bytes detected, will be handled by websocket module')
# Create WebSocket object
ws = websocket(ssl_sock, True)
try:
ws = websocket(ssl_sock, True)
print('WebSocket object created')
except Exception as e:
print('Failed to create WebSocket object:', e)
ssl_sock.close()
raise
# Send and receive data
ws.write('Hello, Secure WebSocket!')
for _ in range(50):
data = ws.read(1024)
print('Received:', data)
time.sleep_ms(100)
# Send and receive data with retries
try:
bytes_written = ws.write('Hello, Secure WebSocket!')
print('Sent message, bytes written:', bytes_written)
except Exception as e:
print('Failed to send message:', e)
ws.close()
raise
# Try reading multiple times to catch initial message or echo
max_attempts = 5
read_timeout = 1 # Short timeout per read
for attempt in range(max_attempts):
try:
data = ws.read(1024)
print('Read attempt', attempt + 1, 'received:', data)
if data:
break
time.sleep(0.5) # Wait briefly before retrying
except Exception as e:
print('Read attempt', attempt + 1, 'error:', e)
time.sleep(0.5)
if time.time() - start_time > read_timeout:
print('Read timeout reached')
break
# Close connection
ws.close()
print('Connection closed')