From 3b79240e447432444098ca22643cd9ed01aeb2de Mon Sep 17 00:00:00 2001 From: stammw Date: Sat, 18 May 2019 11:16:21 +0200 Subject: [PATCH] H3: make server receive a Request struct --- quinn-h3/examples/h3.rs | 2 +- quinn-h3/src/lib.rs | 6 +++++ quinn-h3/src/proto/connection.rs | 3 +++ quinn-h3/src/proto/headers.rs | 25 ++++++++++++++++++ quinn-h3/src/server.rs | 45 ++++++++++++++++++++++++++------ 5 files changed, 72 insertions(+), 9 deletions(-) diff --git a/quinn-h3/examples/h3.rs b/quinn-h3/examples/h3.rs index 55e25164c..31a44d28b 100644 --- a/quinn-h3/examples/h3.rs +++ b/quinn-h3/examples/h3.rs @@ -187,7 +187,7 @@ fn handle_connection( } fn handle_request(request: RequestReady) -> impl Future { - println!("received request: {:?}", request.headers()); + println!("received request: {:?}", request.request()); futures::future::ok(()) } diff --git a/quinn-h3/src/lib.rs b/quinn-h3/src/lib.rs index 9421d4313..31d257370 100644 --- a/quinn-h3/src/lib.rs +++ b/quinn-h3/src/lib.rs @@ -83,3 +83,9 @@ impl From for Error { } } } + +impl From for Error { + fn from(err: proto::headers::Error) -> Error { + Error::Peer(format!("invalid headers: {:?}", err)) + } +} diff --git a/quinn-h3/src/proto/connection.rs b/quinn-h3/src/proto/connection.rs index 3d12080f3..e9d7a1a6b 100644 --- a/quinn-h3/src/proto/connection.rs +++ b/quinn-h3/src/proto/connection.rs @@ -96,6 +96,7 @@ pub enum Error { HeaderListTooLarge, InvalidHeaderName(String), InvalidHeaderValue(String), + InvalidRequest(String), Settings { reason: String }, EncodeError { reason: EncoderError }, DecodeError { reason: DecoderError }, @@ -120,6 +121,8 @@ impl From for Error { match err { headers::Error::InvalidHeaderName(s) => Error::InvalidHeaderName(s), headers::Error::InvalidHeaderValue(s) => Error::InvalidHeaderValue(s), + headers::Error::InvalidRequest(e) => Error::InvalidRequest(format!("{:?}", e)), + headers::Error::MissingMethod => Error::InvalidRequest("missing method".into()), } } } diff --git a/quinn-h3/src/proto/headers.rs b/quinn-h3/src/proto/headers.rs index 2a0fbf014..d1ca78417 100644 --- a/quinn-h3/src/proto/headers.rs +++ b/quinn-h3/src/proto/headers.rs @@ -29,6 +29,28 @@ impl Header { } } + pub fn into_request_parts(self) -> Result<(Method, Uri, HeaderMap), Error> { + let mut uri = Uri::builder(); + + if let Some(path) = self.pseudo.path { + uri.path_and_query(path.as_bytes()); + } + + if let Some(scheme) = self.pseudo.scheme { + uri.scheme(scheme.as_bytes()); + } + + if let Some(authority) = self.pseudo.authority { + uri.authority(authority.as_bytes()); + } + + Ok(( + self.pseudo.method.ok_or(Error::MissingMethod)?, + uri.build().map_err(|e| Error::InvalidRequest(e))?, + self.fields, + )) + } + pub fn len(&self) -> usize { self.pseudo.len() + self.fields.len() } @@ -271,9 +293,12 @@ fn to_string(src: Bytes) -> String { unsafe { String::from_utf8_unchecked(src) } } +#[derive(Debug)] pub enum Error { InvalidHeaderName(std::string::String), InvalidHeaderValue(std::string::String), + InvalidRequest(http::Error), + MissingMethod, } impl Error { diff --git a/quinn-h3/src/server.rs b/quinn-h3/src/server.rs index 79b98631d..156284186 100644 --- a/quinn-h3/src/server.rs +++ b/quinn-h3/src/server.rs @@ -3,6 +3,7 @@ use std::net::ToSocketAddrs; use futures::task; use futures::{try_ready, Async, Future, Poll, Stream}; +use http::Request; use quinn::{EndpointBuilder, EndpointDriver, EndpointError, RecvStream, SendStream}; use quinn_proto::StreamId; use slog::{self, o, Logger}; @@ -186,12 +187,12 @@ impl Future for RecvRequest { Some(x) => x, None => return Err(Error::Internal("Recv request invalid state")), }; - return Ok(Async::Ready(RequestReady { - headers: decoded, + return Ok(Async::Ready(RequestReady::build( + decoded, frame_stream, - send: Some(send), - conn: self.conn.clone(), - })); + send, + self.conn.clone(), + )?)); } } } @@ -202,14 +203,42 @@ impl Future for RecvRequest { } pub struct RequestReady { - headers: Header, + request: Request<()>, frame_stream: FrameStream, send: Option, conn: ConnectionRef, } impl RequestReady { - pub fn headers<'a>(&'a self) -> &'a Header { - &self.headers + fn build( + headers: Header, + frame_stream: FrameStream, + send: SendStream, + conn: ConnectionRef, + ) -> Result { + let (method, uri, headers) = headers.into_request_parts()?; + let mut request = Request::builder(); + request.method(method); + request.uri(uri); + request.version(http::version::Version::HTTP_2); // TODO change once available + match request.headers_mut() { + Some(h) => *h = headers, + None => return Err(Error::peer("invalid header")), + } + + let request = request + .body(()) + .map_err(|e| Error::Peer(format!("invalid request: {:?}", e)))?; + + Ok(Self { + request, + frame_stream, + conn, + send: Some(send), + }) + } + + pub fn request<'a>(&'a self) -> &'a Request<()> { + &self.request } }