Skip to content

Commit 41404e6

Browse files
authored
Merge pull request #2491 from p-alik/issue-786-mysql-ssl-support
Issue 786 mysql ssl support
2 parents dd5f41d + 9dc434e commit 41404e6

File tree

5 files changed

+80
-2
lines changed

5 files changed

+80
-2
lines changed

CHANGELOG.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ for Rust libraries in [RFC #1105](https://github.com/rust-lang/rfcs/blob/master/
88

99
### Added
1010

11+
* `MysqlConnection::establish` is able to initiate SSL connection. The database URL should contain `ssl_mode` parameter with a value of the [MySQL client command option `--ssl-mode`](https://dev.mysql.com/doc/refman/5.7/en/connection-options.html#option_general_ssl-mode) if desired.
12+
1113
* `Connection` and `SimpleConnection` traits are implemented for a broader range
1214
of `r2d2::PooledConnection<M>` types when the `r2d2` feature is enabled.
1315

@@ -80,7 +82,7 @@ for Rust libraries in [RFC #1105](https://github.com/rust-lang/rfcs/blob/master/
8082
* Support for `uuid` version < 0.7.0 has been removed.
8183
* Support for `bigdecimal` < 0.0.13 has been removed.
8284
* Support for `pq-sys` < 0.4.0 has been removed.
83-
* Support for `mysqlclient-sys` < 0.2.0 has been removed.
85+
* Support for `mysqlclient-sys` < 0.2.5 has been removed.
8486
* Support for `time` types has been removed.
8587
* Support for `chrono` < 0.4.19 has been removed.
8688
* The `NonNull` trait for sql types has been removed in favour of the new `SqlType` trait.

diesel/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ byteorder = { version = "1.0", optional = true }
1717
chrono = { version = "0.4.19", optional = true, default-features = false, features = ["clock", "std"] }
1818
libc = { version = "0.2.0", optional = true }
1919
libsqlite3-sys = { version = ">=0.17.2, <0.24.0", optional = true, features = ["bundled_bindings"] }
20-
mysqlclient-sys = { version = "0.2.0", optional = true }
20+
mysqlclient-sys = { version = "0.2.5", optional = true }
2121
pq-sys = { version = "0.4.0", optional = true }
2222
quickcheck = { version = "1.0.3", optional = true }
2323
serde_json = { version = ">=0.8.0, <2.0", optional = true }

diesel/src/mysql/connection/mod.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,13 @@ impl Connection for MysqlConnection {
5656
type Backend = Mysql;
5757
type TransactionManager = AnsiTransactionManager;
5858

59+
/// Establishes a new connection to the MySQL database
60+
/// `database_url` may be enhanced by GET parameters
61+
/// `mysql://[user[:password]@]host/database_name[?unix_socket=socket-path&ssl_mode=SSL_MODE*]`
62+
///
63+
/// * `unix_socket` excepts the path to the unix socket
64+
/// * `ssl_mode` expects a value defined for MySQL client command option `--ssl-mode`
65+
/// See <https://dev.mysql.com/doc/refman/5.7/en/connection-options.html#option_general_ssl-mode>
5966
fn establish(database_url: &str) -> ConnectionResult<Self> {
6067
use crate::result::ConnectionError::CouldntSetupConfiguration;
6168

diesel/src/mysql/connection/raw.rs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,10 @@ impl RawConnection {
4848
let unix_socket = connection_options.unix_socket();
4949
let client_flags = connection_options.client_flags();
5050

51+
if let Some(ssl_mode) = connection_options.ssl_mode() {
52+
self.set_ssl_mode(ssl_mode)
53+
}
54+
5155
unsafe {
5256
// Make sure you don't use the fake one!
5357
ffi::mysql_real_connect(
@@ -180,6 +184,19 @@ impl RawConnection {
180184
unsafe { ffi::mysql_next_result(self.0.as_ptr()) };
181185
self.did_an_error_occur()
182186
}
187+
188+
fn set_ssl_mode(&self, ssl_mode: mysqlclient_sys::mysql_ssl_mode) {
189+
let v = ssl_mode as u32;
190+
let v_ptr: *const u32 = &v;
191+
let n = ptr::NonNull::new(v_ptr as *mut u32).expect("NonNull::new failed");
192+
unsafe {
193+
mysqlclient_sys::mysql_options(
194+
self.0.as_ptr(),
195+
mysqlclient_sys::mysql_option::MYSQL_OPT_SSL_MODE,
196+
n.as_ptr() as *const std::ffi::c_void,
197+
)
198+
};
199+
}
183200
}
184201

185202
impl Drop for RawConnection {

diesel/src/mysql/connection/url.rs

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ use std::ffi::{CStr, CString};
88

99
use crate::result::{ConnectionError, ConnectionResult};
1010

11+
use mysqlclient_sys::mysql_ssl_mode;
12+
1113
bitflags::bitflags! {
1214
pub struct CapabilityFlags: u32 {
1315
const CLIENT_LONG_PASSWORD = 0x00000001;
@@ -46,6 +48,7 @@ pub struct ConnectionOptions {
4648
port: Option<u16>,
4749
unix_socket: Option<CString>,
4850
client_flags: CapabilityFlags,
51+
ssl_mode: Option<mysql_ssl_mode>,
4952
}
5053

5154
impl ConnectionOptions {
@@ -73,6 +76,24 @@ impl ConnectionOptions {
7376
_ => None,
7477
};
7578

79+
let ssl_mode = match query_pairs.get("ssl_mode") {
80+
Some(v) => {
81+
let ssl_mode = match v.to_lowercase().as_str() {
82+
"disabled" => mysql_ssl_mode::SSL_MODE_DISABLED,
83+
"preferred" => mysql_ssl_mode::SSL_MODE_PREFERRED,
84+
"required" => mysql_ssl_mode::SSL_MODE_REQUIRED,
85+
"verify_ca" => mysql_ssl_mode::SSL_MODE_VERIFY_CA,
86+
"verify_identity" => mysql_ssl_mode::SSL_MODE_VERIFY_IDENTITY,
87+
_ => {
88+
let msg = "unknown ssl_mode";
89+
return Err(ConnectionError::InvalidConnectionUrl(msg.into()));
90+
}
91+
};
92+
Some(ssl_mode)
93+
}
94+
_ => None,
95+
};
96+
7697
let host = match url.host() {
7798
Some(Host::Ipv6(host)) => Some(CString::new(host.to_string())?),
7899
Some(host) if host.to_string() == "localhost" && unix_socket != None => None,
@@ -101,6 +122,7 @@ impl ConnectionOptions {
101122
port: url.port(),
102123
unix_socket: unix_socket,
103124
client_flags: client_flags,
125+
ssl_mode: ssl_mode,
104126
})
105127
}
106128

@@ -131,6 +153,10 @@ impl ConnectionOptions {
131153
pub fn client_flags(&self) -> CapabilityFlags {
132154
self.client_flags
133155
}
156+
157+
pub fn ssl_mode(&self) -> Option<mysql_ssl_mode> {
158+
self.ssl_mode
159+
}
134160
}
135161

136162
fn decode_into_cstring(s: &str) -> ConnectionResult<CString> {
@@ -266,3 +292,29 @@ fn unix_socket_tests() {
266292
conn_opts.unix_socket.unwrap()
267293
);
268294
}
295+
296+
#[test]
297+
fn ssl_mode() {
298+
let ssl_mode = |url| ConnectionOptions::parse(url).unwrap().ssl_mode();
299+
assert_eq!(ssl_mode("mysql://localhost"), None);
300+
assert_eq!(
301+
ssl_mode("mysql://localhost?ssl_mode=disabled"),
302+
Some(mysql_ssl_mode::SSL_MODE_DISABLED)
303+
);
304+
assert_eq!(
305+
ssl_mode("mysql://localhost?ssl_mode=PREFERRED"),
306+
Some(mysql_ssl_mode::SSL_MODE_PREFERRED)
307+
);
308+
assert_eq!(
309+
ssl_mode("mysql://localhost?ssl_mode=required"),
310+
Some(mysql_ssl_mode::SSL_MODE_REQUIRED)
311+
);
312+
assert_eq!(
313+
ssl_mode("mysql://localhost?ssl_mode=VERIFY_CA"),
314+
Some(mysql_ssl_mode::SSL_MODE_VERIFY_CA)
315+
);
316+
assert_eq!(
317+
ssl_mode("mysql://localhost?ssl_mode=verify_identity"),
318+
Some(mysql_ssl_mode::SSL_MODE_VERIFY_IDENTITY)
319+
);
320+
}

0 commit comments

Comments
 (0)