summaryrefslogtreecommitdiffstats
path: root/testing/web-platform/tests/tools/third_party/websockets/experiments/optimization/parse_handshake.py
blob: af5a4ecae2c03353ba3e855bcdb5d74b0101466c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
"""Benchark parsing WebSocket handshake requests."""

# The parser for responses is designed similarly and should perform similarly.

import sys
import timeit

from websockets.http11 import Request
from websockets.streams import StreamReader


CHROME_HANDSHAKE = (
    b"GET / HTTP/1.1\r\n"
    b"Host: localhost:5678\r\n"
    b"Connection: Upgrade\r\n"
    b"Pragma: no-cache\r\n"
    b"Cache-Control: no-cache\r\n"
    b"User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) "
    b"AppleWebKit/537.36 (KHTML, like Gecko) Chrome/111.0.0.0 Safari/537.36\r\n"
    b"Upgrade: websocket\r\n"
    b"Origin: null\r\n"
    b"Sec-WebSocket-Version: 13\r\n"
    b"Accept-Encoding: gzip, deflate, br\r\n"
    b"Accept-Language: en-GB,en;q=0.9,en-US;q=0.8,fr;q=0.7\r\n"
    b"Sec-WebSocket-Key: ebkySAl+8+e6l5pRKTMkyQ==\r\n"
    b"Sec-WebSocket-Extensions: permessage-deflate; client_max_window_bits\r\n"
    b"\r\n"
)

FIREFOX_HANDSHAKE = (
    b"GET / HTTP/1.1\r\n"
    b"Host: localhost:5678\r\n"
    b"User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:109.0) "
    b"Gecko/20100101 Firefox/111.0\r\n"
    b"Accept: */*\r\n"
    b"Accept-Language: en-US,en;q=0.7,fr-FR;q=0.3\r\n"
    b"Accept-Encoding: gzip, deflate, br\r\n"
    b"Sec-WebSocket-Version: 13\r\n"
    b"Origin: null\r\n"
    b"Sec-WebSocket-Extensions: permessage-deflate\r\n"
    b"Sec-WebSocket-Key: 1PuS+hnb+0AXsL7z2hNAhw==\r\n"
    b"Connection: keep-alive, Upgrade\r\n"
    b"Sec-Fetch-Dest: websocket\r\n"
    b"Sec-Fetch-Mode: websocket\r\n"
    b"Sec-Fetch-Site: cross-site\r\n"
    b"Pragma: no-cache\r\n"
    b"Cache-Control: no-cache\r\n"
    b"Upgrade: websocket\r\n"
    b"\r\n"
)

WEBSOCKETS_HANDSHAKE = (
    b"GET / HTTP/1.1\r\n"
    b"Host: localhost:8765\r\n"
    b"Upgrade: websocket\r\n"
    b"Connection: Upgrade\r\n"
    b"Sec-WebSocket-Key: 9c55e0/siQ6tJPCs/QR8ZA==\r\n"
    b"Sec-WebSocket-Version: 13\r\n"
    b"Sec-WebSocket-Extensions: permessage-deflate; client_max_window_bits\r\n"
    b"User-Agent: Python/3.11 websockets/11.0\r\n"
    b"\r\n"
)


def parse_handshake(handshake):
    reader = StreamReader()
    reader.feed_data(handshake)
    parser = Request.parse(reader.read_line)
    try:
        next(parser)
    except StopIteration:
        pass
    else:
        assert False, "parser should return request"
    reader.feed_eof()
    assert reader.at_eof(), "parser should consume all data"


def run_benchmark(name, handshake, number=10000):
    ph = (
        min(
            timeit.repeat(
                "parse_handshake(handshake)",
                number=number,
                globals={"parse_handshake": parse_handshake, "handshake": handshake},
            )
        )
        / number
        * 1_000_000
    )
    print(f"{name}\t{len(handshake)}\t{ph:.1f}")


if __name__ == "__main__":
    print("Sizes are in bytes. Times are in µs per frame.", file=sys.stderr)
    print("Run `tabs -16` for clean output. Pipe stdout to TSV for saving.")
    print(file=sys.stderr)

    print("client\tsize\ttime")
    run_benchmark("Chrome", CHROME_HANDSHAKE)
    run_benchmark("Firefox", FIREFOX_HANDSHAKE)
    run_benchmark("websockets", WEBSOCKETS_HANDSHAKE)