-
-
Couldn't load subscription status.
- Fork 1.7k
Description
Add support for servers to receive requests that wish to upgrade to a different protocol, such as websockets. A proposed API follows:
Proposal
Response-
pub fn upgrade(proto: header::Upgrade) -> (Response, server::Upgrade)This sets the
StatusCode::SwitchingProtocols, and theUpgradeheader provided. It returns theResponse, in case other headers need to be added, and aserver::Upgradetype, explained next.
-
server::Upgradeimpl Future for server::Upgrade- This type is a
Futurethat resolves to the underlying IO object that is being upgraded.
Usage
// inside a `Service`
fn call(&self, req: Request) -> Self::Future {
if wants_ws_upgrade(&req) {
let (res, upgrade) = Response::upgrade(Upgrade::ws());
self.ws_queue.send(res);
future::ok(res)
} else {
self.handle_http(req)
}
}A theoretical websocket server would also exist, and a channel, the ws_queue, would be used to give the socket to the websocket server.
Implementation
The server::Upgrade could wrap a futures::sync::oneshot::Receiver. The purpose for wrapping one is to hide the implementation details.
When upgrading protocols, the response is only supposed to send headers. A blank newline after a header block with a 101 response code is supposed to be for the already upgraded protocol. That means sending a body with an upgrade response is an error.
If it is possible with some Into impls to allow Response::upgrade to return a Response<()>, that would probably be ideal. I imagine it might not be doable, in which case, it will need to be enforced at runtime. This will still work, as the server::Upgrade can be sent a hyper::Error noting that a body was illegal.
It would be nice if the type could be server::Upgrade<T>, where T is the specific IO type being used internally. However, that might not be possible either, as the Service may not have a way to know what type is being used (it might be possible for a user to have encoded the type in their new_service, and thus Service, and be able to statically guarantee the type, though!). If not, then the return type will need to be a Box<AsyncRead + AsyncWrite>.
Any buffered bytes internally associated with the socket should be returned as well, as a Chunk.