🕌

【Python】h2.connection とプレーンな socketを使って HTTP/2 リクエストを送信する

2024/07/10に公開

h2.connection の使い方を学ぶためにプレーンな socket で HTTP/2 リクエストを送信するクライアントコードの例を試してみた。

サーバーからのレスポンスをまとめて取得し、レスポンスデータを解析して生成することで生成されたイベントオブジェクトをもとにレスポンスヘッダーやボディを取得したり、ループの終了を行っている。

h2 モジュールのインストール

pip install h2

HTTP/2 クライアントのコード

client.py
import socket
import h2.connection
import h2.events

# https://github.com/python-hyper/h2/blob/master/examples/plain_sockets/plain_sockets_client.py
# h2c サーバー
# https://zenn.dev/masakielastic/articles/618f9f44f327f4

SERVER_NAME = '0.0.0.0'
SERVER_PORT = 8000

socket.setdefaulttimeout(15)
s = socket.create_connection((SERVER_NAME, SERVER_PORT))

c = h2.connection.H2Connection()
c.initiate_connection()
s.sendall(c.data_to_send())

headers = [
    (':method', 'GET'),
    (':path', '/'),
    (':authority', SERVER_NAME),
    (':scheme', 'http'),
]
c.send_headers(1, headers, end_stream=True)
s.sendall(c.data_to_send())

body = b''
response_stream_ended = False

while not response_stream_ended:
    data = s.recv(65536 * 1024)
    if not data:
        break

    events = c.receive_data(data)
    for event in events:
        print(event)
        if isinstance(event, h2.events.DataReceived):
            c.acknowledge_received_data(event.flow_controlled_length, event.stream_id)
            body += event.data
        if isinstance(event, h2.events.StreamEnded):
            response_stream_ended = True
            break

    s.sendall(c.data_to_send())


print(body.decode())

c.close_connection()
s.sendall(c.data_to_send())

s.close()

Discussion