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 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}