sqlx_mysql/protocol/connect/
handshake_response.rs

1use crate::io::MySqlBufMutExt;
2use crate::io::{BufMutExt, ProtocolEncode};
3use crate::protocol::auth::AuthPlugin;
4use crate::protocol::connect::ssl_request::SslRequest;
5use crate::protocol::Capabilities;
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 ProtocolEncode<'_, Capabilities> for HandshakeResponse<'_> {
31    fn encode_with(
32        &self,
33        buf: &mut Vec<u8>,
34        mut context: Capabilities,
35    ) -> Result<(), crate::Error> {
36        if self.auth_plugin.is_none() {
37            // ensure PLUGIN_AUTH is set *only* if we have a defined plugin
38            context.remove(Capabilities::PLUGIN_AUTH);
39        }
40
41        // NOTE: Half of this packet is identical to the SSL Request packet
42        SslRequest {
43            max_packet_size: self.max_packet_size,
44            collation: self.collation,
45        }
46        .encode_with(buf, context)?;
47
48        buf.put_str_nul(self.username);
49
50        if context.contains(Capabilities::PLUGIN_AUTH_LENENC_DATA) {
51            buf.put_bytes_lenenc(self.auth_response.unwrap_or_default());
52        } else if context.contains(Capabilities::SECURE_CONNECTION) {
53            let response = self.auth_response.unwrap_or_default();
54
55            let response_len = u8::try_from(response.len())
56                .map_err(|_| err_protocol!("auth_response.len() too long: {}", response.len()))?;
57
58            buf.push(response_len);
59            buf.extend(response);
60        } else {
61            buf.push(0);
62        }
63
64        if context.contains(Capabilities::CONNECT_WITH_DB) {
65            if let Some(database) = &self.database {
66                buf.put_str_nul(database);
67            } else {
68                buf.push(0);
69            }
70        }
71
72        if context.contains(Capabilities::PLUGIN_AUTH) {
73            if let Some(plugin) = &self.auth_plugin {
74                buf.put_str_nul(plugin.name());
75            } else {
76                buf.push(0);
77            }
78        }
79
80        Ok(())
81    }
82}