From 6c6796dae731a39928ef5c712636ae9f8168fc47 Mon Sep 17 00:00:00 2001 From: Ottavio Campana Date: Mon, 19 Aug 2019 10:49:22 +0200 Subject: [PATCH] Added the possibility of passing an external socket to HTTP20Connection ONVIF defines the Uplink service based on HTTP/2 and connection reversal, in order to have cameras connect to cloud services while having NAT between themselves and the remote service (For details, https://www.onvif.org/specs/srv/uplink/ONVIF-Uplink-Spec.pdf) With this patch, it is possible on the cloud side to accept an incoming connection from a listining socket and to pass the new socket to HTTP20Connection, so that the cloud software can use the reverted connection and turn itself into a client. Example code for implementing it: import socket, ssl, time from hyper import HTTP20Connection from hyper.common.bufsocket import BufferedSocket context = ssl.SSLContext (ssl.PROTOCOL_TLSv1_2) context.load_cert_chain ("server.cert", "server.key") bindsocket = socket.socket () bindsocket.bind(('', 8081)) bindsocket.listen(5) with context.wrap_socket (bindsocket, server_side=True) as ssock: while True: newsocket, fromaddr = ssock.accept() req = newsocket.read () if b'Connection: Upgrade' in req and b'Upgrade: h2c-reverse': newsocket.write (b'HTTP/1.1 101 Switching Protocols\r\nConnection: Upgrade\r\nUpgrade: h2c-reverse\r\n\r\n') newsocket.write (b'PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n') c = HTTP20Connection ('unused.org', external_socket = BufferedSocket (newsocket)) c.request('POST', '/onvif/device_service', headers = { 'Content-Type': 'application/soap+xml; charset=utf-8'}, body=b'')) resp = c.get_response () print (resp.read ()) --- hyper/http20/connection.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/hyper/http20/connection.py b/hyper/http20/connection.py index b8be292b..816c20ac 100644 --- a/hyper/http20/connection.py +++ b/hyper/http20/connection.py @@ -102,7 +102,7 @@ class HTTP20Connection(object): def __init__(self, host, port=None, secure=None, window_manager=None, enable_push=False, ssl_context=None, proxy_host=None, proxy_port=None, force_proto=None, proxy_headers=None, - timeout=None, **kwargs): + timeout=None, external_socket=None, **kwargs): """ Creates an HTTP/2 connection to a specific server. """ @@ -154,6 +154,8 @@ def __init__(self, host, port=None, secure=None, window_manager=None, # timeout self._timeout = timeout + self._sock = external_socket + return def __init_state(self):