Skip to content

Commit adc7a17

Browse files
committed
add more testcases
1 parent dfe6b32 commit adc7a17

5 files changed

Lines changed: 365 additions & 48 deletions

File tree

lib/vey-http/src/server/request.rs

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -672,4 +672,48 @@ mod tests {
672672
.unwrap();
673673
assert!(!request.keep_alive());
674674
}
675+
676+
#[tokio::test]
677+
async fn read_http11_masque_connect_udp() {
678+
let content = b"GET /.well-known/masque/udp/target.example.com/443/ HTTP/1.1\r\n\
679+
Host: proxy.example.com\r\n\
680+
Connection: Upgrade\r\n\
681+
Upgrade: connect-udp\r\n\
682+
Capsule-Protocol: ?1\r\n\r\n";
683+
let stream = tokio_test::io::Builder::new().read(content).build();
684+
let mut buf_stream = BufReader::new(stream);
685+
let mut version = Version::HTTP_11;
686+
let request =
687+
HttpProxyClientRequest::parse(&mut buf_stream, 4096, &mut version, parse_more_header)
688+
.await
689+
.unwrap();
690+
691+
assert_eq!(request.version, Version::HTTP_11);
692+
assert_eq!(version, Version::HTTP_11);
693+
assert_eq!(request.method, Method::GET);
694+
assert_eq!(
695+
request.uri,
696+
Uri::from_static("/.well-known/masque/udp/target.example.com/443/")
697+
);
698+
assert!(request.keep_alive());
699+
assert!(request.body_type().is_none());
700+
assert_eq!(request.upgrade_token(), Some(&HttpUpgradeToken::ConnectUdp));
701+
let host = request.host.as_ref().unwrap();
702+
assert_eq!(host.host_str(), "proxy.example.com");
703+
assert_eq!(host.port(), 0);
704+
assert_eq!(
705+
request
706+
.hop_by_hop_headers
707+
.get(header::UPGRADE)
708+
.map(|v| v.to_str()),
709+
Some("connect-udp")
710+
);
711+
assert_eq!(
712+
request
713+
.end_to_end_headers
714+
.get(HeaderName::from_static("capsule-protocol"))
715+
.map(|v| v.to_str()),
716+
Some("?1")
717+
);
718+
}
675719
}

lib/vey-http/src/uri/well_known/easy_proxy.rs

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,10 @@ impl WellKnownUriParser<'_> {
3131
let host = self
3232
.next_path_segment()
3333
.ok_or(UriParseError::RequiredFieldNotFound("target_host"))?;
34-
let host = Host::from_str(host).map_err(|_| UriParseError::NotValidHost("target_host"))?;
34+
let host = percent_encoding::percent_decode_str(host)
35+
.decode_utf8()
36+
.map_err(|_| UriParseError::NotValidHost("target_host"))?;
37+
let host = Host::from_str(&host).map_err(|_| UriParseError::NotValidHost("target_host"))?;
3538

3639
let port = self
3740
.next_path_segment()
@@ -126,6 +129,21 @@ mod tests {
126129
assert_eq!(uri.query().unwrap(), "name=foo");
127130
}
128131

132+
#[test]
133+
fn valid_http_ipv6_percent_encoded() {
134+
let parsed =
135+
setup_parser("/.well-known/easy-proxy/http/2001%3Adb8%3A%3A1/8080/get").unwrap();
136+
let WellKnownUri::EasyProxy(protocol, target, uri) = parsed else {
137+
panic!("not parsed as easy-proxy")
138+
};
139+
assert_eq!(protocol, HttpProxySubProtocol::HttpForward);
140+
assert_eq!(target.host_str(), "2001:db8::1");
141+
assert_eq!(target.port(), 8080);
142+
assert_eq!(uri.scheme_str().unwrap(), "http");
143+
assert_eq!(uri.authority().unwrap().as_str(), "[2001:db8::1]:8080");
144+
assert_eq!(uri.path(), "/get");
145+
}
146+
129147
#[test]
130148
fn valid_https() {
131149
let parsed =

lib/vey-http/src/uri/well_known/masque.rs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,16 @@ mod tests {
107107
assert_eq!(addr.port(), 443);
108108
}
109109

110+
#[test]
111+
fn udp_valid_ipv6_percent_encoded() {
112+
let parsed = setup_parser("/.well-known/masque/udp/2001%3Adb8%3A%3A1/443/").unwrap();
113+
let WellKnownUri::Masque(HttpMasque::Udp(addr)) = parsed else {
114+
panic!("not parsed as masque/udp")
115+
};
116+
assert_eq!(addr.host_str(), "2001:db8::1");
117+
assert_eq!(addr.port(), 443);
118+
}
119+
110120
#[test]
111121
fn ip_missing_target() {
112122
let err = setup_parser("/.well-known/masque/ip/").unwrap_err();
@@ -147,6 +157,16 @@ mod tests {
147157
assert_eq!(proto.unwrap(), 17);
148158
}
149159

160+
#[test]
161+
fn ip_valid_ipv6_percent_encoded() {
162+
let parsed = setup_parser("/.well-known/masque/ip/2001%3Adb8%3A%3A2/17/").unwrap();
163+
let WellKnownUri::Masque(HttpMasque::Ip(host, proto)) = parsed else {
164+
panic!("not parsed as masque/ip")
165+
};
166+
assert_eq!(host.unwrap().to_string(), "2001:db8::2");
167+
assert_eq!(proto.unwrap(), 17);
168+
}
169+
150170
#[test]
151171
fn ip_wildcards() {
152172
let parsed = setup_parser("/.well-known/masque/ip/*/*/").unwrap();

lib/vey-http/src/uri/well_known/mod.rs

Lines changed: 114 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -90,89 +90,156 @@ mod tests {
9090
use super::*;
9191

9292
#[test]
93-
fn next_path_segment_empty() {
94-
let uri = Uri::from_static("/");
93+
fn next_path_segment_skips_empty_segments() {
94+
let uri = Uri::from_static("///a//b/c///");
9595
let mut parser = WellKnownUriParser::new(&uri);
96-
assert_eq!(parser.next_path_segment(), None);
97-
}
98-
99-
#[test]
100-
fn next_path_segment_single() {
101-
let uri = Uri::from_static("/test/");
102-
let mut parser = WellKnownUriParser::new(&uri);
103-
assert_eq!(parser.next_path_segment(), Some("test"));
104-
assert_eq!(parser.next_path_segment(), None);
105-
}
10696

107-
#[test]
108-
fn next_path_segment_multiple() {
109-
let uri = Uri::from_static("/a/b/c/");
110-
let mut parser = WellKnownUriParser::new(&uri);
11197
assert_eq!(parser.next_path_segment(), Some("a"));
11298
assert_eq!(parser.next_path_segment(), Some("b"));
11399
assert_eq!(parser.next_path_segment(), Some("c"));
114100
assert_eq!(parser.next_path_segment(), None);
115101
}
116102

117103
#[test]
118-
fn next_path_segment_with_leading_slash() {
119-
let uri = Uri::from_static("//a/b/");
120-
let mut parser = WellKnownUriParser::new(&uri);
121-
assert_eq!(parser.next_path_segment(), Some("a"));
122-
assert_eq!(parser.next_path_segment(), Some("b"));
123-
assert_eq!(parser.next_path_segment(), None);
104+
fn parse_returns_none_for_non_well_known_paths() {
105+
for uri in [
106+
Uri::default(),
107+
Uri::from_static("/"),
108+
Uri::from_static("///"),
109+
Uri::from_static("/other-path"),
110+
Uri::from_static("/.well-known/"),
111+
] {
112+
assert!(WellKnownUri::parse(&uri).unwrap().is_none());
113+
}
124114
}
125115

126116
#[test]
127-
fn next_path_segment_only_slashes() {
128-
let uri = Uri::from_static("///");
129-
let mut parser = WellKnownUriParser::new(&uri);
130-
assert_eq!(parser.next_path_segment(), None);
117+
fn parse_unsupported_well_known_name() {
118+
let uri = Uri::from_static("/.well-known/unknown/value");
119+
let result = WellKnownUri::parse(&uri).unwrap().unwrap();
120+
let WellKnownUri::Unsupported(suffix) = result else {
121+
panic!("not parsed as unsupported")
122+
};
123+
124+
assert_eq!(suffix, "unknown");
131125
}
132126

133127
#[test]
134-
fn parse_empty_uri() {
135-
let uri = Uri::default();
136-
assert!(WellKnownUri::parse(&uri).unwrap().is_none());
128+
fn parse_easy_proxy_dispatch() {
129+
let uri = Uri::from_static("/.well-known/easy-proxy/http/target.example/8080/path?q=1");
130+
let result = WellKnownUri::parse(&uri).unwrap().unwrap();
131+
let WellKnownUri::EasyProxy(protocol, target, target_uri) = result else {
132+
panic!("not parsed as easy-proxy")
133+
};
134+
135+
assert_eq!(protocol, HttpProxySubProtocol::HttpForward);
136+
assert_eq!(target.host_str(), "target.example");
137+
assert_eq!(target.port(), 8080);
138+
assert_eq!(
139+
target_uri,
140+
Uri::from_static("http://target.example:8080/path?q=1")
141+
);
137142
}
138143

139144
#[test]
140-
fn parse_non_well_known() {
141-
let uri = Uri::from_static("/other-path");
142-
assert!(WellKnownUri::parse(&uri).unwrap().is_none());
145+
fn parse_easy_proxy_ipv6_dispatch() {
146+
let uri = Uri::from_static("/.well-known/easy-proxy/https/2001%3Adb8%3A%3A2/8443/api");
147+
let result = WellKnownUri::parse(&uri).unwrap().unwrap();
148+
let WellKnownUri::EasyProxy(protocol, target, target_uri) = result else {
149+
panic!("not parsed as easy-proxy")
150+
};
151+
152+
assert_eq!(protocol, HttpProxySubProtocol::HttpsForward);
153+
assert_eq!(target.host_str(), "2001:db8::2");
154+
assert_eq!(target.port(), 8443);
155+
assert_eq!(
156+
target_uri,
157+
Uri::from_static("https://[2001:db8::2]:8443/api")
158+
);
143159
}
144160

145161
#[test]
146-
fn parse_missing_protocol() {
147-
let uri = Uri::from_static("/.well-known/");
148-
assert!(WellKnownUri::parse(&uri).unwrap().is_none());
162+
fn parse_masque_udp_dispatch() {
163+
let uri = Uri::from_static("/.well-known/masque/udp/192.0.2.1/53");
164+
let result = WellKnownUri::parse(&uri).unwrap().unwrap();
165+
let WellKnownUri::Masque(HttpMasque::Udp(addr)) = result else {
166+
panic!("not parsed as masque udp")
167+
};
168+
169+
assert_eq!(addr.host_str(), "192.0.2.1");
170+
assert_eq!(addr.port(), 53);
149171
}
150172

151173
#[test]
152-
fn parse_unsupported_protocol() {
153-
let uri = Uri::from_static("/.well-known/unknown");
174+
fn parse_masque_udp_ipv6_dispatch() {
175+
let uri = Uri::from_static("/.well-known/masque/udp/2001%3Adb8%3A%3A3/53");
154176
let result = WellKnownUri::parse(&uri).unwrap().unwrap();
155-
assert_eq!(result.suffix(), "unknown")
177+
let WellKnownUri::Masque(HttpMasque::Udp(addr)) = result else {
178+
panic!("not parsed as masque udp")
179+
};
180+
181+
assert_eq!(addr.host_str(), "2001:db8::3");
182+
assert_eq!(addr.port(), 53);
156183
}
157184

158185
#[test]
159-
fn parse_easy_proxy() {
160-
let uri = Uri::from_static("/.well-known/easy-proxy/http/target.com/80/path?query=1");
186+
fn parse_masque_ip_dispatch() {
187+
let uri = Uri::from_static("/.well-known/masque/ip/example.com/17");
161188
let result = WellKnownUri::parse(&uri).unwrap().unwrap();
162-
assert_eq!(result.suffix(), "easy-proxy");
189+
let WellKnownUri::Masque(HttpMasque::Ip(host, proto)) = result else {
190+
panic!("not parsed as masque ip")
191+
};
192+
193+
assert_eq!(host.unwrap().to_string(), "example.com");
194+
assert_eq!(proto, Some(17));
163195
}
164196

165197
#[test]
166-
fn parse_masque_udp() {
167-
let uri = Uri::from_static("/.well-known/masque/udp/192.0.2.1/53");
198+
fn parse_masque_ip_ipv6_dispatch() {
199+
let uri = Uri::from_static("/.well-known/masque/ip/2001%3Adb8%3A%3A4/17");
168200
let result = WellKnownUri::parse(&uri).unwrap().unwrap();
169-
assert_eq!(result.suffix(), "masque");
201+
let WellKnownUri::Masque(HttpMasque::Ip(host, proto)) = result else {
202+
panic!("not parsed as masque ip")
203+
};
204+
205+
assert_eq!(host.unwrap().to_string(), "2001:db8::4");
206+
assert_eq!(proto, Some(17));
170207
}
171208

172209
#[test]
173-
fn parse_error_invalid_masque_segment() {
174-
let uri = Uri::from_static("/.well-known/masque/invalid");
210+
fn parse_unsupported_masque_segment() {
211+
let uri = Uri::from_static("/.well-known/masque/unknown-protocol");
175212
let result = WellKnownUri::parse(&uri).unwrap().unwrap();
176-
assert_eq!(result.suffix(), "masque/invalid")
213+
let WellKnownUri::Unsupported(suffix) = result else {
214+
panic!("not parsed as unsupported")
215+
};
216+
217+
assert_eq!(suffix, "masque/unknown-protocol");
218+
assert_eq!(
219+
WellKnownUri::Unsupported(suffix).suffix(),
220+
"masque/unknown-protocol"
221+
);
222+
}
223+
224+
#[test]
225+
fn parse_propagates_easy_proxy_error() {
226+
let uri = Uri::from_static("/.well-known/easy-proxy/");
227+
let err = WellKnownUri::parse(&uri).unwrap_err();
228+
229+
assert!(matches!(
230+
err,
231+
UriParseError::RequiredFieldNotFound("scheme")
232+
));
233+
}
234+
235+
#[test]
236+
fn parse_propagates_masque_error() {
237+
let uri = Uri::from_static("/.well-known/masque/");
238+
let err = WellKnownUri::parse(&uri).unwrap_err();
239+
240+
assert!(matches!(
241+
err,
242+
UriParseError::RequiredFieldNotFound("segment")
243+
));
177244
}
178245
}

0 commit comments

Comments
 (0)