Skip to main content

tokio_websockets/upgrade/
mod.rs

1//! HTTP upgrade request and response generation and validation helpers.
2
3use std::fmt;
4#[cfg(feature = "server")]
5pub(crate) mod client_request;
6#[cfg(feature = "client")]
7pub(crate) mod server_response;
8
9/// A parsed HTTP/1.1 101 Switching Protocols response.
10/// These responses typically do not contain a body, therefore it is omitted.
11#[cfg(feature = "client")]
12pub type Response = http::Response<()>;
13
14/// Errors that occur during the HTTP upgrade handshake between client and
15/// server.
16#[derive(Debug)]
17#[non_exhaustive]
18pub enum Error {
19    /// Header required in the request or response is not present.
20    MissingHeader(&'static str),
21    /// `Upgrade` header sent by the client does not match "websocket".
22    UpgradeNotWebSocket,
23    /// `Connection` header sent by the client does not contain "Upgrade".
24    ConnectionNotUpgrade,
25    /// `Sec-WebSocket-Version` header sent by the client is not supported by
26    /// the server.
27    UnsupportedWebSocketVersion,
28    /// Failed to parse client request or server response.
29    Parsing(httparse::Error),
30    /// Server did not return a HTTP Switching Protocols response.
31    DidNotSwitchProtocols(u16),
32    /// Server returned a `Sec-WebSocket-Accept` that is not compatible with the
33    /// `Sec-WebSocket-Key` sent by the client.
34    WrongWebSocketAccept,
35}
36
37impl fmt::Display for Error {
38    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
39        match self {
40            Error::MissingHeader(header) => {
41                f.write_str("missing required header: ")?;
42                f.write_str(header)
43            }
44            Error::UpgradeNotWebSocket => f.write_str("upgrade header value was not websocket"),
45            Error::ConnectionNotUpgrade => f.write_str("connection header value was not upgrade"),
46            Error::UnsupportedWebSocketVersion => f.write_str("unsupported WebSocket version"),
47            Error::Parsing(e) => e.fmt(f),
48            Error::DidNotSwitchProtocols(status) => {
49                f.write_str("expected HTTP 101 Switching Protocols, got status code ")?;
50                f.write_fmt(format_args!("{status}"))
51            }
52            Error::WrongWebSocketAccept => f.write_str("mismatching Sec-WebSocket-Accept header"),
53        }
54    }
55}
56
57impl std::error::Error for Error {
58    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
59        match self {
60            Error::MissingHeader(_)
61            | Error::UpgradeNotWebSocket
62            | Error::ConnectionNotUpgrade
63            | Error::UnsupportedWebSocketVersion
64            | Error::DidNotSwitchProtocols(_)
65            | Error::WrongWebSocketAccept => None,
66            Error::Parsing(e) => Some(e),
67        }
68    }
69}
70
71impl From<httparse::Error> for Error {
72    fn from(err: httparse::Error) -> Self {
73        Self::Parsing(err)
74    }
75}