-
-
Notifications
You must be signed in to change notification settings - Fork 1.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Client Protocol Upgrades #1395
Comments
This looks great! The channel based approach we discussed also seems to be equally ergonomic and a looks much simpler to implement without adding another type parameter to virtually all types in |
Well, shoot. The reason I liked this was for the end user API, but I think it might be impossible to do in 0.11 because:
What exact user API were you thinking with channels? |
struct Upgrade<T: AsyncRead + AsyncWrite> {
io: T,
response: MessageHead<RawStatus>
handle: Handle
}
fn main() {
let client = Client::configure().enable_upgrades().build();
let upgrade_rx = client.upgrades();
let upgrade_task = upgrade_rx.then(|upgrade: Upgrade| {
do_something(upgrade);
Ok(())
});
let handle = client.handle();
handle.spawn(upgrade_task);
let req = Request::new(Method::Get, "https://example.domain/".parse()?)
.with_header(Connection::upgrade())
.with_header(Upgrade::websocket());
let req = client.request(req).and_then(|res| {
handle_req(res);
Ok(())
});
core.run(req).unwrap();
} But come to think of it, that is a lot of boilerplate for a single request. My use case is kind of like a proxy I would make a stream of requests, so I am biased. |
If there is an upgrade, what does What I preferred about the initial proposed API is that handling an upgrade was local to the |
Yes.
|
Ah OK, it wasn't in the original message I got in email, didn't notice the edit. So, a user would receive the I suppose it allows working without a breaking change, but my personal opinion is that it kind of feels far away from the rest of the code. Hm, does that even matter? I suppose that the underlying connection is being used in an upgrade perhaps doesn't matter to the other place that received a |
Ok, sorry it's taken so long to get back here, I haven't had much time to focus on this feature, but it's now needed in Conduit, so it's got my attention again. I've started with the idea that the client could use a lower-level API of running HTTP over a single connection, and there is where upgrades can be handled at first (as well as custom pools and whatever else). I feel that designing an API to work directly with the higher level |
I too tried to take a stab at it a while ago. The problem seems to be with the pool. At the dispatcher level, I could extract the |
A solution for #1449 was just merged to master, that introduces a lower-level connection API, where it is possible to make The |
There's a proposed PR at #1563 to add this feature (and for servers). |
…er (#1563) - Adds `Body::on_upgrade()` that returns an `OnUpgrade` future. - Adds `hyper::upgrade` module containing types for dealing with upgrades. - Adds `server::conn::Connection::with_upgrades()` method to enable these upgrades when using lower-level API (because of a missing `Send` bound on the transport generic). - Client connections are automatically enabled. - Optimizes request parsing, to make up for extra work to look for upgrade requests. - Returns a smaller `DecodedLength` type instead of the fatter `Decoder`, which should also allow a couple fewer branches. - Removes the `Decode::Ignore` wrapper enum, and instead ignoring 1xx responses is handled directly in the response parsing code. Ref #1563 Closes #1395
(For handling server protocol upgrades, see #1323)
HTTP/1 allows starting a different protocol with an HTTP/1 request, and the desired protocol in an
Upgrade
header. We should support this.Edit: removed bad API proposal.
The text was updated successfully, but these errors were encountered: