rbdc_mysql/protocol/connect/
handshake_response.rs

1use crate::io::MySqlBufMutExt;
2use crate::protocol::auth::AuthPlugin;
3use crate::protocol::connect::ssl_request::SslRequest;
4use crate::protocol::Capabilities;
5use rbdc::io::{BufMutExt, Encode};
6
7// https://dev.mysql.com/doc/internals/en/connection-phase-packets.html#packet-Protocol::HandshakeResponse
8// https://mariadb.com/kb/en/connection/#client-handshake-response
9
10#[derive(Debug)]
11pub struct HandshakeResponse<'a> {
12    pub database: Option<&'a str>,
13
14    /// Max size of a command packet that the client wants to send to the server
15    pub max_packet_size: u32,
16
17    /// Default collation for the connection
18    pub collation: u8,
19
20    /// Name of the SQL account which client wants to log in
21    pub username: &'a str,
22
23    /// Authentication method used by the client
24    pub auth_plugin: Option<AuthPlugin>,
25
26    /// Opaque authentication response
27    pub auth_response: Option<&'a [u8]>,
28}
29
30impl Encode<'_, Capabilities> for HandshakeResponse<'_> {
31    fn encode_with(&self, buf: &mut Vec<u8>, mut capabilities: Capabilities) {
32        if self.auth_plugin.is_none() {
33            // ensure PLUGIN_AUTH is set *only* if we have a defined plugin
34            capabilities.remove(Capabilities::PLUGIN_AUTH);
35        }
36
37        // NOTE: Half of this packet is identical to the SSL Request packet
38        SslRequest {
39            max_packet_size: self.max_packet_size,
40            collation: self.collation,
41        }
42        .encode_with(buf, capabilities);
43
44        buf.put_str_nul(self.username);
45
46        if capabilities.contains(Capabilities::PLUGIN_AUTH_LENENC_DATA) {
47            buf.put_bytes_lenenc(self.auth_response.unwrap_or_default().to_owned());
48        } else if capabilities.contains(Capabilities::SECURE_CONNECTION) {
49            let response = self.auth_response.unwrap_or_default();
50
51            buf.push(response.len() as u8);
52            buf.extend(response);
53        } else {
54            buf.push(0);
55        }
56
57        if capabilities.contains(Capabilities::CONNECT_WITH_DB) {
58            if let Some(database) = &self.database {
59                buf.put_str_nul(database);
60            } else {
61                buf.push(0);
62            }
63        }
64
65        if capabilities.contains(Capabilities::PLUGIN_AUTH) {
66            if let Some(plugin) = &self.auth_plugin {
67                buf.put_str_nul(plugin.name());
68            } else {
69                buf.push(0);
70            }
71        }
72    }
73}