feat(net): add socket timeouts to Server and Client

While these methods are marked unstable in libstd, this is behind a
feature flag, `timeouts`. The Client and Server both have
`set_read_timeout` and `set_write_timeout` methods, that will affect all
connections with that entity.

BREAKING CHANGE: Any custom implementation of NetworkStream must now
  implement `set_read_timeout` and `set_write_timeout`, so those will
  break. Most users who only use the provided streams should work with
  no changes needed.

Closes #315
This commit is contained in:
Sean McArthur
2015-06-16 11:02:36 -07:00
parent 421422b620
commit 7d1f154cb7
11 changed files with 311 additions and 50 deletions

View File

@@ -4,6 +4,8 @@ use std::cmp::min;
use std::fmt;
use std::io::{self, Write, BufWriter, BufRead, Read};
use std::net::Shutdown;
#[cfg(feature = "timeouts")]
use std::time::Duration;
use httparse;
@@ -192,6 +194,19 @@ impl HttpMessage for Http11Message {
})
}
#[cfg(feature = "timeouts")]
#[inline]
fn set_read_timeout(&self, dur: Option<Duration>) -> io::Result<()> {
self.get_ref().set_read_timeout(dur)
}
#[cfg(feature = "timeouts")]
#[inline]
fn set_write_timeout(&self, dur: Option<Duration>) -> io::Result<()> {
self.get_ref().set_write_timeout(dur)
}
#[inline]
fn close_connection(&mut self) -> ::Result<()> {
try!(self.get_mut().close(Shutdown::Both));
Ok(())
@@ -214,13 +229,27 @@ impl Http11Message {
/// Gets a mutable reference to the underlying `NetworkStream`, regardless of the state of the
/// `Http11Message`.
pub fn get_mut(&mut self) -> &mut Box<NetworkStream + Send> {
pub fn get_ref(&self) -> &(NetworkStream + Send) {
if self.stream.is_some() {
self.stream.as_mut().unwrap()
&**self.stream.as_ref().unwrap()
} else if self.writer.is_some() {
self.writer.as_mut().unwrap().get_mut().get_mut()
&**self.writer.as_ref().unwrap().get_ref().get_ref()
} else if self.reader.is_some() {
self.reader.as_mut().unwrap().get_mut().get_mut()
&**self.reader.as_ref().unwrap().get_ref().get_ref()
} else {
panic!("Http11Message lost its underlying stream somehow");
}
}
/// Gets a mutable reference to the underlying `NetworkStream`, regardless of the state of the
/// `Http11Message`.
pub fn get_mut(&mut self) -> &mut (NetworkStream + Send) {
if self.stream.is_some() {
&mut **self.stream.as_mut().unwrap()
} else if self.writer.is_some() {
&mut **self.writer.as_mut().unwrap().get_mut().get_mut()
} else if self.reader.is_some() {
&mut **self.reader.as_mut().unwrap().get_mut().get_mut()
} else {
panic!("Http11Message lost its underlying stream somehow");
}
@@ -344,6 +373,16 @@ impl<R: Read> HttpReader<R> {
}
}
/// Gets a borrowed reference to the underlying Reader.
pub fn get_ref(&self) -> &R {
match *self {
SizedReader(ref r, _) => r,
ChunkedReader(ref r, _) => r,
EofReader(ref r) => r,
EmptyReader(ref r) => r,
}
}
/// Gets a mutable reference to the underlying Reader.
pub fn get_mut(&mut self) -> &mut R {
match *self {

View File

@@ -4,6 +4,8 @@ use std::io::{self, Write, Read, Cursor};
use std::net::Shutdown;
use std::ascii::AsciiExt;
use std::mem;
#[cfg(feature = "timeouts")]
use std::time::Duration;
use http::{
Protocol,
@@ -398,6 +400,19 @@ impl<S> HttpMessage for Http2Message<S> where S: CloneableStream {
Ok(head)
}
#[cfg(feature = "timeouts")]
#[inline]
fn set_read_timeout(&self, _dur: Option<Duration>) -> io::Result<()> {
Ok(())
}
#[cfg(feature = "timeouts")]
#[inline]
fn set_write_timeout(&self, _dur: Option<Duration>) -> io::Result<()> {
Ok(())
}
#[inline]
fn close_connection(&mut self) -> ::Result<()> {
Ok(())
}

View File

@@ -1,12 +1,16 @@
//! Defines the `HttpMessage` trait that serves to encapsulate the operations of a single
//! request-response cycle on any HTTP connection.
use std::fmt::Debug;
use std::any::{Any, TypeId};
use std::fmt::Debug;
use std::io::{Read, Write};
use std::mem;
#[cfg(feature = "timeouts")]
use std::io;
#[cfg(feature = "timeouts")]
use std::time::Duration;
use typeable::Typeable;
use header::Headers;
@@ -62,7 +66,10 @@ pub trait HttpMessage: Write + Read + Send + Any + Typeable + Debug {
fn get_incoming(&mut self) -> ::Result<ResponseHead>;
/// Set the read timeout duration for this message.
#[cfg(feature = "timeouts")]
fn set_read_timeout(&self, dur: Option<Duration>) -> ::Result<()>;
fn set_read_timeout(&self, dur: Option<Duration>) -> io::Result<()>;
/// Set the write timeout duration for this message.
#[cfg(feature = "timeouts")]
fn set_write_timeout(&self, dur: Option<Duration>) -> io::Result<()>;
/// Closes the underlying HTTP connection.
fn close_connection(&mut self) -> ::Result<()>;
}