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