Skip to content

Commit a9e101c

Browse files
author
jayjamesjay
authored
Merge branch 'master' into v0.5.0
2 parents fbf342d + 38e2c25 commit a9e101c

File tree

2 files changed

+65
-4
lines changed

2 files changed

+65
-4
lines changed

src/request.rs

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ use std::{
99
fmt,
1010
io::{self, Read, Write},
1111
net::{TcpStream, ToSocketAddrs},
12+
path::Path,
1213
time::Duration,
1314
};
1415

@@ -248,6 +249,7 @@ pub struct Request<'a> {
248249
connect_timeout: Option<Duration>,
249250
read_timeout: Option<Duration>,
250251
write_timeout: Option<Duration>,
252+
root_cert_file_pem: Option<&'a Path>,
251253
}
252254

253255
impl<'a> Request<'a> {
@@ -261,6 +263,7 @@ impl<'a> Request<'a> {
261263
connect_timeout: Some(Duration::from_secs(60)),
262264
read_timeout: Some(Duration::from_secs(60)),
263265
write_timeout: Some(Duration::from_secs(60)),
266+
root_cert_file_pem: None,
264267
}
265268
}
266269

@@ -345,6 +348,12 @@ impl<'a> Request<'a> {
345348
self
346349
}
347350

351+
///Add a file containing the PEM-encoded certificates that should be added in the trusted root store.
352+
pub fn root_cert_file_pem(&mut self, file_path: &'a Path) -> &mut Self {
353+
self.root_cert_file_pem = Some(file_path);
354+
self
355+
}
356+
348357
///Sends HTTP request.
349358
///
350359
///Creates `TcpStream` (and wraps it with `TlsStream` if needed). Writes request message
@@ -361,7 +370,12 @@ impl<'a> Request<'a> {
361370
stream.set_write_timeout(self.write_timeout)?;
362371

363372
if self.inner.uri.scheme() == "https" {
364-
let mut stream = tls::Config::default().connect(host, stream)?;
373+
let mut cnf = tls::Config::default();
374+
let cnf = match self.root_cert_file_pem {
375+
Some(p) => cnf.add_root_cert_file_pem(p)?,
376+
None => &mut cnf,
377+
};
378+
let mut stream = cnf.connect(host, stream)?;
365379
self.inner.send(&mut stream, writer)
366380
} else {
367381
self.inner.send(&mut stream, writer)

src/tls.rs

Lines changed: 50 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,15 @@
11
//!secure connection over TLS
22
33
use crate::error::Error as HttpError;
4-
use std::io;
4+
use std::fs::File;
5+
use std::io::{self, BufReader};
6+
use std::path::Path;
7+
8+
#[cfg(feature = "native-tls")]
9+
use std::io::prelude::*;
10+
11+
#[cfg(feature = "rust-tls")]
12+
use crate::error::ParseErr;
513

614
#[cfg(not(any(feature = "native-tls", feature = "rust-tls")))]
715
compile_error!("one of the `native-tls` or `rust-tls` features must be enabled");
@@ -50,14 +58,18 @@ impl<S: io::Read + io::Write> io::Write for Conn<S> {
5058

5159
///client configuration
5260
pub struct Config {
61+
#[cfg(feature = "native-tls")]
62+
extra_root_certs: Vec<native_tls::Certificate>,
5363
#[cfg(feature = "rust-tls")]
5464
client_config: std::sync::Arc<rustls::ClientConfig>,
5565
}
5666

5767
impl Default for Config {
5868
#[cfg(feature = "native-tls")]
5969
fn default() -> Self {
60-
Config {}
70+
Config {
71+
extra_root_certs: vec![],
72+
}
6173
}
6274

6375
#[cfg(feature = "rust-tls")]
@@ -74,18 +86,53 @@ impl Default for Config {
7486
}
7587

7688
impl Config {
89+
#[cfg(feature = "native-tls")]
90+
pub fn add_root_cert_file_pem(&mut self, file_path: &Path) -> Result<&mut Self, HttpError> {
91+
let f = File::open(file_path)?;
92+
let f = BufReader::new(f);
93+
let mut pem_crt = vec![];
94+
for line in f.lines() {
95+
let line = line?;
96+
let is_end_cert = line.contains("-----END");
97+
pem_crt.append(&mut line.into_bytes());
98+
pem_crt.push(b'\n');
99+
if is_end_cert {
100+
let crt = native_tls::Certificate::from_pem(&pem_crt)?;
101+
self.extra_root_certs.push(crt);
102+
pem_crt.clear();
103+
}
104+
}
105+
Ok(self)
106+
}
107+
77108
#[cfg(feature = "native-tls")]
78109
pub fn connect<H, S>(&self, hostname: H, stream: S) -> Result<Conn<S>, HttpError>
79110
where
80111
H: AsRef<str>,
81112
S: io::Read + io::Write,
82113
{
83-
let connector = native_tls::TlsConnector::new()?;
114+
let mut connector_builder = native_tls::TlsConnector::builder();
115+
for crt in self.extra_root_certs.iter() {
116+
connector_builder.add_root_certificate((*crt).clone());
117+
}
118+
let connector = connector_builder.build()?;
84119
let stream = connector.connect(hostname.as_ref(), stream)?;
85120

86121
Ok(Conn { stream })
87122
}
88123

124+
#[cfg(feature = "rust-tls")]
125+
pub fn add_root_cert_file_pem(&mut self, file_path: &Path) -> Result<&mut Self, HttpError> {
126+
let f = File::open(file_path)?;
127+
let mut f = BufReader::new(f);
128+
let config = std::sync::Arc::make_mut(&mut self.client_config);
129+
let _ = config
130+
.root_store
131+
.add_pem_file(&mut f)
132+
.map_err(|_| HttpError::from(ParseErr::Invalid))?;
133+
Ok(self)
134+
}
135+
89136
#[cfg(feature = "rust-tls")]
90137
pub fn connect<H, S>(&self, hostname: H, stream: S) -> Result<Conn<S>, HttpError>
91138
where

0 commit comments

Comments
 (0)