@@ -167,10 +167,60 @@ impl FromStr for ClientConfigKey {
167
167
}
168
168
}
169
169
170
+ /// Represents a CA certificate provided by the user.
171
+ ///
172
+ /// This is used to configure the client to trust a specific certificate. See
173
+ /// [Self::from_pem] for an example
174
+ #[ derive( Debug , Clone ) ]
175
+ pub struct Certificate ( reqwest:: tls:: Certificate ) ;
176
+
177
+ impl Certificate {
178
+ /// Create a `Certificate` from a PEM encoded certificate.
179
+ ///
180
+ /// # Example from a PEM file
181
+ ///
182
+ /// ```no_run
183
+ /// # use object_store::Certificate;
184
+ /// # use std::fs::File;
185
+ /// # use std::io::Read;
186
+ /// let mut buf = Vec::new();
187
+ /// File::open("my_cert.pem").unwrap()
188
+ /// .read_to_end(&mut buf).unwrap();
189
+ /// let cert = Certificate::from_pem(&buf).unwrap();
190
+ ///
191
+ /// ```
192
+ pub fn from_pem ( pem : & [ u8 ] ) -> Result < Self > {
193
+ Ok ( Self (
194
+ reqwest:: tls:: Certificate :: from_pem ( pem) . map_err ( map_client_error) ?,
195
+ ) )
196
+ }
197
+
198
+ /// Create a collection of `Certificate` from a PEM encoded certificate
199
+ /// bundle.
200
+ ///
201
+ /// Files that contain such collections have extensions such as `.crt`,
202
+ /// `.cer` and `.pem` files.
203
+ pub fn from_pem_bundle ( pem_bundle : & [ u8 ] ) -> Result < Vec < Self > > {
204
+ Ok ( reqwest:: tls:: Certificate :: from_pem_bundle ( pem_bundle)
205
+ . map_err ( map_client_error) ?
206
+ . into_iter ( )
207
+ . map ( Self )
208
+ . collect ( ) )
209
+ }
210
+
211
+ /// Create a `Certificate` from a binary DER encoded certificate.
212
+ pub fn from_der ( der : & [ u8 ] ) -> Result < Self > {
213
+ Ok ( Self (
214
+ reqwest:: tls:: Certificate :: from_der ( der) . map_err ( map_client_error) ?,
215
+ ) )
216
+ }
217
+ }
218
+
170
219
/// HTTP client configuration for remote object stores
171
220
#[ derive( Debug , Clone ) ]
172
221
pub struct ClientOptions {
173
222
user_agent : Option < ConfigValue < HeaderValue > > ,
223
+ root_certificates : Vec < Certificate > ,
174
224
content_type_map : HashMap < String , String > ,
175
225
default_content_type : Option < String > ,
176
226
default_headers : Option < HeaderMap > ,
@@ -201,6 +251,7 @@ impl Default for ClientOptions {
201
251
// we opt for a slightly higher default timeout of 30 seconds
202
252
Self {
203
253
user_agent : None ,
254
+ root_certificates : Default :: default ( ) ,
204
255
content_type_map : Default :: default ( ) ,
205
256
default_content_type : None ,
206
257
default_headers : None ,
@@ -310,6 +361,15 @@ impl ClientOptions {
310
361
self
311
362
}
312
363
364
+ /// Add a custom root certificate.
365
+ ///
366
+ /// This can be used to connect to a server that has a self-signed
367
+ /// certificate for example.
368
+ pub fn with_root_certificate ( mut self , certificate : Certificate ) -> Self {
369
+ self . root_certificates . push ( certificate) ;
370
+ self
371
+ }
372
+
313
373
/// Set the default CONTENT_TYPE for uploads
314
374
pub fn with_default_content_type ( mut self , mime : impl Into < String > ) -> Self {
315
375
self . default_content_type = Some ( mime. into ( ) ) ;
@@ -541,6 +601,10 @@ impl ClientOptions {
541
601
builder = builder. proxy ( proxy) ;
542
602
}
543
603
604
+ for certificate in & self . root_certificates {
605
+ builder = builder. add_root_certificate ( certificate. 0 . clone ( ) ) ;
606
+ }
607
+
544
608
if let Some ( timeout) = & self . timeout {
545
609
builder = builder. timeout ( timeout. get ( ) ?)
546
610
}
0 commit comments