Skip to content

Commit f60933a

Browse files
authored
Merge pull request redis-rs#305 from gferon/redis-tls
2 parents 26b5026 + 5a7a108 commit f60933a

File tree

9 files changed

+488
-44
lines changed

9 files changed

+488
-44
lines changed

.travis.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ before_cache:
2121
before_install: |
2222
sudo add-apt-repository ppa:chris-lea/redis-server -y
2323
sudo apt-get update
24-
sudo apt-get install redis-server=5:6.0.5-1chl1~xenial1 -y
24+
sudo apt-get install redis-server=5:6.0.5-1chl1~xenial1 stunnel -y
2525
2626
matrix:
2727
include:

Cargo.toml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,11 @@ rand = { version = "0.7.0", optional = true }
5353
async-std = { version = "1.5.0", optional = true}
5454
async-trait = "0.1.24"
5555

56+
# Only needed for TLS
57+
native-tls = { version = "0.2", optional = true }
58+
tokio-tls = { version = "0.3", optional = true }
59+
async-native-tls = { version = "0.3", optional = true }
60+
5661
[features]
5762
default = ["acl", "streams", "geospatial", "tokio-comp", "async-std-comp", "script"]
5863
acl = []
@@ -61,8 +66,11 @@ tokio-rt-core = ["tokio-comp", "tokio/rt-core"]
6166
geospatial = []
6267
cluster = ["crc16", "rand"]
6368
script = ["sha1"]
69+
tls = ["native-tls"]
6470
async-std-comp = ["aio", "async-std"]
71+
async-std-tls-comp = ["async-std-comp", "async-native-tls", "tls"]
6572
tokio-comp = ["aio", "tokio"]
73+
tokio-tls-comp = ["tls", "tokio-tls"]
6674
connection-manager = ["tokio-rt-core", "arc-swap", "futures"]
6775
streams = []
6876

@@ -77,6 +85,7 @@ criterion = "0.3"
7785
partial-io = { version = "0.3", features = ["tokio", "quickcheck"] }
7886
quickcheck = "0.6"
7987
tokio = { version = "0.2", features = ["rt-core", "macros", "time"] }
88+
tempdir = "0.3"
8089

8190
[[test]]
8291
name = "test_async"

Makefile

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,28 +5,32 @@ test:
55
@echo "===================================================================="
66
@echo "Testing Connection Type TCP without features"
77
@echo "===================================================================="
8-
@REDISRS_SERVER_TYPE=tcp RUST_TEST_THREADS=1 cargo test --no-default-features --tests -- --nocapture
8+
@REDISRS_SERVER_TYPE=tcp cargo test --no-default-features --tests -- --nocapture --test-threads=1
99

1010
@echo "===================================================================="
1111
@echo "Testing Connection Type TCP with all features"
1212
@echo "===================================================================="
13-
@REDISRS_SERVER_TYPE=tcp RUST_TEST_THREADS=1 cargo test --all-features -- --nocapture
13+
@REDISRS_SERVER_TYPE=tcp cargo test --all-features -- --nocapture --test-threads=1
14+
15+
@echo "===================================================================="
16+
@echo "Testing Connection Type TCP with all features and TLS support"
17+
@echo "===================================================================="
18+
@REDISRS_SERVER_TYPE=tcp+tls cargo test --all-features -- --nocapture --test-threads=1
1419

1520
@echo "===================================================================="
1621
@echo "Testing Connection Type UNIX"
1722
@echo "===================================================================="
18-
@REDISRS_SERVER_TYPE=unix cargo test --test parser --test test_basic --test test_types --all-features
23+
@REDISRS_SERVER_TYPE=unix cargo test --test parser --test test_basic --test test_types --all-features -- --test-threads=1
1924

2025
@echo "===================================================================="
2126
@echo "Testing Connection Type UNIX SOCKETS"
2227
@echo "===================================================================="
2328
@REDISRS_SERVER_TYPE=unix cargo test --all-features -- --skip test_cluster
2429

25-
test-single: RUST_TEST_THREADS=1
2630
test-single: test
2731

2832
bench:
29-
@RUST_TEST_THREADS=1 cargo bench --all-features
33+
cargo bench --all-features --test-threads=1
3034

3135
docs: build
3236
@cargo doc --no-deps

examples/basic.rs

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
use redis::{self, transaction, Commands};
22

33
use std::collections::HashMap;
4+
use std::env;
45

56
/// This function demonstrates how a return value can be coerced into a
67
/// hashmap of tuples. This is particularly useful for responses like
@@ -134,9 +135,9 @@ fn do_atomic_increment(con: &mut redis::Connection) -> redis::RedisResult<()> {
134135
}
135136

136137
/// Runs all the examples and propagates errors up.
137-
fn do_redis_code() -> redis::RedisResult<()> {
138+
fn do_redis_code(url: &str) -> redis::RedisResult<()> {
138139
// general connection handling
139-
let client = redis::Client::open("redis://127.0.0.1/")?;
140+
let client = redis::Client::open(url)?;
140141
let mut con = client.get_connection()?;
141142

142143
// read some config and print it.
@@ -154,7 +155,12 @@ fn do_redis_code() -> redis::RedisResult<()> {
154155

155156
fn main() {
156157
// at this point the errors are fatal, let's just fail hard.
157-
match do_redis_code() {
158+
let url = if env::args().nth(1) == Some("--tls".into()) {
159+
"rediss://127.0.0.1:6380/#insecure"
160+
} else {
161+
"redis://127.0.0.1:6379/"
162+
};
163+
match do_redis_code(url) {
158164
Err(err) => {
159165
println!("Could not execute example:");
160166
println!(" {}: {}", err.category(), err);

src/aio.rs

Lines changed: 92 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,12 @@ use tokio::{
2323
#[cfg(feature = "tokio-comp")]
2424
use tokio::net::TcpStream as TcpStreamTokio;
2525

26+
#[cfg(feature = "tokio-tls-comp")]
27+
use tokio_tls::TlsStream as TlsStreamTokio;
28+
29+
#[cfg(feature = "tls")]
30+
use native_tls::TlsConnector;
31+
2632
#[cfg(any(feature = "tokio-comp", feature = "async-std-comp"))]
2733
use tokio_util::codec::Decoder;
2834

@@ -52,7 +58,16 @@ use crate::aio_async_std;
5258
pub(crate) trait Connect {
5359
/// Performs a TCP connection
5460
async fn connect_tcp(socket_addr: SocketAddr) -> RedisResult<ActualConnection>;
55-
/// Performans an UNIX connection
61+
62+
// Performs a TCP TLS connection
63+
#[cfg(feature = "tls")]
64+
async fn connect_tcp_tls(
65+
hostname: &str,
66+
socket_addr: SocketAddr,
67+
insecure: bool,
68+
) -> RedisResult<ActualConnection>;
69+
70+
/// Performs a UNIX connection
5671
#[cfg(unix)]
5772
async fn connect_unix(path: &Path) -> RedisResult<ActualConnection>;
5873
}
@@ -61,6 +76,9 @@ pub(crate) trait Connect {
6176
mod tokio_aio {
6277
use super::{async_trait, ActualConnection, Connect, RedisResult, SocketAddr, TcpStreamTokio};
6378

79+
#[cfg(feature = "tls")]
80+
use super::TlsConnector;
81+
6482
#[cfg(unix)]
6583
use super::{Path, UnixStreamTokio};
6684

@@ -73,6 +91,27 @@ mod tokio_aio {
7391
.await
7492
.map(ActualConnection::TcpTokio)?)
7593
}
94+
#[cfg(feature = "tls")]
95+
async fn connect_tcp_tls(
96+
hostname: &str,
97+
socket_addr: SocketAddr,
98+
insecure: bool,
99+
) -> RedisResult<ActualConnection> {
100+
let tls_connector: tokio_tls::TlsConnector = if insecure {
101+
TlsConnector::builder()
102+
.danger_accept_invalid_certs(true)
103+
.danger_accept_invalid_hostnames(true)
104+
.use_sni(false)
105+
.build()?
106+
} else {
107+
TlsConnector::new()?
108+
}
109+
.into();
110+
Ok(tls_connector
111+
.connect(hostname, TcpStreamTokio::connect(&socket_addr).await?)
112+
.await
113+
.map(ActualConnection::TcpTlsTokio)?)
114+
}
76115
#[cfg(unix)]
77116
async fn connect_unix(path: &Path) -> RedisResult<ActualConnection> {
78117
Ok(UnixStreamTokio::connect(path)
@@ -87,13 +126,19 @@ pub(crate) enum ActualConnection {
87126
/// Represents a Tokio TCP connection.
88127
#[cfg(feature = "tokio-comp")]
89128
TcpTokio(TcpStreamTokio),
129+
/// Represents a Tokio TLS encrypted TCP connection
130+
#[cfg(feature = "tokio-tls-comp")]
131+
TcpTlsTokio(TlsStreamTokio<TcpStreamTokio>),
90132
/// Represents a Tokio Unix connection.
91133
#[cfg(unix)]
92134
#[cfg(feature = "tokio-comp")]
93135
UnixTokio(UnixStreamTokio),
94136
/// Represents an Async_std TCP connection.
95137
#[cfg(feature = "async-std-comp")]
96138
TcpAsyncStd(aio_async_std::TcpStreamAsyncStdWrapped),
139+
/// Represents an Async_std TLS encrypted TCP connection.
140+
#[cfg(feature = "async-std-tls-comp")]
141+
TcpTlsAsyncStd(aio_async_std::TlsStreamAsyncStdWrapped),
97142
/// Represents an Async_std Unix connection.
98143
#[cfg(feature = "async-std-comp")]
99144
#[cfg(unix)]
@@ -109,11 +154,15 @@ impl AsyncWrite for ActualConnection {
109154
match &mut *self {
110155
#[cfg(feature = "tokio-comp")]
111156
ActualConnection::TcpTokio(r) => Pin::new(r).poll_write(cx, buf),
157+
#[cfg(feature = "tokio-tls-comp")]
158+
ActualConnection::TcpTlsTokio(r) => Pin::new(r).poll_write(cx, buf),
112159
#[cfg(unix)]
113160
#[cfg(feature = "tokio-comp")]
114161
ActualConnection::UnixTokio(r) => Pin::new(r).poll_write(cx, buf),
115162
#[cfg(feature = "async-std-comp")]
116163
ActualConnection::TcpAsyncStd(r) => Pin::new(r).poll_write(cx, buf),
164+
#[cfg(feature = "async-std-tls-comp")]
165+
ActualConnection::TcpTlsAsyncStd(r) => Pin::new(r).poll_write(cx, buf),
117166
#[cfg(feature = "async-std-comp")]
118167
#[cfg(unix)]
119168
ActualConnection::UnixAsyncStd(r) => Pin::new(r).poll_write(cx, buf),
@@ -124,11 +173,15 @@ impl AsyncWrite for ActualConnection {
124173
match &mut *self {
125174
#[cfg(feature = "tokio-comp")]
126175
ActualConnection::TcpTokio(r) => Pin::new(r).poll_flush(cx),
176+
#[cfg(feature = "tokio-tls-comp")]
177+
ActualConnection::TcpTlsTokio(r) => Pin::new(r).poll_flush(cx),
127178
#[cfg(unix)]
128179
#[cfg(feature = "tokio-comp")]
129180
ActualConnection::UnixTokio(r) => Pin::new(r).poll_flush(cx),
130181
#[cfg(feature = "async-std-comp")]
131182
ActualConnection::TcpAsyncStd(r) => Pin::new(r).poll_flush(cx),
183+
#[cfg(feature = "async-std-tls-comp")]
184+
ActualConnection::TcpTlsAsyncStd(r) => Pin::new(r).poll_flush(cx),
132185
#[cfg(feature = "async-std-comp")]
133186
#[cfg(unix)]
134187
ActualConnection::UnixAsyncStd(r) => Pin::new(r).poll_flush(cx),
@@ -139,11 +192,15 @@ impl AsyncWrite for ActualConnection {
139192
match &mut *self {
140193
#[cfg(feature = "tokio-comp")]
141194
ActualConnection::TcpTokio(r) => Pin::new(r).poll_shutdown(cx),
195+
#[cfg(feature = "tokio-tls-comp")]
196+
ActualConnection::TcpTlsTokio(r) => Pin::new(r).poll_shutdown(cx),
142197
#[cfg(unix)]
143198
#[cfg(feature = "tokio-comp")]
144199
ActualConnection::UnixTokio(r) => Pin::new(r).poll_shutdown(cx),
145200
#[cfg(feature = "async-std-comp")]
146201
ActualConnection::TcpAsyncStd(r) => Pin::new(r).poll_shutdown(cx),
202+
#[cfg(feature = "async-std-tls-comp")]
203+
ActualConnection::TcpTlsAsyncStd(r) => Pin::new(r).poll_shutdown(cx),
147204
#[cfg(feature = "async-std-comp")]
148205
#[cfg(unix)]
149206
ActualConnection::UnixAsyncStd(r) => Pin::new(r).poll_shutdown(cx),
@@ -160,11 +217,15 @@ impl AsyncRead for ActualConnection {
160217
match &mut *self {
161218
#[cfg(feature = "tokio-comp")]
162219
ActualConnection::TcpTokio(r) => Pin::new(r).poll_read(cx, buf),
220+
#[cfg(feature = "tokio-tls-comp")]
221+
ActualConnection::TcpTlsTokio(r) => Pin::new(r).poll_read(cx, buf),
163222
#[cfg(unix)]
164223
#[cfg(feature = "tokio-comp")]
165224
ActualConnection::UnixTokio(r) => Pin::new(r).poll_read(cx, buf),
166225
#[cfg(feature = "async-std-comp")]
167226
ActualConnection::TcpAsyncStd(r) => Pin::new(r).poll_read(cx, buf),
227+
#[cfg(feature = "async-std-tls-comp")]
228+
ActualConnection::TcpTlsAsyncStd(r) => Pin::new(r).poll_read(cx, buf),
168229
#[cfg(feature = "async-std-comp")]
169230
#[cfg(unix)]
170231
ActualConnection::UnixAsyncStd(r) => Pin::new(r).poll_read(cx, buf),
@@ -414,10 +475,27 @@ async fn connect_simple<T: Connect>(
414475
Ok(match *connection_info.addr {
415476
ConnectionAddr::Tcp(ref host, port) => {
416477
let socket_addr = get_socket_addrs(host, port)?;
417-
418478
<T>::connect_tcp(socket_addr).await?
419479
}
420480

481+
#[cfg(feature = "tls")]
482+
ConnectionAddr::TcpTls {
483+
ref host,
484+
port,
485+
insecure,
486+
} => {
487+
let socket_addr = get_socket_addrs(host, port)?;
488+
<T>::connect_tcp_tls(host, socket_addr, insecure).await?
489+
}
490+
491+
#[cfg(not(feature = "tls"))]
492+
ConnectionAddr::TcpTls { .. } => {
493+
fail!((
494+
ErrorKind::InvalidClientConfig,
495+
"Cannot connect to TCP with TLS without the tls feature"
496+
));
497+
}
498+
421499
#[cfg(unix)]
422500
ConnectionAddr::Unix(ref path) => <T>::connect_unix(path).await?,
423501

@@ -796,12 +874,24 @@ impl MultiplexedConnection {
796874
let (pipeline, driver) = Pipeline::new(codec);
797875
(pipeline, boxed(driver))
798876
}
877+
#[cfg(feature = "tokio-tls-comp")]
878+
ActualConnection::TcpTlsTokio(tls) => {
879+
let codec = ValueCodec::default().framed(tls);
880+
let (pipeline, driver) = Pipeline::new(codec);
881+
(pipeline, boxed(driver))
882+
}
799883
#[cfg(feature = "async-std-comp")]
800884
ActualConnection::TcpAsyncStd(tcp) => {
801885
let codec = ValueCodec::default().framed(tcp);
802886
let (pipeline, driver) = Pipeline::new(codec);
803887
(pipeline, boxed(driver))
804888
}
889+
#[cfg(feature = "async-std-tls-comp")]
890+
ActualConnection::TcpTlsAsyncStd(tcp) => {
891+
let codec = ValueCodec::default().framed(tcp);
892+
let (pipeline, driver) = Pipeline::new(codec);
893+
(pipeline, boxed(driver))
894+
}
805895
#[cfg(unix)]
806896
#[cfg(feature = "tokio-comp")]
807897
ActualConnection::UnixTokio(unix) => {

0 commit comments

Comments
 (0)