Skip to content

Commit 4301956

Browse files
authored
Fix net spit and join functions (#1906)
* fix: net.split_net_host_port handling of None Signed-off-by: John Gardiner Myers <[email protected]> * fix: net.split_net_host_port panic if missing colon Signed-off-by: John Gardiner Myers <[email protected]> * fix: net.split_net_host_port handle IPv6 address literal Signed-off-by: John Gardiner Myers <[email protected]> * fix: net.join_net_host_port handling of None Signed-off-by: John Gardiner Myers <[email protected]> * fix: net.join_net_host_port handle IPv6 address literals Signed-off-by: John Gardiner Myers <[email protected]> --------- Signed-off-by: John Gardiner Myers <[email protected]>
1 parent 309b593 commit 4301956

File tree

1 file changed

+308
-13
lines changed

1 file changed

+308
-13
lines changed

kclvm/runtime/src/net/mod.rs

Lines changed: 308 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -19,12 +19,78 @@ pub extern "C-unwind" fn kclvm_net_split_host_port(
1919
let kwargs = ptr_as_ref(kwargs);
2020
let ctx = mut_ptr_as_ref(ctx);
2121

22-
if let Some(string) = get_call_arg_str(args, kwargs, 0, Some("ip_end_point")) {
23-
let mut list = ValueRef::list(None);
24-
for s in string.split(':') {
25-
list.list_append(&ValueRef::str(s));
22+
if let Some(ip_end_point) = get_call_arg(args, kwargs, 0, Some("ip_end_point")) {
23+
if ip_end_point.is_none() {
24+
return ValueRef::none().into_raw(ctx);
25+
}
26+
let ip_end_point_str = ip_end_point.as_str();
27+
match ip_end_point_str.rsplit_once(':') {
28+
None => panic!(
29+
"ip_end_point \"{}\" missing port",
30+
ip_end_point_str.escape_default()
31+
),
32+
Some((host, port)) => {
33+
if host.starts_with('[') {
34+
match ip_end_point_str.find(']') {
35+
None => panic!(
36+
"ip_end_point \"{}\" missing ']'",
37+
ip_end_point_str.escape_default()
38+
),
39+
Some(end) => {
40+
if end > host.len() || !ip_end_point_str[end + 1..].starts_with(':') {
41+
panic!(
42+
"ip_end_point \"{}\" missing port",
43+
ip_end_point_str.escape_default()
44+
);
45+
}
46+
if end < host.len() - 1 {
47+
panic!(
48+
"ip_end_point \"{}\" too many colons",
49+
ip_end_point_str.escape_default()
50+
);
51+
}
52+
if ip_end_point_str[1..].contains('[') {
53+
panic!(
54+
"ip_end_point \"{}\" unexpected '['",
55+
ip_end_point_str.escape_default()
56+
);
57+
}
58+
if port.contains(']') {
59+
panic!(
60+
"ip_end_point \"{}\" unexpected ']'",
61+
ip_end_point_str.escape_default()
62+
);
63+
}
64+
return ValueRef::list(Some(&[
65+
&ValueRef::str(&host[1..end]),
66+
&ValueRef::str(port),
67+
]))
68+
.into_raw(ctx);
69+
}
70+
}
71+
}
72+
if host.contains(':') {
73+
panic!(
74+
"ip_end_point \"{}\" too many colons",
75+
ip_end_point_str.escape_default()
76+
);
77+
}
78+
if ip_end_point_str[1..].contains('[') {
79+
panic!(
80+
"ip_end_point \"{}\" unexpected '['",
81+
ip_end_point_str.escape_default()
82+
);
83+
}
84+
if ip_end_point_str.contains(']') {
85+
panic!(
86+
"ip_end_point \"{}\" unexpected ']'",
87+
ip_end_point_str.escape_default()
88+
);
89+
}
90+
return ValueRef::list(Some(&[&ValueRef::str(host), &ValueRef::str(port)]))
91+
.into_raw(ctx);
92+
}
2693
}
27-
return list.into_raw(ctx);
2894
}
2995

3096
panic!("split_host_port() missing 1 required positional argument: 'ip_end_point'");
@@ -43,14 +109,15 @@ pub extern "C-unwind" fn kclvm_net_join_host_port(
43109
let kwargs = ptr_as_ref(kwargs);
44110
let ctx = mut_ptr_as_ref(ctx);
45111

46-
if let Some(host) = get_call_arg_str(args, kwargs, 0, Some("host")) {
47-
if let Some(port) = args.arg_i_int(1, None).or(kwargs.kwarg_int("port", None)) {
48-
let s = format!("{host}:{port}");
49-
return ValueRef::str(s.as_ref()).into_raw(ctx);
50-
}
51-
if let Some(port) = args.arg_i_str(1, None).or(kwargs.kwarg_str("port", None)) {
52-
let s = format!("{host}:{port}");
53-
return ValueRef::str(s.as_ref()).into_raw(ctx);
112+
if let Some(host) = get_call_arg(args, kwargs, 0, Some("host")) {
113+
if let Some(port) = get_call_arg(args, kwargs, 1, Some("port")) {
114+
if host.is_none() || port.is_none() {
115+
return ValueRef::none().into_raw(ctx);
116+
}
117+
if host.as_str().contains(':') {
118+
return ValueRef::str(format!("[{host}]:{port}").as_ref()).into_raw(ctx);
119+
}
120+
return ValueRef::str(format!("{host}:{port}").as_ref()).into_raw(ctx);
54121
}
55122
}
56123
panic!("join_host_port() missing 2 required positional arguments: 'host' and 'port'");
@@ -602,3 +669,231 @@ pub extern "C-unwind" fn kclvm_net_is_unspecified_IP(
602669
}
603670
panic!("is_unspecified_IP() missing 1 required positional argument: 'ip'");
604671
}
672+
673+
#[cfg(test)]
674+
mod test_net {
675+
use super::*;
676+
677+
#[test]
678+
fn test_split_host_port() {
679+
let cases = [
680+
(ValueRef::none(), ValueRef::none()),
681+
(
682+
ValueRef::str("invalid.invalid:21"),
683+
ValueRef::list(Some(&[
684+
&ValueRef::str("invalid.invalid"),
685+
&ValueRef::str("21"),
686+
])),
687+
),
688+
(
689+
ValueRef::str("192.0.2.1:14"),
690+
ValueRef::list(Some(&[&ValueRef::str("192.0.2.1"), &ValueRef::str("14")])),
691+
),
692+
(
693+
ValueRef::str("[2001:db8::]:80"),
694+
ValueRef::list(Some(&[&ValueRef::str("2001:db8::"), &ValueRef::str("80")])),
695+
),
696+
];
697+
let mut ctx = Context::default();
698+
for (ip_end_point, expected) in cases.iter() {
699+
unsafe {
700+
let actual = &*kclvm_net_split_host_port(
701+
&mut ctx,
702+
&ValueRef::list(Some(&[&ip_end_point])),
703+
&ValueRef::dict(None),
704+
);
705+
assert_eq!(expected, actual);
706+
}
707+
unsafe {
708+
let actual = &*kclvm_net_split_host_port(
709+
&mut ctx,
710+
&ValueRef::list(None),
711+
&ValueRef::dict(Some(&[("ip_end_point", ip_end_point)])),
712+
);
713+
assert_eq!(expected, actual);
714+
}
715+
}
716+
}
717+
718+
#[test]
719+
fn test_split_host_port_invalid() {
720+
let prev_hook = std::panic::take_hook();
721+
// Disable print panic info in stderr.
722+
std::panic::set_hook(Box::new(|_| {}));
723+
assert_panic(
724+
"split_host_port() missing 1 required positional argument: 'ip_end_point'",
725+
|| {
726+
let mut ctx = Context::new();
727+
let args = ValueRef::list(None).into_raw(&mut ctx);
728+
let kwargs = ValueRef::dict(None).into_raw(&mut ctx);
729+
kclvm_net_split_host_port(ctx.into_raw(), args, kwargs);
730+
},
731+
);
732+
assert_panic("ip_end_point \"test-host\" missing port", || {
733+
let ctx = Context::new();
734+
let args = &ValueRef::list(Some(&[&ValueRef::str("test-host")]));
735+
kclvm_net_split_host_port(ctx.into_raw(), args, &ValueRef::dict(None));
736+
});
737+
assert_panic("ip_end_point \"test-host:7:80\" too many colons", || {
738+
let ctx = Context::new();
739+
let args = &ValueRef::list(Some(&[&ValueRef::str("test-host:7:80")]));
740+
kclvm_net_split_host_port(ctx.into_raw(), args, &ValueRef::dict(None));
741+
});
742+
assert_panic("ip_end_point \"[2001:db8::]\" missing port", || {
743+
let ctx = Context::new();
744+
let args = &ValueRef::list(Some(&[&ValueRef::str("[2001:db8::]")]));
745+
kclvm_net_split_host_port(ctx.into_raw(), args, &ValueRef::dict(None));
746+
});
747+
assert_panic("ip_end_point \"[2001:db8::]80\" missing port", || {
748+
let ctx = Context::new();
749+
let args = &ValueRef::list(Some(&[&ValueRef::str("[2001:db8::]80")]));
750+
kclvm_net_split_host_port(ctx.into_raw(), args, &ValueRef::dict(None));
751+
});
752+
assert_panic("ip_end_point \"[2001:db8::]9:80\" missing port", || {
753+
let ctx = Context::new();
754+
let args = &ValueRef::list(Some(&[&ValueRef::str("[2001:db8::]9:80")]));
755+
kclvm_net_split_host_port(ctx.into_raw(), args, &ValueRef::dict(None));
756+
});
757+
assert_panic("ip_end_point \"[2001:db8::]:9:80\" too many colons", || {
758+
let ctx = Context::new();
759+
let args = &ValueRef::list(Some(&[&ValueRef::str("[2001:db8::]:9:80")]));
760+
kclvm_net_split_host_port(ctx.into_raw(), args, &ValueRef::dict(None));
761+
});
762+
assert_panic("ip_end_point \"[2001:db8:::80\" missing ']'", || {
763+
let ctx = Context::new();
764+
let args = &ValueRef::list(Some(&[&ValueRef::str("[2001:db8:::80")]));
765+
kclvm_net_split_host_port(ctx.into_raw(), args, &ValueRef::dict(None));
766+
});
767+
assert_panic("ip_end_point \"t[est-host:80\" unexpected '['", || {
768+
let ctx = Context::new();
769+
let args = &ValueRef::list(Some(&[&ValueRef::str("t[est-host:80")]));
770+
kclvm_net_split_host_port(ctx.into_raw(), args, &ValueRef::dict(None));
771+
});
772+
assert_panic("ip_end_point \"]test-host:80\" unexpected ']'", || {
773+
let ctx = Context::new();
774+
let args = &ValueRef::list(Some(&[&ValueRef::str("]test-host:80")]));
775+
kclvm_net_split_host_port(ctx.into_raw(), args, &ValueRef::dict(None));
776+
});
777+
assert_panic("ip_end_point \"[[2001:db8::]:80\" unexpected '['", || {
778+
let ctx = Context::new();
779+
let args = &ValueRef::list(Some(&[&ValueRef::str("[[2001:db8::]:80")]));
780+
kclvm_net_split_host_port(ctx.into_raw(), args, &ValueRef::dict(None));
781+
});
782+
assert_panic("ip_end_point \"[2001:db8::]:]80\" unexpected ']'", || {
783+
let ctx = Context::new();
784+
let args = &ValueRef::list(Some(&[&ValueRef::str("[2001:db8::]:]80")]));
785+
kclvm_net_split_host_port(ctx.into_raw(), args, &ValueRef::dict(None));
786+
});
787+
std::panic::set_hook(prev_hook);
788+
}
789+
790+
#[test]
791+
fn test_join_host_port() {
792+
let cases = [
793+
(ValueRef::none(), ValueRef::none(), ValueRef::none()),
794+
(ValueRef::none(), ValueRef::int(21), ValueRef::none()),
795+
(ValueRef::none(), ValueRef::str("21"), ValueRef::none()),
796+
(
797+
ValueRef::str("invalid.invalid"),
798+
ValueRef::none(),
799+
ValueRef::none(),
800+
),
801+
(
802+
ValueRef::str("invalid.invalid"),
803+
ValueRef::int(21),
804+
ValueRef::str("invalid.invalid:21"),
805+
),
806+
(
807+
ValueRef::str("invalid.invalid"),
808+
ValueRef::str("21"),
809+
ValueRef::str("invalid.invalid:21"),
810+
),
811+
(
812+
ValueRef::str("192.0.2.1"),
813+
ValueRef::int(14),
814+
ValueRef::str("192.0.2.1:14"),
815+
),
816+
(
817+
ValueRef::str("192.0.2.1"),
818+
ValueRef::str("14"),
819+
ValueRef::str("192.0.2.1:14"),
820+
),
821+
(
822+
ValueRef::str("2001:db8::"),
823+
ValueRef::int(14),
824+
ValueRef::str("[2001:db8::]:14"),
825+
),
826+
(
827+
ValueRef::str("2001:db8::"),
828+
ValueRef::str("14"),
829+
ValueRef::str("[2001:db8::]:14"),
830+
),
831+
];
832+
let mut ctx = Context::default();
833+
for (host, port, expected) in cases.iter() {
834+
unsafe {
835+
let actual = &*kclvm_net_join_host_port(
836+
&mut ctx,
837+
&ValueRef::list(Some(&[&host, &port])),
838+
&ValueRef::dict(None),
839+
);
840+
assert_eq!(expected, actual);
841+
}
842+
unsafe {
843+
let actual = &*kclvm_net_join_host_port(
844+
&mut ctx,
845+
&ValueRef::list(None),
846+
&ValueRef::dict(Some(&[("host", host), ("port", port)])),
847+
);
848+
assert_eq!(expected, actual);
849+
}
850+
}
851+
}
852+
853+
#[test]
854+
fn test_join_host_port_invalid() {
855+
let prev_hook = std::panic::take_hook();
856+
// Disable print panic info in stderr.
857+
std::panic::set_hook(Box::new(|_| {}));
858+
assert_panic(
859+
"join_host_port() missing 2 required positional arguments: 'host' and 'port'",
860+
|| {
861+
let mut ctx = Context::new();
862+
let args = ValueRef::list(None).into_raw(&mut ctx);
863+
let kwargs = ValueRef::dict(None).into_raw(&mut ctx);
864+
kclvm_net_join_host_port(ctx.into_raw(), args, kwargs);
865+
},
866+
);
867+
assert_panic(
868+
"join_host_port() missing 2 required positional arguments: 'host' and 'port'",
869+
|| {
870+
let mut ctx = Context::new();
871+
let args =
872+
ValueRef::list(Some(&[&ValueRef::str("invalid.invalid")])).into_raw(&mut ctx);
873+
let kwargs = ValueRef::dict(None).into_raw(&mut ctx);
874+
kclvm_net_join_host_port(ctx.into_raw(), args, kwargs);
875+
},
876+
);
877+
assert_panic(
878+
"join_host_port() missing 2 required positional arguments: 'host' and 'port'",
879+
|| {
880+
let mut ctx = Context::new();
881+
let args = ValueRef::list(None).into_raw(&mut ctx);
882+
let kwargs = ValueRef::dict(Some(&[("host", &ValueRef::str("invalid.invalid"))]))
883+
.into_raw(&mut ctx);
884+
kclvm_net_join_host_port(ctx.into_raw(), args, kwargs);
885+
},
886+
);
887+
assert_panic(
888+
"join_host_port() missing 2 required positional arguments: 'host' and 'port'",
889+
|| {
890+
let mut ctx = Context::new();
891+
let args = ValueRef::list(None).into_raw(&mut ctx);
892+
let kwargs =
893+
ValueRef::dict(Some(&[("port", &ValueRef::str("80"))])).into_raw(&mut ctx);
894+
kclvm_net_join_host_port(ctx.into_raw(), args, kwargs);
895+
},
896+
);
897+
std::panic::set_hook(prev_hook);
898+
}
899+
}

0 commit comments

Comments
 (0)