python-hyper / hyper

HTTP/2 for Python.
http://hyper.rtfd.org/en/latest/
MIT License
1.05k stars 191 forks source link

Hyper may try to receive an empty body from the HEAD response. #357

Open johejo opened 6 years ago

johejo commented 6 years ago

In a non-secure HTTP/2 HEAD request, hyper try to receive an empty body. However, if I send a HEAD request to http://nghttp2.org/httpbin/get, it is successful. They also succeed when executed with the --h2 option added. My private server log shows that the server is probably returning the correct HEAD response. HTTP server: h2o v2.2.3

mitsuo-Antergos% hyper head http://165.242.111.92/ --debug     
Url Info: {'fragment': None, 'host': '165.242.111.92', 'netloc': '165.242.111.92', 'path': '/', 'port': 80, 'query': None, 'scheme': 'http', 'secure': False}
Commandline Argument: Namespace(_url='http://165.242.111.92/', body=None, debug=True, h2=False, headers={}, items=[], method='HEAD', url=<hyper.cli.UrlInfo object at 0x7f276463bb70>)
Selected protocol: None
recv for stream 0 with set() already present
Traceback (most recent call last):
  File "/usr/lib/python3.6/site-packages/hyper/common/connection.py", line 136, in get_response
    return self._conn.get_response(*args, **kwargs)
  File "/usr/lib/python3.6/site-packages/hyper/http11/connection.py", line 304, in get_response
    raise HTTPUpgrade(H2C_PROTOCOL, self._sock)
hyper.common.exceptions.HTTPUpgrade

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/usr/bin/hyper", line 11, in <module>
    load_entry_point('hyper==0.8.0.dev0', 'console_scripts', 'hyper')()
  File "/usr/lib/python3.6/site-packages/hyper/cli.py", line 259, in main
    data = request(args)
  File "/usr/lib/python3.6/site-packages/hyper/cli.py", line 249, in request
    response = conn.get_response()
  File "/usr/lib/python3.6/site-packages/hyper/common/connection.py", line 147, in get_response
    self._conn._connect_upgrade(e.sock)
  File "/usr/lib/python3.6/site-packages/hyper/http20/connection.py", line 416, in _connect_upgrade
    self._recv_cb()
  File "/usr/lib/python3.6/site-packages/hyper/http20/connection.py", line 787, in _recv_cb
    self._single_read()
  File "/usr/lib/python3.6/site-packages/hyper/http20/connection.py", line 685, in _single_read
    events = conn.receive_data(data)
  File "/usr/lib/python3.6/site-packages/h2/connection.py", line 1531, in receive_data
    events.extend(self._receive_frame(frame))
  File "/usr/lib/python3.6/site-packages/h2/connection.py", line 1554, in _receive_frame
    frames, events = self._frame_dispatch_table[frame.__class__](frame)
  File "/usr/lib/python3.6/site-packages/h2/connection.py", line 1721, in _receive_data_frame
    flow_controlled_length
  File "/usr/lib/python3.6/site-packages/h2/stream.py", line 1124, in receive_data
    self._track_content_length(len(data), end_stream)
  File "/usr/lib/python3.6/site-packages/h2/stream.py", line 1370, in _track_content_length
    raise InvalidBodyLengthError(expected, actual)
h2.exceptions.InvalidBodyLengthError: InvalidBodyLengthError: Expected 177 bytes, received 0
Lukasa commented 6 years ago

Yup, I suspect this is probably wrong. Patches to resolve it would be very welcome. :smile:

johejo commented 6 years ago

Also, a deadlock has occurred in an HTTP/1.1 HEAD request trying to read an empty body.

johejo commented 6 years ago

When I traced the part that crashed with InvalidBodyLengthError, the "request_method" which is the instance variable of H2Stream class remained None. Even with a successful GET request, it will remain None as well. Is this correct? When executing with the - -h2 option, "request_method" is correctly set to b 'HEAD' or b'GET'.