1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117
use super::{Result}; use super::specifier::{Specifier, SpecifierClass, SpecifierStack, SpecifierNode}; use std::rc::Rc; use std::str::FromStr; pub fn spec(s: &str) -> Result<Rc<dyn Specifier>> { Specifier::from_stack(&SpecifierStack::from_str(s)?) } fn some_checks(s: &str) -> Result<()> { #[cfg(not(feature = "ssl"))] { if s.starts_with("wss://") { Err("SSL is not compiled in. Use ws:// or get/make another Websocat build.\nYou can also try to workaround missing SSL by using ws-c:cmd:socat trick (see some ws-c: example)")? } } #[cfg(not(any(target_os = "linux", target_os = "android")))] { if s.starts_with("abstract") { warn!("Abstract-namespaced UNIX sockets are unlikely to be supported here"); } } if s.starts_with("open:") { return Err("There is no `open:` address type. Consider `open-async:` or `readfile:` or `writefile:` or `appendfile:`")?; } #[cfg(not(unix))] { if s.starts_with("unix") || s.starts_with("abstract") { Err("`unix*:` or `abstract*:` are not supported in this Websocat build")? } } #[cfg(not(feature = "tokio-process"))] { if s.starts_with("sh-c:") { Err("`sh-c:` is not supported in this Websocat build")? } else if s.starts_with("exec:") { Err("`exec:` is not supported in this Websocat build")? } } Ok(()) } impl FromStr for SpecifierStack { type Err = Box<dyn (::std::error::Error)>; #[cfg_attr(feature = "cargo-clippy", allow(cyclomatic_complexity))] fn from_str(s: &str) -> Result<SpecifierStack> { some_checks(s)?; let mut s = s.to_string(); let mut overlays = vec![]; let addrtype; let addr; let mut found = false; 'a: loop { macro_rules! my { ($x:expr) => { for pre in $x.get_prefixes() { if s.starts_with(pre) { let rest = &s[pre.len()..].to_string(); if let Some(a) = $x.alias_info() { s = format!("{}{}", a, rest); continue 'a; } else if $x.is_overlay() { let cls = Rc::new($x) as Rc<dyn SpecifierClass>; overlays.push(SpecifierNode{cls}); s = rest.to_string(); continue 'a; } else { addr = rest.to_string(); let cls = Rc::new($x) as Rc<dyn SpecifierClass>; addrtype = SpecifierNode{cls}; #[allow(unused_assignments)] { found = true; } break 'a; } } } }; } list_of_all_specifier_classes!(my); if !found { if let Some(colon) = s.find(':') { Err(format!( "Unknown address or overlay type of `{}:`", &s[..colon] ))?; } else { Err(format!("Unknown address or overlay type of `{}`\nMaybe you forgot the `:` character?", s))?; } } } Ok(SpecifierStack { addr, addrtype, overlays, }) } } impl dyn Specifier { pub fn from_stack(st: &SpecifierStack) -> Result<Rc<dyn Specifier>> { let mut x = st.addrtype.cls.construct(st.addr.as_str())?; for overlay in st.overlays.iter().rev() { x = overlay.cls.construct_overlay(x)?; } Ok(x) } }