13 releases (5 stable)

new 1.1.1 Dec 4, 2024
1.1.0 Sep 6, 2024
1.0.2 Apr 25, 2020
1.0.1 Mar 17, 2020
0.1.1 Jul 7, 2019

#316 in Parser implementations

Download history 883/week @ 2024-08-19 668/week @ 2024-08-26 1170/week @ 2024-09-02 1147/week @ 2024-09-09 1553/week @ 2024-09-16 1978/week @ 2024-09-23 919/week @ 2024-09-30 724/week @ 2024-10-07 685/week @ 2024-10-14 594/week @ 2024-10-21 531/week @ 2024-10-28 693/week @ 2024-11-04 598/week @ 2024-11-11 606/week @ 2024-11-18 360/week @ 2024-11-25 1189/week @ 2024-12-02

2,781 downloads per month
Used in 6 crates (5 directly)

BSD-3-Clause

17KB
259 lines

DSN (Data Source Name) parser

crates.io Test & Build docs

DSN format:

<driver>://<username>:<password>@<protocol>(<address>)/<database>?param1=value1&...&paramN=valueN

A DSN in its fullest form:

driver://username:password@protocol(address)/dbname?param=value

The address changes depending on the protocol

For TCP/UDP address have the form host:port, example:

postgresql://user:pass@tcp(localhost:5432)/dbname

For protocol unix (Unix domain sockets) the address is the absolute path to the socket, for example:

mysql://user@unix(/path/to/socket)/database

For protocol file (sqlite) use the absolute path as the address, example:

sqlite://@file(/full/unix/path/to/file.db)

percent-encode

Percent-encode username and password with characters like @, for example if password is:

!A4T@hh'cUj7LXXvk"

From the command line you can encode it with:

echo -n "\!A4T@hh'cUj7LXXvk\"" | jq -s -R -r @uri

or

echo -n "\!A4T@hh'cUj7LXXvk\"" | xxd -p |sed 's/../%&/g'

Then you can build the dsn:

mysql://root:!A4T%40hh'cUj7LXXvk%22@tcp(10.0.0.1:3306)/test

or

mysql://root:%21%41%34%54%40%68%68%27%63%55%6a%37%4c%58%58%76%6b%22@tcp(10.0.0.1:3306)/test

Example using the mysql create crates.io

DSN:

mysql://user:password@tcp(db.example.com)/mydb?tls=skip-verify

Code:

// if using clap asking for the DSN as an argument
let dsn = matches.value_of("DSN").unwrap();
let dsn = dsn::parse(dsn).unwrap_or_else(|e| {
    eprintln!("{}", e);
    process::exit(1);
});

let mut opts = mysql::OptsBuilder::new();
opts.user(dsn.username);
opts.pass(dsn.password);
opts.ip_or_hostname(dsn.host);
if let Some(port) = dsn.port {
    opts.tcp_port(port);
}
opts.socket(dsn.socket);
opts.db_name(dsn.database);

// mysql ssl options
let mut ssl_opts = mysql::SslOpts::default();
if let Some(tls) = dsn.params.get("tls") {
    if *tls == "skip-verify" {
        ssl_opts.set_danger_accept_invalid_certs(true);
    }
}
opts.ssl_opts(ssl_opts);

let pool = mysql::Pool::new_manual(3, 50, opts).unwrap_or_else(|e| {
    eprintln!("Could not connect to MySQL: {}", e);
    process::exit(1);
});

Dependencies

~13KB