1extern crate percent_encoding;
2extern crate url;
3
4use self::percent_encoding::percent_decode;
5use self::url::{Host, Url};
6use alloc::ffi::CString;
7use core::ffi::CStr;
8use std::collections::HashMap;
9
10use crate::result::{ConnectionError, ConnectionResult};
11
12use mysqlclient_sys::mysql_ssl_mode;
13
14bitflags::bitflags! {
15 #[derive(#[automatically_derived]
impl ::core::clone::Clone for CapabilityFlags {
#[inline]
fn clone(&self) -> CapabilityFlags {
let _:
::core::clone::AssertParamIsClone<<CapabilityFlags as
::bitflags::__private::PublicFlags>::Internal>;
*self
}
}
impl CapabilityFlags {
#[allow(deprecated, non_upper_case_globals,)]
pub const CLIENT_LONG_PASSWORD: Self = Self::from_bits_retain(0x00000001);
#[allow(deprecated, non_upper_case_globals,)]
pub const CLIENT_FOUND_ROWS: Self = Self::from_bits_retain(0x00000002);
#[allow(deprecated, non_upper_case_globals,)]
pub const CLIENT_LONG_FLAG: Self = Self::from_bits_retain(0x00000004);
#[allow(deprecated, non_upper_case_globals,)]
pub const CLIENT_CONNECT_WITH_DB: Self =
Self::from_bits_retain(0x00000008);
#[allow(deprecated, non_upper_case_globals,)]
pub const CLIENT_NO_SCHEMA: Self = Self::from_bits_retain(0x00000010);
#[allow(deprecated, non_upper_case_globals,)]
pub const CLIENT_COMPRESS: Self = Self::from_bits_retain(0x00000020);
#[allow(deprecated, non_upper_case_globals,)]
pub const CLIENT_ODBC: Self = Self::from_bits_retain(0x00000040);
#[allow(deprecated, non_upper_case_globals,)]
pub const CLIENT_LOCAL_FILES: Self = Self::from_bits_retain(0x00000080);
#[allow(deprecated, non_upper_case_globals,)]
pub const CLIENT_IGNORE_SPACE: Self = Self::from_bits_retain(0x00000100);
#[allow(deprecated, non_upper_case_globals,)]
pub const CLIENT_PROTOCOL_41: Self = Self::from_bits_retain(0x00000200);
#[allow(deprecated, non_upper_case_globals,)]
pub const CLIENT_INTERACTIVE: Self = Self::from_bits_retain(0x00000400);
#[allow(deprecated, non_upper_case_globals,)]
pub const CLIENT_SSL: Self = Self::from_bits_retain(0x00000800);
#[allow(deprecated, non_upper_case_globals,)]
pub const CLIENT_IGNORE_SIGPIPE: Self =
Self::from_bits_retain(0x00001000);
#[allow(deprecated, non_upper_case_globals,)]
pub const CLIENT_TRANSACTIONS: Self = Self::from_bits_retain(0x00002000);
#[allow(deprecated, non_upper_case_globals,)]
pub const CLIENT_RESERVED: Self = Self::from_bits_retain(0x00004000);
#[allow(deprecated, non_upper_case_globals,)]
pub const CLIENT_SECURE_CONNECTION: Self =
Self::from_bits_retain(0x00008000);
#[allow(deprecated, non_upper_case_globals,)]
pub const CLIENT_MULTI_STATEMENTS: Self =
Self::from_bits_retain(0x00010000);
#[allow(deprecated, non_upper_case_globals,)]
pub const CLIENT_MULTI_RESULTS: Self = Self::from_bits_retain(0x00020000);
#[allow(deprecated, non_upper_case_globals,)]
pub const CLIENT_PS_MULTI_RESULTS: Self =
Self::from_bits_retain(0x00040000);
#[allow(deprecated, non_upper_case_globals,)]
pub const CLIENT_PLUGIN_AUTH: Self = Self::from_bits_retain(0x00080000);
#[allow(deprecated, non_upper_case_globals,)]
pub const CLIENT_CONNECT_ATTRS: Self = Self::from_bits_retain(0x00100000);
#[allow(deprecated, non_upper_case_globals,)]
pub const CLIENT_PLUGIN_AUTH_LENENC_CLIENT_DATA: Self =
Self::from_bits_retain(0x00200000);
#[allow(deprecated, non_upper_case_globals,)]
pub const CLIENT_CAN_HANDLE_EXPIRED_PASSWORDS: Self =
Self::from_bits_retain(0x00400000);
#[allow(deprecated, non_upper_case_globals,)]
pub const CLIENT_SESSION_TRACK: Self = Self::from_bits_retain(0x00800000);
#[allow(deprecated, non_upper_case_globals,)]
pub const CLIENT_DEPRECATE_EOF: Self = Self::from_bits_retain(0x01000000);
}
impl ::bitflags::Flags for CapabilityFlags {
const FLAGS: &'static [::bitflags::Flag<CapabilityFlags>] =
&[{
#[allow(deprecated, non_upper_case_globals,)]
::bitflags::Flag::new("CLIENT_LONG_PASSWORD",
CapabilityFlags::CLIENT_LONG_PASSWORD)
},
{
#[allow(deprecated, non_upper_case_globals,)]
::bitflags::Flag::new("CLIENT_FOUND_ROWS",
CapabilityFlags::CLIENT_FOUND_ROWS)
},
{
#[allow(deprecated, non_upper_case_globals,)]
::bitflags::Flag::new("CLIENT_LONG_FLAG",
CapabilityFlags::CLIENT_LONG_FLAG)
},
{
#[allow(deprecated, non_upper_case_globals,)]
::bitflags::Flag::new("CLIENT_CONNECT_WITH_DB",
CapabilityFlags::CLIENT_CONNECT_WITH_DB)
},
{
#[allow(deprecated, non_upper_case_globals,)]
::bitflags::Flag::new("CLIENT_NO_SCHEMA",
CapabilityFlags::CLIENT_NO_SCHEMA)
},
{
#[allow(deprecated, non_upper_case_globals,)]
::bitflags::Flag::new("CLIENT_COMPRESS",
CapabilityFlags::CLIENT_COMPRESS)
},
{
#[allow(deprecated, non_upper_case_globals,)]
::bitflags::Flag::new("CLIENT_ODBC",
CapabilityFlags::CLIENT_ODBC)
},
{
#[allow(deprecated, non_upper_case_globals,)]
::bitflags::Flag::new("CLIENT_LOCAL_FILES",
CapabilityFlags::CLIENT_LOCAL_FILES)
},
{
#[allow(deprecated, non_upper_case_globals,)]
::bitflags::Flag::new("CLIENT_IGNORE_SPACE",
CapabilityFlags::CLIENT_IGNORE_SPACE)
},
{
#[allow(deprecated, non_upper_case_globals,)]
::bitflags::Flag::new("CLIENT_PROTOCOL_41",
CapabilityFlags::CLIENT_PROTOCOL_41)
},
{
#[allow(deprecated, non_upper_case_globals,)]
::bitflags::Flag::new("CLIENT_INTERACTIVE",
CapabilityFlags::CLIENT_INTERACTIVE)
},
{
#[allow(deprecated, non_upper_case_globals,)]
::bitflags::Flag::new("CLIENT_SSL",
CapabilityFlags::CLIENT_SSL)
},
{
#[allow(deprecated, non_upper_case_globals,)]
::bitflags::Flag::new("CLIENT_IGNORE_SIGPIPE",
CapabilityFlags::CLIENT_IGNORE_SIGPIPE)
},
{
#[allow(deprecated, non_upper_case_globals,)]
::bitflags::Flag::new("CLIENT_TRANSACTIONS",
CapabilityFlags::CLIENT_TRANSACTIONS)
},
{
#[allow(deprecated, non_upper_case_globals,)]
::bitflags::Flag::new("CLIENT_RESERVED",
CapabilityFlags::CLIENT_RESERVED)
},
{
#[allow(deprecated, non_upper_case_globals,)]
::bitflags::Flag::new("CLIENT_SECURE_CONNECTION",
CapabilityFlags::CLIENT_SECURE_CONNECTION)
},
{
#[allow(deprecated, non_upper_case_globals,)]
::bitflags::Flag::new("CLIENT_MULTI_STATEMENTS",
CapabilityFlags::CLIENT_MULTI_STATEMENTS)
},
{
#[allow(deprecated, non_upper_case_globals,)]
::bitflags::Flag::new("CLIENT_MULTI_RESULTS",
CapabilityFlags::CLIENT_MULTI_RESULTS)
},
{
#[allow(deprecated, non_upper_case_globals,)]
::bitflags::Flag::new("CLIENT_PS_MULTI_RESULTS",
CapabilityFlags::CLIENT_PS_MULTI_RESULTS)
},
{
#[allow(deprecated, non_upper_case_globals,)]
::bitflags::Flag::new("CLIENT_PLUGIN_AUTH",
CapabilityFlags::CLIENT_PLUGIN_AUTH)
},
{
#[allow(deprecated, non_upper_case_globals,)]
::bitflags::Flag::new("CLIENT_CONNECT_ATTRS",
CapabilityFlags::CLIENT_CONNECT_ATTRS)
},
{
#[allow(deprecated, non_upper_case_globals,)]
::bitflags::Flag::new("CLIENT_PLUGIN_AUTH_LENENC_CLIENT_DATA",
CapabilityFlags::CLIENT_PLUGIN_AUTH_LENENC_CLIENT_DATA)
},
{
#[allow(deprecated, non_upper_case_globals,)]
::bitflags::Flag::new("CLIENT_CAN_HANDLE_EXPIRED_PASSWORDS",
CapabilityFlags::CLIENT_CAN_HANDLE_EXPIRED_PASSWORDS)
},
{
#[allow(deprecated, non_upper_case_globals,)]
::bitflags::Flag::new("CLIENT_SESSION_TRACK",
CapabilityFlags::CLIENT_SESSION_TRACK)
},
{
#[allow(deprecated, non_upper_case_globals,)]
::bitflags::Flag::new("CLIENT_DEPRECATE_EOF",
CapabilityFlags::CLIENT_DEPRECATE_EOF)
}];
type Bits = u32;
fn bits(&self) -> u32 { CapabilityFlags::bits(self) }
fn from_bits_retain(bits: u32) -> CapabilityFlags {
CapabilityFlags::from_bits_retain(bits)
}
}
#[allow(dead_code, deprecated, unused_doc_comments, unused_attributes,
unused_mut, unused_imports, non_upper_case_globals, clippy ::
assign_op_pattern, clippy :: indexing_slicing, clippy :: same_name_method,
clippy :: iter_without_into_iter,)]
const _: () =
{
#[repr(transparent)]
pub struct InternalBitFlags(u32);
#[automatically_derived]
#[doc(hidden)]
unsafe impl ::core::clone::TrivialClone for InternalBitFlags { }
#[automatically_derived]
impl ::core::clone::Clone for InternalBitFlags {
#[inline]
fn clone(&self) -> InternalBitFlags {
let _: ::core::clone::AssertParamIsClone<u32>;
*self
}
}
#[automatically_derived]
impl ::core::marker::Copy for InternalBitFlags { }
#[automatically_derived]
impl ::core::marker::StructuralPartialEq for InternalBitFlags { }
#[automatically_derived]
impl ::core::cmp::PartialEq for InternalBitFlags {
#[inline]
fn eq(&self, other: &InternalBitFlags) -> bool {
self.0 == other.0
}
}
#[automatically_derived]
impl ::core::cmp::Eq for InternalBitFlags {
#[inline]
#[doc(hidden)]
#[coverage(off)]
fn assert_fields_are_eq(&self) {
let _: ::core::cmp::AssertParamIsEq<u32>;
}
}
#[automatically_derived]
impl ::core::cmp::PartialOrd for InternalBitFlags {
#[inline]
fn partial_cmp(&self, other: &InternalBitFlags)
-> ::core::option::Option<::core::cmp::Ordering> {
::core::cmp::PartialOrd::partial_cmp(&self.0, &other.0)
}
}
#[automatically_derived]
impl ::core::cmp::Ord for InternalBitFlags {
#[inline]
fn cmp(&self, other: &InternalBitFlags) -> ::core::cmp::Ordering {
::core::cmp::Ord::cmp(&self.0, &other.0)
}
}
#[automatically_derived]
impl ::core::hash::Hash for InternalBitFlags {
#[inline]
fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) {
::core::hash::Hash::hash(&self.0, state)
}
}
impl ::bitflags::__private::PublicFlags for CapabilityFlags {
type Primitive = u32;
type Internal = InternalBitFlags;
}
impl ::bitflags::__private::core::default::Default for
InternalBitFlags {
#[inline]
fn default() -> Self { InternalBitFlags::empty() }
}
impl ::bitflags::__private::core::fmt::Debug for InternalBitFlags {
fn fmt(&self,
f: &mut ::bitflags::__private::core::fmt::Formatter<'_>)
-> ::bitflags::__private::core::fmt::Result {
if self.is_empty() {
f.write_fmt(format_args!("{0:#x}",
<u32 as ::bitflags::Bits>::EMPTY))
} else {
::bitflags::__private::core::fmt::Display::fmt(self, f)
}
}
}
impl ::bitflags::__private::core::fmt::Display for InternalBitFlags {
fn fmt(&self,
f: &mut ::bitflags::__private::core::fmt::Formatter<'_>)
-> ::bitflags::__private::core::fmt::Result {
::bitflags::parser::to_writer(&CapabilityFlags(*self), f)
}
}
impl ::bitflags::__private::core::str::FromStr for InternalBitFlags {
type Err = ::bitflags::parser::ParseError;
fn from_str(s: &str)
->
::bitflags::__private::core::result::Result<Self,
Self::Err> {
::bitflags::parser::from_str::<CapabilityFlags>(s).map(|flags|
flags.0)
}
}
impl ::bitflags::__private::core::convert::AsRef<u32> for
InternalBitFlags {
fn as_ref(&self) -> &u32 { &self.0 }
}
impl ::bitflags::__private::core::convert::From<u32> for
InternalBitFlags {
fn from(bits: u32) -> Self { Self::from_bits_retain(bits) }
}
#[allow(dead_code, deprecated, unused_attributes)]
impl InternalBitFlags {
#[inline]
pub const fn empty() -> Self {
Self(<u32 as ::bitflags::Bits>::EMPTY)
}
#[inline]
pub const fn all() -> Self {
let mut truncated = <u32 as ::bitflags::Bits>::EMPTY;
let mut i = 0;
{
{
let flag =
<CapabilityFlags as
::bitflags::Flags>::FLAGS[i].value().bits();
truncated = truncated | flag;
i += 1;
}
};
{
{
let flag =
<CapabilityFlags as
::bitflags::Flags>::FLAGS[i].value().bits();
truncated = truncated | flag;
i += 1;
}
};
{
{
let flag =
<CapabilityFlags as
::bitflags::Flags>::FLAGS[i].value().bits();
truncated = truncated | flag;
i += 1;
}
};
{
{
let flag =
<CapabilityFlags as
::bitflags::Flags>::FLAGS[i].value().bits();
truncated = truncated | flag;
i += 1;
}
};
{
{
let flag =
<CapabilityFlags as
::bitflags::Flags>::FLAGS[i].value().bits();
truncated = truncated | flag;
i += 1;
}
};
{
{
let flag =
<CapabilityFlags as
::bitflags::Flags>::FLAGS[i].value().bits();
truncated = truncated | flag;
i += 1;
}
};
{
{
let flag =
<CapabilityFlags as
::bitflags::Flags>::FLAGS[i].value().bits();
truncated = truncated | flag;
i += 1;
}
};
{
{
let flag =
<CapabilityFlags as
::bitflags::Flags>::FLAGS[i].value().bits();
truncated = truncated | flag;
i += 1;
}
};
{
{
let flag =
<CapabilityFlags as
::bitflags::Flags>::FLAGS[i].value().bits();
truncated = truncated | flag;
i += 1;
}
};
{
{
let flag =
<CapabilityFlags as
::bitflags::Flags>::FLAGS[i].value().bits();
truncated = truncated | flag;
i += 1;
}
};
{
{
let flag =
<CapabilityFlags as
::bitflags::Flags>::FLAGS[i].value().bits();
truncated = truncated | flag;
i += 1;
}
};
{
{
let flag =
<CapabilityFlags as
::bitflags::Flags>::FLAGS[i].value().bits();
truncated = truncated | flag;
i += 1;
}
};
{
{
let flag =
<CapabilityFlags as
::bitflags::Flags>::FLAGS[i].value().bits();
truncated = truncated | flag;
i += 1;
}
};
{
{
let flag =
<CapabilityFlags as
::bitflags::Flags>::FLAGS[i].value().bits();
truncated = truncated | flag;
i += 1;
}
};
{
{
let flag =
<CapabilityFlags as
::bitflags::Flags>::FLAGS[i].value().bits();
truncated = truncated | flag;
i += 1;
}
};
{
{
let flag =
<CapabilityFlags as
::bitflags::Flags>::FLAGS[i].value().bits();
truncated = truncated | flag;
i += 1;
}
};
{
{
let flag =
<CapabilityFlags as
::bitflags::Flags>::FLAGS[i].value().bits();
truncated = truncated | flag;
i += 1;
}
};
{
{
let flag =
<CapabilityFlags as
::bitflags::Flags>::FLAGS[i].value().bits();
truncated = truncated | flag;
i += 1;
}
};
{
{
let flag =
<CapabilityFlags as
::bitflags::Flags>::FLAGS[i].value().bits();
truncated = truncated | flag;
i += 1;
}
};
{
{
let flag =
<CapabilityFlags as
::bitflags::Flags>::FLAGS[i].value().bits();
truncated = truncated | flag;
i += 1;
}
};
{
{
let flag =
<CapabilityFlags as
::bitflags::Flags>::FLAGS[i].value().bits();
truncated = truncated | flag;
i += 1;
}
};
{
{
let flag =
<CapabilityFlags as
::bitflags::Flags>::FLAGS[i].value().bits();
truncated = truncated | flag;
i += 1;
}
};
{
{
let flag =
<CapabilityFlags as
::bitflags::Flags>::FLAGS[i].value().bits();
truncated = truncated | flag;
i += 1;
}
};
{
{
let flag =
<CapabilityFlags as
::bitflags::Flags>::FLAGS[i].value().bits();
truncated = truncated | flag;
i += 1;
}
};
{
{
let flag =
<CapabilityFlags as
::bitflags::Flags>::FLAGS[i].value().bits();
truncated = truncated | flag;
i += 1;
}
};
let _ = i;
Self(truncated)
}
#[inline]
pub const fn bits(&self) -> u32 { self.0 }
#[inline]
pub const fn from_bits(bits: u32)
-> ::bitflags::__private::core::option::Option<Self> {
let truncated = Self::from_bits_truncate(bits).0;
if truncated == bits {
::bitflags::__private::core::option::Option::Some(Self(bits))
} else { ::bitflags::__private::core::option::Option::None }
}
#[inline]
pub const fn from_bits_truncate(bits: u32) -> Self {
Self(bits & Self::all().0)
}
#[inline]
pub const fn from_bits_retain(bits: u32) -> Self { Self(bits) }
#[inline]
pub fn from_name(name: &str)
-> ::bitflags::__private::core::option::Option<Self> {
{
if name == "CLIENT_LONG_PASSWORD" {
return ::bitflags::__private::core::option::Option::Some(Self(CapabilityFlags::CLIENT_LONG_PASSWORD.bits()));
}
};
;
{
if name == "CLIENT_FOUND_ROWS" {
return ::bitflags::__private::core::option::Option::Some(Self(CapabilityFlags::CLIENT_FOUND_ROWS.bits()));
}
};
;
{
if name == "CLIENT_LONG_FLAG" {
return ::bitflags::__private::core::option::Option::Some(Self(CapabilityFlags::CLIENT_LONG_FLAG.bits()));
}
};
;
{
if name == "CLIENT_CONNECT_WITH_DB" {
return ::bitflags::__private::core::option::Option::Some(Self(CapabilityFlags::CLIENT_CONNECT_WITH_DB.bits()));
}
};
;
{
if name == "CLIENT_NO_SCHEMA" {
return ::bitflags::__private::core::option::Option::Some(Self(CapabilityFlags::CLIENT_NO_SCHEMA.bits()));
}
};
;
{
if name == "CLIENT_COMPRESS" {
return ::bitflags::__private::core::option::Option::Some(Self(CapabilityFlags::CLIENT_COMPRESS.bits()));
}
};
;
{
if name == "CLIENT_ODBC" {
return ::bitflags::__private::core::option::Option::Some(Self(CapabilityFlags::CLIENT_ODBC.bits()));
}
};
;
{
if name == "CLIENT_LOCAL_FILES" {
return ::bitflags::__private::core::option::Option::Some(Self(CapabilityFlags::CLIENT_LOCAL_FILES.bits()));
}
};
;
{
if name == "CLIENT_IGNORE_SPACE" {
return ::bitflags::__private::core::option::Option::Some(Self(CapabilityFlags::CLIENT_IGNORE_SPACE.bits()));
}
};
;
{
if name == "CLIENT_PROTOCOL_41" {
return ::bitflags::__private::core::option::Option::Some(Self(CapabilityFlags::CLIENT_PROTOCOL_41.bits()));
}
};
;
{
if name == "CLIENT_INTERACTIVE" {
return ::bitflags::__private::core::option::Option::Some(Self(CapabilityFlags::CLIENT_INTERACTIVE.bits()));
}
};
;
{
if name == "CLIENT_SSL" {
return ::bitflags::__private::core::option::Option::Some(Self(CapabilityFlags::CLIENT_SSL.bits()));
}
};
;
{
if name == "CLIENT_IGNORE_SIGPIPE" {
return ::bitflags::__private::core::option::Option::Some(Self(CapabilityFlags::CLIENT_IGNORE_SIGPIPE.bits()));
}
};
;
{
if name == "CLIENT_TRANSACTIONS" {
return ::bitflags::__private::core::option::Option::Some(Self(CapabilityFlags::CLIENT_TRANSACTIONS.bits()));
}
};
;
{
if name == "CLIENT_RESERVED" {
return ::bitflags::__private::core::option::Option::Some(Self(CapabilityFlags::CLIENT_RESERVED.bits()));
}
};
;
{
if name == "CLIENT_SECURE_CONNECTION" {
return ::bitflags::__private::core::option::Option::Some(Self(CapabilityFlags::CLIENT_SECURE_CONNECTION.bits()));
}
};
;
{
if name == "CLIENT_MULTI_STATEMENTS" {
return ::bitflags::__private::core::option::Option::Some(Self(CapabilityFlags::CLIENT_MULTI_STATEMENTS.bits()));
}
};
;
{
if name == "CLIENT_MULTI_RESULTS" {
return ::bitflags::__private::core::option::Option::Some(Self(CapabilityFlags::CLIENT_MULTI_RESULTS.bits()));
}
};
;
{
if name == "CLIENT_PS_MULTI_RESULTS" {
return ::bitflags::__private::core::option::Option::Some(Self(CapabilityFlags::CLIENT_PS_MULTI_RESULTS.bits()));
}
};
;
{
if name == "CLIENT_PLUGIN_AUTH" {
return ::bitflags::__private::core::option::Option::Some(Self(CapabilityFlags::CLIENT_PLUGIN_AUTH.bits()));
}
};
;
{
if name == "CLIENT_CONNECT_ATTRS" {
return ::bitflags::__private::core::option::Option::Some(Self(CapabilityFlags::CLIENT_CONNECT_ATTRS.bits()));
}
};
;
{
if name == "CLIENT_PLUGIN_AUTH_LENENC_CLIENT_DATA" {
return ::bitflags::__private::core::option::Option::Some(Self(CapabilityFlags::CLIENT_PLUGIN_AUTH_LENENC_CLIENT_DATA.bits()));
}
};
;
{
if name == "CLIENT_CAN_HANDLE_EXPIRED_PASSWORDS" {
return ::bitflags::__private::core::option::Option::Some(Self(CapabilityFlags::CLIENT_CAN_HANDLE_EXPIRED_PASSWORDS.bits()));
}
};
;
{
if name == "CLIENT_SESSION_TRACK" {
return ::bitflags::__private::core::option::Option::Some(Self(CapabilityFlags::CLIENT_SESSION_TRACK.bits()));
}
};
;
{
if name == "CLIENT_DEPRECATE_EOF" {
return ::bitflags::__private::core::option::Option::Some(Self(CapabilityFlags::CLIENT_DEPRECATE_EOF.bits()));
}
};
;
let _ = name;
::bitflags::__private::core::option::Option::None
}
#[inline]
pub const fn is_empty(&self) -> bool {
self.0 == <u32 as ::bitflags::Bits>::EMPTY
}
#[inline]
pub const fn is_all(&self) -> bool {
Self::all().0 | self.0 == self.0
}
#[inline]
pub const fn intersects(&self, other: Self) -> bool {
self.0 & other.0 != <u32 as ::bitflags::Bits>::EMPTY
}
#[inline]
pub const fn contains(&self, other: Self) -> bool {
self.0 & other.0 == other.0
}
#[inline]
pub fn insert(&mut self, other: Self) {
*self = Self(self.0).union(other);
}
#[inline]
pub fn remove(&mut self, other: Self) {
*self = Self(self.0).difference(other);
}
#[inline]
pub fn toggle(&mut self, other: Self) {
*self = Self(self.0).symmetric_difference(other);
}
#[inline]
pub fn set(&mut self, other: Self, value: bool) {
if value { self.insert(other); } else { self.remove(other); }
}
#[inline]
#[must_use]
pub const fn intersection(self, other: Self) -> Self {
Self(self.0 & other.0)
}
#[inline]
#[must_use]
pub const fn union(self, other: Self) -> Self {
Self(self.0 | other.0)
}
#[inline]
#[must_use]
pub const fn difference(self, other: Self) -> Self {
Self(self.0 & !other.0)
}
#[inline]
#[must_use]
pub const fn symmetric_difference(self, other: Self) -> Self {
Self(self.0 ^ other.0)
}
#[inline]
#[must_use]
pub const fn complement(self) -> Self {
Self::from_bits_truncate(!self.0)
}
}
impl ::bitflags::__private::core::fmt::Binary for InternalBitFlags {
fn fmt(&self, f: &mut ::bitflags::__private::core::fmt::Formatter)
-> ::bitflags::__private::core::fmt::Result {
let inner = self.0;
::bitflags::__private::core::fmt::Binary::fmt(&inner, f)
}
}
impl ::bitflags::__private::core::fmt::Octal for InternalBitFlags {
fn fmt(&self, f: &mut ::bitflags::__private::core::fmt::Formatter)
-> ::bitflags::__private::core::fmt::Result {
let inner = self.0;
::bitflags::__private::core::fmt::Octal::fmt(&inner, f)
}
}
impl ::bitflags::__private::core::fmt::LowerHex for InternalBitFlags {
fn fmt(&self, f: &mut ::bitflags::__private::core::fmt::Formatter)
-> ::bitflags::__private::core::fmt::Result {
let inner = self.0;
::bitflags::__private::core::fmt::LowerHex::fmt(&inner, f)
}
}
impl ::bitflags::__private::core::fmt::UpperHex for InternalBitFlags {
fn fmt(&self, f: &mut ::bitflags::__private::core::fmt::Formatter)
-> ::bitflags::__private::core::fmt::Result {
let inner = self.0;
::bitflags::__private::core::fmt::UpperHex::fmt(&inner, f)
}
}
impl ::bitflags::__private::core::ops::BitOr for InternalBitFlags {
type Output = Self;
#[inline]
fn bitor(self, other: InternalBitFlags) -> Self {
self.union(other)
}
}
impl ::bitflags::__private::core::ops::BitOrAssign for
InternalBitFlags {
#[inline]
fn bitor_assign(&mut self, other: Self) { self.insert(other); }
}
impl ::bitflags::__private::core::ops::BitXor for InternalBitFlags {
type Output = Self;
#[inline]
fn bitxor(self, other: Self) -> Self {
self.symmetric_difference(other)
}
}
impl ::bitflags::__private::core::ops::BitXorAssign for
InternalBitFlags {
#[inline]
fn bitxor_assign(&mut self, other: Self) { self.toggle(other); }
}
impl ::bitflags::__private::core::ops::BitAnd for InternalBitFlags {
type Output = Self;
#[inline]
fn bitand(self, other: Self) -> Self { self.intersection(other) }
}
impl ::bitflags::__private::core::ops::BitAndAssign for
InternalBitFlags {
#[inline]
fn bitand_assign(&mut self, other: Self) {
*self =
Self::from_bits_retain(self.bits()).intersection(other);
}
}
impl ::bitflags::__private::core::ops::Sub for InternalBitFlags {
type Output = Self;
#[inline]
fn sub(self, other: Self) -> Self { self.difference(other) }
}
impl ::bitflags::__private::core::ops::SubAssign for InternalBitFlags
{
#[inline]
fn sub_assign(&mut self, other: Self) { self.remove(other); }
}
impl ::bitflags::__private::core::ops::Not for InternalBitFlags {
type Output = Self;
#[inline]
fn not(self) -> Self { self.complement() }
}
impl ::bitflags::__private::core::iter::Extend<InternalBitFlags> for
InternalBitFlags {
fn extend<T: ::bitflags::__private::core::iter::IntoIterator<Item
= Self>>(&mut self, iterator: T) {
for item in iterator { self.insert(item) }
}
}
impl ::bitflags::__private::core::iter::FromIterator<InternalBitFlags>
for InternalBitFlags {
fn from_iter<T: ::bitflags::__private::core::iter::IntoIterator<Item
= Self>>(iterator: T) -> Self {
use ::bitflags::__private::core::iter::Extend;
let mut result = Self::empty();
result.extend(iterator);
result
}
}
impl InternalBitFlags {
#[inline]
pub const fn iter(&self)
-> ::bitflags::iter::Iter<CapabilityFlags> {
::bitflags::iter::Iter::__private_const_new(<CapabilityFlags
as ::bitflags::Flags>::FLAGS,
CapabilityFlags::from_bits_retain(self.bits()),
CapabilityFlags::from_bits_retain(self.bits()))
}
#[inline]
pub const fn iter_names(&self)
-> ::bitflags::iter::IterNames<CapabilityFlags> {
::bitflags::iter::IterNames::__private_const_new(<CapabilityFlags
as ::bitflags::Flags>::FLAGS,
CapabilityFlags::from_bits_retain(self.bits()),
CapabilityFlags::from_bits_retain(self.bits()))
}
}
impl ::bitflags::__private::core::iter::IntoIterator for
InternalBitFlags {
type Item = CapabilityFlags;
type IntoIter = ::bitflags::iter::Iter<CapabilityFlags>;
fn into_iter(self) -> Self::IntoIter { self.iter() }
}
impl InternalBitFlags {
#[inline]
pub fn bits_mut(&mut self) -> &mut u32 { &mut self.0 }
}
#[allow(dead_code, deprecated, unused_attributes)]
impl CapabilityFlags {
#[inline]
pub const fn empty() -> Self { Self(InternalBitFlags::empty()) }
#[inline]
pub const fn all() -> Self { Self(InternalBitFlags::all()) }
#[inline]
pub const fn bits(&self) -> u32 { self.0.bits() }
#[inline]
pub const fn from_bits(bits: u32)
-> ::bitflags::__private::core::option::Option<Self> {
match InternalBitFlags::from_bits(bits) {
::bitflags::__private::core::option::Option::Some(bits) =>
::bitflags::__private::core::option::Option::Some(Self(bits)),
::bitflags::__private::core::option::Option::None =>
::bitflags::__private::core::option::Option::None,
}
}
#[inline]
pub const fn from_bits_truncate(bits: u32) -> Self {
Self(InternalBitFlags::from_bits_truncate(bits))
}
#[inline]
pub const fn from_bits_retain(bits: u32) -> Self {
Self(InternalBitFlags::from_bits_retain(bits))
}
#[inline]
pub fn from_name(name: &str)
-> ::bitflags::__private::core::option::Option<Self> {
match InternalBitFlags::from_name(name) {
::bitflags::__private::core::option::Option::Some(bits) =>
::bitflags::__private::core::option::Option::Some(Self(bits)),
::bitflags::__private::core::option::Option::None =>
::bitflags::__private::core::option::Option::None,
}
}
#[inline]
pub const fn is_empty(&self) -> bool { self.0.is_empty() }
#[inline]
pub const fn is_all(&self) -> bool { self.0.is_all() }
#[inline]
pub const fn intersects(&self, other: Self) -> bool {
self.0.intersects(other.0)
}
#[inline]
pub const fn contains(&self, other: Self) -> bool {
self.0.contains(other.0)
}
#[inline]
pub fn insert(&mut self, other: Self) { self.0.insert(other.0) }
#[inline]
pub fn remove(&mut self, other: Self) { self.0.remove(other.0) }
#[inline]
pub fn toggle(&mut self, other: Self) { self.0.toggle(other.0) }
#[inline]
pub fn set(&mut self, other: Self, value: bool) {
self.0.set(other.0, value)
}
#[inline]
#[must_use]
pub const fn intersection(self, other: Self) -> Self {
Self(self.0.intersection(other.0))
}
#[inline]
#[must_use]
pub const fn union(self, other: Self) -> Self {
Self(self.0.union(other.0))
}
#[inline]
#[must_use]
pub const fn difference(self, other: Self) -> Self {
Self(self.0.difference(other.0))
}
#[inline]
#[must_use]
pub const fn symmetric_difference(self, other: Self) -> Self {
Self(self.0.symmetric_difference(other.0))
}
#[inline]
#[must_use]
pub const fn complement(self) -> Self {
Self(self.0.complement())
}
}
impl ::bitflags::__private::core::fmt::Binary for CapabilityFlags {
fn fmt(&self, f: &mut ::bitflags::__private::core::fmt::Formatter)
-> ::bitflags::__private::core::fmt::Result {
let inner = self.0;
::bitflags::__private::core::fmt::Binary::fmt(&inner, f)
}
}
impl ::bitflags::__private::core::fmt::Octal for CapabilityFlags {
fn fmt(&self, f: &mut ::bitflags::__private::core::fmt::Formatter)
-> ::bitflags::__private::core::fmt::Result {
let inner = self.0;
::bitflags::__private::core::fmt::Octal::fmt(&inner, f)
}
}
impl ::bitflags::__private::core::fmt::LowerHex for CapabilityFlags {
fn fmt(&self, f: &mut ::bitflags::__private::core::fmt::Formatter)
-> ::bitflags::__private::core::fmt::Result {
let inner = self.0;
::bitflags::__private::core::fmt::LowerHex::fmt(&inner, f)
}
}
impl ::bitflags::__private::core::fmt::UpperHex for CapabilityFlags {
fn fmt(&self, f: &mut ::bitflags::__private::core::fmt::Formatter)
-> ::bitflags::__private::core::fmt::Result {
let inner = self.0;
::bitflags::__private::core::fmt::UpperHex::fmt(&inner, f)
}
}
impl ::bitflags::__private::core::ops::BitOr for CapabilityFlags {
type Output = Self;
#[inline]
fn bitor(self, other: CapabilityFlags) -> Self {
self.union(other)
}
}
impl ::bitflags::__private::core::ops::BitOrAssign for CapabilityFlags
{
#[inline]
fn bitor_assign(&mut self, other: Self) { self.insert(other); }
}
impl ::bitflags::__private::core::ops::BitXor for CapabilityFlags {
type Output = Self;
#[inline]
fn bitxor(self, other: Self) -> Self {
self.symmetric_difference(other)
}
}
impl ::bitflags::__private::core::ops::BitXorAssign for
CapabilityFlags {
#[inline]
fn bitxor_assign(&mut self, other: Self) { self.toggle(other); }
}
impl ::bitflags::__private::core::ops::BitAnd for CapabilityFlags {
type Output = Self;
#[inline]
fn bitand(self, other: Self) -> Self { self.intersection(other) }
}
impl ::bitflags::__private::core::ops::BitAndAssign for
CapabilityFlags {
#[inline]
fn bitand_assign(&mut self, other: Self) {
*self =
Self::from_bits_retain(self.bits()).intersection(other);
}
}
impl ::bitflags::__private::core::ops::Sub for CapabilityFlags {
type Output = Self;
#[inline]
fn sub(self, other: Self) -> Self { self.difference(other) }
}
impl ::bitflags::__private::core::ops::SubAssign for CapabilityFlags {
#[inline]
fn sub_assign(&mut self, other: Self) { self.remove(other); }
}
impl ::bitflags::__private::core::ops::Not for CapabilityFlags {
type Output = Self;
#[inline]
fn not(self) -> Self { self.complement() }
}
impl ::bitflags::__private::core::iter::Extend<CapabilityFlags> for
CapabilityFlags {
fn extend<T: ::bitflags::__private::core::iter::IntoIterator<Item
= Self>>(&mut self, iterator: T) {
for item in iterator { self.insert(item) }
}
}
impl ::bitflags::__private::core::iter::FromIterator<CapabilityFlags>
for CapabilityFlags {
fn from_iter<T: ::bitflags::__private::core::iter::IntoIterator<Item
= Self>>(iterator: T) -> Self {
use ::bitflags::__private::core::iter::Extend;
let mut result = Self::empty();
result.extend(iterator);
result
}
}
impl CapabilityFlags {
#[inline]
pub const fn iter(&self)
-> ::bitflags::iter::Iter<CapabilityFlags> {
::bitflags::iter::Iter::__private_const_new(<CapabilityFlags
as ::bitflags::Flags>::FLAGS,
CapabilityFlags::from_bits_retain(self.bits()),
CapabilityFlags::from_bits_retain(self.bits()))
}
#[inline]
pub const fn iter_names(&self)
-> ::bitflags::iter::IterNames<CapabilityFlags> {
::bitflags::iter::IterNames::__private_const_new(<CapabilityFlags
as ::bitflags::Flags>::FLAGS,
CapabilityFlags::from_bits_retain(self.bits()),
CapabilityFlags::from_bits_retain(self.bits()))
}
}
impl ::bitflags::__private::core::iter::IntoIterator for
CapabilityFlags {
type Item = CapabilityFlags;
type IntoIter = ::bitflags::iter::Iter<CapabilityFlags>;
fn into_iter(self) -> Self::IntoIter { self.iter() }
}
};Clone, #[automatically_derived]
impl ::core::marker::Copy for CapabilityFlags { }Copy)]
16 pub struct CapabilityFlags: u32 {
17 const CLIENT_LONG_PASSWORD = 0x00000001;
18 const CLIENT_FOUND_ROWS = 0x00000002;
19 const CLIENT_LONG_FLAG = 0x00000004;
20 const CLIENT_CONNECT_WITH_DB = 0x00000008;
21 const CLIENT_NO_SCHEMA = 0x00000010;
22 const CLIENT_COMPRESS = 0x00000020;
23 const CLIENT_ODBC = 0x00000040;
24 const CLIENT_LOCAL_FILES = 0x00000080;
25 const CLIENT_IGNORE_SPACE = 0x00000100;
26 const CLIENT_PROTOCOL_41 = 0x00000200;
27 const CLIENT_INTERACTIVE = 0x00000400;
28 const CLIENT_SSL = 0x00000800;
29 const CLIENT_IGNORE_SIGPIPE = 0x00001000;
30 const CLIENT_TRANSACTIONS = 0x00002000;
31 const CLIENT_RESERVED = 0x00004000;
32 const CLIENT_SECURE_CONNECTION = 0x00008000;
33 const CLIENT_MULTI_STATEMENTS = 0x00010000;
34 const CLIENT_MULTI_RESULTS = 0x00020000;
35 const CLIENT_PS_MULTI_RESULTS = 0x00040000;
36 const CLIENT_PLUGIN_AUTH = 0x00080000;
37 const CLIENT_CONNECT_ATTRS = 0x00100000;
38 const CLIENT_PLUGIN_AUTH_LENENC_CLIENT_DATA = 0x00200000;
39 const CLIENT_CAN_HANDLE_EXPIRED_PASSWORDS = 0x00400000;
40 const CLIENT_SESSION_TRACK = 0x00800000;
41 const CLIENT_DEPRECATE_EOF = 0x01000000;
42 }
43}
44
45pub(super) struct ConnectionOptions {
46 host: Option<CString>,
47 user: CString,
48 password: Option<CString>,
49 database: Option<CString>,
50 port: Option<u16>,
51 unix_socket: Option<CString>,
52 client_flags: CapabilityFlags,
53 ssl_mode: Option<mysql_ssl_mode>,
54 ssl_ca: Option<CString>,
55 ssl_cert: Option<CString>,
56 ssl_key: Option<CString>,
57 local_infile: Option<bool>,
58}
59
60impl ConnectionOptions {
61 pub(super) fn parse(database_url: &str) -> ConnectionResult<Self> {
62 let url = match Url::parse(database_url) {
63 Ok(url) => url,
64 Err(_) => return Err(connection_url_error()),
65 };
66
67 if url.scheme() != "mysql" {
68 return Err(connection_url_error());
69 }
70
71 if url.path_segments().map(Iterator::count).unwrap_or(0) > 1 {
72 return Err(connection_url_error());
73 }
74
75 let query_pairs = url.query_pairs().into_owned().collect::<HashMap<_, _>>();
76 if query_pairs.contains_key("database") {
77 return Err(connection_url_error());
78 }
79
80 let unix_socket = match query_pairs.get("unix_socket") {
81 Some(v) => Some(CString::new(v.as_bytes())?),
82 _ => None,
83 };
84
85 let ssl_ca = match query_pairs.get("ssl_ca") {
86 Some(v) => Some(CString::new(v.as_bytes())?),
87 _ => None,
88 };
89
90 let ssl_cert = match query_pairs.get("ssl_cert") {
91 Some(v) => Some(CString::new(v.as_bytes())?),
92 _ => None,
93 };
94
95 let ssl_key = match query_pairs.get("ssl_key") {
96 Some(v) => Some(CString::new(v.as_bytes())?),
97 _ => None,
98 };
99
100 let ssl_mode = match query_pairs.get("ssl_mode") {
101 Some(v) => {
102 let ssl_mode = match v.to_lowercase().as_str() {
103 "disabled" => mysql_ssl_mode::SSL_MODE_DISABLED,
104 "preferred" => mysql_ssl_mode::SSL_MODE_PREFERRED,
105 "required" => mysql_ssl_mode::SSL_MODE_REQUIRED,
106 "verify_ca" => mysql_ssl_mode::SSL_MODE_VERIFY_CA,
107 "verify_identity" => mysql_ssl_mode::SSL_MODE_VERIFY_IDENTITY,
108 _ => {
109 let msg = "unknown ssl_mode";
110 return Err(ConnectionError::InvalidConnectionUrl(msg.into()));
111 }
112 };
113 Some(ssl_mode)
114 }
115 _ => None,
116 };
117
118 let local_infile = match query_pairs.get("local_infile") {
119 Some(v) => match v.parse() {
120 Ok(v) => Some(v),
121 Err(_) => {
122 let msg = "unknown local_infile";
123 return Err(ConnectionError::InvalidConnectionUrl(msg.into()));
124 }
125 },
126 None => None,
127 };
128
129 let host = match url.host() {
130 Some(Host::Ipv6(host)) => Some(CString::new(host.to_string())?),
131 Some(host) if host.to_string() == "localhost" && unix_socket.is_some() => None,
132 Some(host) => Some(CString::new(host.to_string())?),
133 None => None,
134 };
135 let user = decode_into_cstring(url.username())?;
136 let password = match url.password() {
137 Some(password) => Some(decode_into_cstring(password)?),
138 None => None,
139 };
140
141 let database = match url.path_segments().and_then(|mut iter| iter.next()) {
142 Some("") | None => None,
143 Some(segment) => Some(CString::new(segment.as_bytes())?),
144 };
145
146 let client_flags = CapabilityFlags::CLIENT_FOUND_ROWS;
148
149 Ok(ConnectionOptions {
150 host,
151 user,
152 password,
153 database,
154 port: url.port(),
155 client_flags,
156 ssl_mode,
157 unix_socket,
158 ssl_ca,
159 ssl_cert,
160 ssl_key,
161 local_infile,
162 })
163 }
164
165 pub(super) fn host(&self) -> Option<&CStr> {
166 self.host.as_deref()
167 }
168
169 pub(super) fn user(&self) -> &CStr {
170 &self.user
171 }
172
173 pub(super) fn password(&self) -> Option<&CStr> {
174 self.password.as_deref()
175 }
176
177 pub(super) fn database(&self) -> Option<&CStr> {
178 self.database.as_deref()
179 }
180
181 pub(super) fn port(&self) -> Option<u16> {
182 self.port
183 }
184
185 pub(super) fn unix_socket(&self) -> Option<&CStr> {
186 self.unix_socket.as_deref()
187 }
188
189 pub(super) fn ssl_ca(&self) -> Option<&CStr> {
190 self.ssl_ca.as_deref()
191 }
192
193 pub(super) fn ssl_cert(&self) -> Option<&CStr> {
194 self.ssl_cert.as_deref()
195 }
196
197 pub(super) fn ssl_key(&self) -> Option<&CStr> {
198 self.ssl_key.as_deref()
199 }
200
201 pub(super) fn client_flags(&self) -> CapabilityFlags {
202 self.client_flags
203 }
204
205 pub(super) fn ssl_mode(&self) -> Option<mysql_ssl_mode> {
206 self.ssl_mode
207 }
208
209 pub(super) fn local_infile(&self) -> Option<bool> {
210 self.local_infile
211 }
212}
213
214fn decode_into_cstring(s: &str) -> ConnectionResult<CString> {
215 let decoded = percent_decode(s.as_bytes())
216 .decode_utf8()
217 .map_err(|_| connection_url_error())?;
218 CString::new(decoded.as_bytes()).map_err(Into::into)
219}
220
221fn connection_url_error() -> ConnectionError {
222 let msg = "MySQL connection URLs must be in the form \
223 `mysql://[[user]:[password]@]host[:port][/database][?unix_socket=socket-path]`";
224 ConnectionError::InvalidConnectionUrl(msg.into())
225}
226
227#[cfg(test)]
228mod tests {
229 use super::*;
230
231 #[diesel_test_helper::test]
232 fn urls_with_schemes_other_than_mysql_are_errors() {
233 assert!(ConnectionOptions::parse("postgres://localhost").is_err());
234 assert!(ConnectionOptions::parse("http://localhost").is_err());
235 assert!(ConnectionOptions::parse("file:///tmp/mysql.sock").is_err());
236 assert!(ConnectionOptions::parse("socket:///tmp/mysql.sock").is_err());
237 assert!(ConnectionOptions::parse("mysql://localhost?database=somedb").is_err());
238 assert!(ConnectionOptions::parse("mysql://localhost").is_ok());
239 }
240
241 #[diesel_test_helper::test]
242 fn urls_must_have_zero_or_one_path_segments() {
243 assert!(ConnectionOptions::parse("mysql://localhost/foo/bar").is_err());
244 assert!(ConnectionOptions::parse("mysql://localhost/foo").is_ok());
245 }
246
247 #[diesel_test_helper::test]
248 fn first_path_segment_is_treated_as_database() {
249 let foo_cstr = CString::new("foo").unwrap();
250 let bar_cstr = CString::new("bar").unwrap();
251 assert_eq!(
252 Some(&*foo_cstr),
253 ConnectionOptions::parse("mysql://localhost/foo")
254 .unwrap()
255 .database()
256 );
257 assert_eq!(
258 Some(&*bar_cstr),
259 ConnectionOptions::parse("mysql://localhost/bar")
260 .unwrap()
261 .database()
262 );
263 assert_eq!(
264 None,
265 ConnectionOptions::parse("mysql://localhost")
266 .unwrap()
267 .database()
268 );
269 }
270
271 #[diesel_test_helper::test]
272 fn userinfo_should_be_percent_decode() {
273 use self::percent_encoding::{AsciiSet, CONTROLS, utf8_percent_encode};
274 const USERINFO_ENCODE_SET: &AsciiSet = &CONTROLS
275 .add(b' ')
276 .add(b'"')
277 .add(b'<')
278 .add(b'>')
279 .add(b'`')
280 .add(b'#')
281 .add(b'?')
282 .add(b'{')
283 .add(b'}')
284 .add(b'/')
285 .add(b':')
286 .add(b';')
287 .add(b'=')
288 .add(b'@')
289 .add(b'[')
290 .add(b'\\')
291 .add(b']')
292 .add(b'^')
293 .add(b'|');
294
295 let username = "x#gfuL?4Zuj{n73m}eeJt0";
296 let encoded_username = utf8_percent_encode(username, USERINFO_ENCODE_SET);
297
298 let password = "x/gfuL?4Zuj{n73m}eeJt1";
299 let encoded_password = utf8_percent_encode(password, USERINFO_ENCODE_SET);
300
301 let db_url = format!("mysql://{encoded_username}:{encoded_password}@localhost/bar",);
302 let db_url = Url::parse(&db_url).unwrap();
303
304 let conn_opts = ConnectionOptions::parse(db_url.as_str()).unwrap();
305 let username = CString::new(username.as_bytes()).unwrap();
306 let password = CString::new(password.as_bytes()).unwrap();
307 assert_eq!(username, conn_opts.user);
308 assert_eq!(password, conn_opts.password.unwrap());
309 }
310
311 #[diesel_test_helper::test]
312 fn ipv6_host_not_wrapped_in_brackets() {
313 let host1 = CString::new("::1").unwrap();
314 let host2 = CString::new("2001:db8:85a3::8a2e:370:7334").unwrap();
315
316 assert_eq!(
317 Some(&*host1),
318 ConnectionOptions::parse("mysql://[::1]").unwrap().host()
319 );
320 assert_eq!(
321 Some(&*host2),
322 ConnectionOptions::parse("mysql://[2001:db8:85a3::8a2e:370:7334]")
323 .unwrap()
324 .host()
325 );
326 }
327
328 #[diesel_test_helper::test]
329 fn unix_socket_tests() {
330 let unix_socket = "/var/run/mysqld.sock";
331 let username = "foo";
332 let password = "bar";
333 let db_url = format!("mysql://{username}:{password}@localhost?unix_socket={unix_socket}",);
334 let conn_opts = ConnectionOptions::parse(db_url.as_str()).unwrap();
335 let cstring = |s| CString::new(s).unwrap();
336 assert_eq!(None, conn_opts.host);
337 assert_eq!(None, conn_opts.port);
338 assert_eq!(cstring(username), conn_opts.user);
339 assert_eq!(cstring(password), conn_opts.password.unwrap());
340 assert_eq!(
341 CString::new(unix_socket).unwrap(),
342 conn_opts.unix_socket.unwrap()
343 );
344 }
345
346 #[diesel_test_helper::test]
347 fn ssl_ca_tests() {
348 let ssl_ca = "/etc/ssl/certs/ca-certificates.crt";
349 let username = "foo";
350 let password = "bar";
351 let db_url = format!("mysql://{username}:{password}@localhost?ssl_ca={ssl_ca}",);
352 let conn_opts = ConnectionOptions::parse(db_url.as_str()).unwrap();
353 let cstring = |s| CString::new(s).unwrap();
354 assert_eq!(Some(cstring("localhost")), conn_opts.host);
355 assert_eq!(None, conn_opts.port);
356 assert_eq!(cstring(username), conn_opts.user);
357 assert_eq!(cstring(password), conn_opts.password.unwrap());
358 assert_eq!(CString::new(ssl_ca).unwrap(), conn_opts.ssl_ca.unwrap());
359
360 let url_with_unix_str_and_ssl_ca = format!(
361 "mysql://{username}:{password}@localhost?unix_socket=/var/run/mysqld.sock&ssl_ca={ssl_ca}"
362 );
363
364 let conn_opts2 = ConnectionOptions::parse(url_with_unix_str_and_ssl_ca.as_str()).unwrap();
365 assert_eq!(None, conn_opts2.host);
366 assert_eq!(None, conn_opts2.port);
367 assert_eq!(CString::new(ssl_ca).unwrap(), conn_opts2.ssl_ca.unwrap());
368 }
369
370 #[diesel_test_helper::test]
371 fn ssl_cert_tests() {
372 let ssl_cert = "/etc/ssl/certs/client-cert.crt";
373 let username = "foo";
374 let password = "bar";
375 let db_url = format!("mysql://{username}:{password}@localhost?ssl_cert={ssl_cert}");
376 let conn_opts = ConnectionOptions::parse(db_url.as_str()).unwrap();
377 let cstring = |s| CString::new(s).unwrap();
378 assert_eq!(Some(cstring("localhost")), conn_opts.host);
379 assert_eq!(None, conn_opts.port);
380 assert_eq!(cstring(username), conn_opts.user);
381 assert_eq!(cstring(password), conn_opts.password.unwrap());
382 assert_eq!(CString::new(ssl_cert).unwrap(), conn_opts.ssl_cert.unwrap());
383
384 let url_with_unix_str_and_ssl_cert = format!(
385 "mysql://{username}:{password}@localhost?unix_socket=/var/run/mysqld.sock&ssl_cert={ssl_cert}"
386 );
387
388 let conn_opts2 = ConnectionOptions::parse(url_with_unix_str_and_ssl_cert.as_str()).unwrap();
389 assert_eq!(None, conn_opts2.host);
390 assert_eq!(None, conn_opts2.port);
391 assert_eq!(
392 CString::new(ssl_cert).unwrap(),
393 conn_opts2.ssl_cert.unwrap()
394 );
395 }
396
397 #[diesel_test_helper::test]
398 fn ssl_key_tests() {
399 let ssl_key = "/etc/ssl/certs/client-key.crt";
400 let username = "foo";
401 let password = "bar";
402 let db_url = format!("mysql://{username}:{password}@localhost?ssl_key={ssl_key}");
403 let conn_opts = ConnectionOptions::parse(db_url.as_str()).unwrap();
404 let cstring = |s| CString::new(s).unwrap();
405 assert_eq!(Some(cstring("localhost")), conn_opts.host);
406 assert_eq!(None, conn_opts.port);
407 assert_eq!(cstring(username), conn_opts.user);
408 assert_eq!(cstring(password), conn_opts.password.unwrap());
409 assert_eq!(CString::new(ssl_key).unwrap(), conn_opts.ssl_key.unwrap());
410
411 let url_with_unix_str_and_ssl_key = format!(
412 "mysql://{username}:{password}@localhost?unix_socket=/var/run/mysqld.sock&ssl_key={ssl_key}"
413 );
414
415 let conn_opts2 = ConnectionOptions::parse(url_with_unix_str_and_ssl_key.as_str()).unwrap();
416 assert_eq!(None, conn_opts2.host);
417 assert_eq!(None, conn_opts2.port);
418 assert_eq!(CString::new(ssl_key).unwrap(), conn_opts2.ssl_key.unwrap());
419 }
420
421 #[diesel_test_helper::test]
422 fn ssl_mode() {
423 let ssl_mode = |url| ConnectionOptions::parse(url).unwrap().ssl_mode();
424 assert_eq!(ssl_mode("mysql://localhost"), None);
425 assert_eq!(
426 ssl_mode("mysql://localhost?ssl_mode=disabled"),
427 Some(mysql_ssl_mode::SSL_MODE_DISABLED)
428 );
429 assert_eq!(
430 ssl_mode("mysql://localhost?ssl_mode=PREFERRED"),
431 Some(mysql_ssl_mode::SSL_MODE_PREFERRED)
432 );
433 assert_eq!(
434 ssl_mode("mysql://localhost?ssl_mode=required"),
435 Some(mysql_ssl_mode::SSL_MODE_REQUIRED)
436 );
437 assert_eq!(
438 ssl_mode("mysql://localhost?ssl_mode=VERIFY_CA"),
439 Some(mysql_ssl_mode::SSL_MODE_VERIFY_CA)
440 );
441 assert_eq!(
442 ssl_mode("mysql://localhost?ssl_mode=verify_identity"),
443 Some(mysql_ssl_mode::SSL_MODE_VERIFY_IDENTITY)
444 );
445 }
446
447 #[diesel_test_helper::test]
448 fn local_infile() {
449 let url = |url| ConnectionOptions::parse(url).map(|v| v.local_infile());
450 assert_eq!(url("mysql://localhost"), Ok(None));
451 assert_eq!(url("mysql://localhost?local_infile=true"), Ok(Some(true)));
452 assert_eq!(url("mysql://localhost?local_infile=false"), Ok(Some(false)));
453 url("mysql://localhost?local_infile=1").unwrap_err();
454 }
455}