| 81 | } |
| 82 | |
| 83 | fn parse_dst_info(subdomain: &str) -> Result<DstInfo> { |
| 84 | let mut parts = subdomain.split('-'); |
| 85 | let app_id = parts.next().context("no app id found")?.to_owned(); |
| 86 | if app_id.is_empty() { |
| 87 | bail!("app id is empty"); |
| 88 | } |
| 89 | let last_part = parts.next(); |
| 90 | let is_tls; |
| 91 | let port; |
| 92 | let is_h2; |
| 93 | match last_part { |
| 94 | None => { |
| 95 | is_tls = false; |
| 96 | is_h2 = false; |
| 97 | port = None; |
| 98 | } |
| 99 | Some(last_part) => { |
| 100 | let (port_str, has_g) = match last_part.strip_suffix('g') { |
| 101 | Some(without_g) => (without_g, true), |
| 102 | None => (last_part, false), |
| 103 | }; |
| 104 | |
| 105 | let (port_str, has_s) = match port_str.strip_suffix('s') { |
| 106 | Some(without_s) => (without_s, true), |
| 107 | None => (port_str, false), |
| 108 | }; |
| 109 | if has_g && has_s { |
| 110 | bail!("invalid sni format: `gs` is not allowed"); |
| 111 | } |
| 112 | is_h2 = has_g; |
| 113 | is_tls = has_s; |
| 114 | port = if port_str.is_empty() { |
| 115 | None |
| 116 | } else { |
| 117 | Some(port_str.parse::<u16>().context("invalid port")?) |
| 118 | }; |
| 119 | } |
| 120 | }; |
| 121 | let port = port.unwrap_or(if is_tls { 443 } else { 80 }); |
| 122 | if parts.next().is_some() { |
| 123 | bail!("invalid sni format"); |
| 124 | } |
| 125 | Ok(DstInfo { |
| 126 | app_id, |
| 127 | port, |
| 128 | is_tls, |
| 129 | is_h2, |
| 130 | }) |
| 131 | } |
| 132 | |
| 133 | pub static NUM_CONNECTIONS: AtomicU64 = AtomicU64::new(0); |
| 134 | |