1use std::{
4 collections::BTreeMap,
5 convert::Infallible,
6 fmt,
7 future::Future,
8 io,
9 pin::Pin,
10 sync::Arc,
11 task::{Context, Poll},
12};
13
14use bytes::Bytes;
15use tokio::io::ReadBuf;
16use tokio::io::{AsyncRead, AsyncReadExt as _, AsyncWrite, AsyncWriteExt as _};
17
18use crate::ClientMiddleware as _;
19use crate::{
20 Conn, Pristine,
21 auth::{AuthEvent, AuthOffer, Ready},
22 codec::{Backend, FrontendMessage},
23 demux::SessionItem,
24 session::{ReadyState, SimpleTransition},
25 startup::{ProtocolVersion, StartupMessage},
26 transport::Buffered,
27};
28
29#[derive(Clone, Copy, Debug, Eq, PartialEq)]
31pub enum BuildError {
32 MissingConnector,
34 MissingTls,
36 MissingAuthentication,
38}
39
40impl fmt::Display for BuildError {
41 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
42 formatter.write_str(match self {
43 Self::MissingConnector => "client connector is required",
44 Self::MissingTls => "an explicit client TLS policy is required",
45 Self::MissingAuthentication => "an explicit client authentication policy is required",
46 })
47 }
48}
49
50impl std::error::Error for BuildError {}
51
52#[derive(Clone, Copy, Debug, Eq, PartialEq)]
54pub enum ClientTlsPolicy {
55 Disabled,
57}
58
59impl ClientTlsPolicy {
60 #[must_use]
62 pub fn libpq<Provider>(
63 mode: crate::pre_startup::SslMode,
64 provider: Provider,
65 ) -> ReloadableClientTls<Provider> {
66 ReloadableClientTls { mode, provider }
67 }
68}
69
70#[derive(Clone)]
72pub struct ReloadableClientTls<Provider> {
73 mode: crate::pre_startup::SslMode,
74 provider: Provider,
75}
76
77impl<Provider> fmt::Debug for ReloadableClientTls<Provider> {
78 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
79 formatter
80 .debug_struct("Libpq")
81 .field("mode", &self.mode)
82 .field("provider", &"<redacted>")
83 .finish()
84 }
85}
86
87pub trait ClientTlsConfiguration {
89 type Provider: ClientTlsProvider;
91
92 fn configured(&self) -> Option<(crate::pre_startup::SslMode, &Self::Provider)>;
94}
95
96impl ClientTlsConfiguration for ClientTlsPolicy {
97 type Provider = ();
98
99 fn configured(&self) -> Option<(crate::pre_startup::SslMode, &Self::Provider)> {
100 None
101 }
102}
103
104impl<Provider: ClientTlsProvider> ClientTlsConfiguration for ReloadableClientTls<Provider> {
105 type Provider = Provider;
106
107 fn configured(&self) -> Option<(crate::pre_startup::SslMode, &Self::Provider)> {
108 Some((self.mode, &self.provider))
109 }
110}
111
112#[derive(Clone)]
119pub struct ClientTlsConfig {
120 server_name: rustls::pki_types::ServerName<'static>,
121 roots: rustls::RootCertStore,
122}
123
124impl ClientTlsConfig {
125 #[must_use]
127 pub fn new(
128 server_name: rustls::pki_types::ServerName<'static>,
129 roots: rustls::RootCertStore,
130 ) -> Self {
131 Self { server_name, roots }
132 }
133}
134
135impl fmt::Debug for ClientTlsConfig {
136 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
137 formatter.write_str("ClientTlsConfig(<redacted>)")
138 }
139}
140
141#[allow(async_fn_in_trait)]
145pub trait ClientTlsProvider {
146 type Error;
148
149 async fn resolve(&self, target: &ConnectTarget) -> Result<ClientTlsConfig, Self::Error>;
151}
152
153#[derive(Debug)]
155pub enum ClientTlsError<ProviderError> {
156 Provider(ProviderError),
158 Handshake(io::Error),
160}
161
162impl<ProviderError: fmt::Display> fmt::Display for ClientTlsError<ProviderError> {
163 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
164 match self {
165 Self::Provider(error) => error.fmt(formatter),
166 Self::Handshake(error) => error.fmt(formatter),
167 }
168 }
169}
170
171impl<ProviderError: std::error::Error + 'static> std::error::Error
172 for ClientTlsError<ProviderError>
173{
174 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
175 match self {
176 Self::Provider(error) => Some(error),
177 Self::Handshake(error) => Some(error),
178 }
179 }
180}
181
182impl ClientTlsProvider for () {
183 type Error = Infallible;
184
185 async fn resolve(&self, _target: &ConnectTarget) -> Result<ClientTlsConfig, Self::Error> {
186 unreachable!("disabled TLS never resolves a provider")
187 }
188}
189
190#[derive(Debug)]
192pub enum ClientTransport<Transport> {
193 Plain(Transport),
195 Tls(Box<crate::tls::ClientTls<Transport>>),
197}
198
199impl<Transport: AsyncRead + AsyncWrite + Unpin> AsyncRead for ClientTransport<Transport> {
200 fn poll_read(
201 mut self: Pin<&mut Self>,
202 cx: &mut Context<'_>,
203 buffer: &mut ReadBuf<'_>,
204 ) -> Poll<io::Result<()>> {
205 match &mut *self {
206 Self::Plain(stream) => Pin::new(stream).poll_read(cx, buffer),
207 Self::Tls(stream) => Pin::new(stream).poll_read(cx, buffer),
208 }
209 }
210}
211
212impl<Transport: AsyncRead + AsyncWrite + Unpin> AsyncWrite for ClientTransport<Transport> {
213 fn poll_write(
214 mut self: Pin<&mut Self>,
215 cx: &mut Context<'_>,
216 buffer: &[u8],
217 ) -> Poll<io::Result<usize>> {
218 match &mut *self {
219 Self::Plain(stream) => Pin::new(stream).poll_write(cx, buffer),
220 Self::Tls(stream) => Pin::new(stream).poll_write(cx, buffer),
221 }
222 }
223
224 fn poll_flush(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
225 match &mut *self {
226 Self::Plain(stream) => Pin::new(stream).poll_flush(cx),
227 Self::Tls(stream) => Pin::new(stream).poll_flush(cx),
228 }
229 }
230
231 fn poll_shutdown(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
232 match &mut *self {
233 Self::Plain(stream) => Pin::new(stream).poll_shutdown(cx),
234 Self::Tls(stream) => Pin::new(stream).poll_shutdown(cx),
235 }
236 }
237}
238
239async fn negotiate_client_tls<Transport, Provider, State, Handler, Evidence>(
240 mut transport: Transport,
241 mode: crate::pre_startup::SslMode,
242 provider: &Provider,
243 target: &ConnectTarget,
244 context: &mut ClientConnectionContext<Evidence>,
245 state: &mut State,
246 handler: &mut Handler,
247) -> Result<ClientTransport<Transport>, ClientTlsError<Provider::Error>>
248where
249 Transport: AsyncRead + AsyncWrite + Unpin,
250 Provider: ClientTlsProvider,
251 Handler: crate::ClientMiddleware<State, ClientConnectionContext<Evidence>>,
252{
253 if !mode.strategy().request_on_first_connection {
254 context.tls = Some(ClientTlsStatus::Plaintext);
255 return Ok(ClientTransport::Plain(transport));
256 }
257 let request = handler.pre_startup(
258 context,
259 state,
260 crate::pre_startup::PreStartupMessage::SslRequest,
261 );
262 let crate::pre_startup::PreStartupMessage::SslRequest = request else {
263 return Err(ClientTlsError::Handshake(io::Error::new(
264 io::ErrorKind::InvalidData,
265 "middleware replaced SSLRequest with an incompatible packet",
266 )));
267 };
268 transport
269 .write_all(&[0, 0, 0, 8, 4, 210, 22, 47])
270 .await
271 .map_err(ClientTlsError::Handshake)?;
272 transport.flush().await.map_err(ClientTlsError::Handshake)?;
273 match transport
274 .read_u8()
275 .await
276 .map_err(ClientTlsError::Handshake)?
277 {
278 b'S' => {
279 let resolved = provider
280 .resolve(target)
281 .await
282 .map_err(ClientTlsError::Provider)?;
283 let config = Arc::new(crate::tls::client_config(mode, resolved.roots));
284 let stream = crate::tls::connect(transport, resolved.server_name, config)
285 .await
286 .map_err(ClientTlsError::Handshake)?;
287 context.tls = Some(ClientTlsStatus::Encrypted);
288 Ok(ClientTransport::Tls(Box::new(stream)))
289 }
290 b'N' if mode.strategy().allow_server_rejection => {
291 context.tls = Some(ClientTlsStatus::Plaintext);
292 Ok(ClientTransport::Plain(transport))
293 }
294 b'N' => Err(ClientTlsError::Handshake(io::Error::new(
295 io::ErrorKind::PermissionDenied,
296 "server rejected required TLS",
297 ))),
298 b'E' => Err(ClientTlsError::Handshake(io::Error::new(
299 io::ErrorKind::ConnectionAborted,
300 "server terminated TLS negotiation",
301 ))),
302 _ => Err(ClientTlsError::Handshake(io::Error::new(
303 io::ErrorKind::InvalidData,
304 "invalid TLS negotiation response",
305 ))),
306 }
307}
308
309#[derive(Clone, Copy, Default, Eq, PartialEq)]
311pub struct TrustClientAuthentication;
312
313#[derive(Clone, Debug, Eq, PartialEq)]
315#[non_exhaustive]
316pub enum ClientAuthenticationChallenge {
317 CleartextPassword,
319 Md5Password([u8; 4]),
321 Sasl(Vec<Bytes>),
323 SaslContinue(Bytes),
325 SaslFinal(Bytes),
327 Gss,
329 Sspi,
331 KerberosV5,
333 TokenContinue(Bytes),
335}
336
337#[derive(Clone, Debug, Eq, PartialEq)]
339#[non_exhaustive]
340pub enum ClientAuthenticationResponse {
341 Password(Bytes),
343 SaslInitial {
345 mechanism: Bytes,
347 response: Bytes,
349 },
350 Sasl(Bytes),
352 Token(Bytes),
354 Verified,
356}
357
358#[allow(async_fn_in_trait)]
362pub trait ClientAuthentication {
363 type Evidence;
365 type Session: ClientAuthenticationSession<Evidence = Self::Evidence, Error = Self::Error>;
367 type Error;
369
370 async fn begin(&self, target: &ConnectTarget) -> Result<Self::Session, Self::Error>;
372}
373
374#[allow(async_fn_in_trait)]
378pub trait ClientAuthenticationSession {
379 type Evidence;
381 type Error;
383
384 async fn respond(
386 &mut self,
387 challenge: ClientAuthenticationChallenge,
388 ) -> Result<ClientAuthenticationResponse, Self::Error>;
389
390 async fn authenticated(self) -> Result<Self::Evidence, Self::Error>;
392}
393
394#[derive(Debug)]
396pub enum ClientAuthenticationError<PolicyError> {
397 Policy(PolicyError),
399 Rejected,
401 InvalidResponse,
403}
404
405impl<PolicyError: fmt::Display> fmt::Display for ClientAuthenticationError<PolicyError> {
406 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
407 match self {
408 Self::Policy(error) => error.fmt(formatter),
409 Self::Rejected => formatter.write_str("server rejected authentication"),
410 Self::InvalidResponse => {
411 formatter.write_str("authentication policy rejected the credential challenge")
412 }
413 }
414 }
415}
416
417impl<PolicyError: std::error::Error + 'static> std::error::Error
418 for ClientAuthenticationError<PolicyError>
419{
420 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
421 match self {
422 Self::Policy(error) => Some(error),
423 Self::Rejected | Self::InvalidResponse => None,
424 }
425 }
426}
427
428enum AuthenticationDriveError<PolicyError> {
429 Policy(PolicyError),
430 Rejected,
431 InvalidResponse,
432 Protocol(io::Error),
433}
434
435impl ClientAuthentication for TrustClientAuthentication {
436 type Evidence = ();
437 type Session = Self;
438 type Error = Infallible;
439
440 async fn begin(&self, _target: &ConnectTarget) -> Result<Self::Session, Self::Error> {
441 Ok(Self)
442 }
443}
444
445impl ClientAuthenticationSession for TrustClientAuthentication {
446 type Evidence = ();
447 type Error = Infallible;
448
449 async fn respond(
450 &mut self,
451 _challenge: ClientAuthenticationChallenge,
452 ) -> Result<ClientAuthenticationResponse, Self::Error> {
453 Ok(ClientAuthenticationResponse::Verified)
454 }
455
456 async fn authenticated(self) -> Result<Self::Evidence, Self::Error> {
457 Ok(())
458 }
459}
460
461impl fmt::Debug for TrustClientAuthentication {
462 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
463 formatter.write_str("Trust")
464 }
465}
466
467#[derive(Clone, Eq, PartialEq)]
469pub struct ConnectTarget {
470 name: String,
471 metadata: BTreeMap<String, String>,
472}
473
474impl fmt::Debug for ConnectTarget {
475 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
476 formatter.write_str("ConnectTarget(<redacted>)")
477 }
478}
479
480impl ConnectTarget {
481 #[must_use]
483 pub fn new(name: impl Into<String>) -> Self {
484 Self {
485 name: name.into(),
486 metadata: BTreeMap::new(),
487 }
488 }
489
490 #[must_use]
492 pub fn name(&self) -> &str {
493 &self.name
494 }
495
496 #[must_use]
498 pub fn with_metadata(mut self, key: impl Into<String>, value: impl Into<String>) -> Self {
499 self.metadata.insert(key.into(), value.into());
500 self
501 }
502
503 #[must_use]
505 pub const fn metadata(&self) -> &BTreeMap<String, String> {
506 &self.metadata
507 }
508}
509
510#[derive(Clone, Default, Eq, PartialEq)]
512pub struct StartupParameters {
513 user: Option<String>,
514 database: Option<String>,
515 extensions: BTreeMap<String, String>,
516}
517
518impl fmt::Debug for StartupParameters {
519 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
520 formatter
521 .debug_struct("StartupParameters")
522 .field("user", &self.user.as_ref().map(|_| "<redacted>"))
523 .field("database", &self.database.as_ref().map(|_| "<redacted>"))
524 .field("extensions", &"<redacted>")
525 .finish()
526 }
527}
528
529impl StartupParameters {
530 #[must_use]
532 pub fn new(user: impl Into<String>) -> Self {
533 Self {
534 user: Some(user.into()),
535 ..Self::default()
536 }
537 }
538
539 #[must_use]
541 pub fn user(&self) -> Option<&str> {
542 self.user.as_deref()
543 }
544
545 #[must_use]
547 pub fn database_name(&self) -> Option<&str> {
548 self.database.as_deref()
549 }
550
551 pub(crate) fn from_wire(message: &StartupMessage) -> io::Result<Self> {
552 let mut parameters = Self::default();
553 for (name, value) in &message.parameters {
554 let name = std::str::from_utf8(name).map_err(|_| {
555 io::Error::new(
556 io::ErrorKind::InvalidData,
557 "startup parameter name is not UTF-8",
558 )
559 })?;
560 let value = std::str::from_utf8(value).map_err(|_| {
561 io::Error::new(
562 io::ErrorKind::InvalidData,
563 "startup parameter value is not UTF-8",
564 )
565 })?;
566 match name {
567 "user" => parameters.user = Some(value.to_owned()),
568 "database" => parameters.database = Some(value.to_owned()),
569 _ => {
570 parameters
571 .extensions
572 .insert(name.to_owned(), value.to_owned());
573 }
574 }
575 }
576 Ok(parameters)
577 }
578
579 #[must_use]
581 pub fn database(mut self, database: impl Into<String>) -> Self {
582 self.database = Some(database.into());
583 self
584 }
585
586 pub fn extension(
592 mut self,
593 name: impl Into<String>,
594 value: impl Into<String>,
595 ) -> Result<Self, StartupParameterError> {
596 let name = name.into();
597 if matches!(name.as_str(), "user" | "database") {
598 return Err(StartupParameterError::ReservedExtension(name));
599 }
600 self.extensions.insert(name, value.into());
601 Ok(self)
602 }
603
604 fn merged_with(mut self, overrides: Self) -> Self {
605 if overrides.user.is_some() {
606 self.user = overrides.user;
607 }
608 if overrides.database.is_some() {
609 self.database = overrides.database;
610 }
611 self.extensions.extend(overrides.extensions);
612 self
613 }
614
615 fn into_message(self) -> Result<StartupMessage, StartupParameterError> {
616 let user = self.user.ok_or(StartupParameterError::MissingUser)?;
617 let mut parameters = self
618 .extensions
619 .into_iter()
620 .map(|(key, value)| (Bytes::from(key), Bytes::from(value)))
621 .collect::<BTreeMap<_, _>>();
622 parameters.insert(Bytes::from_static(b"user"), Bytes::from(user));
623 if let Some(database) = self.database {
624 parameters.insert(Bytes::from_static(b"database"), Bytes::from(database));
625 }
626 Ok(StartupMessage {
627 version: ProtocolVersion::V3_2,
628 parameters,
629 })
630 }
631}
632
633#[derive(Clone, Eq, PartialEq)]
635pub enum StartupParameterError {
636 ReservedExtension(String),
638 MissingUser,
640}
641
642impl fmt::Debug for StartupParameterError {
643 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
644 formatter.write_str(match self {
645 Self::ReservedExtension(_) => "ReservedExtension(<redacted>)",
646 Self::MissingUser => "MissingUser",
647 })
648 }
649}
650
651impl fmt::Display for StartupParameterError {
652 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
653 match self {
654 Self::ReservedExtension(name) => {
655 write!(formatter, "startup extension name `{name}` is reserved")
656 }
657 Self::MissingUser => formatter.write_str("startup user is required"),
658 }
659 }
660}
661
662impl std::error::Error for StartupParameterError {}
663
664#[derive(Clone, Copy, Debug, Eq, PartialEq)]
666pub struct ProtocolLimits {
667 max_frame_len: usize,
668}
669
670impl Default for ProtocolLimits {
671 fn default() -> Self {
672 Self {
673 max_frame_len: 1024 * 1024,
674 }
675 }
676}
677
678impl ProtocolLimits {
679 pub fn max_frame_len(mut self, limit: usize) -> Result<Self, ProtocolLimitError> {
685 if !(5..=i32::MAX as usize + 1).contains(&limit) {
686 return Err(ProtocolLimitError);
687 }
688 self.max_frame_len = limit;
689 Ok(self)
690 }
691
692 #[must_use]
694 pub fn without_frame_limit(mut self) -> Self {
695 self.max_frame_len = i32::MAX as usize + 1;
696 self
697 }
698}
699
700#[derive(Clone, Copy, Debug, Eq, PartialEq)]
702pub struct ProtocolLimitError;
703
704impl fmt::Display for ProtocolLimitError {
705 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
706 formatter.write_str("frame limit is outside PostgreSQL's tagged-frame range")
707 }
708}
709
710impl std::error::Error for ProtocolLimitError {}
711
712#[derive(Clone, Debug, Eq, PartialEq)]
714pub struct ClientConnectionContext<Evidence = ()> {
715 target: ConnectTarget,
716 tls: Option<ClientTlsStatus>,
717 identity: Option<Evidence>,
718 backend_key: Option<crate::demux::CancelKey>,
719}
720
721#[derive(Clone, Copy, Debug, Eq, PartialEq)]
723pub enum ClientTlsStatus {
724 Plaintext,
726 Encrypted,
728}
729
730impl<Evidence> ClientConnectionContext<Evidence> {
731 #[must_use]
733 pub const fn target(&self) -> &ConnectTarget {
734 &self.target
735 }
736
737 #[must_use]
739 pub const fn tls(&self) -> Option<ClientTlsStatus> {
740 self.tls
741 }
742
743 #[must_use]
749 pub const fn identity(&self) -> &Evidence {
750 match &self.identity {
751 Some(identity) => identity,
752 None => panic!("identity is not known before authentication"),
753 }
754 }
755
756 #[must_use]
758 pub const fn identity_if_known(&self) -> Option<&Evidence> {
759 self.identity.as_ref()
760 }
761
762 #[must_use]
764 pub const fn backend_key(&self) -> Option<&crate::demux::CancelKey> {
765 self.backend_key.as_ref()
766 }
767}
768
769#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
771pub struct IdentityHandler;
772impl<C> crate::MiddlewareFactory<C> for IdentityHandler {
773 type Handler = Self;
774 fn create(&self, _: &C) -> Self {
775 *self
776 }
777}
778impl<S, C> crate::ClientMiddleware<S, C> for IdentityHandler {}
779
780pub struct ClientInitialContext {
782 target: ConnectTarget,
783}
784impl ClientInitialContext {
785 #[must_use]
787 pub const fn target(&self) -> &ConnectTarget {
788 &self.target
789 }
790}
791
792pub struct Client<
794 Connector = (),
795 Tls = ClientTlsPolicy,
796 Authentication = TrustClientAuthentication,
797 Middleware = IdentityHandler,
798> {
799 connector: Connector,
800 tls: Tls,
801 authentication: Authentication,
802 defaults: StartupParameters,
803 limits: ProtocolLimits,
804 middleware: Middleware,
805}
806
807impl<Connector: Clone, Tls: Clone, Authentication: Clone, Middleware: Clone> Clone
808 for Client<Connector, Tls, Authentication, Middleware>
809{
810 fn clone(&self) -> Self {
811 Self {
812 connector: self.connector.clone(),
813 tls: self.tls.clone(),
814 authentication: self.authentication.clone(),
815 defaults: self.defaults.clone(),
816 limits: self.limits,
817 middleware: self.middleware.clone(),
818 }
819 }
820}
821
822impl Client<()> {
823 #[must_use]
825 pub fn builder() -> ClientBuilder {
826 ClientBuilder::default()
827 }
828}
829
830impl<Connector, Tls: fmt::Debug, Authentication: fmt::Debug, Middleware> fmt::Debug
831 for Client<Connector, Tls, Authentication, Middleware>
832{
833 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
834 formatter
835 .debug_struct("Client")
836 .field("tls", &self.tls)
837 .field("authentication", &self.authentication)
838 .finish_non_exhaustive()
839 }
840}
841
842pub struct ClientBuilder<
844 Connector = (),
845 Tls = (),
846 Authentication = (),
847 Middleware = IdentityHandler,
848> {
849 connector: Option<Connector>,
850 tls: Option<Tls>,
851 authentication: Option<Authentication>,
852 defaults: StartupParameters,
853 limits: ProtocolLimits,
854 middleware: Middleware,
855}
856
857impl Default for ClientBuilder<()> {
858 fn default() -> Self {
859 Self {
860 connector: None,
861 tls: None,
862 authentication: None,
863 defaults: StartupParameters::default(),
864 limits: ProtocolLimits::default(),
865 middleware: IdentityHandler,
866 }
867 }
868}
869
870impl ClientBuilder<()> {
871 #[must_use]
873 pub fn connector<Next, Work, Transport, Error>(
874 self,
875 connector: Next,
876 ) -> ClientBuilder<Next, (), ()>
877 where
878 Next: Fn(&ConnectTarget) -> Work,
879 Work: Future<Output = Result<Transport, Error>>,
880 {
881 ClientBuilder {
882 connector: Some(connector),
883 tls: self.tls,
884 authentication: self.authentication,
885 defaults: self.defaults,
886 limits: self.limits,
887 middleware: self.middleware,
888 }
889 }
890}
891
892impl<Connector, Tls, Authentication, Middleware>
893 ClientBuilder<Connector, Tls, Authentication, Middleware>
894{
895 #[must_use]
897 pub fn tls<Next>(
898 self,
899 tls: Next,
900 ) -> ClientBuilder<Connector, Next, Authentication, Middleware> {
901 ClientBuilder {
902 connector: self.connector,
903 tls: Some(tls),
904 authentication: self.authentication,
905 defaults: self.defaults,
906 limits: self.limits,
907 middleware: self.middleware,
908 }
909 }
910
911 #[must_use]
913 pub fn authentication<Next>(
914 self,
915 authentication: Next,
916 ) -> ClientBuilder<Connector, Tls, Next, Middleware> {
917 ClientBuilder {
918 connector: self.connector,
919 tls: self.tls,
920 authentication: Some(authentication),
921 defaults: self.defaults,
922 limits: self.limits,
923 middleware: self.middleware,
924 }
925 }
926
927 #[must_use]
929 pub fn startup_parameters(mut self, defaults: StartupParameters) -> Self {
930 self.defaults = defaults;
931 self
932 }
933
934 #[must_use]
936 pub fn protocol_limits(mut self, limits: ProtocolLimits) -> Self {
937 self.limits = limits;
938 self
939 }
940
941 #[must_use]
943 pub fn middleware<Next>(
944 self,
945 factory: Next,
946 ) -> ClientBuilder<Connector, Tls, Authentication, crate::MiddlewareChain<Middleware, Next>>
947 {
948 ClientBuilder {
949 connector: self.connector,
950 tls: self.tls,
951 authentication: self.authentication,
952 defaults: self.defaults,
953 limits: self.limits,
954 middleware: crate::MiddlewareChain(self.middleware, factory),
955 }
956 }
957
958 pub fn build(self) -> Result<Client<Connector, Tls, Authentication, Middleware>, BuildError> {
964 Ok(Client {
965 connector: self.connector.ok_or(BuildError::MissingConnector)?,
966 tls: self.tls.ok_or(BuildError::MissingTls)?,
967 authentication: self
968 .authentication
969 .ok_or(BuildError::MissingAuthentication)?,
970 defaults: self.defaults,
971 limits: self.limits,
972 middleware: self.middleware,
973 })
974 }
975}
976
977#[derive(Debug)]
979pub enum ConnectError<ConnectorError, TlsError = Infallible, AuthenticationError = Infallible> {
980 Connector(ConnectorError),
982 Tls(TlsError),
984 Authentication(AuthenticationError),
986 Startup(StartupParameterError),
988 Protocol(io::Error),
990}
991
992#[derive(Debug)]
994pub enum CancelError<ConnectorError> {
995 Connector(ConnectorError),
997 Protocol(io::Error),
999}
1000
1001impl<E: fmt::Display> fmt::Display for CancelError<E> {
1002 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
1003 match self {
1004 Self::Connector(error) => error.fmt(formatter),
1005 Self::Protocol(error) => error.fmt(formatter),
1006 }
1007 }
1008}
1009impl<E: std::error::Error + 'static> std::error::Error for CancelError<E> {
1010 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
1011 match self {
1012 Self::Connector(error) => Some(error),
1013 Self::Protocol(error) => Some(error),
1014 }
1015 }
1016}
1017
1018impl<ConnectorError: fmt::Display, TlsError: fmt::Display, AuthenticationError: fmt::Display>
1019 fmt::Display for ConnectError<ConnectorError, TlsError, AuthenticationError>
1020{
1021 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1022 match self {
1023 Self::Connector(error) => error.fmt(f),
1024 Self::Tls(error) => error.fmt(f),
1025 Self::Authentication(error) => error.fmt(f),
1026 Self::Startup(error) => error.fmt(f),
1027 Self::Protocol(error) => error.fmt(f),
1028 }
1029 }
1030}
1031impl<ConnectorError, TlsError, AuthenticationError> std::error::Error
1032 for ConnectError<ConnectorError, TlsError, AuthenticationError>
1033where
1034 ConnectorError: std::error::Error + 'static,
1035 TlsError: std::error::Error + 'static,
1036 AuthenticationError: std::error::Error + 'static,
1037{
1038 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
1039 match self {
1040 Self::Connector(error) => Some(error),
1041 Self::Tls(error) => Some(error),
1042 Self::Authentication(error) => Some(error),
1043 Self::Startup(error) => Some(error),
1044 Self::Protocol(error) => Some(error),
1045 }
1046 }
1047}
1048
1049#[derive(Debug)]
1051pub enum ConnectionClean {}
1052
1053#[derive(Debug)]
1055pub enum ConnectionChanged {}
1056
1057pub struct ClientConnection<
1059 Transport,
1060 State,
1061 Cleanliness = ConnectionClean,
1062 Evidence = (),
1063 Handler = IdentityHandler,
1064> {
1065 core: ClientConnectionCore<Transport, Cleanliness, Evidence, Handler>,
1066 state: State,
1067}
1068
1069pub(crate) struct ClientConnectionCore<Transport, Cleanliness, Evidence, Handler> {
1070 connection: Conn<Buffered<Transport, Backend>, Ready, Cleanliness>,
1071 handler: Handler,
1072 context: ClientConnectionContext<Evidence>,
1073}
1074
1075impl<Transport, State, Cleanliness, Evidence, Handler>
1076 ClientConnection<Transport, State, Cleanliness, Evidence, Handler>
1077{
1078 #[must_use]
1080 pub const fn context(&self) -> &ClientConnectionContext<Evidence> {
1081 &self.core.context
1082 }
1083
1084 #[must_use]
1087 pub const fn state(&self) -> &State {
1088 &self.state
1089 }
1090
1091 pub async fn receive_wire(&mut self) -> io::Result<crate::codec::BackendMessage>
1098 where
1099 Transport: AsyncRead + Unpin,
1100 Handler: crate::ClientMiddleware<State, ClientConnectionContext<Evidence>>,
1101 {
1102 let message = self.core.receive_wire_raw().await?;
1103 Ok(self.core.intercept_backend(&mut self.state, message))
1104 }
1105
1106 pub fn into_parts(self) -> (Transport, State, Handler, ClientConnectionContext<Evidence>) {
1109 (
1110 self.core.connection.into_transport().into_inner(),
1111 self.state,
1112 self.core.handler,
1113 self.core.context,
1114 )
1115 }
1116}
1117
1118impl<Transport, Cleanliness, Evidence, Handler>
1119 ClientConnectionCore<Transport, Cleanliness, Evidence, Handler>
1120{
1121 pub(crate) const fn context(&self) -> &ClientConnectionContext<Evidence> {
1122 &self.context
1123 }
1124 pub(crate) async fn receive_wire_raw(&mut self) -> io::Result<crate::codec::BackendMessage>
1125 where
1126 Transport: AsyncRead + Unpin,
1127 {
1128 self.connection.receive_backend_wire().await
1129 }
1130
1131 pub(crate) fn intercept_backend<State>(
1132 &mut self,
1133 state: &mut State,
1134 message: crate::codec::BackendMessage,
1135 ) -> crate::codec::BackendMessage
1136 where
1137 Handler: crate::ClientMiddleware<State, ClientConnectionContext<Evidence>>,
1138 {
1139 self.handler.backend(&self.context, state, message)
1140 }
1141
1142 pub(crate) fn intercept_frontend<State>(
1143 &mut self,
1144 state: &mut State,
1145 message: FrontendMessage,
1146 ) -> FrontendMessage
1147 where
1148 Handler: crate::ClientMiddleware<State, ClientConnectionContext<Evidence>>,
1149 {
1150 self.handler.frontend(&self.context, state, message)
1151 }
1152
1153 pub(crate) async fn send_wire_raw(&mut self, message: FrontendMessage) -> io::Result<()>
1154 where
1155 Transport: AsyncWrite + Unpin,
1156 {
1157 self.connection.push_frame(message.to_frame()?)?;
1158 self.connection.flush().await
1159 }
1160
1161 pub(crate) fn into_parts(self) -> (Transport, Handler, ClientConnectionContext<Evidence>) {
1162 (
1163 self.connection.into_transport().into_inner(),
1164 self.handler,
1165 self.context,
1166 )
1167 }
1168}
1169
1170fn intercept_auth_response<State, Evidence, Handler>(
1171 handler: &mut Handler,
1172 context: &ClientConnectionContext<Evidence>,
1173 state: &mut State,
1174 response: Bytes,
1175) -> Result<Bytes, AuthenticationDriveError<Infallible>>
1176where
1177 Handler: crate::ClientMiddleware<State, ClientConnectionContext<Evidence>>,
1178{
1179 match handler.frontend(
1180 context,
1181 state,
1182 crate::codec::FrontendMessage::PasswordResponse(response),
1183 ) {
1184 crate::codec::FrontendMessage::PasswordResponse(response) => Ok(response),
1185 _ => Err(AuthenticationDriveError::InvalidResponse),
1186 }
1187}
1188
1189async fn complete_password<Transport, Policy, State, Handler>(
1190 connection: Conn<Buffered<Transport, Backend>, crate::auth::PasswordResponse>,
1191 challenge: ClientAuthenticationChallenge,
1192 policy: &mut Policy,
1193 context: &ClientConnectionContext<Policy::Evidence>,
1194 state: &mut State,
1195 handler: &mut Handler,
1196) -> Result<
1197 Conn<Buffered<Transport, Backend>, crate::auth::AwaitingStartupReady>,
1198 AuthenticationDriveError<Policy::Error>,
1199>
1200where
1201 Transport: AsyncRead + AsyncWrite + Unpin,
1202 Policy: ClientAuthenticationSession,
1203 Handler: crate::ClientMiddleware<State, ClientConnectionContext<Policy::Evidence>>,
1204{
1205 let response = policy
1206 .respond(challenge)
1207 .await
1208 .map_err(AuthenticationDriveError::Policy)?;
1209 let ClientAuthenticationResponse::Password(password) = response else {
1210 let _ = connection.into_transport();
1211 return Err(AuthenticationDriveError::InvalidResponse);
1212 };
1213 let password = intercept_auth_response(handler, context, state, password)
1214 .map_err(|_| AuthenticationDriveError::InvalidResponse)?;
1215 let (mut awaiting, frame) = connection
1216 .password(&password)
1217 .map_err(AuthenticationDriveError::Protocol)?;
1218 awaiting
1219 .push_frame(frame)
1220 .map_err(AuthenticationDriveError::Protocol)?;
1221 awaiting
1222 .flush()
1223 .await
1224 .map_err(AuthenticationDriveError::Protocol)?;
1225 let message = awaiting
1226 .receive_backend_wire()
1227 .await
1228 .map_err(AuthenticationDriveError::Protocol)?;
1229 let message = handler.backend(context, state, message);
1230 match awaiting.offer(message) {
1231 Ok(crate::auth::AuthCompletion::Ok(connection)) => Ok(connection),
1232 Ok(crate::auth::AuthCompletion::Error { conn, .. }) => {
1233 let _ = conn.into_transport();
1234 Err(AuthenticationDriveError::Rejected)
1235 }
1236 Err((conn, _)) => {
1237 let _ = conn.into_transport();
1238 Err(AuthenticationDriveError::Protocol(io::Error::new(
1239 io::ErrorKind::InvalidData,
1240 "illegal authentication completion",
1241 )))
1242 }
1243 }
1244}
1245
1246async fn complete_sasl<Transport, Policy, State, Handler>(
1247 connection: Conn<Buffered<Transport, Backend>, crate::auth::SaslInitial>,
1248 mechanisms: Vec<Bytes>,
1249 policy: &mut Policy,
1250 context: &ClientConnectionContext<Policy::Evidence>,
1251 state: &mut State,
1252 handler: &mut Handler,
1253) -> Result<
1254 Conn<Buffered<Transport, Backend>, crate::auth::AwaitingStartupReady>,
1255 AuthenticationDriveError<Policy::Error>,
1256>
1257where
1258 Transport: AsyncRead + AsyncWrite + Unpin,
1259 Policy: ClientAuthenticationSession,
1260 Handler: crate::ClientMiddleware<State, ClientConnectionContext<Policy::Evidence>>,
1261{
1262 let response = policy
1263 .respond(ClientAuthenticationChallenge::Sasl(mechanisms))
1264 .await
1265 .map_err(AuthenticationDriveError::Policy)?;
1266 let ClientAuthenticationResponse::SaslInitial {
1267 mechanism,
1268 response,
1269 } = response
1270 else {
1271 let _ = connection.into_transport();
1272 return Err(AuthenticationDriveError::InvalidResponse);
1273 };
1274 let response = intercept_auth_response(handler, context, state, response)
1275 .map_err(|_| AuthenticationDriveError::InvalidResponse)?;
1276 let (mut sasl, frame) = connection
1277 .sasl(&mechanism, &response)
1278 .map_err(AuthenticationDriveError::Protocol)?;
1279 sasl.push_frame(frame)
1280 .map_err(AuthenticationDriveError::Protocol)?;
1281 sasl.flush()
1282 .await
1283 .map_err(AuthenticationDriveError::Protocol)?;
1284 loop {
1285 let message = sasl
1286 .receive_backend_wire()
1287 .await
1288 .map_err(AuthenticationDriveError::Protocol)?;
1289 let message = handler.backend(context, state, message);
1290 match sasl.offer_backend(message) {
1291 Ok(crate::auth::SaslEvent::Continue { conn, challenge }) => {
1292 let response = policy
1293 .respond(ClientAuthenticationChallenge::SaslContinue(challenge))
1294 .await
1295 .map_err(AuthenticationDriveError::Policy)?;
1296 let ClientAuthenticationResponse::Sasl(response) = response else {
1297 let _ = conn.into_transport();
1298 return Err(AuthenticationDriveError::InvalidResponse);
1299 };
1300 let response = intercept_auth_response(handler, context, state, response)
1301 .map_err(|_| AuthenticationDriveError::InvalidResponse)?;
1302 let (mut next, frame) = conn.respond(response);
1303 next.push_frame(frame)
1304 .map_err(AuthenticationDriveError::Protocol)?;
1305 next.flush()
1306 .await
1307 .map_err(AuthenticationDriveError::Protocol)?;
1308 sasl = next;
1309 }
1310 Ok(crate::auth::SaslEvent::Final { conn, server_final }) => {
1311 let response = policy
1312 .respond(ClientAuthenticationChallenge::SaslFinal(server_final))
1313 .await
1314 .map_err(AuthenticationDriveError::Policy)?;
1315 if response != ClientAuthenticationResponse::Verified {
1316 let _ = conn.into_transport();
1317 return Err(AuthenticationDriveError::InvalidResponse);
1318 }
1319 let mut awaiting = conn.verified();
1320 let message = awaiting
1321 .receive_backend_wire()
1322 .await
1323 .map_err(AuthenticationDriveError::Protocol)?;
1324 let message = handler.backend(context, state, message);
1325 return match awaiting.offer(message) {
1326 Ok(crate::auth::AuthCompletion::Ok(connection)) => Ok(connection),
1327 Ok(crate::auth::AuthCompletion::Error { conn, .. }) => {
1328 let _ = conn.into_transport();
1329 Err(AuthenticationDriveError::Rejected)
1330 }
1331 Err((conn, _)) => {
1332 let _ = conn.into_transport();
1333 Err(AuthenticationDriveError::Protocol(io::Error::new(
1334 io::ErrorKind::InvalidData,
1335 "illegal SASL authentication completion",
1336 )))
1337 }
1338 };
1339 }
1340 Ok(crate::auth::SaslEvent::Error { conn, .. }) => {
1341 let _ = conn.into_transport();
1342 return Err(AuthenticationDriveError::Rejected);
1343 }
1344 Err((conn, _)) => {
1345 let _ = conn.into_transport();
1346 return Err(AuthenticationDriveError::Protocol(io::Error::new(
1347 io::ErrorKind::InvalidData,
1348 "illegal SASL authentication message",
1349 )));
1350 }
1351 }
1352 }
1353}
1354
1355async fn complete_token<Transport, Policy, State, Handler>(
1356 connection: Conn<Buffered<Transport, Backend>, crate::auth::TokenResponse>,
1357 challenge: ClientAuthenticationChallenge,
1358 policy: &mut Policy,
1359 context: &ClientConnectionContext<Policy::Evidence>,
1360 state: &mut State,
1361 handler: &mut Handler,
1362) -> Result<
1363 Conn<Buffered<Transport, Backend>, crate::auth::AwaitingStartupReady>,
1364 AuthenticationDriveError<Policy::Error>,
1365>
1366where
1367 Transport: AsyncRead + AsyncWrite + Unpin,
1368 Policy: ClientAuthenticationSession,
1369 Handler: crate::ClientMiddleware<State, ClientConnectionContext<Policy::Evidence>>,
1370{
1371 let response = policy
1372 .respond(challenge)
1373 .await
1374 .map_err(AuthenticationDriveError::Policy)?;
1375 let ClientAuthenticationResponse::Token(token) = response else {
1376 let _ = connection.into_transport();
1377 return Err(AuthenticationDriveError::InvalidResponse);
1378 };
1379 let token = intercept_auth_response(handler, context, state, token)
1380 .map_err(|_| AuthenticationDriveError::InvalidResponse)?;
1381 let (mut waiting, frame) = connection.respond(token);
1382 waiting
1383 .push_frame(frame)
1384 .map_err(AuthenticationDriveError::Protocol)?;
1385 waiting
1386 .flush()
1387 .await
1388 .map_err(AuthenticationDriveError::Protocol)?;
1389 loop {
1390 let message = waiting
1391 .receive_backend_wire()
1392 .await
1393 .map_err(AuthenticationDriveError::Protocol)?;
1394 let message = handler.backend(context, state, message);
1395 match waiting.offer(message) {
1396 Ok(crate::auth::TokenAuthEvent::Continue { conn, token }) => {
1397 let response = policy
1398 .respond(ClientAuthenticationChallenge::TokenContinue(token))
1399 .await
1400 .map_err(AuthenticationDriveError::Policy)?;
1401 let ClientAuthenticationResponse::Token(token) = response else {
1402 let _ = conn.into_transport();
1403 return Err(AuthenticationDriveError::InvalidResponse);
1404 };
1405 let token = intercept_auth_response(handler, context, state, token)
1406 .map_err(|_| AuthenticationDriveError::InvalidResponse)?;
1407 let (mut next, frame) = conn.respond(token);
1408 next.push_frame(frame)
1409 .map_err(AuthenticationDriveError::Protocol)?;
1410 next.flush()
1411 .await
1412 .map_err(AuthenticationDriveError::Protocol)?;
1413 waiting = next;
1414 }
1415 Ok(crate::auth::TokenAuthEvent::Ok(connection)) => return Ok(connection),
1416 Ok(crate::auth::TokenAuthEvent::Error { conn, .. }) => {
1417 let _ = conn.into_transport();
1418 return Err(AuthenticationDriveError::Rejected);
1419 }
1420 Err((conn, _)) => {
1421 let _ = conn.into_transport();
1422 return Err(AuthenticationDriveError::Protocol(io::Error::new(
1423 io::ErrorKind::InvalidData,
1424 "illegal token authentication message",
1425 )));
1426 }
1427 }
1428 }
1429}
1430
1431enum SessionEstablishError<AuthenticationError> {
1432 Authentication(ClientAuthenticationError<AuthenticationError>),
1433 Protocol(io::Error),
1434}
1435
1436fn replace_session_item(
1437 item: SessionItem,
1438 replacement: crate::codec::BackendMessage,
1439) -> Option<SessionItem> {
1440 match (item, replacement) {
1441 (SessionItem::Message(_), message) => Some(SessionItem::Message(message)),
1442 (
1443 SessionItem::ReadyForQuery {
1444 parameters_changed, ..
1445 },
1446 crate::codec::BackendMessage::ReadyForQuery(status),
1447 ) => Some(SessionItem::ReadyForQuery {
1448 status,
1449 parameters_changed,
1450 }),
1451 (
1452 SessionItem::CommandComplete {
1453 command, notices, ..
1454 },
1455 crate::codec::BackendMessage::CommandComplete(tag),
1456 ) => Some(SessionItem::CommandComplete {
1457 tag,
1458 command,
1459 notices,
1460 }),
1461 _ => None,
1462 }
1463}
1464
1465#[allow(clippy::too_many_arguments, clippy::too_many_lines)] async fn establish_client_session<Transport, Authentication, State, Handler>(
1467 transport: ClientTransport<Transport>,
1468 startup: &StartupMessage,
1469 target: &ConnectTarget,
1470 authentication_policy: &Authentication,
1471 max_frame_len: usize,
1472 context: &ClientConnectionContext<Authentication::Evidence>,
1473 state: &mut State,
1474 handler: &mut Handler,
1475) -> Result<
1476 (
1477 Conn<Buffered<ClientTransport<Transport>, Backend>, Ready>,
1478 Authentication::Evidence,
1479 Option<crate::demux::CancelKey>,
1480 ),
1481 SessionEstablishError<Authentication::Error>,
1482>
1483where
1484 Transport: AsyncRead + AsyncWrite + Unpin,
1485 Authentication: ClientAuthentication,
1486 Handler: crate::ClientMiddleware<State, ClientConnectionContext<Authentication::Evidence>>,
1487{
1488 let mut policy = authentication_policy.begin(target).await.map_err(|error| {
1489 SessionEstablishError::Authentication(ClientAuthenticationError::Policy(error))
1490 })?;
1491 let buffered = Buffered::with_max_frame_len(transport, max_frame_len)
1492 .map_err(SessionEstablishError::Protocol)?;
1493 let (mut startup_connection, packet) = Conn::new(buffered)
1494 .startup(startup)
1495 .map_err(SessionEstablishError::Protocol)?;
1496 startup_connection.push_startup_packet(&packet);
1497 let mut authentication = startup_connection.authentication();
1498 if let Err(error) = authentication.flush().await {
1499 let _ = authentication.into_transport();
1500 return Err(SessionEstablishError::Protocol(error));
1501 }
1502 let awaiting_ready = loop {
1503 let message = match authentication.receive_backend_wire().await {
1504 Ok(message) => message,
1505 Err(error) => {
1506 let _ = authentication.into_transport();
1507 return Err(SessionEstablishError::Protocol(error));
1508 }
1509 };
1510 let message = handler.backend(context, state, message);
1511 match authentication.offer_backend(message) {
1512 Ok(AuthEvent::Authentication(AuthOffer::Ok(connection))) => break connection,
1513 Ok(AuthEvent::Negotiate { conn, .. }) => authentication = conn,
1514 Ok(AuthEvent::Authentication(AuthOffer::Cleartext(connection))) => {
1515 break complete_password(
1516 connection,
1517 ClientAuthenticationChallenge::CleartextPassword,
1518 &mut policy,
1519 context,
1520 state,
1521 handler,
1522 )
1523 .await
1524 .map_err(session_authentication_error)?;
1525 }
1526 Ok(AuthEvent::Authentication(AuthOffer::Md5 { conn, salt })) => {
1527 break complete_password(
1528 conn,
1529 ClientAuthenticationChallenge::Md5Password(salt),
1530 &mut policy,
1531 context,
1532 state,
1533 handler,
1534 )
1535 .await
1536 .map_err(session_authentication_error)?;
1537 }
1538 Ok(AuthEvent::Authentication(AuthOffer::Sasl { conn, mechanisms })) => {
1539 break complete_sasl(conn, mechanisms, &mut policy, context, state, handler)
1540 .await
1541 .map_err(session_authentication_error)?;
1542 }
1543 Ok(AuthEvent::Authentication(AuthOffer::Gss(conn))) => {
1544 break complete_token(
1545 conn,
1546 ClientAuthenticationChallenge::Gss,
1547 &mut policy,
1548 context,
1549 state,
1550 handler,
1551 )
1552 .await
1553 .map_err(session_authentication_error)?;
1554 }
1555 Ok(AuthEvent::Authentication(AuthOffer::Sspi(conn))) => {
1556 break complete_token(
1557 conn,
1558 ClientAuthenticationChallenge::Sspi,
1559 &mut policy,
1560 context,
1561 state,
1562 handler,
1563 )
1564 .await
1565 .map_err(session_authentication_error)?;
1566 }
1567 Ok(AuthEvent::Authentication(AuthOffer::KerberosV5(conn))) => {
1568 break complete_token(
1569 conn,
1570 ClientAuthenticationChallenge::KerberosV5,
1571 &mut policy,
1572 context,
1573 state,
1574 handler,
1575 )
1576 .await
1577 .map_err(session_authentication_error)?;
1578 }
1579 Ok(AuthEvent::Error { conn, .. }) => {
1580 let _ = conn.into_transport();
1581 return Err(SessionEstablishError::Authentication(
1582 ClientAuthenticationError::Rejected,
1583 ));
1584 }
1585 Err((conn, _, source)) => {
1586 authentication = conn;
1587 if let Some(source) = source {
1588 let _ = authentication.into_transport();
1589 return Err(SessionEstablishError::Protocol(source));
1590 }
1591 }
1592 }
1593 };
1594 let mut awaiting_ready = awaiting_ready;
1595 let mut backend_key = None;
1596 let ready = loop {
1597 let item = match awaiting_ready.receive().await {
1598 Ok(item) => item,
1599 Err(error) => {
1600 let _ = awaiting_ready.into_transport();
1601 return Err(SessionEstablishError::Protocol(error));
1602 }
1603 };
1604 if let crate::codec::BackendMessage::BackendKeyData {
1605 process_id,
1606 secret_key,
1607 } = item.clone().into_backend_message()
1608 {
1609 backend_key = Some(crate::demux::CancelKey {
1610 process_id,
1611 secret_key,
1612 });
1613 }
1614 let replacement = handler.backend(context, state, item.clone().into_backend_message());
1615 let Some(item) = replace_session_item(item, replacement) else {
1616 let _ = awaiting_ready.into_transport();
1617 return Err(SessionEstablishError::Protocol(io::Error::new(
1618 io::ErrorKind::InvalidData,
1619 "middleware replacement during startup readiness is not phase-compatible",
1620 )));
1621 };
1622 match awaiting_ready.offer_ready(item) {
1623 Ok(ready) => break ready,
1624 Err((connection, SessionItem::Message(_))) => awaiting_ready = connection,
1625 Err((connection, _)) => {
1626 let _ = connection.into_transport();
1627 return Err(SessionEstablishError::Protocol(io::Error::new(
1628 io::ErrorKind::InvalidData,
1629 "startup did not reach an idle operational phase",
1630 )));
1631 }
1632 }
1633 };
1634 let identity = policy.authenticated().await.map_err(|error| {
1635 SessionEstablishError::Authentication(ClientAuthenticationError::Policy(error))
1636 })?;
1637 Ok((ready, identity, backend_key))
1638}
1639
1640fn session_authentication_error<Error>(
1641 error: AuthenticationDriveError<Error>,
1642) -> SessionEstablishError<Error> {
1643 match error {
1644 AuthenticationDriveError::Policy(error) => {
1645 SessionEstablishError::Authentication(ClientAuthenticationError::Policy(error))
1646 }
1647 AuthenticationDriveError::Rejected => {
1648 SessionEstablishError::Authentication(ClientAuthenticationError::Rejected)
1649 }
1650 AuthenticationDriveError::InvalidResponse => {
1651 SessionEstablishError::Authentication(ClientAuthenticationError::InvalidResponse)
1652 }
1653 AuthenticationDriveError::Protocol(error) => SessionEstablishError::Protocol(error),
1654 }
1655}
1656
1657fn map_session_error<ConnectorError, TlsError, AuthenticationError>(
1658 error: SessionEstablishError<AuthenticationError>,
1659) -> ConnectError<ConnectorError, TlsError, ClientAuthenticationError<AuthenticationError>> {
1660 match error {
1661 SessionEstablishError::Authentication(error) => ConnectError::Authentication(error),
1662 SessionEstablishError::Protocol(error) => ConnectError::Protocol(error),
1663 }
1664}
1665
1666#[derive(Debug)]
1668pub struct QueryError(io::Error);
1669
1670impl fmt::Display for QueryError {
1671 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
1672 self.0.fmt(formatter)
1673 }
1674}
1675
1676impl std::error::Error for QueryError {
1677 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
1678 Some(&self.0)
1679 }
1680}
1681
1682impl<Transport, State, Cleanliness, Evidence, Handler>
1683 ClientConnection<Transport, State, Cleanliness, Evidence, Handler>
1684where
1685 Transport: AsyncRead + AsyncWrite + Unpin,
1686 Handler: crate::ClientMiddleware<State, ClientConnectionContext<Evidence>>,
1687{
1688 #[allow(clippy::too_many_lines)]
1699 pub async fn simple_query(
1700 self,
1701 query: &[u8],
1702 ) -> Result<
1703 (
1704 ClientConnection<Transport, State, ConnectionChanged, Evidence, Handler>,
1705 Vec<crate::codec::BackendMessage>,
1706 ),
1707 QueryError,
1708 > {
1709 let Self {
1710 core:
1711 ClientConnectionCore {
1712 connection,
1713 mut handler,
1714 context,
1715 },
1716 mut state,
1717 } = self;
1718 let outbound = handler.frontend(
1719 &context,
1720 &mut state,
1721 crate::codec::FrontendMessage::Query(Bytes::copy_from_slice(query)),
1722 );
1723 let crate::codec::FrontendMessage::Query(query) = outbound else {
1724 let _ = connection.into_transport();
1725 return Err(QueryError(io::Error::new(
1726 io::ErrorKind::InvalidData,
1727 "middleware replaced Query with an incompatible message",
1728 )));
1729 };
1730 let (mut query_connection, frame) = connection.push_query(&query).map_err(QueryError)?;
1731 if let Err(error) = query_connection.push_frame(frame) {
1732 let _ = query_connection.into_transport();
1733 return Err(QueryError(error));
1734 }
1735 if let Err(error) = query_connection.flush().await {
1736 let _ = query_connection.into_transport();
1737 return Err(QueryError(error));
1738 }
1739 let mut messages = Vec::new();
1740 loop {
1741 let item = match query_connection.receive().await {
1742 Ok(item) => item,
1743 Err(error) => {
1744 let _ = query_connection.into_transport();
1745 return Err(QueryError(error));
1746 }
1747 };
1748 let observed =
1749 handler.backend(&context, &mut state, item.clone().into_backend_message());
1750 let Some(item) = replace_session_item(item, observed.clone()) else {
1751 let _ = query_connection.into_transport();
1752 return Err(QueryError(io::Error::new(
1753 io::ErrorKind::InvalidData,
1754 "middleware replacement during simple query is not phase-compatible",
1755 )));
1756 };
1757 messages.push(observed);
1758 match query_connection.offer(item) {
1759 Ok(SimpleTransition::Continue(connection, _)) => query_connection = connection,
1760 Ok(SimpleTransition::Ready(
1761 ReadyState::Clean(connection)
1762 | ReadyState::Dirty {
1763 conn: connection, ..
1764 },
1765 )) => {
1766 return Ok((
1767 ClientConnection {
1768 core: ClientConnectionCore {
1769 connection: connection.transition(),
1770 handler,
1771 context,
1772 },
1773 state,
1774 },
1775 messages,
1776 ));
1777 }
1778 Ok(SimpleTransition::Error(connection, _)) => {
1779 let _ = connection.into_transport();
1780 return Err(QueryError(io::Error::other(
1781 "backend rejected simple query",
1782 )));
1783 }
1784 Ok(SimpleTransition::CopyIn(connection, _)) => {
1785 let _ = connection.into_transport();
1786 return Err(QueryError(io::Error::other("simple query entered COPY IN")));
1787 }
1788 Ok(SimpleTransition::CopyOut(connection, _)) => {
1789 let _ = connection.into_transport();
1790 return Err(QueryError(io::Error::other(
1791 "simple query entered COPY OUT",
1792 )));
1793 }
1794 Ok(SimpleTransition::CopyBoth(connection, _)) => {
1795 let _ = connection.into_transport();
1796 return Err(QueryError(io::Error::other(
1797 "simple query entered COPY BOTH",
1798 )));
1799 }
1800 Err((connection, _)) => {
1801 let _ = connection.into_transport();
1802 return Err(QueryError(io::Error::new(
1803 io::ErrorKind::InvalidData,
1804 "illegal simple-query response",
1805 )));
1806 }
1807 }
1808 }
1809 }
1810}
1811
1812impl<Connector, Tls, Authentication, Middleware, Work, Transport, Error>
1813 Client<Connector, Tls, Authentication, Middleware>
1814where
1815 Connector: Fn(&ConnectTarget) -> Work,
1816 Work: Future<Output = Result<Transport, Error>>,
1817 Transport: AsyncRead + AsyncWrite + Unpin,
1818 Authentication: ClientAuthentication,
1819 Tls: ClientTlsConfiguration,
1820 Middleware: crate::MiddlewareFactory<ClientInitialContext>,
1821{
1822 pub async fn connect<State>(
1831 &self,
1832 target: ConnectTarget,
1833 overrides: StartupParameters,
1834 mut state: State,
1835 ) -> Result<
1836 ClientConnection<
1837 ClientTransport<Transport>,
1838 State,
1839 ConnectionClean,
1840 Authentication::Evidence,
1841 <Middleware as crate::MiddlewareFactory<ClientInitialContext>>::Handler,
1842 >,
1843 ConnectError<
1844 Error,
1845 ClientTlsError<<Tls::Provider as ClientTlsProvider>::Error>,
1846 ClientAuthenticationError<Authentication::Error>,
1847 >,
1848 >
1849 where
1850 <Middleware as crate::MiddlewareFactory<ClientInitialContext>>::Handler:
1851 crate::ClientMiddleware<State, ClientConnectionContext<Authentication::Evidence>>,
1852 {
1853 let core = self.connect_core(target, overrides, &mut state).await?;
1854 Ok(ClientConnection {
1855 core: ClientConnectionCore {
1856 connection: core.connection.transition(),
1857 handler: core.handler,
1858 context: core.context,
1859 },
1860 state,
1861 })
1862 }
1863
1864 pub(crate) async fn connect_core<State>(
1867 &self,
1868 target: ConnectTarget,
1869 overrides: StartupParameters,
1870 state: &mut State,
1871 ) -> Result<
1872 ClientConnectionCore<
1873 ClientTransport<Transport>,
1874 Pristine,
1875 Authentication::Evidence,
1876 <Middleware as crate::MiddlewareFactory<ClientInitialContext>>::Handler,
1877 >,
1878 ConnectError<
1879 Error,
1880 ClientTlsError<<Tls::Provider as ClientTlsProvider>::Error>,
1881 ClientAuthenticationError<Authentication::Error>,
1882 >,
1883 >
1884 where
1885 <Middleware as crate::MiddlewareFactory<ClientInitialContext>>::Handler:
1886 crate::ClientMiddleware<State, ClientConnectionContext<Authentication::Evidence>>,
1887 {
1888 let mut handler = self.middleware.create(&ClientInitialContext {
1889 target: target.clone(),
1890 });
1891 let startup = self
1892 .defaults
1893 .clone()
1894 .merged_with(overrides)
1895 .into_message()
1896 .map_err(ConnectError::Startup)?;
1897 let mut context = ClientConnectionContext {
1898 target: target.clone(),
1899 tls: None,
1900 identity: None,
1901 backend_key: None,
1902 };
1903 let transport = (self.connector)(&target)
1904 .await
1905 .map_err(ConnectError::Connector)?;
1906 let configured_tls = self.tls.configured();
1907 let transport = match configured_tls {
1908 None => {
1909 context.tls = Some(ClientTlsStatus::Plaintext);
1910 ClientTransport::Plain(transport)
1911 }
1912 Some((mode, provider)) => negotiate_client_tls(
1913 transport,
1914 mode,
1915 provider,
1916 &target,
1917 &mut context,
1918 state,
1919 &mut handler,
1920 )
1921 .await
1922 .map_err(ConnectError::Tls)?,
1923 };
1924 let first_startup = handler.startup(&context, state, startup.clone());
1925 let first = establish_client_session(
1926 transport,
1927 &first_startup,
1928 &target,
1929 &self.authentication,
1930 self.limits.max_frame_len,
1931 &context,
1932 state,
1933 &mut handler,
1934 )
1935 .await;
1936 let retry_provider = match configured_tls {
1937 Some((crate::pre_startup::SslMode::Allow, provider)) if first.is_err() => {
1938 Some(provider)
1939 }
1940 _ => None,
1941 };
1942 let (ready, identity, backend_key) = if let Some(provider) = retry_provider {
1943 let transport = (self.connector)(&target)
1944 .await
1945 .map_err(ConnectError::Connector)?;
1946 context.tls = None;
1950 let transport = negotiate_client_tls(
1951 transport,
1952 crate::pre_startup::SslMode::Require,
1953 provider,
1954 &target,
1955 &mut context,
1956 state,
1957 &mut handler,
1958 )
1959 .await
1960 .map_err(ConnectError::Tls)?;
1961 let retry_startup = handler.startup(&context, state, startup);
1962 establish_client_session(
1963 transport,
1964 &retry_startup,
1965 &target,
1966 &self.authentication,
1967 self.limits.max_frame_len,
1968 &context,
1969 state,
1970 &mut handler,
1971 )
1972 .await
1973 .map_err(map_session_error)?
1974 } else {
1975 first.map_err(map_session_error)?
1976 };
1977 Ok(ClientConnectionCore {
1978 connection: ready,
1979 handler,
1980 context: {
1981 context.identity = Some(identity);
1982 context.backend_key = backend_key;
1983 context
1984 },
1985 })
1986 }
1987}
1988
1989impl<Connector, Tls, Authentication, Middleware, Work, Transport, Error>
1990 Client<Connector, Tls, Authentication, Middleware>
1991where
1992 Connector: Fn(&ConnectTarget) -> Work,
1993 Work: Future<Output = Result<Transport, Error>>,
1994 Transport: AsyncWrite + Unpin,
1995{
1996 pub async fn cancel(
2005 &self,
2006 target: &ConnectTarget,
2007 key: &crate::demux::CancelKey,
2008 ) -> Result<(), CancelError<Error>> {
2009 let mut transport = (self.connector)(target)
2010 .await
2011 .map_err(CancelError::Connector)?;
2012 let packet = crate::pre_startup::PreStartupMessage::CancelRequest {
2013 process_id: key.process_id,
2014 secret_key: key.secret_key.clone(),
2015 }
2016 .to_packet()
2017 .map_err(CancelError::Protocol)?;
2018 tokio::io::AsyncWriteExt::write_all(&mut transport, &packet)
2019 .await
2020 .map_err(CancelError::Protocol)?;
2021 tokio::io::AsyncWriteExt::shutdown(&mut transport)
2022 .await
2023 .map_err(CancelError::Protocol)
2024 }
2025}