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 theUpgrade
header provided. It returns theResponse
, in case other headers need to be added, and aserver::Upgrade
type, explained next.
-
server::Upgrade
impl Future for server::Upgrade
- This type is a
Future
that 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
.