tiberius/client/config/
ado_net.rs

1use super::{ConfigString, ServerDefinition};
2use std::str::FromStr;
3
4pub(crate) struct AdoNetConfig {
5    dict: connection_string::AdoNetString,
6}
7
8impl FromStr for AdoNetConfig {
9    type Err = crate::error::Error;
10
11    fn from_str(s: &str) -> crate::Result<Self> {
12        let dict = s.parse()?;
13        Ok(Self { dict })
14    }
15}
16
17impl ConfigString for AdoNetConfig {
18    fn dict(&self) -> &std::collections::HashMap<String, String> {
19        &self.dict
20    }
21
22    fn server(&self) -> crate::Result<ServerDefinition> {
23        fn parse_port(parts: &[&str]) -> crate::Result<Option<u16>> {
24            Ok(match parts.first() {
25                Some(s) => Some(s.parse()?),
26                None => None,
27            })
28        }
29
30        fn parse_server(parts: Vec<&str>) -> crate::Result<ServerDefinition> {
31            if parts.is_empty() || parts.len() >= 3 {
32                return Err(crate::Error::Conversion("Server value faulty.".into()));
33            }
34
35            let definition = if parts[0].contains('\\') {
36                let port = parse_port(&parts[1..])?;
37                let parts: Vec<&str> = parts[0].split('\\').collect();
38
39                ServerDefinition {
40                    host: Some(parts[0].replace("(local)", "localhost")),
41                    port,
42                    instance: Some(parts[1].into()),
43                }
44            } else {
45                // Connect using a TCP target
46                ServerDefinition {
47                    host: Some(parts[0].replace("(local)", "localhost")),
48                    port: parse_port(&parts[1..])?,
49                    instance: None,
50                }
51            };
52
53            Ok(definition)
54        }
55
56        match self
57            .dict
58            .get("server")
59            .or_else(|| self.dict.get("data source"))
60        {
61            Some(value) if value.starts_with("tcp:") => {
62                parse_server(value[4..].split(',').collect())
63            }
64            Some(value) => parse_server(value.split(',').collect()),
65            None => Ok(ServerDefinition {
66                host: None,
67                port: None,
68                instance: None,
69            }),
70        }
71    }
72}
73
74#[cfg(test)]
75mod tests {
76    use super::*;
77    use crate::client::AuthMethod;
78
79    #[cfg(any(
80        feature = "rustls",
81        feature = "native-tls",
82        feature = "vendored-openssl"
83    ))]
84    use crate::EncryptionLevel;
85
86    #[test]
87    fn server_parsing_no_browser() -> crate::Result<()> {
88        let test_str = "server=tcp:my-server.com,4200";
89        let ado: AdoNetConfig = test_str.parse()?;
90        let server = ado.server()?;
91
92        assert_eq!(Some("my-server.com".to_string()), server.host);
93        assert_eq!(Some(4200), server.port);
94        assert_eq!(None, server.instance);
95
96        let test_str = "data source=tcp:my-server.com,4200";
97        let ado: AdoNetConfig = test_str.parse()?;
98        let server = ado.server()?;
99
100        assert_eq!(Some("my-server.com".to_string()), server.host);
101        assert_eq!(Some(4200), server.port);
102        assert_eq!(None, server.instance);
103
104        Ok(())
105    }
106
107    #[test]
108    fn server_parsing_no_tcp() -> crate::Result<()> {
109        let test_str = "server=my-server.com,4200";
110        let ado: AdoNetConfig = test_str.parse()?;
111        let server = ado.server()?;
112
113        assert_eq!(Some("my-server.com".to_string()), server.host);
114        assert_eq!(Some(4200), server.port);
115        assert_eq!(None, server.instance);
116
117        let test_str = "data source=my-server.com,4200";
118        let ado: AdoNetConfig = test_str.parse()?;
119        let server = ado.server()?;
120
121        assert_eq!(Some("my-server.com".to_string()), server.host);
122        assert_eq!(Some(4200), server.port);
123        assert_eq!(None, server.instance);
124
125        Ok(())
126    }
127
128    #[test]
129    fn server_parsing_local() -> crate::Result<()> {
130        let test_str = "server=tcp:(local),4200";
131        let ado: AdoNetConfig = test_str.parse()?;
132        let server = ado.server()?;
133
134        assert_eq!(Some("localhost".to_string()), server.host);
135        assert_eq!(Some(4200), server.port);
136        assert_eq!(None, server.instance);
137
138        let test_str = "data source=tcp:(local),4200";
139        let ado: AdoNetConfig = test_str.parse()?;
140        let server = ado.server()?;
141
142        assert_eq!(Some("localhost".to_string()), server.host);
143        assert_eq!(Some(4200), server.port);
144        assert_eq!(None, server.instance);
145
146        Ok(())
147    }
148
149    #[test]
150    fn server_parsing_local_no_tcp() -> crate::Result<()> {
151        let test_str = "server=(local),4200";
152        let ado: AdoNetConfig = test_str.parse()?;
153        let server = ado.server()?;
154
155        assert_eq!(Some("localhost".to_string()), server.host);
156        assert_eq!(Some(4200), server.port);
157        assert_eq!(None, server.instance);
158
159        let test_str = "data source=(local),4200";
160        let ado: AdoNetConfig = test_str.parse()?;
161        let server = ado.server()?;
162
163        assert_eq!(Some("localhost".to_string()), server.host);
164        assert_eq!(Some(4200), server.port);
165        assert_eq!(None, server.instance);
166
167        Ok(())
168    }
169
170    #[test]
171    fn server_parsing_no_port() -> crate::Result<()> {
172        let test_str = "server=tcp:my-server.com";
173        let ado: AdoNetConfig = test_str.parse()?;
174        let server = ado.server()?;
175
176        assert_eq!(Some("my-server.com".to_string()), server.host);
177        assert_eq!(None, server.port);
178        assert_eq!(None, server.instance);
179
180        let test_str = "server=my-server.com";
181        let ado: AdoNetConfig = test_str.parse()?;
182        let server = ado.server()?;
183
184        assert_eq!(Some("my-server.com".to_string()), server.host);
185        assert_eq!(None, server.port);
186        assert_eq!(None, server.instance);
187
188        Ok(())
189    }
190
191    #[test]
192    fn server_parsing_with_browser() -> crate::Result<()> {
193        let test_str = "server=tcp:my-server.com\\TIBERIUS";
194        let ado: AdoNetConfig = test_str.parse()?;
195        let server = ado.server()?;
196
197        assert_eq!(Some("my-server.com".to_string()), server.host);
198        assert_eq!(None, server.port);
199        assert_eq!(Some("TIBERIUS".to_string()), server.instance);
200
201        let test_str = "data source=tcp:my-server.com\\TIBERIUS";
202        let ado: AdoNetConfig = test_str.parse()?;
203        let server = ado.server()?;
204
205        assert_eq!(Some("my-server.com".to_string()), server.host);
206        assert_eq!(None, server.port);
207        assert_eq!(Some("TIBERIUS".to_string()), server.instance);
208
209        Ok(())
210    }
211
212    #[test]
213    fn server_parsing_with_browser_and_port() -> crate::Result<()> {
214        let test_str = "server=tcp:my-server.com\\TIBERIUS,666";
215        let ado: AdoNetConfig = test_str.parse()?;
216        let server = ado.server()?;
217
218        assert_eq!(Some("my-server.com".to_string()), server.host);
219        assert_eq!(Some(666), server.port);
220        assert_eq!(Some("TIBERIUS".to_string()), server.instance);
221
222        let test_str = "data source=tcp:my-server.com\\TIBERIUS,666";
223        let ado: AdoNetConfig = test_str.parse()?;
224        let server = ado.server()?;
225
226        assert_eq!(Some("my-server.com".to_string()), server.host);
227        assert_eq!(Some(666), server.port);
228        assert_eq!(Some("TIBERIUS".to_string()), server.instance);
229
230        Ok(())
231    }
232
233    #[test]
234    fn database_parsing() -> crate::Result<()> {
235        let test_str = "database=Foo";
236        let ado: AdoNetConfig = test_str.parse()?;
237
238        assert_eq!(Some("Foo".to_string()), ado.database());
239
240        let test_str = "databaseName=Foo";
241        let jdbc: AdoNetConfig = test_str.parse()?;
242
243        assert_eq!(Some("Foo".to_string()), jdbc.database());
244
245        let test_str = "Initial Catalog=Foo";
246        let jdbc: AdoNetConfig = test_str.parse()?;
247
248        assert_eq!(Some("Foo".to_string()), jdbc.database());
249
250        Ok(())
251    }
252
253    #[test]
254    fn trust_cert_parsing_true() -> crate::Result<()> {
255        let test_str = "TrustServerCertificate=true";
256        let ado: AdoNetConfig = test_str.parse()?;
257
258        assert!(ado.trust_cert()?);
259
260        Ok(())
261    }
262
263    #[test]
264    fn trust_cert_parsing_false() -> crate::Result<()> {
265        let test_str = "TrustServerCertificate=false";
266        let ado: AdoNetConfig = test_str.parse()?;
267
268        assert!(!ado.trust_cert()?);
269
270        Ok(())
271    }
272
273    #[test]
274    fn trust_cert_parsing_yes() -> crate::Result<()> {
275        let test_str = "TrustServerCertificate=yes";
276        let ado: AdoNetConfig = test_str.parse()?;
277
278        assert!(ado.trust_cert()?);
279
280        Ok(())
281    }
282
283    #[test]
284    fn trust_cert_parsing_no() -> crate::Result<()> {
285        let test_str = "TrustServerCertificate=no";
286        let ado: AdoNetConfig = test_str.parse()?;
287
288        assert!(!ado.trust_cert()?);
289
290        Ok(())
291    }
292
293    #[test]
294    fn trust_cert_parsing_missing() -> crate::Result<()> {
295        let test_str = "Something=foo;";
296        let ado: AdoNetConfig = test_str.parse()?;
297
298        assert!(!ado.trust_cert()?);
299
300        Ok(())
301    }
302
303    #[test]
304    fn trust_cert_parsing_faulty() -> crate::Result<()> {
305        let test_str = "TrustServerCertificate=musti;";
306        let ado: AdoNetConfig = test_str.parse()?;
307
308        assert!(ado.trust_cert().is_err());
309
310        Ok(())
311    }
312
313    #[test]
314    fn trust_cert_ca_parsing_ok() -> crate::Result<()> {
315        let test_str = "TrustServerCertificateCA=someca.crt;";
316        let ado: AdoNetConfig = test_str.parse()?;
317
318        assert_eq!(Some("someca.crt".to_string()), ado.trust_cert_ca());
319
320        Ok(())
321    }
322
323    #[test]
324    fn parsing_sql_server_authentication() -> crate::Result<()> {
325        let test_str = "uid=Musti; pwd=Naukio;";
326        let ado: AdoNetConfig = test_str.parse()?;
327
328        assert_eq!(
329            AuthMethod::sql_server("Musti", "Naukio"),
330            ado.authentication()?
331        );
332
333        Ok(())
334    }
335
336    #[test]
337    #[cfg(windows)]
338    fn parsing_sspi_authentication() -> crate::Result<()> {
339        let test_str = "IntegratedSecurity=SSPI;";
340        let ado: AdoNetConfig = test_str.parse()?;
341
342        assert_eq!(AuthMethod::Integrated, ado.authentication()?);
343
344        let test_str = "Integrated Security=SSPI;";
345        let ado: AdoNetConfig = test_str.parse()?;
346
347        assert_eq!(AuthMethod::Integrated, ado.authentication()?);
348
349        Ok(())
350    }
351
352    #[test]
353    #[cfg(all(feature = "integrated-auth-gssapi", unix))]
354    fn parsing_sspi_authentication() -> crate::Result<()> {
355        let test_str = "IntegratedSecurity=true;";
356        let ado: AdoNetConfig = test_str.parse()?;
357
358        assert_eq!(AuthMethod::Integrated, ado.authentication()?);
359
360        let test_str = "Integrated Security=true;";
361        let ado: AdoNetConfig = test_str.parse()?;
362
363        assert_eq!(AuthMethod::Integrated, ado.authentication()?);
364
365        Ok(())
366    }
367
368    #[test]
369    #[cfg(windows)]
370    fn parsing_windows_authentication() -> crate::Result<()> {
371        let test_str = "uid=Musti;pwd=Naukio; IntegratedSecurity=SSPI;";
372        let ado: AdoNetConfig = test_str.parse()?;
373
374        assert_eq!(
375            AuthMethod::windows("Musti", "Naukio"),
376            ado.authentication()?
377        );
378
379        let test_str = "uid=Musti;pwd=Naukio; Integrated Security=SSPI;";
380        let ado: AdoNetConfig = test_str.parse()?;
381
382        assert_eq!(
383            AuthMethod::windows("Musti", "Naukio"),
384            ado.authentication()?
385        );
386
387        Ok(())
388    }
389
390    #[test]
391    fn parsing_database() -> crate::Result<()> {
392        let test_str = "database=Cats;";
393        let ado: AdoNetConfig = test_str.parse()?;
394
395        assert_eq!(Some("Cats".to_string()), ado.database());
396
397        Ok(())
398    }
399
400    #[test]
401    fn parsing_login_credentials_escaping() -> crate::Result<()> {
402        let test_str = "User ID=musti; Password='abc;}45';";
403        let ado: AdoNetConfig = test_str.parse()?;
404
405        assert_eq!(
406            AuthMethod::sql_server("musti", "abc;}45"),
407            ado.authentication()?
408        );
409
410        Ok(())
411    }
412
413    #[test]
414    #[cfg(any(
415        feature = "rustls",
416        feature = "native-tls",
417        feature = "vendored-openssl"
418    ))]
419    fn encryption_parsing_on() -> crate::Result<()> {
420        let test_str = "encrypt=true";
421        let ado: AdoNetConfig = test_str.parse()?;
422
423        assert_eq!(EncryptionLevel::Required, ado.encrypt()?);
424
425        Ok(())
426    }
427
428    #[test]
429    #[cfg(any(
430        feature = "rustls",
431        feature = "native-tls",
432        feature = "vendored-openssl"
433    ))]
434    fn encryption_parsing_off() -> crate::Result<()> {
435        let test_str = "encrypt=false";
436        let ado: AdoNetConfig = test_str.parse()?;
437
438        assert_eq!(EncryptionLevel::Off, ado.encrypt()?);
439
440        Ok(())
441    }
442
443    #[test]
444    #[cfg(any(
445        feature = "rustls",
446        feature = "native-tls",
447        feature = "vendored-openssl"
448    ))]
449    fn encryption_parsing_plaintext() -> crate::Result<()> {
450        let test_str = "encrypt=DANGER_PLAINTEXT";
451        let ado: AdoNetConfig = test_str.parse()?;
452
453        assert_eq!(EncryptionLevel::NotSupported, ado.encrypt()?);
454
455        Ok(())
456    }
457
458    #[test]
459    #[cfg(any(
460        feature = "rustls",
461        feature = "native-tls",
462        feature = "vendored-openssl"
463    ))]
464    fn encryption_parsing_missing() -> crate::Result<()> {
465        let test_str = "";
466        let ado: AdoNetConfig = test_str.parse()?;
467
468        assert_eq!(EncryptionLevel::Off, ado.encrypt()?);
469
470        Ok(())
471    }
472
473    #[test]
474    fn application_name_parsing() -> crate::Result<()> {
475        let test_str = "Application Name=meow";
476        let ado: AdoNetConfig = test_str.parse()?;
477
478        assert_eq!(Some("meow".into()), ado.application_name());
479
480        let test_str = "ApplicationName=meow";
481        let ado: AdoNetConfig = test_str.parse()?;
482
483        assert_eq!(Some("meow".into()), ado.application_name());
484
485        Ok(())
486    }
487}