docs: handshake documentation
This commit is contained in:
parent
eb8410718d
commit
c61b6021db
5 changed files with 28 additions and 3 deletions
|
|
@ -7,15 +7,20 @@ use crate::reader::backend::BackendProtoReader;
|
|||
use crate::writer::frontend::FrontendProtoWriter;
|
||||
use crate::writer::protowriter::ProtoFlush;
|
||||
|
||||
/// Performs client-side handshake with the server until the `ReadyForQuery` message is received.
|
||||
/// For more info visit the [`55.2.1. Start-up`](https://www.postgresql.org/docs/current/protocol-flow.html#PROTOCOL-FLOW-START-UP)
|
||||
pub async fn do_client_handshake(
|
||||
writer: &mut (impl FrontendProtoWriter + ProtoFlush),
|
||||
reader: &mut impl BackendProtoReader,
|
||||
request: HandshakeRequest,
|
||||
) -> Result<HandshakeResponse, ClientHandshakeError> {
|
||||
|
||||
// Send StartupMessage without SSLRequest
|
||||
let startup_message: StartupMessageData = request.into();
|
||||
writer.write_startup_message(startup_message).await?;
|
||||
writer.flush().await?;
|
||||
|
||||
// Wait for AuthenticationOk
|
||||
let auth = reader.read_proto().await?;
|
||||
if !matches!(
|
||||
auth,
|
||||
|
|
@ -24,6 +29,7 @@ pub async fn do_client_handshake(
|
|||
return Err(ClientHandshakeError::UnexpectedAuthResponse(auth));
|
||||
}
|
||||
|
||||
// Read server parameter messages until ReadyForQuery is received
|
||||
let mut messages = Vec::new();
|
||||
loop {
|
||||
let msg = reader.read_proto().await?;
|
||||
|
|
|
|||
|
|
@ -3,11 +3,14 @@ use crate::message::special::StartupMessageData;
|
|||
|
||||
#[derive(Debug)]
|
||||
pub struct HandshakeRequest {
|
||||
version: i32,
|
||||
parameters: Vec<(PgString, PgString)>,
|
||||
pub version: i32,
|
||||
pub parameters: Vec<(PgString, PgString)>,
|
||||
}
|
||||
|
||||
impl HandshakeRequest {
|
||||
|
||||
/// Creates a new `HandshakeRequest` with the specified version.
|
||||
/// Expected `version` is 196608 (3.0).
|
||||
pub fn new(version: i32) -> Self {
|
||||
Self {
|
||||
version,
|
||||
|
|
@ -15,6 +18,9 @@ impl HandshakeRequest {
|
|||
}
|
||||
}
|
||||
|
||||
/// Adds a parameter to the startup message.
|
||||
/// Generally recognized names are `user`, `database`, `option` and `replication` but others can be used.
|
||||
/// For more info visit [`StartupMessage`](https://www.postgresql.org/docs/current/protocol-message-formats.html#PROTOCOL-MESSAGE-FORMATS-STARTUPMESSAGE)
|
||||
pub fn parameter(mut self, key: &str, value: &str) -> Self {
|
||||
self.parameters.push((key.into(), value.into()));
|
||||
self
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ pub struct HandshakeResponse {
|
|||
impl HandshakeResponse {
|
||||
pub fn new(name: &str, pid: i32, key: i32) -> Self {
|
||||
Self {
|
||||
version: format!("16.0 ({name})", name = name),
|
||||
version: format!("16.0 ({name})"),
|
||||
process_id: pid,
|
||||
secret_key: key,
|
||||
}
|
||||
|
|
@ -37,6 +37,7 @@ impl TryFrom<&[BackendMessage]> for HandshakeResponse {
|
|||
process_id = Some(data.process);
|
||||
secret_key = Some(data.secret);
|
||||
}
|
||||
// Different messages are ignored during the handshake
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,11 +7,15 @@ use crate::reader::frontend::FrontendProtoReader;
|
|||
use crate::writer::backend::BackendProtoWriter;
|
||||
use crate::writer::protowriter::ProtoFlush;
|
||||
|
||||
/// Performs server-side handshake with the client until ending it with `ReadyForQuery` message.
|
||||
/// For more info visit the [`55.2.1. Start-up`](https://www.postgresql.org/docs/current/protocol-flow.html#PROTOCOL-FLOW-START-UP)
|
||||
pub async fn do_server_handshake(
|
||||
writer: &mut (impl BackendProtoWriter + ProtoFlush),
|
||||
reader: &mut impl FrontendProtoReader,
|
||||
response: HandshakeResponse,
|
||||
) -> Result<HandshakeRequest, ServerHandshakeError> {
|
||||
|
||||
// Check if client requested SSL
|
||||
match &reader.peek_special_message().await? {
|
||||
Some(msg @ SpecialMessage::SSLRequest) => {
|
||||
reader.consume_special_message(msg).await?;
|
||||
|
|
@ -23,6 +27,7 @@ pub async fn do_server_handshake(
|
|||
}
|
||||
}
|
||||
|
||||
// Wait for mandatory StartupMessage
|
||||
let startup_message = match &reader.peek_special_message().await? {
|
||||
Some(msg @ SpecialMessage::StartupMessage(data)) => {
|
||||
reader.consume_special_message(msg).await?;
|
||||
|
|
@ -33,15 +38,18 @@ pub async fn do_server_handshake(
|
|||
}
|
||||
};
|
||||
|
||||
// Authenticate client
|
||||
writer
|
||||
.write_proto(BackendMessage::from(AuthenticationOkData { status: 0 }))
|
||||
.await?;
|
||||
|
||||
// Send server parameters
|
||||
let messages: Vec<BackendMessage> = response.into();
|
||||
for message in messages {
|
||||
writer.write_proto(message).await?;
|
||||
}
|
||||
|
||||
// Finish the handshake
|
||||
writer
|
||||
.write_proto(BackendMessage::from(ReadyForQueryData { status: b'I' }))
|
||||
.await?;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue