|
| 1 | +#!/usr/bin/env python3 |
| 2 | + |
| 3 | +""" |
| 4 | +plain_sockets_client.py |
| 5 | +~~~~~~~~~~~~~~~~~~~~~~~ |
| 6 | +
|
| 7 | +Just enough code to send a GET request via h2 to an HTTP/2 server and receive a response body. |
| 8 | +This is *not* a complete production-ready HTTP/2 client! |
| 9 | +""" |
| 10 | + |
| 11 | +import socket |
| 12 | +import ssl |
| 13 | +import certifi |
| 14 | + |
| 15 | +import h2.connection |
| 16 | +import h2.events |
| 17 | + |
| 18 | + |
| 19 | +SERVER_NAME = 'http2.golang.org' |
| 20 | +SERVER_PORT = 443 |
| 21 | + |
| 22 | +# generic socket and ssl configuration |
| 23 | +socket.setdefaulttimeout(15) |
| 24 | +ctx = ssl.create_default_context(cafile=certifi.where()) |
| 25 | +ctx.set_alpn_protocols(['h2']) |
| 26 | + |
| 27 | +# open a socket to the server and initiate TLS/SSL |
| 28 | +s = socket.create_connection((SERVER_NAME, SERVER_PORT)) |
| 29 | +s = ctx.wrap_socket(s, server_hostname=SERVER_NAME) |
| 30 | + |
| 31 | +c = h2.connection.H2Connection() |
| 32 | +c.initiate_connection() |
| 33 | +s.sendall(c.data_to_send()) |
| 34 | + |
| 35 | +headers = [ |
| 36 | + (':method', 'GET'), |
| 37 | + (':path', '/reqinfo'), |
| 38 | + (':authority', SERVER_NAME), |
| 39 | + (':scheme', 'https'), |
| 40 | +] |
| 41 | +c.send_headers(1, headers, end_stream=True) |
| 42 | +s.sendall(c.data_to_send()) |
| 43 | + |
| 44 | +body = b'' |
| 45 | +response_stream_ended = False |
| 46 | +while not response_stream_ended: |
| 47 | + # read raw data from the socket |
| 48 | + data = s.recv(65536 * 1024) |
| 49 | + if not data: |
| 50 | + break |
| 51 | + |
| 52 | + # feed raw data into h2, and process resulting events |
| 53 | + events = c.receive_data(data) |
| 54 | + for event in events: |
| 55 | + print(event) |
| 56 | + if isinstance(event, h2.events.DataReceived): |
| 57 | + # update flow control so the server doesn't starve us |
| 58 | + c.acknowledge_received_data(event.flow_controlled_length, event.stream_id) |
| 59 | + # more response body data received |
| 60 | + body += event.data |
| 61 | + if isinstance(event, h2.events.StreamEnded): |
| 62 | + # response body completed, let's exit the loop |
| 63 | + response_stream_ended = True |
| 64 | + break |
| 65 | + # send any pending data to the server |
| 66 | + s.sendall(c.data_to_send()) |
| 67 | + |
| 68 | +print("Response fully received:") |
| 69 | +print(body.decode()) |
| 70 | + |
| 71 | +# tell the server we are closing the h2 connection |
| 72 | +c.close_connection() |
| 73 | +s.sendall(c.data_to_send()) |
| 74 | + |
| 75 | +# close the socket |
| 76 | +s.close() |
0 commit comments