1

I'm trying to use hyper.contrib HTTP20Adapter with the requests module as described here, but even with following the example for using HTTP/2 in this way, it still uses HTTP/1.1. This results in ConnectionResetError and HTTP/2 is never attempted. If I use hyper HTTPConnection, it also uses HTTP/1.1 and fails. But if I use HTTP20Connection, it uses HTTP/2 and succeeds. Is there a way to force requests with the HTTP20Adapter to use only HTTP/2?

First test, using HTTPConnection. A wireshark trace confirms that this resulted in an HTTP/1.1 GET and a Connection Reset.

>>> from hyper import HTTPConnection
>>> c = HTTPConnection('10.11.22.33:8080')
>>> c.request('GET', '/my/path/')
>>> resp = c.get_response()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/root/Python/myApp/lib64/python3.6/site-packages/hyper/common/connection.py", line 129, in get_response
    return self._conn.get_response(*args, **kwargs)
  File "/root/Python/myApp/lib64/python3.6/site-packages/hyper/http11/connection.py", line 203, in get_response
    self._sock.fill()
  File "/root/Python/myApp/lib64/python3.6/site-packages/hyper/common/bufsocket.py", line 169, in fill
    raise ConnectionResetError()
ConnectionResetError

Second test, using HTTP20Connection. This resulted in an HTTP/2 GET request and a successful response.

>>> from hyper import HTTP20Connection
>>> c = HTTP20Connection('10.11.22.33:8080')
>>> c.request('GET', '/my/path/')
1
>>> resp = c.get_response()
>>> print(resp.headers)
HTTPHeaderMap([(b'server', b'nginx/1.14.1'), (b'date', b'Wed, 12 Aug 2020 13:29:34 GMT'), (b'content-type', b'application/problem+json'), (b'3gpp-sbi-message-priority', b'10'), (b'x-envoy-upstream-service-time', b'109')])

Third test, using requests with an adapter. This also resulted in an HTTP/1.1 request and ConnectionResetError. HTTP/2 was not seen over the wire.

>>> import requests
>>> from hyper.contrib import HTTP20Adapter
>>> 
>>> s = requests.Session()
>>> s.mount('http://10.11.22.33:8080', HTTP20Adapter())
>>> s
<requests.sessions.Session object at 0x7f68f3487f28>
>>> 
>>> 
>>> r = s.get('http://10.11.22.33:8080/my/path/')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/root/Python/myApp/lib64/python3.6/site-packages/requests/sessions.py", line 543, in get
    return self.request('GET', url, **kwargs)
  File "/root/Python/myApp/lib64/python3.6/site-packages/requests/sessions.py", line 530, in request
    resp = self.send(prep, **send_kwargs)
  File "/root/Python/myApp/lib64/python3.6/site-packages/requests/sessions.py", line 643, in send
    r = adapter.send(request, **kwargs)
  File "/root/Python/myApp/lib64/python3.6/site-packages/hyper/contrib.py", line 80, in send
    resp = conn.get_response()
  File "/root/Python/myApp/lib64/python3.6/site-packages/hyper/common/connection.py", line 129, in get_response
    return self._conn.get_response(*args, **kwargs)
  File "/root/Python/myApp/lib64/python3.6/site-packages/hyper/http11/connection.py", line 203, in get_response
    self._sock.fill()
  File "/root/Python/myApp/lib64/python3.6/site-packages/hyper/common/bufsocket.py", line 169, in fill
    raise ConnectionResetError()
ConnectionResetError

I really need to get this last test working, as the rest of my framework is using the requests module.

Rusty Lemur
  • 1,697
  • 1
  • 21
  • 54

1 Answers1

1

I would suggest that you use a monkeypatch here.

Write a custom request something like below to use HTTP20Connection instead of HTTP11Connection

from hyper.http20.connection import HTTP20Connection


def custom_request(self, method, url, body=None, headers=None):

    headers = headers or {}
    if self._conn.__class__.__name__ == 'HTTP11Connection':
        self._conn = HTTP20Connection(
                self._host, self._port, **self._h2_kwargs
                )
    try:
        return self._conn.request(
                method=method, url=url, body=body, headers=headers
        )
    except TLSUpgrade as e:
        assert e.negotiated in H2_NPN_PROTOCOLS
        self._conn = HTTP20Connection(
                self._host, self._port, **self._h2_kwargs
        )
        self._conn._sock = e.sock
        self._conn._send_preamble()
        return self._conn.request(
                method=method, url=url, body=body, headers=headers
        )

After this you can monkeypatch as follows

from hyper.common.connection import HTTPConnection
HTTPConnection.request = custom_request
SAbdulRS
  • 11
  • 2