Skip to content

Commit

Permalink
feat(server): make Http compatible with TcpServer
Browse files Browse the repository at this point in the history
This implements `From<Message> for Request` and `Into<Message> for
Response`, allowing an `Http` instance to be used with a `TcpServer`
from tokio-proto.

Closes #1036

BREAKING CHANGE: This makes `Request.remote_addr` an
  `Option<SocketAddr>`, instead of `SocketAddr`.
  • Loading branch information
seanmonstar committed Feb 4, 2017
1 parent c42f18d commit 6fbeeb2
Show file tree
Hide file tree
Showing 2 changed files with 42 additions and 15 deletions.
34 changes: 23 additions & 11 deletions src/server/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -236,20 +236,32 @@ impl<T: Io + 'static> Future for ProtoBindTransport<T> {
}
}

struct HttpService<T> {
inner: T,
remote_addr: SocketAddr,
impl From<Message<ProtoRequest, http::TokioBody>> for Request {
fn from(message: Message<ProtoRequest, http::TokioBody>) -> Request {
let (head, body) = match message {
Message::WithoutBody(head) => (head.0, http::Body::empty()),
Message::WithBody(head, body) => (head.0, body.into()),
};
request::new(None, head, body)
}
}

fn map_response_to_message(res: Response) -> Message<ProtoResponse, http::TokioBody> {
let (head, body) = response::split(res);
if let Some(body) = body {
Message::WithBody(ProtoResponse(head), body.into())
} else {
Message::WithoutBody(ProtoResponse(head))
impl Into<Message<ProtoResponse, http::TokioBody>> for Response {
fn into(self) -> Message<ProtoResponse, http::TokioBody> {
let (head, body) = response::split(self);
if let Some(body) = body {
Message::WithBody(ProtoResponse(head), body.into())
} else {
Message::WithoutBody(ProtoResponse(head))
}
}
}

struct HttpService<T> {
inner: T,
remote_addr: SocketAddr,
}

type ResponseHead = http::MessageHead<::StatusCode>;

impl<T> Service for HttpService<T>
Expand All @@ -265,8 +277,8 @@ impl<T> Service for HttpService<T>
Message::WithoutBody(head) => (head.0, http::Body::empty()),
Message::WithBody(head, body) => (head.0, body.into()),
};
let req = request::new(self.remote_addr, head, body);
self.inner.call(req).map(map_response_to_message)
let req = request::new(Some(self.remote_addr), head, body);
self.inner.call(req).map(Into::into)
}
}

Expand Down
23 changes: 19 additions & 4 deletions src/server/request.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ pub struct Request {
uri: Uri,
version: HttpVersion,
headers: Headers,
remote_addr: SocketAddr,
remote_addr: Option<SocketAddr>,
body: Body,
}

Expand All @@ -40,8 +40,11 @@ impl Request {
pub fn version(&self) -> &HttpVersion { &self.version }

/// The remote socket address of this request
///
/// This is an `Option`, because some underlying transports may not have
/// a socket address, such as Unix Sockets.
#[inline]
pub fn remote_addr(&self) -> &SocketAddr { &self.remote_addr }
pub fn remote_addr(&self) -> Option<&SocketAddr> { self.remote_addr.as_ref() }

/// The target path of this Request.
#[inline]
Expand Down Expand Up @@ -82,9 +85,9 @@ impl fmt::Debug for Request {
}
}

pub fn new(addr: SocketAddr, incoming: RequestHead, body: Body) -> Request {
pub fn new(addr: Option<SocketAddr>, incoming: RequestHead, body: Body) -> Request {
let MessageHead { version, subject: RequestLine(method, uri), headers } = incoming;
debug!("Request::new: addr={}, req=\"{} {} {}\"", addr, method, uri, version);
debug!("Request::new: addr={}, req=\"{} {} {}\"", MaybeAddr(&addr), method, uri, version);
debug!("Request::new: headers={:?}", headers);

Request {
Expand All @@ -96,3 +99,15 @@ pub fn new(addr: SocketAddr, incoming: RequestHead, body: Body) -> Request {
body: body,
}
}

struct MaybeAddr<'a>(&'a Option<SocketAddr>);

impl<'a> fmt::Display for MaybeAddr<'a> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self.0 {
Some(ref addr) => fmt::Display::fmt(addr, f),
None => f.write_str("None"),
}
}
}

0 comments on commit 6fbeeb2

Please sign in to comment.