polyoxide_venue/socket.rs
1//! The socket half of the class table: close codes and handshake statuses.
2//!
3//! This crate depends on no socket library, so the table for a transport
4//! error's own kinds is a macro, [`impl_ws_classification!`](crate::impl_ws_classification),
5//! which expands it against `polyoxide_ws::WsError` in the venue crate: an
6//! I/O error (a TLS EOF included), a protocol error and a closed connection
7//! are [`Network`](Class::Network); a bad URL, a malformed handshake request,
8//! a TLS configuration error, an attack-attempt detection, a capacity limit,
9//! a use after close and an operation the transport cannot perform are
10//! [`InvalidRequest`](Class::InvalidRequest); a
11//! server close goes through [`class_for_close_code`]; a handshake refused
12//! with an HTTP status goes through [`class_for_handshake_status`]; anything
13//! else is [`Network`](Class::Network).
14
15use std::sync::Arc;
16
17use crate::{class_for_status, Class};
18
19/// The class of a socket the server closed, from the close frame's code.
20///
21/// | Close code | Class |
22/// | --- | --- |
23/// | 1002, 1003, 1007, 1008, 1009, 1010, 4000–4999 | [`VenueRefusal`](Class::VenueRefusal), with the code in decimal |
24/// | everything else, and no code at all | [`Network`](Class::Network) |
25///
26/// The `VenueRefusal` codes say the server objected to what it was sent: a
27/// protocol violation, an unacceptable or oversized message, a policy breach,
28/// or an application's own reason. Every other code, 1000, 1001, 1006 and
29/// 1011–1013 among them, says the connection ended without the request being
30/// at fault.
31pub fn class_for_close_code(code: Option<u16>) -> Class {
32 match code {
33 Some(code @ (1002 | 1003 | 1007..=1010 | 4000..=4999)) => Class::VenueRefusal {
34 code: Some(Arc::from(code.to_string())),
35 },
36 _ => Class::Network,
37 }
38}
39
40/// The class of a WebSocket upgrade the server refused with an HTTP status.
41///
42/// The status rule ([`class_for_status`]), with any status outside 400–599 a
43/// [`Decode`](Class::Decode): the server answered, but not with an upgrade.
44pub fn class_for_handshake_status(status: u16) -> Class {
45 class_for_status(status).unwrap_or(Class::Decode)
46}
47
48#[cfg(test)]
49mod tests {
50 use super::*;
51
52 fn refusal(code: &str) -> Class {
53 Class::VenueRefusal {
54 code: Some(Arc::from(code)),
55 }
56 }
57
58 #[test]
59 fn every_close_code_row() {
60 let rows = [
61 // The codes the table names.
62 (Some(1000), Class::Network),
63 (Some(1001), Class::Network),
64 (Some(1006), Class::Network),
65 (Some(1011), Class::Network),
66 (Some(1012), Class::Network),
67 (Some(1013), Class::Network),
68 (Some(1002), refusal("1002")),
69 (Some(1003), refusal("1003")),
70 (Some(1007), refusal("1007")),
71 (Some(1008), refusal("1008")),
72 (Some(1009), refusal("1009")),
73 (Some(1010), refusal("1010")),
74 (Some(4000), refusal("4000")),
75 (Some(4404), refusal("4404")),
76 (Some(4999), refusal("4999")),
77 // The ones it does not.
78 (None, Class::Network),
79 (Some(1004), Class::Network),
80 (Some(1005), Class::Network),
81 (Some(1014), Class::Network),
82 (Some(1015), Class::Network),
83 (Some(2999), Class::Network),
84 (Some(3000), Class::Network),
85 (Some(3999), Class::Network),
86 (Some(5000), Class::Network),
87 ];
88 for (code, class) in rows {
89 assert_eq!(class_for_close_code(code), class, "close code {code:?}");
90 }
91 }
92
93 #[test]
94 fn a_handshake_status_follows_the_status_rule() {
95 let rows = [
96 (101, Class::Decode),
97 (200, Class::Decode),
98 (301, Class::Decode),
99 (400, Class::VenueRefusal { code: None }),
100 (401, Class::Unauthorized),
101 (403, Class::Unauthorized),
102 (404, Class::VenueRefusal { code: None }),
103 (418, Class::Restricted),
104 (429, Class::RateLimited { retry_after: None }),
105 (451, Class::Restricted),
106 (502, Class::Unavailable { code: None }),
107 (503, Class::Unavailable { code: None }),
108 ];
109 for (status, class) in rows {
110 assert_eq!(class_for_handshake_status(status), class, "status {status}");
111 }
112 }
113}