encode / httpcore

A minimal HTTP client. ⚙️
https://www.encode.io/httpcore/
BSD 3-Clause "New" or "Revised" License
465 stars 105 forks source link

Support connection `Upgrade` and `CONNECT`. #872

Closed MtkN1 closed 8 months ago

MtkN1 commented 9 months ago

In cases of CONNECT and Upgrade requests, it is necessary to handle the incoming data (h11.Connection.trailing_data).

https://h11.readthedocs.io/en/latest/api.html?highlight=trailing_data#switching-protocols

However, accessing trailing_data in HTTPCore requires a very lengthy property access.

with httpcore.ConnectionPool() as http:
    with http.stream("GET", url, headers=headers) as response:
        # Get the trailing data.
        trailing_data, _ = response.stream._stream._connection._h11_state.trailing_data

Making this accessible through the public API would be beneficial for developers using the "network_stream".

Related HTTPCore documentation: https://www.encode.io/httpcore/extensions/#network_stream

Here is what tomchristie suggested in the discussion. https://github.com/encode/httpcore/discussions/871#discussioncomment-8223419

We could then either...

  • Make the available through a publicly documented response extension.trailing_data
  • Ensure that the is returned by the network stream, on the first .trailing_data``.read()

The second one of these is neatest from the user-perspective.

We'd probably implement that as a proxy class onto the underlying network stream, that's able to additionally deal with pushing the trailing data in the event back onto the stream...h11

# This kinda thing...
class UpgradeNetworkStream():
    def __init__(self, leading_data, network_stream):
        # We need to push any data that's already been read back onto the stream.
        self._leading_data = leading_data
        self._network_stream = network_stream

    def read(...)
        if self._leading_data:
            initial = self._leading_data
            self._leading_data = b''
            return initial
        else:
            return self._network_stream.read()

[!IMPORTANT]

  • We're using Polar.sh so you can upvote and help fund this issue.
  • We receive the funding once the issue is completed & confirmed by you.
  • Thank you in advance for helping prioritize & fund our backlog.

Fund with Polar

tomchristie commented 9 months ago

Thanks @MtkN1. If you (or anyone else) would like to work on this, a good starting point might be a PR that raises an exception in HTTP11Connection/AsyncHTTP11Connection whenever an Upgrade/CONNECT occurs.

tomchristie commented 8 months ago

Thank you @MtkN1 for contributing to close this issue! ⭐

The rewards from this issue, totalling $200, has been shared with you.

What now?

  1. Create a Polar account
  2. See incoming rewards & setup Stripe to receive them
  3. Get payouts as backers finalize their payments

If you already have a Polar account setup, you don't need to do anything.

MtkN1 commented 8 months ago

Wow, I'm surprised there's such a reward! I've set up Polar since I have a Stripe account 🙂