diff --git a/Cargo.toml b/Cargo.toml index bd47dcf..bf1b51b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,7 +4,6 @@ version = "0.1.11" edition = "2021" authors = ["Xudong Huang "] repository = "https://github.com/Xudong-Huang/may_minihttp.git" -homepage = "https://github.com/Xudong-Huang/may_minihttp.git" documentation = "https://docs.rs/may_minihttp" description = "Mini http server that implemented on top of [may](https://github.com/Xudong-Huang/may)" readme = "README.md" @@ -32,7 +31,7 @@ serde_json = { version = "1", optional = true } tracing = { version = "0.1", default-features = false, features = ["std"], optional = true } [dev-dependencies] -atoi = "2" +atoi = "3" num_cpus = "1.0" smallvec = "1.1" env_logger = "0.11" @@ -43,12 +42,12 @@ yarte = { version = "0.15", features = ["bytes-buf", "json"] } buf-min = { version = "0.7", features = ["bytes"] } mimalloc = { version = "0.1", default-features = false } -nanorand = { version = "0.7", default-features = false, features = ["std", "wyrand"] } +nanorand = { version = "0.8", default-features = false, features = ["std", "wyrand"] } # Load testing and integration testing goose = "0.18.1" gumdrop = "0.8" -testcontainers = "0.15" +testcontainers = "0.28" tokio = { version = "1", features = ["full"] } rcgen = "0.14" flate2 = "1.1" diff --git a/examples/techempower.rs b/examples/techempower.rs index 19762fe..96c8054 100644 --- a/examples/techempower.rs +++ b/examples/techempower.rs @@ -230,7 +230,7 @@ mod __impl { id: 0, message: "Additional fortune added at request time.", }); - fortunes.sort_by(|it, next| it.message.cmp(next.message)); + fortunes.sort_unstable_by(|it, next| it.message.cmp(next.message)); let mut body = unsafe { std::ptr::read(buf) }; ywrite_html!(body, "{{> fortune }}"); @@ -298,7 +298,7 @@ mod __impl { fn new_service(&self, id: usize) -> Self::Service { let db = self.db_pool.get_connection(id); - let rng = WyRand::new(); + let rng = WyRand::new_seed(0); Techempower { db, rng } } } diff --git a/src/request.rs b/src/request.rs index 7cae11e..db4246e 100644 --- a/src/request.rs +++ b/src/request.rs @@ -694,19 +694,15 @@ pub(crate) fn decode_with_close<'header, 'buf, 'stream, const N: usize>( // so we can transfer the mutable reference to Request let buf: &[u8] = unsafe { std::mem::transmute(req_buf.chunk()) }; - // Wait for complete headers before parsing to prevent token errors (issue #18: a head split - // across TCP segments). Only the first MAX_REQUEST_HEAD_BYTES are searched: a head that has - // not ended by then is refused rather than buffered without bound. + // No separate `\r\n\r\n` pre-scan: `httparse` returns `Status::Partial` on any truncated + // head (mid-method, mid-path, mid-header, or no terminating `\r\n\r\n` yet), which maps to + // `Ok(None)` below, and malformed bytes are a permanent 400 whatever arrives later. Only the + // first MAX_REQUEST_HEAD_BYTES are parsed: a head that has not ended by then is refused (431) + // rather than buffered or re-parsed without bound. let window = &buf[..buf.len().min(MAX_REQUEST_HEAD_BYTES)]; - if !window.windows(4).any(|w| w == b"\r\n\r\n") { - if buf.len() >= MAX_REQUEST_HEAD_BYTES { - return reject(431, "request head too large"); - } - return Ok(None); // Need more data - } let header_limit = headers.len(); - let status = match req.parse_with_uninit_headers(buf, headers) { + let status = match req.parse_with_uninit_headers(window, headers) { Ok(s) => s, Err(httparse::Error::TooManyHeaders) => { warn!( @@ -723,6 +719,9 @@ pub(crate) fn decode_with_close<'header, 'buf, 'stream, const N: usize>( let len = match status { httparse::Status::Complete(amt) => amt, + httparse::Status::Partial if buf.len() >= MAX_REQUEST_HEAD_BYTES => { + return reject(431, "request head too large"); + } httparse::Status::Partial => return Ok(None), }; let framing = framing(&req)?; diff --git a/tests/test_server.rs b/tests/test_server.rs index 699d921..6780d6a 100644 --- a/tests/test_server.rs +++ b/tests/test_server.rs @@ -34,7 +34,7 @@ impl ConfigurableTestServer { // For now, start with default - we'll add configuration support next let server_handle = thread::spawn(move || { let _server = HttpServer(TestService) - .start(&format!("127.0.0.1:{}", port)) + .start(format!("127.0.0.1:{}", port)) .expect("Failed to start test server"); while !shutdown_clone.load(Ordering::Relaxed) {