diff --git a/Cargo.lock b/Cargo.lock index 982b17f..e936ad4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -79,7 +79,6 @@ dependencies = [ "either", "flume", "hashbrown", - "httparse", "indexmap", "itoa", "log", @@ -123,6 +122,7 @@ dependencies = [ "criterion", "hashbrown", "hex", + "httparse", "itoa", "log", "memchr", diff --git a/aquatic_http/Cargo.toml b/aquatic_http/Cargo.toml index ffee029..c56cf9b 100644 --- a/aquatic_http/Cargo.toml +++ b/aquatic_http/Cargo.toml @@ -22,7 +22,6 @@ aquatic_http_protocol = { path = "../aquatic_http_protocol" } either = "1" flume = "0.7" hashbrown = { version = "0.7", features = ["serde"] } -httparse = "1" indexmap = "1" itoa = "0.4" log = "0.4" diff --git a/aquatic_http/src/lib/network/connection.rs b/aquatic_http/src/lib/network/connection.rs index 294faae..419a0bc 100644 --- a/aquatic_http/src/lib/network/connection.rs +++ b/aquatic_http/src/lib/network/connection.rs @@ -9,7 +9,7 @@ use mio::net::TcpStream; use native_tls::{TlsAcceptor, MidHandshakeTlsStream}; use aquatic_common_tcp::network::stream::Stream; -use aquatic_http_protocol::request::Request; +use aquatic_http_protocol::request::{Request, RequestParseError}; use crate::common::*; @@ -17,10 +17,9 @@ use crate::common::*; #[derive(Debug)] pub enum RequestReadError { NeedMoreData, - Invalid(anyhow::Error), StreamEnded, + Parse(anyhow::Error), Io(::std::io::Error), - Parse(::httparse::Error), } @@ -71,31 +70,20 @@ impl EstablishedConnection { } } - let mut headers = [httparse::EMPTY_HEADER; 16]; - let mut http_request = httparse::Request::new(&mut headers); + match Request::from_bytes(&self.buf[..self.bytes_read]){ + Ok(request) => { + self.clear_buffer(); - match http_request.parse(&self.buf[..self.bytes_read]){ - Ok(httparse::Status::Complete(_)) => { - if let Some(path) = http_request.path { - let res_request = Request::from_http_get_path(path); - - self.clear_buffer(); - - res_request.map_err(RequestReadError::Invalid) - } else { - self.clear_buffer(); - - Err(RequestReadError::Invalid(anyhow::anyhow!("no http path"))) - } + Ok(request) }, - Ok(httparse::Status::Partial) => { + Err(RequestParseError::NeedMoreData) => { Err(RequestReadError::NeedMoreData) }, - Err(err) => { + Err(RequestParseError::Invalid(err)) => { self.clear_buffer(); Err(RequestReadError::Parse(err)) - } + }, } } diff --git a/aquatic_http/src/lib/network/mod.rs b/aquatic_http/src/lib/network/mod.rs index 1724548..16f4e88 100644 --- a/aquatic_http/src/lib/network/mod.rs +++ b/aquatic_http/src/lib/network/mod.rs @@ -227,8 +227,8 @@ pub fn handle_connection_read_event( // Stop reading data (defer to later events) break; }, - Err(RequestReadError::Invalid(err)) => { - info!("error reading request (invalid): {}", err); + Err(RequestReadError::Parse(err)) => { + info!("error reading request (invalid): {:#?}", err); let meta = ConnectionMeta { worker_index: socket_worker_index, @@ -253,11 +253,6 @@ pub fn handle_connection_read_event( break }, - Err(RequestReadError::Parse(err)) => { - ::log::info!("request httparse error: {}", err); - - break - }, Err(RequestReadError::Io(err)) => { ::log::info!("error reading request (io): {}", err); diff --git a/aquatic_http_protocol/Cargo.toml b/aquatic_http_protocol/Cargo.toml index d9ed4f3..27f5cbb 100644 --- a/aquatic_http_protocol/Cargo.toml +++ b/aquatic_http_protocol/Cargo.toml @@ -23,6 +23,7 @@ anyhow = "1" bendy = { version = "0.3", features = ["std", "serde"] } hashbrown = { version = "0.7", features = ["serde"] } hex = { version = "0.4", default-features = false } +httparse = "1" itoa = "0.4" log = "0.4" memchr = "2" diff --git a/aquatic_http_protocol/src/request.rs b/aquatic_http_protocol/src/request.rs index cd1ddc1..ba3fc29 100644 --- a/aquatic_http_protocol/src/request.rs +++ b/aquatic_http_protocol/src/request.rs @@ -109,6 +109,12 @@ impl ScrapeRequest { } +pub enum RequestParseError { + NeedMoreData, + Invalid(anyhow::Error), +} + + #[derive(Debug, Clone, PartialEq, Eq)] pub enum Request { Announce(AnnounceRequest), @@ -117,6 +123,30 @@ pub enum Request { impl Request { + /// Parse Request from HTTP request bytes + pub fn from_bytes(bytes: &[u8]) -> Result { + let mut headers = [httparse::EMPTY_HEADER; 16]; + let mut http_request = httparse::Request::new(&mut headers); + + match http_request.parse(bytes){ + Ok(httparse::Status::Complete(_)) => { + if let Some(path) = http_request.path { + let res_request = Self::from_http_get_path(path); + + res_request.map_err(RequestParseError::Invalid) + } else { + Err(RequestParseError::Invalid(anyhow::anyhow!("no http path"))) + } + }, + Ok(httparse::Status::Partial) => { + Err(RequestParseError::NeedMoreData) + }, + Err(err) => { + Err(RequestParseError::Invalid(anyhow::anyhow!("httparse: {:?}", err))) + } + } + } + /// Parse Request from http path (GET `/announce?info_hash=...`) /// /// Existing serde-url decode crates were insufficient, so the decision was