Project homepage Mailing List  Warmcat.com  API Docs  Github Mirror 
    npro  
 Modern all-safe Rust Network Protocol library supporting h1, h2, h3, ws, wt sans-IO and with socket IO + tls
git clone https://npro.rs/repo/npro
 
root / crates / npro-test / transcripts / h1-reqline-no-method.json
Author[]Andy Green <andy@warmcat.com> 2026-10-03 09:24 UTC
Committer[]Andy Green <andy@warmcat.com> 2026-10-05 06:32 UTC
Tree836374f4c7b7fcae13fc91fc4a6f53f400177304   Raw Patch
 
npro-test: read the C transcripts, and keep copies of them
npro-test: read the C transcripts, and keep copies of them

C lws' api-test-sansio records each connection it drives through the
sansIO half as an lws-transcript/1 file: the bytes in and out, what the
application was given, and when.  They are the byte-exact specification
npro replays against.  The 48 from C main-dev 75b415f4 are copied into
crates/npro-test/transcripts, along with:
- C-COMMIT, naming the commit they came from;
- README.lws.md, the C README that specifies the format and each
  connection's application.

scripts/sync-c-oracle.sh refreshes them all from a C checkout, so a
change to one is always a change made in C first.

The reader is a strict, non-recursive parser for exactly this format,
not a general JSON parser, so the crate needs no dependency.  It refuses:
- unknown keys and duplicate keys;
- string escapes;
- anything but lowercase hex of whole bytes;
- a step that is not a time and one of rx, tx, app_rx or an empty close;
- step times going backwards;
- numbers past 64 bits;
- more than MAX_STEPS steps or MAX_BYTES of text;
- a file not named for its case.

A seed of 0 reads as None, the connection drawing nothing from lws'
random.  Tests cover each refusal and every truncation of a text.  They
also read every vendored file and check what the C README promises: the
fixed start times, and seeds only on client connections.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019kg5Eemy68ZaqDBcUJQG6J
diff --git a/Cargo.lock b/Cargo.lock index 852c0a8..e86a423 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5,3 +5,7 @@ version = 4 [[package]] name = "npro" version = "0.0.2" + +[[package]] +name = "npro-test" +version = "0.0.2" diff --git a/crates/npro-test/Cargo.toml b/crates/npro-test/Cargo.toml new file mode 100644 index 0000000..8b26318 --- /dev/null +++ b/crates/npro-test/Cargo.toml @@ -0,0 +1,13 @@ +[package] +name = "npro-test" +description = "Test support for npro: the C transcripts and the harness that replays them" +publish = false +version.workspace = true +edition.workspace = true +rust-version.workspace = true +license.workspace = true +homepage.workspace = true +repository.workspace = true + +[lints] +workspace = true diff --git a/crates/npro-test/src/lib.rs b/crates/npro-test/src/lib.rs new file mode 100644 index 0000000..5f2f67c --- /dev/null +++ b/crates/npro-test/src/lib.rs @@ -0,0 +1,14 @@ +//! Test support for npro, not published. +//! +//! C lws records connections driven through its sansIO half as +//! transcripts: the bytes in and out, what the application was given, and +//! when (`minimal-examples-lowlevel/api-tests/api-test-sansio` in the C +//! tree). They are the byte-exact specification npro is checked against. +//! This crate reads them; copies of them, with where they came from, are in +//! this crate's `transcripts/` directory. + +#![forbid(unsafe_code)] + +mod transcript; + +pub use transcript::{Error, MAX_BYTES, MAX_STEPS, Side, Step, StepKind, Transcript, vendored}; diff --git a/crates/npro-test/src/transcript.rs b/crates/npro-test/src/transcript.rs new file mode 100644 index 0000000..a23d527 --- /dev/null +++ b/crates/npro-test/src/transcript.rs @@ -0,0 +1,644 @@ +//! The `lws-transcript/1` format, as C lws' `api-test-sansio` writes it. +//! +//! A transcript is one JSON object: the format, the connection's name, which +//! side lws was on, the time the run started, the seed of lws' random, and +//! the steps. Each step is a time and one of: bytes the peer sent (`rx`), +//! bytes lws wrote (`tx`), a payload lws gave the application (`app_rx`), or +//! lws releasing the transport (`close`). The C tree's +//! `transcripts/README.md`, copied beside the transcripts here, is the +//! specification. +//! +//! The reader takes that format and nothing else: only the keys it defines, +//! each once; lowercase hex; no string escapes; no recursion. Anything else +//! is a new format version, and refused. + +use std::{ + fmt, fs, io, + num::NonZeroU64, + path::{Path, PathBuf}, +}; + +/// The one format version this reader takes. +const FORMAT: &str = "lws-transcript/1"; + +/// The largest transcript file read, in bytes. +pub const MAX_BYTES: usize = 1 << 20; + +/// The most steps one transcript may have. +pub const MAX_STEPS: usize = 4096; + +/// Which side of the connection lws was on. +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub enum Side { + /// The peer connected to lws. + Server, + /// lws connected to the peer. + Client, +} + +/// What happened at one step. +#[derive(Clone, Debug, PartialEq, Eq)] +pub enum StepKind { + /// The peer sent these bytes, handed to lws at the step's time. + Rx(Vec<u8>), + /// lws wrote these bytes. How many writes it took is not behaviour. + Tx(Vec<u8>), + /// lws gave the application this payload: a response body, or a ws + /// message's payload. How a payload is split into deliveries is not + /// behaviour, only the concatenation of each message or body. + AppRx(Vec<u8>), + /// lws released the connection's transport. + Close, +} + +/// One step of a transcript. +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct Step { + /// When, in microseconds after the run's start, `t0_us`. + pub t_us: u64, + /// What happened. + pub kind: StepKind, +} + +/// One connection's life, as recorded by C lws. +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct Transcript { + /// The connection's name, which is also its file's. + pub case: String, + /// Which side lws was on. + pub side: Side, + /// The monotonic time when the run starts, in microseconds. + pub t0_us: u64, + /// The wall time at `t0_us`, in seconds since 1970. + pub t0_wall: u64, + /// The seed of lws' random, reseeded when this connection starts; `None` + /// when nothing in its bytes depends on lws' random. + pub seed: Option<NonZeroU64>, + /// What happened, in order. Step times never go backwards. + pub steps: Vec<Step>, +} + +/// Why a transcript could not be read. +#[derive(Debug)] +pub enum Error { + /// The file could not be read. + Io(io::Error), + /// The file is larger than [`MAX_BYTES`]. + TooLarge, + /// The text is not the JSON this format allows at this byte offset. + Syntax { + /// Byte offset of the problem. + offset: usize, + /// What was expected there. + expected: &'static str, + }, + /// `format` names a version other than `lws-transcript/1`. + UnknownFormat, + /// A key the format does not define, at this byte offset. + UnknownKey { + /// Byte offset of the key. + offset: usize, + }, + /// A key given twice. + DuplicateKey(&'static str), + /// A key the format requires is missing. + MissingKey(&'static str), + /// `side` is neither `server` nor `client`. + BadSide { + /// Byte offset of the value. + offset: usize, + }, + /// A payload that is not lowercase hex of whole bytes. + BadHex { + /// Byte offset of the value. + offset: usize, + }, + /// A step that is not a time and exactly one of `rx`, `tx`, `app_rx` or + /// an empty `close`. + BadStep { + /// Byte offset of the step. + offset: usize, + }, + /// A number too large for 64 bits. + Overflow { + /// Byte offset of the number. + offset: usize, + }, + /// More than [`MAX_STEPS`] steps. + TooManySteps, + /// A step earlier than the one before it. + TimeGoesBackwards { + /// Index of the step. + step: usize, + }, + /// The file's name is not its `case`. + CaseMismatch, +} + +impl fmt::Display for Error { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Self::Io(e) => write!(f, "cannot read transcript: {e}"), + Self::TooLarge => write!(f, "transcript larger than {MAX_BYTES} bytes"), + Self::Syntax { offset, expected } => { + write!(f, "at byte {offset}: expected {expected}") + } + Self::UnknownFormat => write!(f, "format is not {FORMAT}"), + Self::UnknownKey { offset } => write!(f, "at byte {offset}: unknown key"), + Self::DuplicateKey(k) => write!(f, "key \"{k}\" given twice"), + Self::MissingKey(k) => write!(f, "key \"{k}\" missing"), + Self::BadSide { offset } => { + write!(f, "at byte {offset}: side is not server or client") + } + Self::BadHex { offset } => { + write!(f, "at byte {offset}: not lowercase hex of whole bytes") + } + Self::BadStep { offset } => write!( + f, + "at byte {offset}: a step is a time and one of rx, tx, app_rx or an empty close" + ), + Self::Overflow { offset } => write!(f, "at byte {offset}: number too large"), + Self::TooManySteps => write!(f, "more than {MAX_STEPS} steps"), + Self::TimeGoesBackwards { step } => write!(f, "step {step} goes back in time"), + Self::CaseMismatch => write!(f, "file name is not the transcript's case"), + } + } +} + +impl std::error::Error for Error { + fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { + match self { + Self::Io(e) => Some(e), + _ => None, + } + } +} + +impl From<io::Error> for Error { + fn from(e: io::Error) -> Self { + Self::Io(e) + } +} + +impl Transcript { + /// Reads a transcript from its text. + /// + /// ``` + /// use npro_test::{Side, StepKind, Transcript}; + /// + /// let t = Transcript::parse(br#"{ + /// "format": "lws-transcript/1", "case": "x", "side": "client", + /// "t0_us": 1000000000, "t0_wall": 1767225600, "seed": 0, + /// "steps": [ {"t": 1000, "tx": "4745"}, {"t": 2000, "close": ""} ] + /// }"#)?; + /// + /// assert_eq!(t.side, Side::Client); + /// assert_eq!(t.steps[0].kind, StepKind::Tx(b"GE".to_vec())); + /// assert_eq!(t.steps[1].kind, StepKind::Close); + /// # Ok::<(), npro_test::Error>(()) + /// ``` + /// + /// # Errors + /// + /// Any departure from the format: see [`Error`]. + pub fn parse(text: &[u8]) -> Result<Self, Error> { + if text.len() > MAX_BYTES { + return Err(Error::TooLarge); + } + + let mut c = Cursor { b: text, pos: 0 }; + let mut format = None; + let mut case = None; + let mut side = None; + let mut t0_us = None; + let mut t0_wall = None; + let mut seed = None; + let mut steps = None; + + c.members(|c, key, at| match key { + "format" => once(&mut format, "format", c.string()?), + "case" => once(&mut case, "case", c.string()?), + "side" => { + let at = c.value_offset(); + let s = match c.string()? { + "server" => Side::Server, + "client" => Side::Client, + _ => return Err(Error::BadSide { offset: at }), + }; + once(&mut side, "side", s) + } + "t0_us" => once(&mut t0_us, "t0_us", c.uint()?), + "t0_wall" => once(&mut t0_wall, "t0_wall", c.uint()?), + "seed" => once(&mut seed, "seed", c.uint()?), + "steps" => once(&mut steps, "steps", c.steps()?), + _ => Err(Error::UnknownKey { offset: at }), + })?; + + c.ws(); + if c.peek().is_some() { + return Err(c.syntax("the end of the text")); + } + + if format.ok_or(Error::MissingKey("format"))? != FORMAT { + return Err(Error::UnknownFormat); + } + + let steps: Vec<Step> = steps.ok_or(Error::MissingKey("steps"))?; + let mut last = 0; + for (i, s) in steps.iter().enumerate() { + if s.t_us < last { + return Err(Error::TimeGoesBackwards { step: i }); + } + last = s.t_us; + } + + Ok(Self { + case: case.ok_or(Error::MissingKey("case"))?.to_owned(), + side: side.ok_or(Error::MissingKey("side"))?, + t0_us: t0_us.ok_or(Error::MissingKey("t0_us"))?, + t0_wall: t0_wall.ok_or(Error::MissingKey("t0_wall"))?, + seed: NonZeroU64::new(seed.ok_or(Error::MissingKey("seed"))?), + steps, + }) + } + + /// Reads a transcript file, whose name must be its case. + /// + /// # Errors + /// + /// The file cannot be read, is larger than [`MAX_BYTES`], is not the + /// format, or is not named for its case. + pub fn read(path: &Path) -> Result<Self, Error> { + let max = u64::try_from(MAX_BYTES).map_err(|_| Error::TooLarge)?; + if fs::metadata(path)?.len() > max { + return Err(Error::TooLarge); + } + + let t = Self::parse(&fs::read(path)?)?; + if path.file_stem().and_then(|s| s.to_str()) != Some(t.case.as_str()) { + return Err(Error::CaseMismatch); + } + + Ok(t) + } +} + +/// The transcripts copied into this crate from the C tree, sorted by case. +/// +/// # Errors +/// +/// The directory cannot be listed, or any `.json` file in it cannot be read +/// as a transcript. +pub fn vendored() -> Result<Vec<Transcript>, Error> { + let dir = Path::new(env!("CARGO_MANIFEST_DIR")).join("transcripts"); + let mut paths: Vec<PathBuf> = fs::read_dir(dir)? + .map(|e| e.map(|e| e.path())) + .collect::<Result<_, _>>()?; + paths.retain(|p| p.extension().is_some_and(|x| x == "json")); + paths.sort(); + + paths.iter().map(|p| Transcript::read(p)).collect() +} + +/// Sets a key's value, refusing a second one. +fn once<T>(slot: &mut Option<T>, key: &'static str, v: T) -> Result<(), Error> { + if slot.replace(v).is_some() { + return Err(Error::DuplicateKey(key)); + } + Ok(()) +} + +/// The digits of lowercase hex, in order of value. +const HEX: &[u8; 16] = b"0123456789abcdef"; + +/// The value of one lowercase hex digit. +fn nibble(c: u8) -> Option<u8> { + HEX.iter() + .position(|&d| d == c) + .and_then(|n| u8::try_from(n).ok()) +} + +/// Decodes lowercase hex of whole bytes. +fn hex(s: &str) -> Option<Vec<u8>> { + let pairs = s.as_bytes().chunks_exact(2); + if !pairs.remainder().is_empty() { + return None; + } + + pairs + .map(|p| match p { + [hi, lo] => Some(nibble(*hi)?.checked_shl(4)? | nibble(*lo)?), + _ => None, + }) + .collect() +} + +/// A position in the text being read. +struct Cursor<'a> { + b: &'a [u8], + pos: usize, +} + +impl<'a> Cursor<'a> { + fn peek(&self) -> Option<u8> { + self.b.get(self.pos).copied() + } + + fn bump(&mut self) { + self.pos = self.pos.saturating_add(1); + } + + fn syntax(&self, expected: &'static str) -> Error { + Error::Syntax { + offset: self.pos, + expected, + } + } + + /// Skips JSON whitespace. + fn ws(&mut self) { + while matches!(self.peek(), Some(b' ' | b'\t' | b'\n' | b'\r')) { + self.bump(); + } + } + + /// The offset of the next value, after any whitespace. + fn value_offset(&mut self) -> usize { + self.ws(); + self.pos + } + + fn eat(&mut self, c: u8, expected: &'static str) -> Result<(), Error> { + self.ws(); + if self.peek() != Some(c) { + return Err(self.syntax(expected)); + } + self.bump(); + Ok(()) + } + + /// A string with no escapes and no control characters. + fn string(&mut self) -> Result<&'a str, Error> { + self.eat(b'"', "a string")?; + let start = self.pos; + loop { + match self.peek() { + None => return Err(self.syntax("the end of the string")), + Some(b'"') => break, + Some(b'\\') => return Err(self.syntax("a string with no escapes")), + Some(c) if c < 0x20 => return Err(self.syntax("no control characters")), + Some(_) => self.bump(), + } + } + let s = self + .b + .get(start..self.pos) + .ok_or_else(|| self.syntax("a string"))?; + self.bump(); + std::str::from_utf8(s).map_err(|_| Error::Syntax { + offset: start, + expected: "UTF-8", + }) + } + + /// An unsigned integer that fits 64 bits. + fn uint(&mut self) -> Result<u64, Error> { + self.ws(); + let start = self.pos; + let mut v: u64 = 0; + while let Some(d) = self.peek().and_then(|c| char::from(c).to_digit(10)) { + v = v + .checked_mul(10) + .and_then(|v| v.checked_add(u64::from(d))) + .ok_or(Error::Overflow { offset: start })?; + self.bump(); + } + if self.pos == start { + return Err(self.syntax("a number")); + } + Ok(v) + } + + /// An object: each member's key and the key's offset are handed to + /// `member`, which must read the value. + fn members( + &mut self, + mut member: impl FnMut(&mut Self, &'a str, usize) -> Result<(), Error>, + ) -> Result<(), Error> { + self.eat(b'{', "{")?; + self.ws(); + if self.peek() == Some(b'}') { + self.bump(); + return Ok(()); + } + loop { + let at = self.value_offset(); + let key = self.string()?; + self.eat(b':', ":")?; + member(self, key, at)?; + self.ws(); + match self.peek() { + Some(b',') => self.bump(), + Some(b'}') => { + self.bump(); + return Ok(()); + } + _ => return Err(self.syntax(", or }")), + } + } + } + + /// The array of steps. + fn steps(&mut self) -> Result<Vec<Step>, Error> { + let mut steps = Vec::new(); + self.eat(b'[', "[")?; + self.ws(); + if self.peek() == Some(b']') { + self.bump(); + return Ok(steps); + } + loop { + if steps.len() >= MAX_STEPS { + return Err(Error::TooManySteps); + } + steps.push(self.step()?); + self.ws(); + match self.peek() { + Some(b',') => self.bump(), + Some(b']') => { + self.bump(); + return Ok(steps); + } + _ => return Err(self.syntax(", or ]")), + } + } + } + + /// One step: a time and exactly one thing that happened. + fn step(&mut self) -> Result<Step, Error> { + let start = self.value_offset(); + let mut t_us = None; + let mut kind = None; + + self.members(|c, key, at| { + if key == "t" { + return once(&mut t_us, "t", c.uint()?); + } + + let v_at = c.value_offset(); + let k = match key { + "rx" | "tx" | "app_rx" => { + let bytes = hex(c.string()?).ok_or(Error::BadHex { offset: v_at })?; + match key { + "rx" => StepKind::Rx(bytes), + "tx" => StepKind::Tx(bytes), + _ => StepKind::AppRx(bytes), + } + } + "close" if c.string()?.is_empty() => StepKind::Close, + "close" => return Err(Error::BadStep { offset: start }), + _ => return Err(Error::UnknownKey { offset: at }), + }; + if kind.replace(k).is_some() { + return Err(Error::BadStep { offset: start }); + } + Ok(()) + })?; + + Ok(Step { + t_us: t_us.ok_or(Error::MissingKey("t"))?, + kind: kind.ok_or(Error::BadStep { offset: start })?, + }) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + const HEAD: &str = r#""format": "lws-transcript/1", "case": "c", "side": "server", + "t0_us": 1000000000, "t0_wall": 1767225600, "seed": 0"#; + + fn with_steps(steps: &str) -> String { + format!("{{ {HEAD}, \"steps\": [ {steps} ] }}") + } + + #[test] + fn reads_every_kind_of_step() { + let t = Transcript::parse( + with_steps( + r#"{"t": 1, "rx": "00ff"}, {"t": 1, "tx": ""}, + {"t": 2, "app_rx": "41"}, {"t": 3, "close": ""}"#, + ) + .as_bytes(), + ) + .unwrap(); + + assert_eq!(t.case, "c"); + assert_eq!(t.side, Side::Server); + assert_eq!(t.seed, None); + let kinds: Vec<_> = t.steps.into_iter().map(|s| s.kind).collect(); + assert_eq!( + kinds, + [ + StepKind::Rx(vec![0, 0xff]), + StepKind::Tx(vec![]), + StepKind::AppRx(b"A".to_vec()), + StepKind::Close + ] + ); + } + + #[test] + fn a_nonzero_seed_is_kept() { + let t = Transcript::parse( + with_steps("") + .replace("\"seed\": 0", "\"seed\": 1") + .as_bytes(), + ) + .unwrap(); + assert_eq!(t.seed, NonZeroU64::new(1)); + } + + fn refused(text: &str) -> Error { + Transcript::parse(text.as_bytes()).unwrap_err() + } + + #[test] + fn refuses_what_the_format_does_not_define() { + assert!(matches!( + refused(&with_steps("").replace("/1", "/2")), + Error::UnknownFormat + )); + assert!(matches!( + refused(&with_steps("").replace("\"server\"", "\"peer\"")), + Error::BadSide { .. } + )); + assert!(matches!( + refused(&with_steps("").replace("\"seed\"", "\"sneed\"")), + Error::UnknownKey { .. } + )); + assert!(matches!( + refused(&with_steps("").replace(", \"seed\": 0", "")), + Error::MissingKey("seed") + )); + assert!(matches!( + refused(&with_steps("").replace("\"seed\": 0", "\"seed\": 0, \"seed\": 1")), + Error::DuplicateKey("seed") + )); + assert!(matches!( + refused(&format!("{} x", with_steps(""))), + Error::Syntax { .. } + )); + } + + #[test] + fn refuses_bad_steps() { + for (steps, why) in [ + (r#"{"t": 1, "rx": "0"}"#, "odd hex"), + (r#"{"t": 1, "rx": "0A"}"#, "uppercase hex"), + (r#"{"t": 1, "rx": "0g"}"#, "not hex"), + (r#"{"t": 1, "close": "00"}"#, "a close with a payload"), + (r#"{"t": 1, "rx": "00", "tx": "00"}"#, "two kinds"), + (r#"{"t": 1}"#, "no kind"), + (r#"{"rx": "00"}"#, "no time"), + (r#"{"t": 1, "rx": "a\"b"}"#, "an escape"), + ( + r#"{"t": 2, "rx": ""}, {"t": 1, "rx": ""}"#, + "time going back", + ), + ( + r#"{"t": 18446744073709551616, "rx": ""}"#, + "a time past 64 bits", + ), + (r#"{"t": 1, "rx": ""},"#, "a trailing comma"), + ] { + assert!( + Transcript::parse(with_steps(steps).as_bytes()).is_err(), + "accepted {why}" + ); + } + } + + #[test] + fn refuses_too_many_steps_and_too_much_text() { + let many = vec![r#"{"t": 0, "rx": ""}"#; MAX_STEPS + 1].join(","); + assert!(matches!(refused(&with_steps(&many)), Error::TooManySteps)); + + let big = vec![b' '; MAX_BYTES + 1]; + assert!(matches!(Transcript::parse(&big), Err(Error::TooLarge))); + } + + #[test] + fn refuses_a_truncated_text() { + // a text cut anywhere must be refused, never read as a shorter one + let text = with_steps(r#"{"t": 1, "rx": "00ff"}, {"t": 2, "close": ""}"#); + for n in 0..text.len() { + assert!( + Transcript::parse(text.as_bytes().get(..n).unwrap()).is_err(), + "accepted a text cut at {n}" + ); + } + assert!(Transcript::parse(text.as_bytes()).is_ok()); + } +} diff --git a/crates/npro-test/tests/vendored.rs b/crates/npro-test/tests/vendored.rs new file mode 100644 index 0000000..2cd4b2d --- /dev/null +++ b/crates/npro-test/tests/vendored.rs @@ -0,0 +1,53 @@ +//! Every transcript copied from C reads, and says what its README says. + +use npro_test::{Side, StepKind, vendored}; + +#[test] +fn every_vendored_transcript_reads() { + let all = vendored().unwrap(); + + // as many as the sync copied: a file that failed to read would have + // failed vendored() itself, so this catches a sync that copied none + let files = std::fs::read_dir(concat!(env!("CARGO_MANIFEST_DIR"), "/transcripts")) + .unwrap() + .filter(|e| { + e.as_ref() + .unwrap() + .path() + .extension() + .is_some_and(|x| x == "json") + }) + .count(); + assert!(files > 0); + assert_eq!(all.len(), files); + + for t in &all { + // the harness starts every run at the same times + assert_eq!(t.t0_us, 1_000_000_000, "{}", t.case); + assert_eq!(t.t0_wall, 1_767_225_600, "{}", t.case); + + // only a client draws lws' random in what these record: its ws key + // and its masks + if t.seed.is_some() { + assert_eq!(t.side, Side::Client, "{} is seeded", t.case); + } + + // a connection with no bytes either way records nothing + assert!( + t.steps + .iter() + .any(|s| matches!(s.kind, StepKind::Rx(_) | StepKind::Tx(_))), + "{} moves no bytes", + t.case + ); + } +} + +#[test] +fn the_c_commit_is_recorded() { + let c = std::fs::read_to_string(concat!(env!("CARGO_MANIFEST_DIR"), "/transcripts/C-COMMIT")) + .unwrap(); + let hash = c.split_whitespace().next().unwrap(); + assert_eq!(hash.len(), 40); + assert!(hash.bytes().all(|b| b.is_ascii_hexdigit())); +} diff --git a/crates/npro-test/transcripts/C-COMMIT b/crates/npro-test/transcripts/C-COMMIT new file mode 100644 index 0000000..27ce8ae --- /dev/null +++ b/crates/npro-test/transcripts/C-COMMIT @@ -0,0 +1 @@ +75b415f4afd5b542badbbf87b6ffec56f3cf3cfc api-test-ws-pmd-takeover: xorshift masks what each left shift would discard diff --git a/crates/npro-test/transcripts/README.lws.md b/crates/npro-test/transcripts/README.lws.md new file mode 100644 index 0000000..b5da82b --- /dev/null +++ b/crates/npro-test/transcripts/README.lws.md @@ -0,0 +1,122 @@ +# lws sansIO transcripts + +Each file here is one connection's life as data: the times, the bytes its +peer sent, the bytes lws wrote, what lws gave the application, and its +close. `api-test-sansio` produces them by driving lws' protocol half with +no socket and no clock of its own (READMEs/README.sans-io-split.md, "Time"), +and checks, in every build that runs it, that what lws does now is still +what is recorded here. They are also the specification a port of the +sansIO half is checked against: fed the same bytes at the same times, with +the same application, it must write the same bytes and deliver the same +payloads. + +## Format + +``` +{ + "format": "lws-transcript/1", + "case": "h1-ws-server", + "side": "server", + "t0_us": 1000000000, + "t0_wall": 1767225600, + "seed": 0, + "steps": [ + {"t": 1000, "rx": "474554..."}, + {"t": 1000, "tx": "485454..."}, + ... + ] +} +``` + +|member|meaning| +|---|---| +|`format`|`lws-transcript/1`. A change to what follows is a new version| +|`case`|the connection's name, and the file's| +|`side`|`server`: the peer connected to lws. `client`: lws connected to the peer| +|`t0_us`|the monotonic time, in microseconds, when the run starts: every step's `t` is after it| +|`t0_wall`|the wall time, seconds since 1970, at `t0_us`. The wall time moves with the monotonic time| +|`seed`|0: nothing in the connection's bytes depends on lws' random. Otherwise lws' random is the xoshiro256** stream seeded with it (`lws_fi_random_seed()`), see "Random" below| +|`steps`|what happened, in order| + +Each step has `t`, microseconds since `t0_us`, and one of: + +|kind|meaning| +|---|---| +|`rx`|the peer sent these bytes, and they are handed to lws at `t`| +|`tx`|lws wrote these bytes to the peer at `t`. Bytes written in several writes at the same time are one step: how many writes it took is not part of the behaviour| +|`app_rx`|lws delivered this payload to the application: a response body, or a ws message's payload. How a message or a body was split into deliveries follows how much lws was handed at a time, and is not behaviour: what a replay must match is the concatenation of the `app_rx` steps of each ws message, and of each response body, and where each of those ends relative to the other steps| +|`close`|lws released the connection's transport. The value is empty| + +Bytes are lowercase hex. A replay hands lws each `rx` at its `t`, telling +it the time first, and runs anything that falls due at a `t` before what +happens then. The `tx`, `app_rx` and `close` steps are what it must see, +in order, at their times. + +## Random + +A connection whose bytes depend on lws' random (a ws client's +`Sec-WebSocket-Key` and its frame masks) has a nonzero `seed`, and the +peer's side of it depends on those bytes too: the 101 response carries the +accept value of the key the client chose. Such a transcript reproduces only +when the random is the seeded stream drawn in the same order. The stream +starts afresh from `seed` when the connection does, so what it draws does not +depend on the connections before it, or on which of them a build has. So: + + - `api-test-sansio` records and checks it only in a build with fault + injection (`LWS_WITH_SYS_FAULT_INJECTION`), which can seed lws' random, + and says so in other builds; + - a port either draws the same bytes from the same stream in the same order + (xoshiro256** seeded by splitmix64, each 64-bit result little-endian, + the vector in `api-test-random-prng`), or its replay treats the drawn + values as free, taking them from its own `tx` and checking what follows + from them (the accept value, the masking) instead of the bytes. + +The tls library's own random, inside its handshakes, is not lws' and is not +covered: no transcript here is under tls yet. + +## The connections and their applications + +A replay needs the same application on lws' side. In each connection it +does only this: + +|case|side|the application| +|---|---|---| +|`h1-ws-server`|server|one vhost with protocols `http` and `echo`. `http`: answers any request 200, `text/plain`, content length 10, body `sansio ok\n`, then completes the transaction (the connection is kept). `echo`: sends each ws message that came in one frame back, as text; it sends nothing for a fragmented one. The peer does an h1 GET, then a ws upgrade to `echo` on the same connection, then sends the masked text frame `Hello` of RFC 6455 5.7| +|`h1-client-get`|client|connects to `sansio`, port 80, h1, `GET /x`, and pulls the response body as it comes| +|`h1-client-cl-junk`, `h1-client-cl-twice`, `h1-client-te-list`|client|as `h1-client-get`. The peer answers 200 with `Content-Length: 10abc`; with `Content-Length: 10` and a second `Content-Length: 5`; or with `Transfer-Encoding: chunked` and a second `Transfer-Encoding: gzip`, which makes the codings a list. lws cannot know where such a body ends: it gives the app none of it, fails the connection and releases it| +|`h1-client-head-chunked`, `h1-client-head-cl`, `h1-client-304-cl`|client|as `h1-client-get`, asking with `HEAD` for the first two. The peer answers 200 with `Transfer-Encoding: chunked`; 200 with `Content-Length: 10`; or, to the `GET`, 304 with `Content-Length: 10`. None of these has a body (RFC 9112 6.3): lws completes the transaction at the end of the headers and gives the app nothing| +|`ws-client`|client|connects to `sansio`, port 80, `GET /echo`, ws subprotocol `echo`; once established, sends one text message `Hello`, and takes the messages it receives| +|`ws-server-version-8`, `ws-server-no-version`, `ws-server-conn-no-upgrade`, `ws-server-no-subprotocol`|server|as `h1-ws-server`. The peer asks for a ws upgrade saying `Sec-WebSocket-Version: 8`; or no version at all; or `Connection: up`, which is not the `upgrade` token; or only the subprotocol `chat`, which the vhost does not have. lws answers the first with 426 and `sec-websocket-version: 13`, the others with 400, each with the usual status page, then shuts the connection down (a half-close, waiting for the peer's; no `close` step follows)| +|`ws-client-rsv1-no-ext`, `ws-client-rsv2`, `ws-client-huge-frame`|client|as `ws-client`, no extension offered. After the 101, the peer sends a frame with RSV1, with RSV2, or whose length is 256MiB + 1: lws gives the app nothing of it and sends a close, status 1002 `rsv bits` for the RSV ones and 1009 `huge frame` for the length; the peer answers the close and lws releases the connection| +|`ws-client-ping-close`|client|as `ws-client`, sending nothing once established. The peer sends a ping `p` and then a close with status 1000 in one read: lws sends the masked pong, then the masked answer to the close with the peer's 1000, and releases the connection| +|`ws-client-interim`|client|as `ws-client`. The peer answers the upgrade with an interim `100 Continue`, then in the same read the 101: lws skips the interim response, goes on waiting, and is established by the 101| +|`ws-client-pmd-rsv2`, `ws-client-pmd-rsv1-continuation`, `ws-client-pmd-rsv1-ping`|client|as `ws-client`, on a vhost offering `permessage-deflate` (no parameters), sending nothing once established, and the peer's 101 accepts `permessage-deflate`. The peer then sends a frame with RSV2; or an uncompressed, unfinished text frame `He` (given to the app) and then a continuation with RSV1; or a ping with RSV1. As above, lws fails the connection, with 1002 `rsv bits`| +|`h1-uri-dotdot-args`, `h1-uri-dot-args`, `h1-uri-plus`, `h1-uri-at-limit`|server|a third vhost, `sansio-uri`, whose only protocol, `http`, answers any request 200, `text/plain`, with the path lws decoded, a newline, then the args, and completes the transaction. The context limits the request URI to 33 bytes and `User-Agent` to 16 (`token_limits`). The peer asks for `/x/..?a=b` (path `/`, args `a=b`), `/x/.?a=b` (path `/x/`), `/a+b?c+d=e+f` (path `/a+b`, args `c d=e f`: `+` is only a space in the args) and a 33-byte path, which is served whole| +|`h1-uri-past-limit`, `h1-header-past-limit`|server|as above. The peer asks for a 34-byte path, or sends a 17-byte `User-Agent`: rather than serving the request with the value cut short, lws answers 414, or 431, with the usual status page saying `Oversized request URI` or `Oversized headers`, and shuts the connection down| +|`h1-reqline-http09`, `h1-reqline-no-method`, `h1-reqline-version-2`, `h1-reqline-version-junk`, `h1-reqline-version-long`|server|as above. The peer sends a request line with no version, `GET /x` (HTTP/0.9); a head with no request line, only `Host: sansio-uri`; or asks for `/x` as `HTTP/2.0`, `HTTP/1.x` or `HTTP/1.10`. A request line is method, target and `HTTP/` digit `.` digit: lws answers 400 with the usual status page, except 505 for the major version it does not speak, and shuts the connection down| +|`h1-reqline-unknown-method`, `h1-reqline-unknown-header-first`|server|as above. The peer asks for `/x` with the method `FOO`, which lws does not implement: 501 (RFC 9110 9.1); or starts its head with `X-Foo: bar`, a header lws does not know, rather than a request line: 400. Either way with the usual status page, and the connection is shut down| +|`h1-reqline-leading-empty`, `h1-reqline-leading-empty-many`|server|as above. The peer sends two empty lines, then its request for `/x`: they are ignored (RFC 9112 2.2) and it is served; or nine: past eight, no request is coming, and lws answers 400 and shuts the connection down| +|`h1-reqline-version-1-2`|server|as above. The peer asks for `/x` as `HTTP/1.2`: a later minor version is served as the highest lws speaks, and the response says `HTTP/1.1`| +|`h2-oversized-headers`|server|a fourth vhost, `sansio-h2`, taking h2 with prior knowledge, whose only protocol is the `http` of `sansio-uri`. The peer sends the preface, an empty SETTINGS and the ack of the server's, then three GET / requests. sid 1: `:authority` entered in the dynamic table, then a 3000 byte user-agent and a 2000 byte referer, not indexed, that the 4096 byte ah cannot hold, then `accept: x` entered in the dynamic table after it filled: answered 431 `Oversized headers`, the connection kept. sid 3: `:authority` and `accept` from the dynamic table: `accept` could not be kept, so it is answered 431 too, rather than served as if the peer had not sent it. sid 5: only `:authority` from the dynamic table, which was kept: served| +|`h1-404-keepalive`|server|a fifth vhost, `sansio-404`, whose 404 document is `/404.html`. `/cb` is mounted on its only protocol, `http`; everything else is a file mount on a directory that does not exist, falling back to `http` for what it cannot open. `http` answers whatever reaches it with `lws_return_http_status()` 404, then completes the transaction. On one kept-alive connection the peer asks for `/x`: lws redirects it to the 404 document with a 302; then for `/404.html`, which is not there either: the 404 status page; then for `/cb/y`: redirected with a 302 again, as `/x` was| +|`ws-server-ping-close`, `ws-server-close-partial`|server|as `h1-ws-server`: after the upgrade, the peer sends, masked, in one read, a ping `p` and then a close with status 1000; or a text frame `Hello` and then the close, while the connection takes at most 4 bytes a write. lws answers the ping with its pong before it answers the close, with the peer's own 1000; the echo of `Hello`, left partly unwritten, goes out whole before the answer to the close, rather than the connection being dropped. After its answer lws reads nothing more, and shuts the connection down| +|`ws-server-huge-frame`|server|as `h1-ws-server`: after the upgrade, the peer sends a masked frame whose length is 256MiB + 1. lws closes with status 1009, `huge frame`| +|`ws-server-pmd-rsv1-continuation`|server|as `h1-ws-server`, on a second vhost, `sansio-pmd`, with `permessage-deflate` (no parameters). The peer asks for a ws upgrade to it offering `permessage-deflate`, which is accepted, then sends an unfinished text frame `He` and a continuation with RSV1: lws closes with status 1002, `rsv bits`, and once the peer answers the close, shuts the connection down| +|`h2-ws-peer-close`|server|a sixth vhost, `sansio-h2ws`, taking h2 with prior knowledge, with the ws protocols of `sansio`. The peer sends the preface and SETTINGS, then an extended CONNECT (RFC 8441) for a ws stream on sid 1 speaking `echo`, which is accepted with 200; then one DATA frame holding, masked, a close with status 1000 and after it a ping `p`. lws answers the close with the peer's own 1000 and END_STREAM, reads nothing after it, so the ping gets no pong, and resets the stream with NO_ERROR, since the peer has not ended its side: not REFUSED_STREAM, which is only for a refused upgrade| +|`h1-post-no-length`|server|as `h1-uri-*`, on `sansio-uri`. The peer sends, in one read, `POST /x?a=1` with neither `Content-Length` nor `Transfer-Encoding`, and behind its head `GET /y?b=2`. The POST has no body (RFC 9112 6.3): lws answers it (path `/x`, args `a=1`), then serves the GET as the next request on the kept-alive connection, rather than taking it as the POST's body and reading until the close| +|`h1-connect-rejected-ua`|server|as `h1-reqline-*`, on `sansio-uri`, in a context that turns away a user agent containing `badbot` with `403 Go away`. The peer sends a CONNECT for `example.com:443` saying it is `badbot/1`: it is refused like any other request of its, 403 with the status page, and the connection shut down, rather than handed to the fallback role first| + +## Recording + +``` + $ ./bin/lws-api-test-sansio --record ../minimal-examples-lowlevel/api-tests/api-test-sansio/transcripts +``` + +from a build with fault injection, so the seeded connections are recorded +too. ctest runs `lws-api-test-sansio --transcripts transcripts` in this +directory's parent, which fails if what lws does differs from what is here, +and says at which line. + +A transcript is behaviour: a change to one is a change to what lws puts on +the wire, and the commit making it says why. A new case adds a file here, +its row above, and its connection's application to the test. diff --git a/crates/npro-test/transcripts/README.md b/crates/npro-test/transcripts/README.md new file mode 100644 index 0000000..f580618 --- /dev/null +++ b/crates/npro-test/transcripts/README.md @@ -0,0 +1,12 @@ +# Transcripts from C lws + +These files are copies of the transcripts C lws' `api-test-sansio` records +and checks itself against +(`minimal-examples-lowlevel/api-tests/api-test-sansio/transcripts` in the +C tree). `C-COMMIT` names the C commit they were taken from. +`README.lws.md` is that directory's README, which specifies the format and +the application each connection needs on lws' side. + +They are behaviour, not fixtures. Do not edit them here: refresh them all +from a C checkout with `scripts/sync-c-oracle.sh`. A commit that changes +them names the C commit that changed them, and says why. diff --git a/crates/npro-test/transcripts/h1-404-keepalive.json b/crates/npro-test/transcripts/h1-404-keepalive.json new file mode 100644 index 0000000..71f8262 --- /dev/null +++ b/crates/npro-test/transcripts/h1-404-keepalive.json @@ -0,0 +1,16 @@ +{ + "format": "lws-transcript/1", + "case": "h1-404-keepalive", + "side": "server", + "t0_us": 1000000000, + "t0_wall": 1767225600, + "seed": 0, + "steps": [ + {"t": 3601000, "rx": "474554202f7820485454502f312e310d0a486f73743a2073616e73696f2d3430340d0a0d0a"}, + {"t": 3601000, "tx": "485454502f312e31203330322052656469726563740d0a6c6f636174696f6e3a202f3430342e68746d6c0d0a636f6e74656e742d747970653a20746578742f68746d6c0d0a636f6e74656e742d6c656e6774683a20300d0a0d0a"}, + {"t": 3602000, "rx": "474554202f3430342e68746d6c20485454502f312e310d0a486f73743a2073616e73696f2d3430340d0a0d0a"}, + {"t": 3602000, "tx": "485454502f312e3120343034204e6f7420466f756e640d0a636f6e74656e742d747970653a20746578742f68746d6c0d0a636f6e74656e742d6c656e6774683a203137330d0a0d0a3c68746d6c3e3c686561643e3c6d65746120636861727365743d7574662d3820687474702d65717569763d22436f6e74656e742d4c616e67756167652220636f6e74656e743d22656e222f3e3c6c696e6b2072656c3d227374796c6573686565742220747970653d22746578742f6373732220687265663d222f6572726f722e637373222f3e3c2f686561643e3c626f64793e3c68313e3430343c2f68313e3c2f626f64793e3c2f68746d6c3e"}, + {"t": 3603000, "rx": "474554202f63622f7920485454502f312e310d0a486f73743a2073616e73696f2d3430340d0a0d0a"}, + {"t": 3603000, "tx": "485454502f312e31203330322052656469726563740d0a6c6f636174696f6e3a202f3430342e68746d6c0d0a636f6e74656e742d747970653a20746578742f68746d6c0d0a636f6e74656e742d6c656e6774683a20300d0a0d0a"} + ] +} diff --git a/crates/npro-test/transcripts/h1-client-304-cl.json b/crates/npro-test/transcripts/h1-client-304-cl.json new file mode 100644 index 0000000..8f3691e --- /dev/null +++ b/crates/npro-test/transcripts/h1-client-304-cl.json @@ -0,0 +1,12 @@ +{ + "format": "lws-transcript/1", + "case": "h1-client-304-cl", + "side": "client", + "t0_us": 1000000000, + "t0_wall": 1767225600, + "seed": 0, + "steps": [ + {"t": 4195000, "tx": "474554202f7820485454502f312e310d0a507261676d613a206e6f2d63616368650d0a43616368652d436f6e74726f6c3a206e6f2d63616368650d0a486f73743a2073616e73696f0d0a4f726967696e3a20687474703a2f2f73616e73696f0d0a636f6e6e656374696f6e3a20636c6f73650d0a0d0a"}, + {"t": 4196000, "rx": "485454502f312e3120333034204e6f74204d6f6469666965640d0a436f6e74656e742d4c656e6774683a2031300d0a0d0a"} + ] +} diff --git a/crates/npro-test/transcripts/h1-client-cl-junk.json b/crates/npro-test/transcripts/h1-client-cl-junk.json new file mode 100644 index 0000000..1b97e65 --- /dev/null +++ b/crates/npro-test/transcripts/h1-client-cl-junk.json @@ -0,0 +1,13 @@ +{ + "format": "lws-transcript/1", + "case": "h1-client-cl-junk", + "side": "client", + "t0_us": 1000000000, + "t0_wall": 1767225600, + "seed": 0, + "steps": [ + {"t": 3701000, "tx": "474554202f7820485454502f312e310d0a507261676d613a206e6f2d63616368650d0a43616368652d436f6e74726f6c3a206e6f2d63616368650d0a486f73743a2073616e73696f0d0a4f726967696e3a20687474703a2f2f73616e73696f0d0a636f6e6e656374696f6e3a20636c6f73650d0a0d0a"}, + {"t": 3702000, "rx": "485454502f312e3120323030204f4b0d0a436f6e74656e742d4c656e6774683a2031306162630d0a0d0a73616e73696f206f6b0a"}, + {"t": 3702000, "close": ""} + ] +} diff --git a/crates/npro-test/transcripts/h1-client-cl-twice.json b/crates/npro-test/transcripts/h1-client-cl-twice.json new file mode 100644 index 0000000..08ddb3f --- /dev/null +++ b/crates/npro-test/transcripts/h1-client-cl-twice.json @@ -0,0 +1,13 @@ +{ + "format": "lws-transcript/1", + "case": "h1-client-cl-twice", + "side": "client", + "t0_us": 1000000000, + "t0_wall": 1767225600, + "seed": 0, + "steps": [ + {"t": 3703000, "tx": "474554202f7820485454502f312e310d0a507261676d613a206e6f2d63616368650d0a43616368652d436f6e74726f6c3a206e6f2d63616368650d0a486f73743a2073616e73696f0d0a4f726967696e3a20687474703a2f2f73616e73696f0d0a636f6e6e656374696f6e3a20636c6f73650d0a0d0a"}, + {"t": 3704000, "rx": "485454502f312e3120323030204f4b0d0a436f6e74656e742d4c656e6774683a2031300d0a436f6e74656e742d4c656e6774683a20350d0a0d0a73616e73696f206f6b0a"}, + {"t": 3704000, "close": ""} + ] +} diff --git a/crates/npro-test/transcripts/h1-client-get.json b/crates/npro-test/transcripts/h1-client-get.json new file mode 100644 index 0000000..6a65d24 --- /dev/null +++ b/crates/npro-test/transcripts/h1-client-get.json @@ -0,0 +1,13 @@ +{ + "format": "lws-transcript/1", + "case": "h1-client-get", + "side": "client", + "t0_us": 1000000000, + "t0_wall": 1767225600, + "seed": 0, + "steps": [ + {"t": 4000, "tx": "474554202f7820485454502f312e310d0a507261676d613a206e6f2d63616368650d0a43616368652d436f6e74726f6c3a206e6f2d63616368650d0a486f73743a2073616e73696f0d0a4f726967696e3a20687474703a2f2f73616e73696f0d0a636f6e6e656374696f6e3a20636c6f73650d0a0d0a"}, + {"t": 5000, "rx": "485454502f312e3120323030204f4b0d0a436f6e74656e742d547970653a20746578742f706c61696e0d0a436f6e74656e742d4c656e6774683a2031300d0a0d0a73616e73696f206f6b0a"}, + {"t": 5000, "app_rx": "73616e73696f206f6b0a"} + ] +} diff --git a/crates/npro-test/transcripts/h1-client-head-chunked.json b/crates/npro-test/transcripts/h1-client-head-chunked.json new file mode 100644 index 0000000..1c51c7c --- /dev/null +++ b/crates/npro-test/transcripts/h1-client-head-chunked.json @@ -0,0 +1,12 @@ +{ + "format": "lws-transcript/1", + "case": "h1-client-head-chunked", + "side": "client", + "t0_us": 1000000000, + "t0_wall": 1767225600, + "seed": 0, + "steps": [ + {"t": 4191000, "tx": "48454144202f7820485454502f312e310d0a507261676d613a206e6f2d63616368650d0a43616368652d436f6e74726f6c3a206e6f2d63616368650d0a486f73743a2073616e73696f0d0a4f726967696e3a20687474703a2f2f73616e73696f0d0a636f6e6e656374696f6e3a20636c6f73650d0a0d0a"}, + {"t": 4192000, "rx": "485454502f312e3120323030204f4b0d0a5472616e736665722d456e636f64696e673a206368756e6b65640d0a0d0a"} + ] +} diff --git a/crates/npro-test/transcripts/h1-client-head-cl.json b/crates/npro-test/transcripts/h1-client-head-cl.json new file mode 100644 index 0000000..7000ad7 --- /dev/null +++ b/crates/npro-test/transcripts/h1-client-head-cl.json @@ -0,0 +1,12 @@ +{ + "format": "lws-transcript/1", + "case": "h1-client-head-cl", + "side": "client", + "t0_us": 1000000000, + "t0_wall": 1767225600, + "seed": 0, + "steps": [ + {"t": 4193000, "tx": "48454144202f7820485454502f312e310d0a507261676d613a206e6f2d63616368650d0a43616368652d436f6e74726f6c3a206e6f2d63616368650d0a486f73743a2073616e73696f0d0a4f726967696e3a20687474703a2f2f73616e73696f0d0a636f6e6e656374696f6e3a20636c6f73650d0a0d0a"}, + {"t": 4194000, "rx": "485454502f312e3120323030204f4b0d0a436f6e74656e742d4c656e6774683a2031300d0a0d0a"} + ] +} diff --git a/crates/npro-test/transcripts/h1-client-te-list.json b/crates/npro-test/transcripts/h1-client-te-list.json new file mode 100644 index 0000000..742136d --- /dev/null +++ b/crates/npro-test/transcripts/h1-client-te-list.json @@ -0,0 +1,13 @@ +{ + "format": "lws-transcript/1", + "case": "h1-client-te-list", + "side": "client", + "t0_us": 1000000000, + "t0_wall": 1767225600, + "seed": 0, + "steps": [ + {"t": 3705000, "tx": "474554202f7820485454502f312e310d0a507261676d613a206e6f2d63616368650d0a43616368652d436f6e74726f6c3a206e6f2d63616368650d0a486f73743a2073616e73696f0d0a4f726967696e3a20687474703a2f2f73616e73696f0d0a636f6e6e656374696f6e3a20636c6f73650d0a0d0a"}, + {"t": 3706000, "rx": "485454502f312e3120323030204f4b0d0a5472616e736665722d456e636f64696e673a206368756e6b65640d0a5472616e736665722d456e636f64696e673a20677a69700d0a0d0a610d0a73616e73696f206f6b0a0d0a300d0a0d0a"}, + {"t": 3706000, "close": ""} + ] +} diff --git a/crates/npro-test/transcripts/h1-connect-rejected-ua.json b/crates/npro-test/transcripts/h1-connect-rejected-ua.json new file mode 100644 index 0000000..2397558 --- /dev/null +++ b/crates/npro-test/transcripts/h1-connect-rejected-ua.json @@ -0,0 +1,12 @@ +{ + "format": "lws-transcript/1", + "case": "h1-connect-rejected-ua", + "side": "server", + "t0_us": 1000000000, + "t0_wall": 1767225600, + "seed": 0, + "steps": [ + {"t": 4101000, "rx": "434f4e4e454354206578616d706c652e636f6d3a34343320485454502f312e310d0a486f73743a206578616d706c652e636f6d3a3434330d0a557365722d4167656e743a20626164626f742f310d0a0d0a"}, + {"t": 4101000, "tx": "485454502f312e312034303320466f7262696464656e0d0a636f6e74656e742d747970653a20746578742f68746d6c0d0a636f6e74656e742d6c656e6774683a203138300d0a0d0a3c68746d6c3e3c686561643e3c6d65746120636861727365743d7574662d3820687474702d65717569763d22436f6e74656e742d4c616e67756167652220636f6e74656e743d22656e222f3e3c6c696e6b2072656c3d227374796c6573686565742220747970653d22746578742f6373732220687265663d222f6572726f722e637373222f3e3c2f686561643e3c626f64793e3c68313e3430333c2f68313e476f20617761793c2f626f64793e3c2f68746d6c3e"} + ] +} diff --git a/crates/npro-test/transcripts/h1-header-past-limit.json b/crates/npro-test/transcripts/h1-header-past-limit.json new file mode 100644 index 0000000..393c917 --- /dev/null +++ b/crates/npro-test/transcripts/h1-header-past-limit.json @@ -0,0 +1,12 @@ +{ + "format": "lws-transcript/1", + "case": "h1-header-past-limit", + "side": "server", + "t0_us": 1000000000, + "t0_wall": 1767225600, + "seed": 0, + "steps": [ + {"t": 3106000, "rx": "474554202f20485454502f312e310d0a486f73743a2073616e73696f2d7572690d0a557365722d4167656e743a2031323334353637383930313233343536370d0a0d0a"}, + {"t": 3106000, "tx": "485454502f312e3120343331205265717565737420486561646572204669656c647320546f6f204c617267650d0a636f6e74656e742d747970653a20746578742f68746d6c0d0a636f6e74656e742d6c656e6774683a203139300d0a0d0a3c68746d6c3e3c686561643e3c6d65746120636861727365743d7574662d3820687474702d65717569763d22436f6e74656e742d4c616e67756167652220636f6e74656e743d22656e222f3e3c6c696e6b2072656c3d227374796c6573686565742220747970653d22746578742f6373732220687265663d222f6572726f722e637373222f3e3c2f686561643e3c626f64793e3c68313e3433313c2f68313e4f76657273697a656420686561646572733c2f626f64793e3c2f68746d6c3e"} + ] +} diff --git a/crates/npro-test/transcripts/h1-post-no-length.json b/crates/npro-test/transcripts/h1-post-no-length.json new file mode 100644 index 0000000..0d8c5c4 --- /dev/null +++ b/crates/npro-test/transcripts/h1-post-no-length.json @@ -0,0 +1,12 @@ +{ + "format": "lws-transcript/1", + "case": "h1-post-no-length", + "side": "server", + "t0_us": 1000000000, + "t0_wall": 1767225600, + "seed": 0, + "steps": [ + {"t": 200001000, "rx": "504f5354202f783f613d3120485454502f312e310d0a486f73743a2073616e73696f2d7572690d0a0d0a474554202f793f623d3220485454502f312e310d0a486f73743a2073616e73696f2d7572690d0a0d0a"}, + {"t": 200001000, "tx": "485454502f312e3120323030204f4b0d0a636f6e74656e742d747970653a20746578742f706c61696e0d0a636f6e74656e742d6c656e6774683a20360d0a0d0a2f780a613d31485454502f312e3120323030204f4b0d0a636f6e74656e742d747970653a20746578742f706c61696e0d0a636f6e74656e742d6c656e6774683a20360d0a0d0a2f790a623d32"} + ] +} diff --git a/crates/npro-test/transcripts/h1-reqline-http09.json b/crates/npro-test/transcripts/h1-reqline-http09.json new file mode 100644 index 0000000..d37ce3c --- /dev/null +++ b/crates/npro-test/transcripts/h1-reqline-http09.json @@ -0,0 +1,12 @@ +{ + "format": "lws-transcript/1", + "case": "h1-reqline-http09", + "side": "server", + "t0_us": 1000000000, + "t0_wall": 1767225600, + "seed": 0, + "steps": [ + {"t": 3107000, "rx": "474554202f780d0a"}, + {"t": 3107000, "tx": "485454502f312e31203430302042616420526571756573740d0a636f6e74656e742d747970653a20746578742f68746d6c0d0a636f6e74656e742d6c656e6774683a203137330d0a0d0a3c68746d6c3e3c686561643e3c6d65746120636861727365743d7574662d3820687474702d65717569763d22436f6e74656e742d4c616e67756167652220636f6e74656e743d22656e222f3e3c6c696e6b2072656c3d227374796c6573686565742220747970653d22746578742f6373732220687265663d222f6572726f722e637373222f3e3c2f686561643e3c626f64793e3c68313e3430303c2f68313e3c2f626f64793e3c2f68746d6c3e"} + ] +} diff --git a/crates/npro-test/transcripts/h1-reqline-leading-empty-many.json b/crates/npro-test/transcripts/h1-reqline-leading-empty-many.json new file mode 100644 index 0000000..b08ba95 --- /dev/null +++ b/crates/npro-test/transcripts/h1-reqline-leading-empty-many.json @@ -0,0 +1,12 @@ +{ + "format": "lws-transcript/1", + "case": "h1-reqline-leading-empty-many", + "side": "server", + "t0_us": 1000000000, + "t0_wall": 1767225600, + "seed": 0, + "steps": [ + {"t": 3116000, "rx": "0d0a0d0a0d0a0d0a0d0a0d0a0d0a0d0a0d0a474554202f7820485454502f312e310d0a486f73743a2073616e73696f2d7572690d0a0d0a"}, + {"t": 3116000, "tx": "485454502f312e31203430302042616420526571756573740d0a636f6e74656e742d747970653a20746578742f68746d6c0d0a636f6e74656e742d6c656e6774683a203137330d0a0d0a3c68746d6c3e3c686561643e3c6d65746120636861727365743d7574662d3820687474702d65717569763d22436f6e74656e742d4c616e67756167652220636f6e74656e743d22656e222f3e3c6c696e6b2072656c3d227374796c6573686565742220747970653d22746578742f6373732220687265663d222f6572726f722e637373222f3e3c2f686561643e3c626f64793e3c68313e3430303c2f68313e3c2f626f64793e3c2f68746d6c3e"} + ] +} diff --git a/crates/npro-test/transcripts/h1-reqline-leading-empty.json b/crates/npro-test/transcripts/h1-reqline-leading-empty.json new file mode 100644 index 0000000..9853559 --- /dev/null +++ b/crates/npro-test/transcripts/h1-reqline-leading-empty.json @@ -0,0 +1,12 @@ +{ + "format": "lws-transcript/1", + "case": "h1-reqline-leading-empty", + "side": "server", + "t0_us": 1000000000, + "t0_wall": 1767225600, + "seed": 0, + "steps": [ + {"t": 3115000, "rx": "0d0a0d0a474554202f7820485454502f312e310d0a486f73743a2073616e73696f2d7572690d0a0d0a"}, + {"t": 3115000, "tx": "485454502f312e3120323030204f4b0d0a636f6e74656e742d747970653a20746578742f706c61696e0d0a636f6e74656e742d6c656e6774683a20330d0a0d0a2f780a"} + ] +} diff --git a/crates/npro-test/transcripts/h1-reqline-no-method.json b/crates/npro-test/transcripts/h1-reqline-no-method.json new file mode 100644 index 0000000..91c702f --- /dev/null +++ b/crates/npro-test/transcripts/h1-reqline-no-method.json @@ -0,0 +1,12 @@ +{ + "format": "lws-transcript/1", + "case": "h1-reqline-no-method", + "side": "server", + "t0_us": 1000000000, + "t0_wall": 1767225600, + "seed": 0, + "steps": [ + {"t": 3108000, "rx": "486f73743a2073616e73696f2d7572690d0a0d0a"}, + {"t": 3108000, "tx": "485454502f312e31203430302042616420526571756573740d0a636f6e74656e742d747970653a20746578742f68746d6c0d0a636f6e74656e742d6c656e6774683a203137330d0a0d0a3c68746d6c3e3c686561643e3c6d65746120636861727365743d7574662d3820687474702d65717569763d22436f6e74656e742d4c616e67756167652220636f6e74656e743d22656e222f3e3c6c696e6b2072656c3d227374796c6573686565742220747970653d22746578742f6373732220687265663d222f6572726f722e637373222f3e3c2f686561643e3c626f64793e3c68313e3430303c2f68313e3c2f626f64793e3c2f68746d6c3e"} + ] +} diff --git a/crates/npro-test/transcripts/h1-reqline-unknown-header-first.json b/crates/npro-test/transcripts/h1-reqline-unknown-header-first.json new file mode 100644 index 0000000..3c82b04 --- /dev/null +++ b/crates/npro-test/transcripts/h1-reqline-unknown-header-first.json @@ -0,0 +1,12 @@ +{ + "format": "lws-transcript/1", + "case": "h1-reqline-unknown-header-first", + "side": "server", + "t0_us": 1000000000, + "t0_wall": 1767225600, + "seed": 0, + "steps": [ + {"t": 3114000, "rx": "582d466f6f3a206261720d0a486f73743a2073616e73696f2d7572690d0a0d0a"}, + {"t": 3114000, "tx": "485454502f312e31203430302042616420526571756573740d0a636f6e74656e742d747970653a20746578742f68746d6c0d0a636f6e74656e742d6c656e6774683a203137330d0a0d0a3c68746d6c3e3c686561643e3c6d65746120636861727365743d7574662d3820687474702d65717569763d22436f6e74656e742d4c616e67756167652220636f6e74656e743d22656e222f3e3c6c696e6b2072656c3d227374796c6573686565742220747970653d22746578742f6373732220687265663d222f6572726f722e637373222f3e3c2f686561643e3c626f64793e3c68313e3430303c2f68313e3c2f626f64793e3c2f68746d6c3e"} + ] +} diff --git a/crates/npro-test/transcripts/h1-reqline-unknown-method.json b/crates/npro-test/transcripts/h1-reqline-unknown-method.json new file mode 100644 index 0000000..d9cc2ea --- /dev/null +++ b/crates/npro-test/transcripts/h1-reqline-unknown-method.json @@ -0,0 +1,12 @@ +{ + "format": "lws-transcript/1", + "case": "h1-reqline-unknown-method", + "side": "server", + "t0_us": 1000000000, + "t0_wall": 1767225600, + "seed": 0, + "steps": [ + {"t": 3113000, "rx": "464f4f202f7820485454502f312e310d0a486f73743a2073616e73696f2d7572690d0a0d0a"}, + {"t": 3113000, "tx": "485454502f312e3120353031204e6f7420496d706c656d656e7465640d0a636f6e74656e742d747970653a20746578742f68746d6c0d0a636f6e74656e742d6c656e6774683a203137330d0a0d0a3c68746d6c3e3c686561643e3c6d65746120636861727365743d7574662d3820687474702d65717569763d22436f6e74656e742d4c616e67756167652220636f6e74656e743d22656e222f3e3c6c696e6b2072656c3d227374796c6573686565742220747970653d22746578742f6373732220687265663d222f6572726f722e637373222f3e3c2f686561643e3c626f64793e3c68313e3530313c2f68313e3c2f626f64793e3c2f68746d6c3e"} + ] +} diff --git a/crates/npro-test/transcripts/h1-reqline-version-1-2.json b/crates/npro-test/transcripts/h1-reqline-version-1-2.json new file mode 100644 index 0000000..5c51538 --- /dev/null +++ b/crates/npro-test/transcripts/h1-reqline-version-1-2.json @@ -0,0 +1,12 @@ +{ + "format": "lws-transcript/1", + "case": "h1-reqline-version-1-2", + "side": "server", + "t0_us": 1000000000, + "t0_wall": 1767225600, + "seed": 0, + "steps": [ + {"t": 3112000, "rx": "474554202f7820485454502f312e320d0a486f73743a2073616e73696f2d7572690d0a0d0a"}, + {"t": 3112000, "tx": "485454502f312e3120323030204f4b0d0a636f6e74656e742d747970653a20746578742f706c61696e0d0a636f6e74656e742d6c656e6774683a20330d0a0d0a2f780a"} + ] +} diff --git a/crates/npro-test/transcripts/h1-reqline-version-2.json b/crates/npro-test/transcripts/h1-reqline-version-2.json new file mode 100644 index 0000000..a9578ca --- /dev/null +++ b/crates/npro-test/transcripts/h1-reqline-version-2.json @@ -0,0 +1,12 @@ +{ + "format": "lws-transcript/1", + "case": "h1-reqline-version-2", + "side": "server", + "t0_us": 1000000000, + "t0_wall": 1767225600, + "seed": 0, + "steps": [ + {"t": 3109000, "rx": "474554202f7820485454502f322e300d0a486f73743a2073616e73696f2d7572690d0a0d0a"}, + {"t": 3109000, "tx": "485454502f312e312035303520485454502056657273696f6e204e6f7420537570706f727465640d0a636f6e74656e742d747970653a20746578742f68746d6c0d0a636f6e74656e742d6c656e6774683a203137330d0a0d0a3c68746d6c3e3c686561643e3c6d65746120636861727365743d7574662d3820687474702d65717569763d22436f6e74656e742d4c616e67756167652220636f6e74656e743d22656e222f3e3c6c696e6b2072656c3d227374796c6573686565742220747970653d22746578742f6373732220687265663d222f6572726f722e637373222f3e3c2f686561643e3c626f64793e3c68313e3530353c2f68313e3c2f626f64793e3c2f68746d6c3e"} + ] +} diff --git a/crates/npro-test/transcripts/h1-reqline-version-junk.json b/crates/npro-test/transcripts/h1-reqline-version-junk.json new file mode 100644 index 0000000..b162843 --- /dev/null +++ b/crates/npro-test/transcripts/h1-reqline-version-junk.json @@ -0,0 +1,12 @@ +{ + "format": "lws-transcript/1", + "case": "h1-reqline-version-junk", + "side": "server", + "t0_us": 1000000000, + "t0_wall": 1767225600, + "seed": 0, + "steps": [ + {"t": 3110000, "rx": "474554202f7820485454502f312e780d0a486f73743a2073616e73696f2d7572690d0a0d0a"}, + {"t": 3110000, "tx": "485454502f312e31203430302042616420526571756573740d0a636f6e74656e742d747970653a20746578742f68746d6c0d0a636f6e74656e742d6c656e6774683a203137330d0a0d0a3c68746d6c3e3c686561643e3c6d65746120636861727365743d7574662d3820687474702d65717569763d22436f6e74656e742d4c616e67756167652220636f6e74656e743d22656e222f3e3c6c696e6b2072656c3d227374796c6573686565742220747970653d22746578742f6373732220687265663d222f6572726f722e637373222f3e3c2f686561643e3c626f64793e3c68313e3430303c2f68313e3c2f626f64793e3c2f68746d6c3e"} + ] +} diff --git a/crates/npro-test/transcripts/h1-reqline-version-long.json b/crates/npro-test/transcripts/h1-reqline-version-long.json new file mode 100644 index 0000000..5e6c7d4 --- /dev/null +++ b/crates/npro-test/transcripts/h1-reqline-version-long.json @@ -0,0 +1,12 @@ +{ + "format": "lws-transcript/1", + "case": "h1-reqline-version-long", + "side": "server", + "t0_us": 1000000000, + "t0_wall": 1767225600, + "seed": 0, + "steps": [ + {"t": 3111000, "rx": "474554202f7820485454502f312e31300d0a486f73743a2073616e73696f2d7572690d0a0d0a"}, + {"t": 3111000, "tx": "485454502f312e31203430302042616420526571756573740d0a636f6e74656e742d747970653a20746578742f68746d6c0d0a636f6e74656e742d6c656e6774683a203137330d0a0d0a3c68746d6c3e3c686561643e3c6d65746120636861727365743d7574662d3820687474702d65717569763d22436f6e74656e742d4c616e67756167652220636f6e74656e743d22656e222f3e3c6c696e6b2072656c3d227374796c6573686565742220747970653d22746578742f6373732220687265663d222f6572726f722e637373222f3e3c2f686561643e3c626f64793e3c68313e3430303c2f68313e3c2f626f64793e3c2f68746d6c3e"} + ] +} diff --git a/crates/npro-test/transcripts/h1-uri-at-limit.json b/crates/npro-test/transcripts/h1-uri-at-limit.json new file mode 100644 index 0000000..298f83f --- /dev/null +++ b/crates/npro-test/transcripts/h1-uri-at-limit.json @@ -0,0 +1,12 @@ +{ + "format": "lws-transcript/1", + "case": "h1-uri-at-limit", + "side": "server", + "t0_us": 1000000000, + "t0_wall": 1767225600, + "seed": 0, + "steps": [ + {"t": 3104000, "rx": "474554202f323334353637383930313233343536373839303132333435363738393031323320485454502f312e310d0a486f73743a2073616e73696f2d7572690d0a0d0a"}, + {"t": 3104000, "tx": "485454502f312e3120323030204f4b0d0a636f6e74656e742d747970653a20746578742f706c61696e0d0a636f6e74656e742d6c656e6774683a2033340d0a0d0a2f32333435363738393031323334353637383930313233343536373839303132330a"} + ] +} diff --git a/crates/npro-test/transcripts/h1-uri-dot-args.json b/crates/npro-test/transcripts/h1-uri-dot-args.json new file mode 100644 index 0000000..be3bda4 --- /dev/null +++ b/crates/npro-test/transcripts/h1-uri-dot-args.json @@ -0,0 +1,12 @@ +{ + "format": "lws-transcript/1", + "case": "h1-uri-dot-args", + "side": "server", + "t0_us": 1000000000, + "t0_wall": 1767225600, + "seed": 0, + "steps": [ + {"t": 3102000, "rx": "474554202f782f2e3f613d6220485454502f312e310d0a486f73743a2073616e73696f2d7572690d0a0d0a"}, + {"t": 3102000, "tx": "485454502f312e3120323030204f4b0d0a636f6e74656e742d747970653a20746578742f706c61696e0d0a636f6e74656e742d6c656e6774683a20370d0a0d0a2f782f0a613d62"} + ] +} diff --git a/crates/npro-test/transcripts/h1-uri-dotdot-args.json b/crates/npro-test/transcripts/h1-uri-dotdot-args.json new file mode 100644 index 0000000..0c6bd0a --- /dev/null +++ b/crates/npro-test/transcripts/h1-uri-dotdot-args.json @@ -0,0 +1,12 @@ +{ + "format": "lws-transcript/1", + "case": "h1-uri-dotdot-args", + "side": "server", + "t0_us": 1000000000, + "t0_wall": 1767225600, + "seed": 0, + "steps": [ + {"t": 3101000, "rx": "474554202f782f2e2e3f613d6220485454502f312e310d0a486f73743a2073616e73696f2d7572690d0a0d0a"}, + {"t": 3101000, "tx": "485454502f312e3120323030204f4b0d0a636f6e74656e742d747970653a20746578742f706c61696e0d0a636f6e74656e742d6c656e6774683a20350d0a0d0a2f0a613d62"} + ] +} diff --git a/crates/npro-test/transcripts/h1-uri-past-limit.json b/crates/npro-test/transcripts/h1-uri-past-limit.json new file mode 100644 index 0000000..b5d6f30 --- /dev/null +++ b/crates/npro-test/transcripts/h1-uri-past-limit.json @@ -0,0 +1,12 @@ +{ + "format": "lws-transcript/1", + "case": "h1-uri-past-limit", + "side": "server", + "t0_us": 1000000000, + "t0_wall": 1767225600, + "seed": 0, + "steps": [ + {"t": 3105000, "rx": "474554202f32333435363738393031323334353637383930313233343536373839303132333420485454502f312e310d0a486f73743a2073616e73696f2d7572690d0a0d0a"}, + {"t": 3105000, "tx": "485454502f312e312034313420526571756573742055524920746f6f204c6f6e670d0a636f6e74656e742d747970653a20746578742f68746d6c0d0a636f6e74656e742d6c656e6774683a203139340d0a0d0a3c68746d6c3e3c686561643e3c6d65746120636861727365743d7574662d3820687474702d65717569763d22436f6e74656e742d4c616e67756167652220636f6e74656e743d22656e222f3e3c6c696e6b2072656c3d227374796c6573686565742220747970653d22746578742f6373732220687265663d222f6572726f722e637373222f3e3c2f686561643e3c626f64793e3c68313e3431343c2f68313e4f76657273697a65642072657175657374205552493c2f626f64793e3c2f68746d6c3e"} + ] +} diff --git a/crates/npro-test/transcripts/h1-uri-plus.json b/crates/npro-test/transcripts/h1-uri-plus.json new file mode 100644 index 0000000..1349156 --- /dev/null +++ b/crates/npro-test/transcripts/h1-uri-plus.json @@ -0,0 +1,12 @@ +{ + "format": "lws-transcript/1", + "case": "h1-uri-plus", + "side": "server", + "t0_us": 1000000000, + "t0_wall": 1767225600, + "seed": 0, + "steps": [ + {"t": 3103000, "rx": "474554202f612b623f632b643d652b6620485454502f312e310d0a486f73743a2073616e73696f2d7572690d0a0d0a"}, + {"t": 3103000, "tx": "485454502f312e3120323030204f4b0d0a636f6e74656e742d747970653a20746578742f706c61696e0d0a636f6e74656e742d6c656e6774683a2031320d0a0d0a2f612b620a6320643d652066"} + ] +} diff --git a/crates/npro-test/transcripts/h1-ws-server.json b/crates/npro-test/transcripts/h1-ws-server.json new file mode 100644 index 0000000..908a85a --- /dev/null +++ b/crates/npro-test/transcripts/h1-ws-server.json @@ -0,0 +1,17 @@ +{ + "format": "lws-transcript/1", + "case": "h1-ws-server", + "side": "server", + "t0_us": 1000000000, + "t0_wall": 1767225600, + "seed": 0, + "steps": [ + {"t": 1000, "rx": "474554202f7820485454502f312e310d0a486f73743a2073616e73696f0d0a0d0a"}, + {"t": 1000, "tx": "485454502f312e3120323030204f4b0d0a636f6e74656e742d747970653a20746578742f706c61696e0d0a636f6e74656e742d6c656e6774683a2031300d0a0d0a73616e73696f206f6b0a"}, + {"t": 2000, "rx": "474554202f6563686f20485454502f312e310d0a486f73743a2073616e73696f0d0a557067726164653a20776562736f636b65740d0a436f6e6e656374696f6e3a20557067726164650d0a5365632d576562536f636b65742d56657273696f6e3a2031330d0a5365632d576562536f636b65742d50726f746f636f6c3a206563686f0d0a5365632d576562536f636b65742d4b65793a206447686c49484e68625842735a5342756232356a5a513d3d0d0a0d0a"}, + {"t": 2000, "tx": "485454502f312e312031303120537769746368696e672050726f746f636f6c730d0a557067726164653a20576562536f636b65740d0a436f6e6e656374696f6e3a20557067726164650d0a5365632d576562536f636b65742d4163636570743a20733370504c4d426954786151396b59477a7a685a52624b2b784f6f3d0d0a5365632d576562536f636b65742d50726f746f636f6c3a206563686f0d0a0d0a"}, + {"t": 3000, "rx": "818537fa213d7f9f4d5158"}, + {"t": 3000, "app_rx": "48656c6c6f"}, + {"t": 3000, "tx": "810548656c6c6f"} + ] +} diff --git a/crates/npro-test/transcripts/h2-oversized-headers.json b/crates/npro-test/transcripts/h2-oversized-headers.json new file mode 100644 index 0000000..0b352f9 --- /dev/null +++ b/crates/npro-test/transcripts/h2-oversized-headers.json @@ -0,0 +1,18 @@ +{ + "format": "lws-transcript/1", + "case": "h2-oversized-headers", + "side": "server", + "t0_us": 1000000000, + "t0_wall": 1767225600, + "seed": 0, + "steps": [ + {"t": 3501000, "rx": "505249202a20485454502f322e300d0a0d0a534d0d0a0d0a000000040000000000000000040100000000"}, + {"t": 3501000, "tx": "000024040000000000000100010000000200000000000300000018000400000000000600010000000800000001000000040100000000"}, + {"t": 3502000, "rx": "0013a3010500000001828684410973616e73696f2d68320f2b7fb9167575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575757575750f247fd10e7272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272727272530178"}, + {"t": 3502000, "tx": "000004080000000001000400000000040800000000000004000000003901040000000100073a73746174757303343331000c636f6e74656e742d7479706509746578742f68746d6c000e636f6e74656e742d6c656e677468033139300000be0001000000013c68746d6c3e3c686561643e3c6d65746120636861727365743d7574662d3820687474702d65717569763d22436f6e74656e742d4c616e67756167652220636f6e74656e743d22656e222f3e3c6c696e6b2072656c3d227374796c6573686565742220747970653d22746578742f6373732220687265663d222f6572726f722e637373222f3e3c2f686561643e3c626f64793e3c68313e3433313c2f68313e4f76657273697a656420686561646572733c2f626f64793e3c2f68746d6c3e"}, + {"t": 3503000, "rx": "000005010500000003828684bfbe"}, + {"t": 3503000, "tx": "000004080000000003000400000000040800000000000004000000003901040000000300073a73746174757303343331000c636f6e74656e742d7479706509746578742f68746d6c000e636f6e74656e742d6c656e677468033139300000be0001000000033c68746d6c3e3c686561643e3c6d65746120636861727365743d7574662d3820687474702d65717569763d22436f6e74656e742d4c616e67756167652220636f6e74656e743d22656e222f3e3c6c696e6b2072656c3d227374796c6573686565742220747970653d22746578742f6373732220687265663d222f6572726f722e637373222f3e3c2f686561643e3c626f64793e3c68313e3433313c2f68313e4f76657273697a656420686561646572733c2f626f64793e3c2f68746d6c3e"}, + {"t": 3504000, "rx": "000004010500000005828684bf"}, + {"t": 3504000, "tx": "000004080000000005000400000000040800000000000004000000003801040000000500073a73746174757303323030000c636f6e74656e742d747970650a746578742f706c61696e000e636f6e74656e742d6c656e67746801320000020001000000052f0a"} + ] +} diff --git a/crates/npro-test/transcripts/h2-ws-peer-close-skint.json b/crates/npro-test/transcripts/h2-ws-peer-close-skint.json new file mode 100644 index 0000000..cc42a3c --- /dev/null +++ b/crates/npro-test/transcripts/h2-ws-peer-close-skint.json @@ -0,0 +1,17 @@ +{ + "format": "lws-transcript/1", + "case": "h2-ws-peer-close-skint", + "side": "server", + "t0_us": 1000000000, + "t0_wall": 1767225600, + "seed": 0, + "steps": [ + {"t": 4051000, "rx": "505249202a20485454502f322e300d0a0d0a534d0d0a0d0a000006040000000000000400000000000000040100000000"}, + {"t": 4051000, "tx": "000024040000000000000100010000000200000000000300000018000400000000000600010000000800000001000000040100000000"}, + {"t": 4052000, "rx": "00006a0104000000010207434f4e4e45435400093a70726f746f636f6c09776562736f636b65748604052f6563686f010b73616e73696f2d6832777300157365632d776562736f636b65742d76657273696f6e02313300167365632d776562736f636b65742d70726f746f636f6c046563686f"}, + {"t": 4052000, "tx": "000004080000000001000400000000040800000000000004000000002a01040000000100073a7374617475730332303000167365632d776562736f636b65742d70726f746f636f6c046563686f"}, + {"t": 4053000, "rx": "00000f00010000000188820000000003e889810000000070"}, + {"t": 4054000, "rx": "00000408000000000100000064"}, + {"t": 4054000, "tx": "000004000100000001880203e8"} + ] +} diff --git a/crates/npro-test/transcripts/h2-ws-peer-close.json b/crates/npro-test/transcripts/h2-ws-peer-close.json new file mode 100644 index 0000000..89bf8ef --- /dev/null +++ b/crates/npro-test/transcripts/h2-ws-peer-close.json @@ -0,0 +1,16 @@ +{ + "format": "lws-transcript/1", + "case": "h2-ws-peer-close", + "side": "server", + "t0_us": 1000000000, + "t0_wall": 1767225600, + "seed": 0, + "steps": [ + {"t": 4001000, "rx": "505249202a20485454502f322e300d0a0d0a534d0d0a0d0a000000040000000000000000040100000000"}, + {"t": 4001000, "tx": "000024040000000000000100010000000200000000000300000018000400000000000600010000000800000001000000040100000000"}, + {"t": 4002000, "rx": "00006a0104000000010207434f4e4e45435400093a70726f746f636f6c09776562736f636b65748604052f6563686f010b73616e73696f2d6832777300157365632d776562736f636b65742d76657273696f6e02313300167365632d776562736f636b65742d70726f746f636f6c046563686f"}, + {"t": 4002000, "tx": "000004080000000001000400000000040800000000000004000000002a01040000000100073a7374617475730332303000167365632d776562736f636b65742d70726f746f636f6c046563686f"}, + {"t": 4003000, "rx": "00000f00000000000188820000000003e889810000000070"}, + {"t": 4003000, "tx": "000004000100000001880203e800000403000000000100000000"} + ] +} diff --git a/crates/npro-test/transcripts/ws-client-huge-frame.json b/crates/npro-test/transcripts/ws-client-huge-frame.json new file mode 100644 index 0000000..df4ba4c --- /dev/null +++ b/crates/npro-test/transcripts/ws-client-huge-frame.json @@ -0,0 +1,17 @@ +{ + "format": "lws-transcript/1", + "case": "ws-client-huge-frame", + "side": "client", + "t0_us": 1000000000, + "t0_wall": 1767225600, + "seed": 1, + "steps": [ + {"t": 3209000, "tx": "474554202f6563686f20485454502f312e310d0a507261676d613a206e6f2d63616368650d0a43616368652d436f6e74726f6c3a206e6f2d63616368650d0a486f73743a2073616e73696f0d0a4f726967696e3a20687474703a2f2f73616e73696f0d0a557067726164653a20776562736f636b65740d0a436f6e6e656374696f6e3a20557067726164650d0a5365632d576562536f636b65742d4b65793a204f766f6d7451704b4357556e5a5737744d52364771773d3d0d0a5365632d576562536f636b65742d50726f746f636f6c3a206563686f0d0a5365632d576562536f636b65742d56657273696f6e3a2031330d0a0d0a"}, + {"t": 3210000, "rx": "485454502f312e312031303120537769746368696e672050726f746f636f6c730d0a557067726164653a20776562736f636b65740d0a436f6e6e656374696f6e3a20557067726164650d0a5365632d576562536f636b65742d50726f746f636f6c3a206563686f0d0a5365632d576562536f636b65742d4163636570743a207253734a662f5a4b516469756c304247494a3675514761776455383d0d0a0d0a"}, + {"t": 3210000, "tx": "8185167398765e16f41a79"}, + {"t": 3211000, "rx": "827f000000001000000148656c6c6f"}, + {"t": 3211000, "tx": "888cbe4852b2bdb93ac7d92d72d4cc293fd7"}, + {"t": 3212000, "rx": "880203e8"}, + {"t": 3212000, "close": ""} + ] +} diff --git a/crates/npro-test/transcripts/ws-client-interim.json b/crates/npro-test/transcripts/ws-client-interim.json new file mode 100644 index 0000000..8bc93ad --- /dev/null +++ b/crates/npro-test/transcripts/ws-client-interim.json @@ -0,0 +1,13 @@ +{ + "format": "lws-transcript/1", + "case": "ws-client-interim", + "side": "client", + "t0_us": 1000000000, + "t0_wall": 1767225600, + "seed": 1, + "steps": [ + {"t": 4181000, "tx": "474554202f6563686f20485454502f312e310d0a507261676d613a206e6f2d63616368650d0a43616368652d436f6e74726f6c3a206e6f2d63616368650d0a486f73743a2073616e73696f0d0a4f726967696e3a20687474703a2f2f73616e73696f0d0a557067726164653a20776562736f636b65740d0a436f6e6e656374696f6e3a20557067726164650d0a5365632d576562536f636b65742d4b65793a204f766f6d7451704b4357556e5a5737744d52364771773d3d0d0a5365632d576562536f636b65742d50726f746f636f6c3a206563686f0d0a5365632d576562536f636b65742d56657273696f6e3a2031330d0a0d0a"}, + {"t": 4182000, "rx": "485454502f312e312031303020436f6e74696e75650d0a0d0a485454502f312e312031303120537769746368696e672050726f746f636f6c730d0a557067726164653a20776562736f636b65740d0a436f6e6e656374696f6e3a20557067726164650d0a5365632d576562536f636b65742d50726f746f636f6c3a206563686f0d0a5365632d576562536f636b65742d4163636570743a207253734a662f5a4b516469756c304247494a3675514761776455383d0d0a0d0a"}, + {"t": 4182000, "tx": "8185167398765e16f41a79"} + ] +} diff --git a/crates/npro-test/transcripts/ws-client-ping-close.json b/crates/npro-test/transcripts/ws-client-ping-close.json new file mode 100644 index 0000000..ad906d8 --- /dev/null +++ b/crates/npro-test/transcripts/ws-client-ping-close.json @@ -0,0 +1,15 @@ +{ + "format": "lws-transcript/1", + "case": "ws-client-ping-close", + "side": "client", + "t0_us": 1000000000, + "t0_wall": 1767225600, + "seed": 1, + "steps": [ + {"t": 3901000, "tx": "474554202f6563686f20485454502f312e310d0a507261676d613a206e6f2d63616368650d0a43616368652d436f6e74726f6c3a206e6f2d63616368650d0a486f73743a2073616e73696f0d0a4f726967696e3a20687474703a2f2f73616e73696f0d0a557067726164653a20776562736f636b65740d0a436f6e6e656374696f6e3a20557067726164650d0a5365632d576562536f636b65742d4b65793a204f766f6d7451704b4357556e5a5737744d52364771773d3d0d0a5365632d576562536f636b65742d50726f746f636f6c3a206563686f0d0a5365632d576562536f636b65742d56657273696f6e3a2031330d0a0d0a"}, + {"t": 3902000, "rx": "485454502f312e312031303120537769746368696e672050726f746f636f6c730d0a557067726164653a20776562736f636b65740d0a436f6e6e656374696f6e3a20557067726164650d0a5365632d576562536f636b65742d50726f746f636f6c3a206563686f0d0a5365632d576562536f636b65742d4163636570743a207253734a662f5a4b516469756c304247494a3675514761776455383d0d0a0d0a"}, + {"t": 3903000, "rx": "890170880203e8"}, + {"t": 3903000, "tx": "8a8116739876668882be4852b2bda0"}, + {"t": 3903000, "close": ""} + ] +} diff --git a/crates/npro-test/transcripts/ws-client-pmd-rsv1-continuation.json b/crates/npro-test/transcripts/ws-client-pmd-rsv1-continuation.json new file mode 100644 index 0000000..b1bf001 --- /dev/null +++ b/crates/npro-test/transcripts/ws-client-pmd-rsv1-continuation.json @@ -0,0 +1,17 @@ +{ + "format": "lws-transcript/1", + "case": "ws-client-pmd-rsv1-continuation", + "side": "client", + "t0_us": 1000000000, + "t0_wall": 1767225600, + "seed": 1, + "steps": [ + {"t": 3405000, "tx": "474554202f6563686f20485454502f312e310d0a507261676d613a206e6f2d63616368650d0a43616368652d436f6e74726f6c3a206e6f2d63616368650d0a486f73743a2073616e73696f0d0a4f726967696e3a20687474703a2f2f73616e73696f0d0a557067726164653a20776562736f636b65740d0a436f6e6e656374696f6e3a20557067726164650d0a5365632d576562536f636b65742d4b65793a204f766f6d7451704b4357556e5a5737744d52364771773d3d0d0a5365632d576562536f636b65742d50726f746f636f6c3a206563686f0d0a5365632d576562536f636b65742d457874656e73696f6e733a207065726d6573736167652d6465666c6174650d0a5365632d576562536f636b65742d56657273696f6e3a2031330d0a0d0a"}, + {"t": 3406000, "rx": "485454502f312e312031303120537769746368696e672050726f746f636f6c730d0a557067726164653a20776562736f636b65740d0a436f6e6e656374696f6e3a20557067726164650d0a5365632d576562536f636b65742d50726f746f636f6c3a206563686f0d0a5365632d576562536f636b65742d4163636570743a207253734a662f5a4b516469756c304247494a3675514761776455383d0d0a5365632d576562536f636b65742d457874656e73696f6e733a207065726d6573736167652d6465666c6174650d0a0d0a"}, + {"t": 3407000, "rx": "01024865c0036c6c6f"}, + {"t": 3407000, "app_rx": "4865"}, + {"t": 3407000, "tx": "888a167398761599ea056053fa1f6200"}, + {"t": 3408000, "rx": "880203e8"}, + {"t": 3408000, "close": ""} + ] +} diff --git a/crates/npro-test/transcripts/ws-client-pmd-rsv1-ping.json b/crates/npro-test/transcripts/ws-client-pmd-rsv1-ping.json new file mode 100644 index 0000000..e541994 --- /dev/null +++ b/crates/npro-test/transcripts/ws-client-pmd-rsv1-ping.json @@ -0,0 +1,16 @@ +{ + "format": "lws-transcript/1", + "case": "ws-client-pmd-rsv1-ping", + "side": "client", + "t0_us": 1000000000, + "t0_wall": 1767225600, + "seed": 1, + "steps": [ + {"t": 3409000, "tx": "474554202f6563686f20485454502f312e310d0a507261676d613a206e6f2d63616368650d0a43616368652d436f6e74726f6c3a206e6f2d63616368650d0a486f73743a2073616e73696f0d0a4f726967696e3a20687474703a2f2f73616e73696f0d0a557067726164653a20776562736f636b65740d0a436f6e6e656374696f6e3a20557067726164650d0a5365632d576562536f636b65742d4b65793a204f766f6d7451704b4357556e5a5737744d52364771773d3d0d0a5365632d576562536f636b65742d50726f746f636f6c3a206563686f0d0a5365632d576562536f636b65742d457874656e73696f6e733a207065726d6573736167652d6465666c6174650d0a5365632d576562536f636b65742d56657273696f6e3a2031330d0a0d0a"}, + {"t": 3410000, "rx": "485454502f312e312031303120537769746368696e672050726f746f636f6c730d0a557067726164653a20776562736f636b65740d0a436f6e6e656374696f6e3a20557067726164650d0a5365632d576562536f636b65742d50726f746f636f6c3a206563686f0d0a5365632d576562536f636b65742d4163636570743a207253734a662f5a4b516469756c304247494a3675514761776455383d0d0a5365632d576562536f636b65742d457874656e73696f6e733a207065726d6573736167652d6465666c6174650d0a0d0a"}, + {"t": 3411000, "rx": "c900"}, + {"t": 3411000, "tx": "888a167398761599ea056053fa1f6200"}, + {"t": 3412000, "rx": "880203e8"}, + {"t": 3412000, "close": ""} + ] +} diff --git a/crates/npro-test/transcripts/ws-client-pmd-rsv2.json b/crates/npro-test/transcripts/ws-client-pmd-rsv2.json new file mode 100644 index 0000000..5d0c4f3 --- /dev/null +++ b/crates/npro-test/transcripts/ws-client-pmd-rsv2.json @@ -0,0 +1,16 @@ +{ + "format": "lws-transcript/1", + "case": "ws-client-pmd-rsv2", + "side": "client", + "t0_us": 1000000000, + "t0_wall": 1767225600, + "seed": 1, + "steps": [ + {"t": 3401000, "tx": "474554202f6563686f20485454502f312e310d0a507261676d613a206e6f2d63616368650d0a43616368652d436f6e74726f6c3a206e6f2d63616368650d0a486f73743a2073616e73696f0d0a4f726967696e3a20687474703a2f2f73616e73696f0d0a557067726164653a20776562736f636b65740d0a436f6e6e656374696f6e3a20557067726164650d0a5365632d576562536f636b65742d4b65793a204f766f6d7451704b4357556e5a5737744d52364771773d3d0d0a5365632d576562536f636b65742d50726f746f636f6c3a206563686f0d0a5365632d576562536f636b65742d457874656e73696f6e733a207065726d6573736167652d6465666c6174650d0a5365632d576562536f636b65742d56657273696f6e3a2031330d0a0d0a"}, + {"t": 3402000, "rx": "485454502f312e312031303120537769746368696e672050726f746f636f6c730d0a557067726164653a20776562736f636b65740d0a436f6e6e656374696f6e3a20557067726164650d0a5365632d576562536f636b65742d50726f746f636f6c3a206563686f0d0a5365632d576562536f636b65742d4163636570743a207253734a662f5a4b516469756c304247494a3675514761776455383d0d0a5365632d576562536f636b65742d457874656e73696f6e733a207065726d6573736167652d6465666c6174650d0a0d0a"}, + {"t": 3403000, "rx": "a10548656c6c6f"}, + {"t": 3403000, "tx": "888a167398761599ea056053fa1f6200"}, + {"t": 3404000, "rx": "880203e8"}, + {"t": 3404000, "close": ""} + ] +} diff --git a/crates/npro-test/transcripts/ws-client-rsv1-no-ext.json b/crates/npro-test/transcripts/ws-client-rsv1-no-ext.json new file mode 100644 index 0000000..93e53f0 --- /dev/null +++ b/crates/npro-test/transcripts/ws-client-rsv1-no-ext.json @@ -0,0 +1,17 @@ +{ + "format": "lws-transcript/1", + "case": "ws-client-rsv1-no-ext", + "side": "client", + "t0_us": 1000000000, + "t0_wall": 1767225600, + "seed": 1, + "steps": [ + {"t": 3201000, "tx": "474554202f6563686f20485454502f312e310d0a507261676d613a206e6f2d63616368650d0a43616368652d436f6e74726f6c3a206e6f2d63616368650d0a486f73743a2073616e73696f0d0a4f726967696e3a20687474703a2f2f73616e73696f0d0a557067726164653a20776562736f636b65740d0a436f6e6e656374696f6e3a20557067726164650d0a5365632d576562536f636b65742d4b65793a204f766f6d7451704b4357556e5a5737744d52364771773d3d0d0a5365632d576562536f636b65742d50726f746f636f6c3a206563686f0d0a5365632d576562536f636b65742d56657273696f6e3a2031330d0a0d0a"}, + {"t": 3202000, "rx": "485454502f312e312031303120537769746368696e672050726f746f636f6c730d0a557067726164653a20776562736f636b65740d0a436f6e6e656374696f6e3a20557067726164650d0a5365632d576562536f636b65742d50726f746f636f6c3a206563686f0d0a5365632d576562536f636b65742d4163636570743a207253734a662f5a4b516469756c304247494a3675514761776455383d0d0a0d0a"}, + {"t": 3202000, "tx": "8185167398765e16f41a79"}, + {"t": 3203000, "rx": "c10548656c6c6f"}, + {"t": 3203000, "tx": "888abe4852b2bda220c1c86830dbca3b"}, + {"t": 3204000, "rx": "880203e8"}, + {"t": 3204000, "close": ""} + ] +} diff --git a/crates/npro-test/transcripts/ws-client-rsv2.json b/crates/npro-test/transcripts/ws-client-rsv2.json new file mode 100644 index 0000000..5639067 --- /dev/null +++ b/crates/npro-test/transcripts/ws-client-rsv2.json @@ -0,0 +1,17 @@ +{ + "format": "lws-transcript/1", + "case": "ws-client-rsv2", + "side": "client", + "t0_us": 1000000000, + "t0_wall": 1767225600, + "seed": 1, + "steps": [ + {"t": 3205000, "tx": "474554202f6563686f20485454502f312e310d0a507261676d613a206e6f2d63616368650d0a43616368652d436f6e74726f6c3a206e6f2d63616368650d0a486f73743a2073616e73696f0d0a4f726967696e3a20687474703a2f2f73616e73696f0d0a557067726164653a20776562736f636b65740d0a436f6e6e656374696f6e3a20557067726164650d0a5365632d576562536f636b65742d4b65793a204f766f6d7451704b4357556e5a5737744d52364771773d3d0d0a5365632d576562536f636b65742d50726f746f636f6c3a206563686f0d0a5365632d576562536f636b65742d56657273696f6e3a2031330d0a0d0a"}, + {"t": 3206000, "rx": "485454502f312e312031303120537769746368696e672050726f746f636f6c730d0a557067726164653a20776562736f636b65740d0a436f6e6e656374696f6e3a20557067726164650d0a5365632d576562536f636b65742d50726f746f636f6c3a206563686f0d0a5365632d576562536f636b65742d4163636570743a207253734a662f5a4b516469756c304247494a3675514761776455383d0d0a0d0a"}, + {"t": 3206000, "tx": "8185167398765e16f41a79"}, + {"t": 3207000, "rx": "a10548656c6c6f"}, + {"t": 3207000, "tx": "888abe4852b2bda220c1c86830dbca3b"}, + {"t": 3208000, "rx": "880203e8"}, + {"t": 3208000, "close": ""} + ] +} diff --git a/crates/npro-test/transcripts/ws-client.json b/crates/npro-test/transcripts/ws-client.json new file mode 100644 index 0000000..50f07f2 --- /dev/null +++ b/crates/npro-test/transcripts/ws-client.json @@ -0,0 +1,15 @@ +{ + "format": "lws-transcript/1", + "case": "ws-client", + "side": "client", + "t0_us": 1000000000, + "t0_wall": 1767225600, + "seed": 1, + "steps": [ + {"t": 6000, "tx": "474554202f6563686f20485454502f312e310d0a507261676d613a206e6f2d63616368650d0a43616368652d436f6e74726f6c3a206e6f2d63616368650d0a486f73743a2073616e73696f0d0a4f726967696e3a20687474703a2f2f73616e73696f0d0a557067726164653a20776562736f636b65740d0a436f6e6e656374696f6e3a20557067726164650d0a5365632d576562536f636b65742d4b65793a204f766f6d7451704b4357556e5a5737744d52364771773d3d0d0a5365632d576562536f636b65742d50726f746f636f6c3a206563686f0d0a5365632d576562536f636b65742d56657273696f6e3a2031330d0a0d0a"}, + {"t": 7000, "rx": "485454502f312e312031303120537769746368696e672050726f746f636f6c730d0a557067726164653a20776562736f636b65740d0a436f6e6e656374696f6e3a20557067726164650d0a5365632d576562536f636b65742d50726f746f636f6c3a206563686f0d0a5365632d576562536f636b65742d4163636570743a207253734a662f5a4b516469756c304247494a3675514761776455383d0d0a0d0a"}, + {"t": 7000, "tx": "8185167398765e16f41a79"}, + {"t": 8000, "rx": "810548656c6c6f"}, + {"t": 8000, "app_rx": "48656c6c6f"} + ] +} diff --git a/crates/npro-test/transcripts/ws-server-close-partial.json b/crates/npro-test/transcripts/ws-server-close-partial.json new file mode 100644 index 0000000..62135a9 --- /dev/null +++ b/crates/npro-test/transcripts/ws-server-close-partial.json @@ -0,0 +1,15 @@ +{ + "format": "lws-transcript/1", + "case": "ws-server-close-partial", + "side": "server", + "t0_us": 1000000000, + "t0_wall": 1767225600, + "seed": 0, + "steps": [ + {"t": 3803000, "rx": "474554202f6563686f20485454502f312e310d0a486f73743a2073616e73696f0d0a557067726164653a20776562736f636b65740d0a436f6e6e656374696f6e3a20557067726164650d0a5365632d576562536f636b65742d56657273696f6e3a2031330d0a5365632d576562536f636b65742d50726f746f636f6c3a206563686f0d0a5365632d576562536f636b65742d4b65793a206447686c49484e68625842735a5342756232356a5a513d3d0d0a0d0a"}, + {"t": 3803000, "tx": "485454502f312e312031303120537769746368696e672050726f746f636f6c730d0a557067726164653a20576562536f636b65740d0a436f6e6e656374696f6e3a20557067726164650d0a5365632d576562536f636b65742d4163636570743a20733370504c4d426954786151396b59477a7a685a52624b2b784f6f3d0d0a5365632d576562536f636b65742d50726f746f636f6c3a206563686f0d0a0d0a"}, + {"t": 3804000, "rx": "81850000000048656c6c6f88820000000003e8"}, + {"t": 3804000, "app_rx": "48656c6c6f"}, + {"t": 3804000, "tx": "810548656c6c6f880203e8"} + ] +} diff --git a/crates/npro-test/transcripts/ws-server-close-when-flushed.json b/crates/npro-test/transcripts/ws-server-close-when-flushed.json new file mode 100644 index 0000000..8bd0794 --- /dev/null +++ b/crates/npro-test/transcripts/ws-server-close-when-flushed.json @@ -0,0 +1,15 @@ +{ + "format": "lws-transcript/1", + "case": "ws-server-close-when-flushed", + "side": "server", + "t0_us": 1000000000, + "t0_wall": 1767225600, + "seed": 0, + "steps": [ + {"t": 3805000, "rx": "474554202f6563686f20485454502f312e310d0a486f73743a2073616e73696f0d0a557067726164653a20776562736f636b65740d0a436f6e6e656374696f6e3a20557067726164650d0a5365632d576562536f636b65742d56657273696f6e3a2031330d0a5365632d576562536f636b65742d50726f746f636f6c3a206563686f0d0a5365632d576562536f636b65742d4b65793a206447686c49484e68625842735a5342756232356a5a513d3d0d0a0d0a"}, + {"t": 3805000, "tx": "485454502f312e312031303120537769746368696e672050726f746f636f6c730d0a557067726164653a20576562536f636b65740d0a436f6e6e656374696f6e3a20557067726164650d0a5365632d576562536f636b65742d4163636570743a20733370504c4d426954786151396b59477a7a685a52624b2b784f6f3d0d0a5365632d576562536f636b65742d50726f746f636f6c3a206563686f0d0a0d0a"}, + {"t": 3806000, "rx": "81830000000042796588820000000003e8"}, + {"t": 3806000, "app_rx": "427965"}, + {"t": 3806000, "tx": "8103427965"} + ] +} diff --git a/crates/npro-test/transcripts/ws-server-conn-no-upgrade.json b/crates/npro-test/transcripts/ws-server-conn-no-upgrade.json new file mode 100644 index 0000000..a8dabda --- /dev/null +++ b/crates/npro-test/transcripts/ws-server-conn-no-upgrade.json @@ -0,0 +1,12 @@ +{ + "format": "lws-transcript/1", + "case": "ws-server-conn-no-upgrade", + "side": "server", + "t0_us": 1000000000, + "t0_wall": 1767225600, + "seed": 0, + "steps": [ + {"t": 3003000, "rx": "474554202f6563686f20485454502f312e310d0a486f73743a2073616e73696f0d0a557067726164653a20776562736f636b65740d0a436f6e6e656374696f6e3a2075700d0a5365632d576562536f636b65742d56657273696f6e3a2031330d0a5365632d576562536f636b65742d50726f746f636f6c3a206563686f0d0a5365632d576562536f636b65742d4b65793a206447686c49484e68625842735a5342756232356a5a513d3d0d0a0d0a"}, + {"t": 3003000, "tx": "485454502f312e31203430302042616420526571756573740d0a636f6e74656e742d747970653a20746578742f68746d6c0d0a636f6e74656e742d6c656e6774683a203137330d0a0d0a3c68746d6c3e3c686561643e3c6d65746120636861727365743d7574662d3820687474702d65717569763d22436f6e74656e742d4c616e67756167652220636f6e74656e743d22656e222f3e3c6c696e6b2072656c3d227374796c6573686565742220747970653d22746578742f6373732220687265663d222f6572726f722e637373222f3e3c2f686561643e3c626f64793e3c68313e3430303c2f68313e3c2f626f64793e3c2f68746d6c3e"} + ] +} diff --git a/crates/npro-test/transcripts/ws-server-huge-frame.json b/crates/npro-test/transcripts/ws-server-huge-frame.json new file mode 100644 index 0000000..e7aaf76 --- /dev/null +++ b/crates/npro-test/transcripts/ws-server-huge-frame.json @@ -0,0 +1,14 @@ +{ + "format": "lws-transcript/1", + "case": "ws-server-huge-frame", + "side": "server", + "t0_us": 1000000000, + "t0_wall": 1767225600, + "seed": 0, + "steps": [ + {"t": 3151000, "rx": "474554202f6563686f20485454502f312e310d0a486f73743a2073616e73696f0d0a557067726164653a20776562736f636b65740d0a436f6e6e656374696f6e3a20557067726164650d0a5365632d576562536f636b65742d56657273696f6e3a2031330d0a5365632d576562536f636b65742d50726f746f636f6c3a206563686f0d0a5365632d576562536f636b65742d4b65793a206447686c49484e68625842735a5342756232356a5a513d3d0d0a0d0a"}, + {"t": 3151000, "tx": "485454502f312e312031303120537769746368696e672050726f746f636f6c730d0a557067726164653a20576562536f636b65740d0a436f6e6e656374696f6e3a20557067726164650d0a5365632d576562536f636b65742d4163636570743a20733370504c4d426954786151396b59477a7a685a52624b2b784f6f3d0d0a5365632d576562536f636b65742d50726f746f636f6c3a206563686f0d0a0d0a"}, + {"t": 3152000, "rx": "82ff000000001000000100000000"}, + {"t": 3152000, "tx": "880c03f168756765206672616d65"} + ] +} diff --git a/crates/npro-test/transcripts/ws-server-no-subprotocol.json b/crates/npro-test/transcripts/ws-server-no-subprotocol.json new file mode 100644 index 0000000..52aa4d4 --- /dev/null +++ b/crates/npro-test/transcripts/ws-server-no-subprotocol.json @@ -0,0 +1,12 @@ +{ + "format": "lws-transcript/1", + "case": "ws-server-no-subprotocol", + "side": "server", + "t0_us": 1000000000, + "t0_wall": 1767225600, + "seed": 0, + "steps": [ + {"t": 3004000, "rx": "474554202f6563686f20485454502f312e310d0a486f73743a2073616e73696f0d0a557067726164653a20776562736f636b65740d0a436f6e6e656374696f6e3a20557067726164650d0a5365632d576562536f636b65742d56657273696f6e3a2031330d0a5365632d576562536f636b65742d50726f746f636f6c3a20636861740d0a5365632d576562536f636b65742d4b65793a206447686c49484e68625842735a5342756232356a5a513d3d0d0a0d0a"}, + {"t": 3004000, "tx": "485454502f312e31203430302042616420526571756573740d0a636f6e74656e742d747970653a20746578742f68746d6c0d0a636f6e74656e742d6c656e6774683a203137330d0a0d0a3c68746d6c3e3c686561643e3c6d65746120636861727365743d7574662d3820687474702d65717569763d22436f6e74656e742d4c616e67756167652220636f6e74656e743d22656e222f3e3c6c696e6b2072656c3d227374796c6573686565742220747970653d22746578742f6373732220687265663d222f6572726f722e637373222f3e3c2f686561643e3c626f64793e3c68313e3430303c2f68313e3c2f626f64793e3c2f68746d6c3e"} + ] +} diff --git a/crates/npro-test/transcripts/ws-server-no-version.json b/crates/npro-test/transcripts/ws-server-no-version.json new file mode 100644 index 0000000..5c00cfc --- /dev/null +++ b/crates/npro-test/transcripts/ws-server-no-version.json @@ -0,0 +1,12 @@ +{ + "format": "lws-transcript/1", + "case": "ws-server-no-version", + "side": "server", + "t0_us": 1000000000, + "t0_wall": 1767225600, + "seed": 0, + "steps": [ + {"t": 3002000, "rx": "474554202f6563686f20485454502f312e310d0a486f73743a2073616e73696f0d0a557067726164653a20776562736f636b65740d0a436f6e6e656374696f6e3a20557067726164650d0a5365632d576562536f636b65742d50726f746f636f6c3a206563686f0d0a5365632d576562536f636b65742d4b65793a206447686c49484e68625842735a5342756232356a5a513d3d0d0a0d0a"}, + {"t": 3002000, "tx": "485454502f312e31203430302042616420526571756573740d0a636f6e74656e742d747970653a20746578742f68746d6c0d0a636f6e74656e742d6c656e6774683a203137330d0a0d0a3c68746d6c3e3c686561643e3c6d65746120636861727365743d7574662d3820687474702d65717569763d22436f6e74656e742d4c616e67756167652220636f6e74656e743d22656e222f3e3c6c696e6b2072656c3d227374796c6573686565742220747970653d22746578742f6373732220687265663d222f6572726f722e637373222f3e3c2f686561643e3c626f64793e3c68313e3430303c2f68313e3c2f626f64793e3c2f68746d6c3e"} + ] +} diff --git a/crates/npro-test/transcripts/ws-server-ping-close.json b/crates/npro-test/transcripts/ws-server-ping-close.json new file mode 100644 index 0000000..4c26e4b --- /dev/null +++ b/crates/npro-test/transcripts/ws-server-ping-close.json @@ -0,0 +1,14 @@ +{ + "format": "lws-transcript/1", + "case": "ws-server-ping-close", + "side": "server", + "t0_us": 1000000000, + "t0_wall": 1767225600, + "seed": 0, + "steps": [ + {"t": 3801000, "rx": "474554202f6563686f20485454502f312e310d0a486f73743a2073616e73696f0d0a557067726164653a20776562736f636b65740d0a436f6e6e656374696f6e3a20557067726164650d0a5365632d576562536f636b65742d56657273696f6e3a2031330d0a5365632d576562536f636b65742d50726f746f636f6c3a206563686f0d0a5365632d576562536f636b65742d4b65793a206447686c49484e68625842735a5342756232356a5a513d3d0d0a0d0a"}, + {"t": 3801000, "tx": "485454502f312e312031303120537769746368696e672050726f746f636f6c730d0a557067726164653a20576562536f636b65740d0a436f6e6e656374696f6e3a20557067726164650d0a5365632d576562536f636b65742d4163636570743a20733370504c4d426954786151396b59477a7a685a52624b2b784f6f3d0d0a5365632d576562536f636b65742d50726f746f636f6c3a206563686f0d0a0d0a"}, + {"t": 3802000, "rx": "8981000000007088820000000003e8"}, + {"t": 3802000, "tx": "8a0170880203e8"} + ] +} diff --git a/crates/npro-test/transcripts/ws-server-pmd-rsv1-continuation.json b/crates/npro-test/transcripts/ws-server-pmd-rsv1-continuation.json new file mode 100644 index 0000000..669f686 --- /dev/null +++ b/crates/npro-test/transcripts/ws-server-pmd-rsv1-continuation.json @@ -0,0 +1,16 @@ +{ + "format": "lws-transcript/1", + "case": "ws-server-pmd-rsv1-continuation", + "side": "server", + "t0_us": 1000000000, + "t0_wall": 1767225600, + "seed": 0, + "steps": [ + {"t": 3301000, "rx": "474554202f6563686f20485454502f312e310d0a486f73743a2073616e73696f2d706d640d0a557067726164653a20776562736f636b65740d0a436f6e6e656374696f6e3a20557067726164650d0a5365632d576562536f636b65742d56657273696f6e3a2031330d0a5365632d576562536f636b65742d50726f746f636f6c3a206563686f0d0a5365632d576562536f636b65742d457874656e73696f6e733a207065726d6573736167652d6465666c6174650d0a5365632d576562536f636b65742d4b65793a206447686c49484e68625842735a5342756232356a5a513d3d0d0a0d0a"}, + {"t": 3301000, "tx": "485454502f312e312031303120537769746368696e672050726f746f636f6c730d0a557067726164653a20576562536f636b65740d0a436f6e6e656374696f6e3a20557067726164650d0a5365632d576562536f636b65742d4163636570743a20733370504c4d426954786151396b59477a7a685a52624b2b784f6f3d0d0a5365632d576562536f636b65742d50726f746f636f6c3a206563686f0d0a7365632d776562736f636b65742d657874656e73696f6e733a207065726d6573736167652d6465666c6174650d0a0d0a"}, + {"t": 3302000, "rx": "0182000000004865c083000000006c6c6f"}, + {"t": 3302000, "app_rx": "4865"}, + {"t": 3302000, "tx": "880a03ea7273762062697473"}, + {"t": 3303000, "rx": "88820000000003ea"} + ] +} diff --git a/crates/npro-test/transcripts/ws-server-version-8.json b/crates/npro-test/transcripts/ws-server-version-8.json new file mode 100644 index 0000000..7896354 --- /dev/null +++ b/crates/npro-test/transcripts/ws-server-version-8.json @@ -0,0 +1,12 @@ +{ + "format": "lws-transcript/1", + "case": "ws-server-version-8", + "side": "server", + "t0_us": 1000000000, + "t0_wall": 1767225600, + "seed": 0, + "steps": [ + {"t": 3001000, "rx": "474554202f6563686f20485454502f312e310d0a486f73743a2073616e73696f0d0a557067726164653a20776562736f636b65740d0a436f6e6e656374696f6e3a20557067726164650d0a5365632d576562536f636b65742d56657273696f6e3a20380d0a5365632d576562536f636b65742d50726f746f636f6c3a206563686f0d0a5365632d576562536f636b65742d4b65793a206447686c49484e68625842735a5342756232356a5a513d3d0d0a0d0a"}, + {"t": 3001000, "tx": "485454502f312e312034323620557067726164652052657175697265640d0a636f6e74656e742d747970653a20746578742f68746d6c0d0a7365632d776562736f636b65742d76657273696f6e3a2031330d0a636f6e74656e742d6c656e6774683a203137330d0a0d0a3c68746d6c3e3c686561643e3c6d65746120636861727365743d7574662d3820687474702d65717569763d22436f6e74656e742d4c616e67756167652220636f6e74656e743d22656e222f3e3c6c696e6b2072656c3d227374796c6573686565742220747970653d22746578742f6373732220687265663d222f6572726f722e637373222f3e3c2f686561643e3c626f64793e3c68313e3432363c2f68313e3c2f626f64793e3c2f68746d6c3e"} + ] +} diff --git a/scripts/sync-c-oracle.sh b/scripts/sync-c-oracle.sh new file mode 100755 index 0000000..ea12256 --- /dev/null +++ b/scripts/sync-c-oracle.sh @@ -0,0 +1,35 @@ +#!/bin/sh +# +# Copy what npro is checked against from a C lws checkout: +# +# scripts/sync-c-oracle.sh /path/to/libwebsockets +# +# The api-test-sansio transcripts and their README go to +# crates/npro-test/transcripts/, replacing what is there, and the C commit +# they came from is recorded in C-COMMIT beside them. The checkout should be +# clean: a transcript is behaviour, and the commit that changes one here +# names the C commit that changed it there. + +set -eu + +if [ $# -ne 1 ] || [ ! -d "$1/minimal-examples-lowlevel/api-tests/api-test-sansio" ]; then + echo "usage: $0 <libwebsockets checkout>" >&2 + exit 1 +fi + +c="$1" +here="$(cd "$(dirname "$0")/.." && pwd)" +src="$c/minimal-examples-lowlevel/api-tests/api-test-sansio/transcripts" +dst="$here/crates/npro-test/transcripts" + +if [ -n "$(git -C "$c" status --porcelain -- "$src")" ]; then + echo "$src has uncommitted changes" >&2 + exit 1 +fi + +rm -f "$dst"/*.json +cp "$src"/*.json "$dst/" +cp "$src/README.md" "$dst/README.lws.md" +git -C "$c" log -1 --format='%H %s' > "$dst/C-COMMIT" + +echo "$(ls "$dst"/*.json | wc -l) transcripts from $(cut -c1-12 "$dst/C-COMMIT")"
Page fetched 0s ago, creation time: 9ms (vhost etag hits: 0%, cache hits: 0%)