Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 13 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,10 @@ authors = ["Sean McArthur <sean.monstar@gmail.com>",
keywords = ["http", "hyper", "hyperium"]

[dependencies]
cookie = "0.1"
httparse = "0.1"
log = "0.3"
mime = "0.0.11"
num_cpus = "0.2"
openssl = "0.6"
rustc-serialize = "0.3"
time = "0.1"
unicase = "0.1"
Expand All @@ -29,4 +27,17 @@ typeable = "0.1"
env_logger = "*"

[features]
default = ["ssl"]
# These are grouped together b/c it doesn't really make sense to
# enable one w/o the other
ssl = ["openssl", "cookie"]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ssl = ["openssl", "cookie/default"]

nightly = []


[dependencies.cookie]
version = "0.1"
optional = true

[dependencies.openssl]
version = "0.6"
optional = true
7 changes: 6 additions & 1 deletion src/client/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,9 @@ use url::ParseError as UrlError;
use header::{Headers, Header, HeaderFormat};
use header::{ContentLength, Location};
use method::Method;
use net::{NetworkConnector, NetworkStream, ContextVerifier};
use net::{NetworkConnector, NetworkStream};
#[cfg(feature = "openssl")]
use net::ContextVerifier;
use status::StatusClass::Redirection;
use {Url};
use Error;
Expand Down Expand Up @@ -84,6 +86,7 @@ impl Client {
}

/// Set the SSL verifier callback for use with OpenSSL.
#[cfg(feature = "openssl")]
pub fn set_ssl_verifier(&mut self, verifier: ContextVerifier) {
self.connector.set_ssl_verifier(verifier);
}
Expand Down Expand Up @@ -149,6 +152,7 @@ impl<C: NetworkConnector<Stream=S> + Send, S: NetworkStream + Send> NetworkConne
Ok(try!(self.0.connect(host, port, scheme)).into())
}
#[inline]
#[cfg(feature = "openssl")]
fn set_ssl_verifier(&mut self, verifier: ContextVerifier) {
self.0.set_ssl_verifier(verifier);
}
Expand All @@ -164,6 +168,7 @@ impl NetworkConnector for Connector {
Ok(try!(self.0.connect(host, port, scheme)).into())
}
#[inline]
#[cfg(feature = "openssl")]
fn set_ssl_verifier(&mut self, verifier: ContextVerifier) {
self.0.set_ssl_verifier(verifier);
}
Expand Down
5 changes: 4 additions & 1 deletion src/client/pool.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@ use std::io::{self, Read, Write};
use std::net::{SocketAddr, Shutdown};
use std::sync::{Arc, Mutex};

use net::{NetworkConnector, NetworkStream, HttpConnector, ContextVerifier};
use net::{NetworkConnector, NetworkStream, HttpConnector};
#[cfg(feature = "openssl")]
use net::ContextVerifier;

/// The `NetworkConnector` that behaves as a connection pool used by hyper's `Client`.
pub struct Pool<C: NetworkConnector> {
Expand Down Expand Up @@ -121,6 +123,7 @@ impl<C: NetworkConnector<Stream=S>, S: NetworkStream + Send> NetworkConnector fo
})
}
#[inline]
#[cfg(feature = "openssl")]
fn set_ssl_verifier(&mut self, verifier: ContextVerifier) {
self.connector.set_ssl_verifier(verifier);
}
Expand Down
16 changes: 6 additions & 10 deletions src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,11 @@ use std::fmt;
use std::io::Error as IoError;

use httparse;
#[cfg(feature = "openssl")]
use openssl::ssl::error::SslError;
use url;

use self::Error::{
Method,
Uri,
Version,
Header,
Status,
Io,
Ssl,
TooLarge
};
use self::Error::*;


/// Result type often returned from methods that can have hyper `Error`s.
Expand All @@ -40,6 +32,7 @@ pub enum Error {
/// An `io::Error` that occurred while trying to read or write to a network stream.
Io(IoError),
/// An error from the `openssl` library.
#[cfg(feature = "openssl")]
Ssl(SslError)
}

Expand All @@ -59,13 +52,15 @@ impl StdError for Error {
Status => "Invalid Status provided",
Uri(ref e) => e.description(),
Io(ref e) => e.description(),
#[cfg(feature = "openssl")]
Ssl(ref e) => e.description(),
}
}

fn cause(&self) -> Option<&StdError> {
match *self {
Io(ref error) => Some(error),
#[cfg(feature = "openssl")]
Ssl(ref error) => Some(error),
Uri(ref error) => Some(error),
_ => None,
Expand All @@ -85,6 +80,7 @@ impl From<url::ParseError> for Error {
}
}

#[cfg(feature = "openssl")]
impl From<SslError> for Error {
fn from(err: SslError) -> Error {
match err {
Expand Down
4 changes: 4 additions & 0 deletions src/header/common/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ pub use self::content_length::ContentLength;
pub use self::content_encoding::ContentEncoding;
pub use self::content_language::ContentLanguage;
pub use self::content_type::ContentType;
#[cfg(feature = "cookie")]
pub use self::cookie::Cookie;
pub use self::date::Date;
pub use self::etag::ETag;
Expand All @@ -42,6 +43,7 @@ pub use self::location::Location;
pub use self::pragma::Pragma;
pub use self::referer::Referer;
pub use self::server::Server;
#[cfg(feature = "cookie")]
pub use self::set_cookie::SetCookie;
pub use self::transfer_encoding::TransferEncoding;
pub use self::upgrade::{Upgrade, Protocol, ProtocolName};
Expand Down Expand Up @@ -329,6 +331,7 @@ mod accept_ranges;
mod allow;
mod authorization;
mod cache_control;
#[cfg(feature = "cookie")]
mod cookie;
mod connection;
mod content_encoding;
Expand All @@ -351,6 +354,7 @@ mod location;
mod pragma;
mod referer;
mod server;
#[cfg(feature = "cookie")]
mod set_cookie;
mod transfer_encoding;
mod upgrade;
Expand Down
2 changes: 2 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,9 @@
extern crate rustc_serialize as serialize;
extern crate time;
extern crate url;
#[cfg(feature = "openssl")]
extern crate openssl;
#[cfg(feature = "cookie")]
extern crate cookie;
extern crate unicase;
extern crate httparse;
Expand Down
31 changes: 29 additions & 2 deletions src/net.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,18 @@ use std::fmt;
use std::io::{self, ErrorKind, Read, Write};
use std::net::{SocketAddr, ToSocketAddrs, TcpStream, TcpListener, Shutdown};
use std::mem;
#[cfg(feature = "openssl")]
use std::path::Path;
#[cfg(feature = "openssl")]
use std::sync::Arc;

#[cfg(feature = "openssl")]
use openssl::ssl::{Ssl, SslStream, SslContext, SSL_VERIFY_NONE};
#[cfg(feature = "openssl")]
use openssl::ssl::SslMethod::Sslv23;
#[cfg(feature = "openssl")]
use openssl::ssl::error::StreamError as SslIoError;
#[cfg(feature = "openssl")]
use openssl::x509::X509FileType;

use typeable::Typeable;
Expand Down Expand Up @@ -72,6 +78,7 @@ pub trait NetworkConnector {
fn connect(&self, host: &str, port: u16, scheme: &str) -> ::Result<Self::Stream>;
/// Sets the given `ContextVerifier` to be used when verifying the SSL context
/// on the establishment of a new connection.
#[cfg(feature = "openssl")]
fn set_ssl_verifier(&mut self, verifier: ContextVerifier);
}

Expand Down Expand Up @@ -147,13 +154,15 @@ pub enum HttpListener {
/// Http variant.
Http(TcpListener),
/// Https variant. The two paths point to the certificate and key PEM files, in that order.
#[cfg(feature = "openssl")]
Https(TcpListener, Arc<SslContext>)
}

impl Clone for HttpListener {
fn clone(&self) -> HttpListener {
match *self {
HttpListener::Http(ref tcp) => HttpListener::Http(tcp.try_clone().unwrap()),
#[cfg(feature = "openssl")]
HttpListener::Https(ref tcp, ref ssl) => HttpListener::Https(tcp.try_clone().unwrap(), ssl.clone()),
}
}
Expand All @@ -167,6 +176,7 @@ impl HttpListener {
}

/// Start listening to an address over HTTPS.
#[cfg(feature = "openssl")]
pub fn https<To: ToSocketAddrs>(addr: To, cert: &Path, key: &Path) -> ::Result<HttpListener> {
let mut ssl_context = try!(SslContext::new(Sslv23));
try!(ssl_context.set_cipher_list("DEFAULT"));
Expand All @@ -177,6 +187,7 @@ impl HttpListener {
}

/// Start listening to an address of HTTPS using the given SslContext
#[cfg(feature = "openssl")]
pub fn https_with_context<To: ToSocketAddrs>(addr: To, ssl_context: SslContext) -> ::Result<HttpListener> {
Ok(HttpListener::Https(try!(TcpListener::bind(addr)), Arc::new(ssl_context)))
}
Expand All @@ -189,6 +200,7 @@ impl NetworkListener for HttpListener {
fn accept(&mut self) -> ::Result<HttpStream> {
match *self {
HttpListener::Http(ref mut tcp) => Ok(HttpStream::Http(CloneTcpStream(try!(tcp.accept()).0))),
#[cfg(feature = "openssl")]
HttpListener::Https(ref mut tcp, ref ssl_context) => {
let stream = CloneTcpStream(try!(tcp.accept()).0);
match SslStream::new_server(&**ssl_context, stream) {
Expand All @@ -206,6 +218,7 @@ impl NetworkListener for HttpListener {
fn local_addr(&mut self) -> io::Result<SocketAddr> {
match *self {
HttpListener::Http(ref mut tcp) => tcp.local_addr(),
#[cfg(feature = "openssl")]
HttpListener::Https(ref mut tcp, _) => tcp.local_addr(),
}
}
Expand Down Expand Up @@ -245,13 +258,15 @@ pub enum HttpStream {
/// A stream over the HTTP protocol.
Http(CloneTcpStream),
/// A stream over the HTTP protocol, protected by SSL.
#[cfg(feature = "openssl")]
Https(SslStream<CloneTcpStream>),
}

impl fmt::Debug for HttpStream {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
match *self {
HttpStream::Http(_) => write!(fmt, "Http HttpStream"),
#[cfg(feature = "openssl")]
HttpStream::Https(_) => write!(fmt, "Https HttpStream"),
}
}
Expand All @@ -262,6 +277,7 @@ impl Read for HttpStream {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
match *self {
HttpStream::Http(ref mut inner) => inner.read(buf),
#[cfg(feature = "openssl")]
HttpStream::Https(ref mut inner) => inner.read(buf)
}
}
Expand All @@ -272,13 +288,15 @@ impl Write for HttpStream {
fn write(&mut self, msg: &[u8]) -> io::Result<usize> {
match *self {
HttpStream::Http(ref mut inner) => inner.write(msg),
#[cfg(feature = "openssl")]
HttpStream::Https(ref mut inner) => inner.write(msg)
}
}
#[inline]
fn flush(&mut self) -> io::Result<()> {
match *self {
HttpStream::Http(ref mut inner) => inner.flush(),
#[cfg(feature = "openssl")]
HttpStream::Https(ref mut inner) => inner.flush(),
}
}
Expand All @@ -289,6 +307,7 @@ impl NetworkStream for HttpStream {
fn peer_addr(&mut self) -> io::Result<SocketAddr> {
match *self {
HttpStream::Http(ref mut inner) => inner.0.peer_addr(),
#[cfg(feature = "openssl")]
HttpStream::Https(ref mut inner) => inner.get_mut().0.peer_addr()
}
}
Expand All @@ -307,16 +326,22 @@ impl NetworkStream for HttpStream {

match *self {
HttpStream::Http(ref mut inner) => shutdown(&mut inner.0, how),
#[cfg(feature = "openssl")]
HttpStream::Https(ref mut inner) => shutdown(&mut inner.get_mut().0, how)
}

}
}

#[cfg(feature = "openssl")]
/// A connector that will produce HttpStreams.
pub struct HttpConnector(pub Option<ContextVerifier>);
#[cfg(not(feature = "openssl"))]
/// A connector that will produce HttpStreams.
pub struct HttpConnector(pub Option<()>);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any reason to keep the Option<()>? Without the verifier, it used to be a struct HttpConnector;.


/// A method that can set verification methods on an SSL context
#[cfg(feature = "openssl")]
pub type ContextVerifier = Box<Fn(&mut SslContext) -> () + Send>;

impl NetworkConnector for HttpConnector {
Expand All @@ -329,6 +354,7 @@ impl NetworkConnector for HttpConnector {
debug!("http scheme");
Ok(HttpStream::Http(CloneTcpStream(try!(TcpStream::connect(addr)))))
},
#[cfg(feature = "openssl")]
"https" => {
debug!("https scheme");
let stream = CloneTcpStream(try!(TcpStream::connect(addr)));
Expand All @@ -341,12 +367,13 @@ impl NetworkConnector for HttpConnector {
let stream = try!(SslStream::new(&context, stream));
Ok(HttpStream::Https(stream))
},
_ => {
x => {
Err(io::Error::new(io::ErrorKind::InvalidInput,
"Invalid scheme for Http"))
format!("Invalid scheme for Http: {}", x)))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Whatcha think of adding a debug! (or info?) here explaining that enabling the feature will let you make https requests?

}
}))
}
#[cfg(feature = "openssl")]
fn set_ssl_verifier(&mut self, verifier: ContextVerifier) {
self.0 = Some(verifier);
}
Expand Down
Loading