diff --git a/src/proto/request.rs b/src/proto/request.rs index 1f02ec430f..adeebdb688 100644 --- a/src/proto/request.rs +++ b/src/proto/request.rs @@ -58,13 +58,9 @@ impl Request { #[inline] pub fn body_ref(&self) -> Option<&B> { self.body.as_ref() } - /// 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. - /// - /// This field is not used for outgoing requests. + #[doc(hidden)] #[inline] + #[deprecated(since="0.11.12", note="This method will be gone in future versions.")] pub fn remote_addr(&self) -> Option { self.remote_addr } /// The target path of this Request. @@ -196,6 +192,10 @@ pub fn split(req: Request) -> (RequestHead, Option) { (head, req.body) } +pub fn addr(req: &mut Request, addr: SocketAddr) { + req.remote_addr = Some(addr); +} + #[cfg(test)] mod tests { /* diff --git a/src/server/mod.rs b/src/server/mod.rs index c4d6329cdc..9e37732421 100644 --- a/src/server/mod.rs +++ b/src/server/mod.rs @@ -352,8 +352,9 @@ impl Server // Future for our server's execution let srv = listener.incoming().for_each(|(socket, addr)| { + let addr_service = SocketAddrService::new(addr, new_service.new_service()?); let s = NotifyService { - inner: try!(new_service.new_service()), + inner: addr_service, info: Rc::downgrade(&info), }; info.borrow_mut().active += 1; @@ -644,6 +645,41 @@ mod addr_stream { } } +// ===== SocketAddrService + +// This is used from `Server::run`, which captures the remote address +// in this service, and then injects it into each `Request`. +struct SocketAddrService { + addr: SocketAddr, + inner: S, +} + +impl SocketAddrService { + fn new(addr: SocketAddr, service: S) -> SocketAddrService { + SocketAddrService { + addr: addr, + inner: service, + } + } +} + +impl Service for SocketAddrService +where + S: Service, +{ + type Request = S::Request; + type Response = S::Response; + type Error = S::Error; + type Future = S::Future; + + fn call(&self, mut req: Self::Request) -> Self::Future { + proto::request::addr(&mut req, self.addr); + self.inner.call(req) + } +} + +// ===== NotifyService ===== + struct NotifyService { inner: S, info: Weak>, diff --git a/tests/server.rs b/tests/server.rs index e55e55e644..fceaf48c33 100644 --- a/tests/server.rs +++ b/tests/server.rs @@ -712,6 +712,22 @@ fn nonempty_parse_eof_returns_error() { core.run(fut).unwrap_err(); } +#[test] +fn remote_addr() { + let server = serve(); + + let mut req = connect(server.addr()); + req.write_all(b"\ + GET / HTTP/1.1\r\n\ + Host: example.domain\r\n\ + \r\n\ + ").unwrap(); + req.read(&mut [0; 256]).unwrap(); + + let client_addr = req.local_addr().unwrap(); + assert_eq!(server.remote_addr(), client_addr); +} + // ------------------------------------------------- // the Server that is used to run all the tests with // ------------------------------------------------- @@ -729,10 +745,23 @@ impl Serve { &self.addr } + pub fn remote_addr(&self) -> SocketAddr { + match self.msg_rx.try_recv() { + Ok(Msg::Addr(addr)) => addr, + other => panic!("expected remote addr, found: {:?}", other), + } + } + fn body(&self) -> Vec { let mut buf = vec![]; - while let Ok(Msg::Chunk(msg)) = self.msg_rx.try_recv() { - buf.extend(&msg); + loop { + match self.msg_rx.try_recv() { + Ok(Msg::Chunk(msg)) => { + buf.extend(&msg); + }, + Ok(Msg::Addr(_)) => {}, + Err(_) => break, + } } buf } @@ -787,8 +816,10 @@ enum Reply { Body(Vec), } +#[derive(Debug)] enum Msg { //Head(Request), + Addr(SocketAddr), Chunk(Vec), } @@ -811,6 +842,11 @@ impl Service for TestService { type Future = Box>; fn call(&self, req: Request) -> Self::Future { let tx = self.tx.clone(); + + #[allow(deprecated)] + let remote_addr = req.remote_addr().expect("remote_addr"); + tx.lock().unwrap().send(Msg::Addr(remote_addr)).unwrap(); + let replies = self.reply.clone(); Box::new(req.body().for_each(move |chunk| { tx.lock().unwrap().send(Msg::Chunk(chunk.to_vec())).unwrap();