Files
val-blog/tmp/lightpanda_probe.py
T

86 lines
2.6 KiB
Python

import asyncio, json, urllib.request, sys
async def recv_one(reader):
b1 = await reader.readexactly(2)
fin_opcode = b1[0]
masked_len = b1[1]
length = masked_len & 0x7F
if length == 126:
ext = await reader.readexactly(2)
length = int.from_bytes(ext, 'big')
elif length == 127:
ext = await reader.readexactly(8)
length = int.from_bytes(ext, 'big')
masked = (masked_len & 0x80) != 0
if masked:
mask = await reader.readexactly(4)
payload = await reader.readexactly(length) if length else b''
if masked:
payload = bytes(b ^ mask[i % 4] for i, b in enumerate(payload))
return fin_opcode & 0x0F, payload
async def send_text(writer, text):
data = text.encode('utf-8')
frame = bytearray()
frame.append(0x81)
n = len(data)
mask = b'ABCD'
if n < 126:
frame.append(0x80 | n)
elif n < (1<<16):
frame.append(0x80 | 126)
frame += n.to_bytes(2, 'big')
else:
frame.append(0x80 | 127)
frame += n.to_bytes(8, 'big')
frame += mask
frame += bytes(b ^ mask[i % 4] for i, b in enumerate(data))
writer.write(frame)
await writer.drain()
async def main():
version = json.load(urllib.request.urlopen('http://127.0.0.1:9222/json/version'))
ws = version['webSocketDebuggerUrl']
assert ws.startswith('ws://')
hostportpath = ws[len('ws://'):]
hostport, _, path = hostportpath.partition('/')
host, port = hostport.split(':')
port = int(port)
path = '/' + path
reader, writer = await asyncio.open_connection(host, port)
key = 'dGhlIHNhbXBsZSBub25jZQ=='
req = (
f'GET {path} HTTP/1.1\r\n'
f'Host: {host}:{port}\r\n'
'Upgrade: websocket\r\n'
'Connection: Upgrade\r\n'
f'Sec-WebSocket-Key: {key}\r\n'
'Sec-WebSocket-Version: 13\r\n\r\n'
)
writer.write(req.encode())
await writer.drain()
resp = await reader.readuntil(b'\r\n\r\n')
print('HANDSHAKE_OK' if b'101' in resp else resp.decode(errors='ignore'))
msgs = [
{"id":1,"method":"Browser.getVersion"},
{"id":2,"method":"Target.getTargets"},
{"id":3,"method":"Target.createTarget","params":{"url":"https://example.com"}},
]
for m in msgs:
await send_text(writer, json.dumps(m))
for _ in range(10):
opcode, payload = await recv_one(reader)
if opcode == 1:
txt = payload.decode('utf-8', errors='ignore')
print(txt)
elif opcode == 8:
print('CLOSE')
break
writer.close()
await writer.wait_closed()
asyncio.run(main())