1#[derive(Debug, PartialEq)]
2pub struct WsUrl<'a> {
7 pub host: &'a str,
8 pub ip: &'a str,
9 pub port: u16,
10
11 pub path: &'a str,
12 pub secure: bool,
13}
14
15impl WsUrl<'_> {
16 pub fn from_str<'a>(ws_url: &'a str) -> Option<WsUrl<'a>> {
18 let (secure, host_start_offset) = if ws_url.starts_with("ws://") {
19 (false, 5)
20 } else if ws_url.starts_with("wss://") {
21 (true, 6)
22 } else {
23 return None;
24 };
25
26 let mut host_end = None;
27 if let Some(ws_url) = ws_url.get(host_start_offset..) {
28 let chars = ws_url.char_indices();
29 for c in chars {
30 if c.1 == '/' {
31 host_end = Some(c.0 + host_start_offset);
32 break;
33 }
34 }
35 }
36
37 let host = ws_url.get(host_start_offset..host_end.unwrap_or(ws_url.len()))?;
38 let path = ws_url.get(host_end.unwrap_or(ws_url.len())..ws_url.len())?;
39 let path = if path.len() == 0 { "/" } else { path };
40
41 let mut host_split = host.split(':');
42 let ip = host_split.next()?;
43 let port = if let Some(port_str) = host_split.next() {
44 u16::from_str_radix(port_str, 10).ok()?
45 } else {
46 match secure {
48 true => 443,
49 false => 80,
50 }
51 };
52
53 if host_split.count() > 0 {
54 return None;
55 }
56
57 Some(WsUrl {
58 host,
59 ip,
60 port,
61 path,
62 secure,
63 })
64 }
65}
66
67#[cfg(feature = "alloc")]
68#[derive(Debug, PartialEq)]
69pub struct WsUrlOwned {
70 pub host: alloc::string::String,
71 pub ip: alloc::string::String,
72 pub port: u16,
73
74 pub path: alloc::string::String,
75 pub secure: bool,
76}
77
78#[cfg(feature = "alloc")]
79impl WsUrlOwned {
80 pub fn new(ws_url: &WsUrl<'_>) -> Self {
81 use crate::alloc::string::ToString;
82
83 Self {
84 host: ws_url.host.to_string(),
85 ip: ws_url.ip.to_string(),
86 port: ws_url.port,
87 path: ws_url.path.to_string(),
88 secure: ws_url.secure,
89 }
90 }
91
92 pub fn as_ref<'a>(&'a self) -> WsUrl<'a> {
93 WsUrl {
94 host: &self.host,
95 ip: &self.ip,
96 port: self.port,
97 path: &self.path,
98 secure: self.secure,
99 }
100 }
101}
102
103#[cfg(test)]
104mod tests {
105 use super::*;
106
107 #[test]
108 fn validate_ws_url_parse() {
109 assert_eq!(
110 WsUrl::from_str("ws://127.0.0.1"),
111 Some(WsUrl {
112 host: "127.0.0.1",
113 ip: "127.0.0.1",
114 port: 80,
115 path: "/",
116 secure: false
117 })
118 );
119
120 assert_eq!(
121 WsUrl::from_str("wss://127.0.0.1"),
122 Some(WsUrl {
123 host: "127.0.0.1",
124 ip: "127.0.0.1",
125 port: 443,
126 path: "/",
127 secure: true
128 })
129 );
130
131 assert_eq!(
132 WsUrl::from_str("ws://127.0.0.1:4321"),
133 Some(WsUrl {
134 host: "127.0.0.1:4321",
135 ip: "127.0.0.1",
136 port: 4321,
137 path: "/",
138 secure: false
139 })
140 );
141
142 assert_eq!(
143 WsUrl::from_str("wss://127.0.0.1:4321"),
144 Some(WsUrl {
145 host: "127.0.0.1:4321",
146 ip: "127.0.0.1",
147 port: 4321,
148 path: "/",
149 secure: true
150 })
151 );
152
153 assert_eq!(
154 WsUrl::from_str("ws://127.0.0.1:4321/cxz/ewq"),
155 Some(WsUrl {
156 host: "127.0.0.1:4321",
157 ip: "127.0.0.1",
158 port: 4321,
159 path: "/cxz/ewq",
160 secure: false
161 })
162 );
163
164 assert_eq!(
165 WsUrl::from_str("wss://127.0.0.1:4321/cxz/ewq"),
166 Some(WsUrl {
167 host: "127.0.0.1:4321",
168 ip: "127.0.0.1",
169 port: 4321,
170 path: "/cxz/ewq",
171 secure: true
172 })
173 );
174
175 assert_eq!(
176 WsUrl::from_str("ws://127.0.0.1/cxz/ewq"),
177 Some(WsUrl {
178 host: "127.0.0.1",
179 ip: "127.0.0.1",
180 port: 80,
181 path: "/cxz/ewq",
182 secure: false
183 })
184 );
185
186 assert_eq!(
187 WsUrl::from_str("wss://127.0.0.1/cxz/ewq"),
188 Some(WsUrl {
189 host: "127.0.0.1",
190 ip: "127.0.0.1",
191 port: 443,
192 path: "/cxz/ewq",
193 secure: true
194 })
195 );
196
197 assert_eq!(WsUrl::from_str("ws://127.0.0.1:d123"), None);
198 assert_eq!(WsUrl::from_str("ws://127.0.0.1:123d"), None);
199
200 assert_eq!(WsUrl::from_str("wsc://127.0.0.1/cxz/ewq"), None);
201 assert_eq!(WsUrl::from_str("ws://127.0.0.1:4321:123/cxz/ewq"), None);
202 }
203}