source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f7201ee416d124d589a820111ba755930df8b75855321a9a1b87312a0597ec8f"
+[[package]]
+name = "either"
+version = "1.6.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457"
+
[[package]]
name = "env_logger"
version = "0.9.0"
"extend",
"fehler",
"hyper",
+ "itertools",
+ "lazy-regex",
"log",
+ "regex",
"structopt",
"tokio",
"void",
"cfg-if",
]
+[[package]]
+name = "itertools"
+version = "0.10.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "69ddb889f9d0d08a67338271fa9b62996bc788c7796a5c18cf057420aaed5eaf"
+dependencies = [
+ "either",
+]
+
[[package]]
name = "itoa"
version = "0.4.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dd25036021b0de88a0aff6b850051563c6516d0bf53f8638938edbb9de732736"
+[[package]]
+name = "lazy-regex"
+version = "2.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "17d198f91272f6e788a5c0bd5d741cf778da4e5bc761ec67b32d5d3b0db34a54"
+dependencies = [
+ "lazy-regex-proc_macros",
+ "once_cell",
+ "regex",
+]
+
+[[package]]
+name = "lazy-regex-proc_macros"
+version = "2.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6c12938b1b92cf5be22940527e15b79fd0c7e706e34bc70816f6a72b3484f84e"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "regex",
+ "syn",
+]
+
[[package]]
name = "lazy_static"
version = "1.4.0"
pub use std::fmt::Debug;
pub use std::io::{self, ErrorKind, Read as _};
pub use std::mem;
-pub use std::net::IpAddr;
+pub use std::net::{IpAddr, Ipv4Addr};
pub use std::path::{Path, PathBuf};
+pub use std::str::FromStr;
pub use anyhow::{anyhow, Context};
pub use extend::ext;
pub use fehler::{throw, throws};
pub use hyper::Uri;
+pub use itertools::Itertools;
+pub use lazy_regex::regex_is_match;
pub use structopt::StructOpt;
pub use tokio::time::Duration;
pub use void::{self, Void};
use crate::prelude::*;
#[derive(Debug,Clone)]
-struct ServerName(pub String);
+pub struct ServerName(pub String);
#[derive(Debug,Clone,Copy)]
-struct ClientName(pub Ipv4Addr);
+pub struct ClientName(pub Ipv4Addr);
#[derive(Debug,Clone)]
-enum SectionName {
+pub enum SectionName {
Link { server: ServerName, client: ClientName },
Client(ClientName),
Server(ServerName), // includes SERVER, which is slightly special
type Err = AE;
#[throws(AE)]
fn from_str(s: &str) -> Self {
- let v4addr = s.parse().context("invalid client name (IPv4 address)")?;
+ let v4addr: Ipv4Addr = s.parse()
+ .context("invalid client name (IPv4 address)")?;
if s != v4addr.to_string() {
throw!(anyhow!("invalid client name (unusual IPv4 address syntax)"));
}
type Err = AE;
#[throws(AE)]
fn from_str(s: &str) -> Self {
- if let Some(bad) = s.chars.find(|c| !{
- c.is_ascii_alphanumeric() || c=='.' || c=='-'
- }) {
- throw!(anyhow!("invalid server name: bad character {:?}", c));
+ if ! regex_is_match!(r"
+ ^ (?: SERVER
+ | [0-9a-z][-0-9a-z]* (:? \.
+ [0-9a-z][-0-9a-z]* )*
+ )"x, s) {
+ throw!(anyhow!("bad syntax for server name"));
}
- if ! s.split('.').all(
- |d| matches!(d.chars().next(),
- Some(c) if c.is_ascii_alphanumeric() )) {
- throw!(anyhow!("invalid server name: must be valid domain name"));
+ if regex_is_match!(r"[a-z-]", s) {
+ throw!(anyhow!("bad syntax for server name \
+ (too much like an IPv4 address)"));
}
- if s == SERVER
-
- d == "." ||
-
- ClientName(s.parse().context(
- "failed to parse client name (IPv4 address)"
- )?)
+ ServerName(s.into())
}
}
match s {
"COMMON" => return SN::Common,
"DEFAULT" => return SN::Default,
+ _ => { }
};
-
- )) {
- // looks like a domain name or IP address
- if let Ok(v4addr) = s.parse() {
- return SN::Client(ClientName(v4addr))
- } else if (s.chars().any(|c| c==':')) {
- throw!(anyhow!("colons not allowed in section names \
- (IPv6 transport is not supported)"));
- } else {
- return SN::Server(
-
+ if let Ok(n@ ServerName(_)) = s.parse() { return SN::Server(n) }
+ if let Ok(n@ ClientName(_)) = s.parse() { return SN::Client(n) }
+ let (server, client) = s.split_ascii_whitespace().collect_tuple()
+ .ok_or_else(|| anyhow!(
+ "bad section name \
+ (must be COMMON, DEFAULT, <server>, <client>, or <server> <client>"
+ ))?;
+ let server = server.parse().context("server name in link section name")?;
+ let client = client.parse().context("client name in link section name")?;
+ SN::Link { server, client }
}
+}