diff --git a/Cargo.toml b/Cargo.toml index 408f52d..91d1565 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,7 +8,7 @@ futures = "0.1" tokio-io = "0.1" tokio-timer = "0.1" bytes = "0.4" -http = { git = "https://github.com/carllerche/http" } +http = { git = "https://github.com/carllerche/http", branch = "uri-parts" } byteorder = "1.0" log = "0.3.8" fnv = "1.0.5" diff --git a/examples/server.rs b/examples/server.rs index f8b7aa3..1f19252 100644 --- a/examples/server.rs +++ b/examples/server.rs @@ -8,6 +8,8 @@ extern crate env_logger; use h2::server; +use http::{response, status}; + use futures::*; use tokio_core::reactor; @@ -34,10 +36,17 @@ pub fn main() { println!("H2 connection bound"); - conn.for_each(|frame| { - println!("RX: {:?}", frame); - Ok(()) - }) + // Receive a request + conn.into_future() + .then(|res| { + let (frame, conn) = res.unwrap(); + println!("Zomg frame; {:?}", frame); + + let mut response = response::Head::default(); + response.status = status::NO_CONTENT; + + conn.send_response(1, response, true) + }) }) .then(|res| { let _ = res.unwrap(); diff --git a/src/frame/headers.rs b/src/frame/headers.rs index 86a051c..fc3d46c 100644 --- a/src/frame/headers.rs +++ b/src/frame/headers.rs @@ -3,7 +3,7 @@ use hpack; use frame::{self, Frame, Head, Kind, Error}; use util::byte_str::ByteStr; -use http::{request, response, Method, StatusCode}; +use http::{request, response, version, uri, Method, StatusCode}; use http::header::{self, HeaderMap, HeaderName, HeaderValue}; use bytes::{BytesMut, Bytes}; @@ -201,7 +201,43 @@ impl Headers { } pub fn into_request(self) -> request::Head { - unimplemented!(); + let mut request = request::Head::default(); + + // TODO: should we distinguish between HTTP_2 and HTTP_2C? + // carllerche/http#42 + request.version = version::HTTP_2; + + if let Some(method) = self.pseudo.method { + request.method = method; + } else { + // TODO: invalid request + unimplemented!(); + } + + // Convert the URI + let mut parts = uri::Parts::default(); + + if let Some(scheme) = self.pseudo.scheme { + // TODO: Don't unwrap + parts.scheme = Some(uri::Scheme::try_from_shared(scheme.into()).unwrap()); + } + + if let Some(authority) = self.pseudo.authority { + // TODO: Don't unwrap + parts.authority = Some(uri::Authority::try_from_shared(authority.into()).unwrap()); + } + + if let Some(path) = self.pseudo.path { + // TODO: Don't unwrap + parts.origin_form = Some(uri::OriginForm::try_from_shared(path.into()).unwrap()); + } + + request.uri = parts.into(); + + // Set the header fields + request.headers = self.fields; + + request } pub fn encode(self, encoder: &mut hpack::Encoder, dst: &mut BytesMut) diff --git a/src/proto/connection.rs b/src/proto/connection.rs index 04fb70e..7ec1666 100644 --- a/src/proto/connection.rs +++ b/src/proto/connection.rs @@ -1,10 +1,11 @@ use {frame, Frame, ConnectionError, Peer, StreamId}; use client::Client; +use server::Server; use proto::{self, ReadySink, State}; use tokio_io::{AsyncRead, AsyncWrite}; -use http::{request}; +use http::{request, response}; use futures::*; @@ -52,6 +53,23 @@ impl Connection } } +impl Connection + where T: AsyncRead + AsyncWrite, +{ + pub fn send_response(self, + id: StreamId, // TODO: Generate one internally? + response: response::Head, + end_of_stream: bool) + -> sink::Send + { + self.send(Frame::Headers { + id: id, + headers: response, + end_of_stream: end_of_stream, + }) + } +} + impl Stream for Connection where T: AsyncRead + AsyncWrite, P: Peer, @@ -126,7 +144,9 @@ impl Sink for Connection match item { Frame::Headers { id, headers, end_of_stream } => { // Ensure ID is valid - try!(P::check_initiating_id(id)); + // TODO: This check should only be done **if** this is a new + // stream ID + // try!(P::check_initiating_id(id)); // TODO: Ensure available capacity for a new stream // This won't be as simple as self.streams.len() as closed diff --git a/src/util/byte_str.rs b/src/util/byte_str.rs index 6882941..7cd4292 100644 --- a/src/util/byte_str.rs +++ b/src/util/byte_str.rs @@ -58,3 +58,9 @@ impl<'a> From<&'a str> for ByteStr { ByteStr { bytes: Bytes::from(src) } } } + +impl From for Bytes { + fn from(src: ByteStr) -> Self { + src.bytes + } +}