chiark / gitweb /
wip parsing
authorIan Jackson <ijackson@chiark.greenend.org.uk>
Fri, 23 Jul 2021 21:12:34 +0000 (22:12 +0100)
committerIan Jackson <ijackson@chiark.greenend.org.uk>
Fri, 23 Jul 2021 21:12:34 +0000 (22:12 +0100)
Signed-off-by: Ian Jackson <ijackson@chiark.greenend.org.uk>
Cargo.lock
Cargo.toml
src/lib.rs
src/prelude.rs
src/types.rs

index b3abe388c36080d6f800ce803413beb0f17c441a..e2c8aa2dba82e2252f49633f934d7c1b39abba64 100644 (file)
@@ -82,6 +82,12 @@ version = "2.1.0"
 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"
@@ -195,7 +201,10 @@ dependencies = [
  "extend",
  "fehler",
  "hyper",
+ "itertools",
+ "lazy-regex",
  "log",
+ "regex",
  "structopt",
  "tokio",
  "void",
@@ -272,12 +281,44 @@ dependencies = [
  "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"
index 96415dae1d01a17bd4b8f64c009fccfbc27c36c2..564b8d1b94399e2ab18cded79700b6b1e318e295 100644 (file)
@@ -15,6 +15,9 @@ env_logger = "0.9"
 extend = "1"
 fehler = "1"
 hyper = "0.14"
+itertools = "0.10"
+lazy-regex = "2"
+regex = "1.5"
 log = "0.4"
 structopt = "0.3"
 tokio = { version = "1", features = ["full"] }
index 0667ee978352e61360bba1e66f66c852a6cef948..1f6a3cdb959468d31bf6e5c75d155423739bdaa9 100644 (file)
@@ -7,4 +7,5 @@
 pub mod prelude;
 
 pub mod config;
+pub mod types;
 pub mod utils;
index dbba79a15f29b5e1ad7b0603a52735d98144e77e..b75262774cc43193808b9bd22be3643661b424a9 100644 (file)
@@ -7,13 +7,16 @@ pub use std::fs;
 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};
index fea9f362abdf07b4f7589ad71f2c10d61dd9a069..38fcbfec452ca6678aa97c9733fddf2d338abc31 100644 (file)
@@ -5,13 +5,13 @@
 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
@@ -24,7 +24,8 @@ impl FromStr for ClientName {
   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)"));
     }
@@ -36,23 +37,18 @@ impl FromStr for ServerName {
   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())
   }
 }
 
@@ -63,16 +59,17 @@ impl FromStr for SectionName {
     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 }
   }
+}