1use std::marker::PhantomData;
10use std::{convert::Infallible, io};
11
12use crate::{
13 codec::{BackendMessage, FrontendMessage},
14 demux::Demux,
15 grammar::{
16 authentication, backend, frontend, pre_startup, server_authentication, server_pre_startup,
17 },
18 pre_startup::{EncryptionReply, PreStartupMessage},
19};
20
21pub trait AcceptsMessage<Message> {
23 fn accepts(&self, message: &Message) -> bool;
25}
26
27pub trait ReconstructableMessage {
29 fn is_reconstructable(&self) -> bool;
31}
32
33impl ReconstructableMessage for FrontendMessage {
34 fn is_reconstructable(&self) -> bool {
35 self.to_frame().is_ok()
36 }
37}
38
39impl ReconstructableMessage for BackendMessage {
40 fn is_reconstructable(&self) -> bool {
41 self.to_frame().is_ok()
42 }
43}
44
45impl ReconstructableMessage for PreStartupMessage {
46 fn is_reconstructable(&self) -> bool {
47 self.to_packet().is_ok()
48 }
49}
50
51impl ReconstructableMessage for EncryptionReply {
52 fn is_reconstructable(&self) -> bool {
53 true
54 }
55}
56
57pub struct AsynchronousBackendMessage(BackendMessage);
59
60impl AsynchronousBackendMessage {
61 #[must_use]
63 pub const fn as_wire(&self) -> &BackendMessage {
64 &self.0
65 }
66
67 #[must_use]
69 pub fn into_wire(self) -> BackendMessage {
70 self.0
71 }
72}
73
74impl TryFrom<BackendMessage> for AsynchronousBackendMessage {
75 type Error = BackendMessage;
76
77 fn try_from(message: BackendMessage) -> Result<Self, Self::Error> {
78 if Demux::is_asynchronous(&message) {
79 Ok(Self(message))
80 } else {
81 Err(message)
82 }
83 }
84}
85
86pub enum TypedBackendMessage<ProtocolMessage> {
88 Protocol(ProtocolMessage),
90 Asynchronous(AsynchronousBackendMessage),
92}
93
94impl<ProtocolMessage> AsRef<BackendMessage> for TypedBackendMessage<ProtocolMessage>
95where
96 ProtocolMessage: AsRef<BackendMessage>,
97{
98 fn as_ref(&self) -> &BackendMessage {
99 match self {
100 Self::Protocol(message) => message.as_ref(),
101 Self::Asynchronous(message) => message.as_wire(),
102 }
103 }
104}
105
106impl<ProtocolMessage> TryFrom<BackendMessage> for TypedBackendMessage<ProtocolMessage>
107where
108 ProtocolMessage: TryFrom<BackendMessage, Error = BackendMessage>,
109{
110 type Error = BackendMessage;
111
112 fn try_from(message: BackendMessage) -> Result<Self, Self::Error> {
113 match AsynchronousBackendMessage::try_from(message) {
114 Ok(message) => Ok(Self::Asynchronous(message)),
115 Err(message) => ProtocolMessage::try_from(message).map(Self::Protocol),
116 }
117 }
118}
119
120impl<ProtocolMessage> From<TypedBackendMessage<ProtocolMessage>> for BackendMessage
121where
122 ProtocolMessage: Into<Self>,
123{
124 fn from(message: TypedBackendMessage<ProtocolMessage>) -> Self {
125 match message {
126 TypedBackendMessage::Protocol(message) => message.into(),
127 TypedBackendMessage::Asynchronous(message) => message.into_wire(),
128 }
129 }
130}
131
132macro_rules! projected_messages {
133 ($state:path, $internal:ty, $external:ty, $project_internal:path, $project_external:path) => {
134 impl AcceptsMessage<$internal> for $state {
135 fn accepts(&self, message: &$internal) -> bool {
136 $project_internal(*self, message).is_some()
137 }
138 }
139
140 impl AcceptsMessage<$external> for $state {
141 fn accepts(&self, message: &$external) -> bool {
142 $project_external(*self, message).is_some()
143 }
144 }
145 };
146}
147
148projected_messages!(
149 pre_startup::RuntimeState,
150 PreStartupMessage,
151 EncryptionReply,
152 pre_startup::project_internal,
153 pre_startup::project_external
154);
155projected_messages!(
156 server_pre_startup::RuntimeState,
157 EncryptionReply,
158 PreStartupMessage,
159 server_pre_startup::project_internal,
160 server_pre_startup::project_external
161);
162projected_messages!(
163 authentication::RuntimeState,
164 FrontendMessage,
165 BackendMessage,
166 authentication::project_internal,
167 authentication::project_external
168);
169projected_messages!(
170 server_authentication::RuntimeState,
171 BackendMessage,
172 FrontendMessage,
173 server_authentication::project_internal,
174 server_authentication::project_external
175);
176
177impl AcceptsMessage<FrontendMessage> for frontend::RuntimeState {
178 fn accepts(&self, message: &FrontendMessage) -> bool {
179 frontend::project_internal(*self, message).is_some()
180 }
181}
182
183impl AcceptsMessage<BackendMessage> for frontend::RuntimeState {
184 fn accepts(&self, message: &BackendMessage) -> bool {
185 Demux::is_asynchronous(message) || frontend::project_external(*self, message).is_some()
186 }
187}
188
189impl AcceptsMessage<BackendMessage> for backend::RuntimeState {
190 fn accepts(&self, message: &BackendMessage) -> bool {
191 Demux::is_asynchronous(message) || backend::project_internal(*self, message).is_some()
192 }
193}
194
195impl AcceptsMessage<FrontendMessage> for backend::RuntimeState {
196 fn accepts(&self, message: &FrontendMessage) -> bool {
197 backend::project_external(*self, message).is_some()
198 }
199}
200
201pub trait MessageMiddleware<Message, State> {
207 type Error;
209
210 fn intercept(&mut self, state: &mut State, message: Message) -> Result<Message, Self::Error>;
216}
217
218#[derive(Clone, Copy, Debug, Eq, PartialEq)]
220pub enum ClientRole {}
221
222#[derive(Clone, Copy, Debug, Eq, PartialEq)]
224pub enum ServerRole {}
225
226pub trait TypedPhase<Role, Wire> {
232 type ProtocolPhase;
234 type Message: AsRef<Wire> + TryFrom<Wire, Error = Wire> + Into<Wire>;
236}
237
238impl TypedPhase<ServerRole, BackendMessage> for crate::auth::Ready {
239 type ProtocolPhase = frontend::Ready;
240 type Message = TypedBackendMessage<frontend::ReadyExternalMessage>;
241}
242
243impl TypedPhase<ClientRole, FrontendMessage> for crate::auth::Ready {
244 type ProtocolPhase = backend::Ready;
245 type Message = backend::ReadyExternalMessage;
246}
247
248impl TypedPhase<ClientRole, PreStartupMessage> for crate::pre_startup::PreStartup {
249 type ProtocolPhase = server_pre_startup::PreStartup;
250 type Message = server_pre_startup::PreStartupExternalMessage;
251}
252
253impl TypedPhase<ServerRole, EncryptionReply> for crate::pre_startup::AwaitingSslReply {
254 type ProtocolPhase = pre_startup::AwaitingSslReply;
255 type Message = pre_startup::AwaitingSslReplyExternalMessage;
256}
257
258impl TypedPhase<ServerRole, EncryptionReply> for crate::pre_startup::AwaitingGssReply {
259 type ProtocolPhase = pre_startup::AwaitingGssReply;
260 type Message = pre_startup::AwaitingGssReplyExternalMessage;
261}
262
263macro_rules! typed_backend_phase {
264 ($connection:path => $protocol:path, $message:path) => {
265 impl TypedPhase<ServerRole, BackendMessage> for $connection {
266 type ProtocolPhase = $protocol;
267 type Message = TypedBackendMessage<$message>;
268 }
269 };
270}
271
272typed_backend_phase!(crate::auth::Auth => authentication::Auth, authentication::AuthExternalMessage);
273typed_backend_phase!(crate::auth::TokenChallenge => authentication::TokenChallenge, authentication::TokenChallengeExternalMessage);
274typed_backend_phase!(crate::auth::Sasl => authentication::Sasl, authentication::SaslExternalMessage);
275typed_backend_phase!(crate::auth::AwaitingAuthOk => authentication::AwaitingAuthOk, authentication::AwaitingAuthOkExternalMessage);
276typed_backend_phase!(crate::auth::AwaitingStartupReady => authentication::AwaitingStartupReady, authentication::AwaitingStartupReadyExternalMessage);
277typed_backend_phase!(crate::session::SimpleQuery => frontend::Simple, frontend::SimpleExternalMessage);
278typed_backend_phase!(crate::session::FunctionCalling => frontend::FunctionCalling, frontend::FunctionCallingExternalMessage);
279typed_backend_phase!(crate::session::Building => frontend::Building, frontend::BuildingExternalMessage);
280typed_backend_phase!(crate::session::BoundBuilding => frontend::BoundBuilding, frontend::BoundBuildingExternalMessage);
281typed_backend_phase!(crate::session::AwaitingReady => frontend::AwaitingReady, frontend::AwaitingReadyExternalMessage);
282typed_backend_phase!(crate::session::CopyIn => frontend::CopyIn, frontend::CopyInExternalMessage);
283typed_backend_phase!(crate::session::CopyOut => frontend::CopyOut, frontend::CopyOutExternalMessage);
284typed_backend_phase!(crate::session::CopyBoth => frontend::CopyBoth, frontend::CopyBothExternalMessage);
285typed_backend_phase!(crate::session::CopyBothClientDone => frontend::CopyBothClientDone, frontend::CopyBothClientDoneExternalMessage);
286typed_backend_phase!(crate::session::CopyBothServerDone => frontend::CopyBothServerDone, frontend::CopyBothServerDoneExternalMessage);
287typed_backend_phase!(crate::session::Draining => frontend::Draining, frontend::DrainingExternalMessage);
288typed_backend_phase!(crate::session::Resetting => frontend::Resetting, frontend::ResettingExternalMessage);
289typed_backend_phase!(crate::session::ResetComplete => frontend::ResetComplete, frontend::ResetCompleteExternalMessage);
290
291macro_rules! typed_frontend_phase {
292 ($connection:ty => $protocol:path, $message:path) => {
293 impl TypedPhase<ClientRole, FrontendMessage> for $connection {
294 type ProtocolPhase = $protocol;
295 type Message = $message;
296 }
297 };
298}
299
300typed_frontend_phase!(crate::server_auth::ServerAuth => server_authentication::Auth, server_authentication::AuthExternalMessage);
301typed_frontend_phase!(crate::server_auth::ServerPassword => server_authentication::PasswordResponse, server_authentication::PasswordResponseExternalMessage);
302typed_frontend_phase!(crate::server_auth::ServerSaslInitial => server_authentication::SaslInitial, server_authentication::SaslInitialExternalMessage);
303typed_frontend_phase!(crate::server_auth::ServerSasl => server_authentication::SaslResponse, server_authentication::SaslResponseExternalMessage);
304typed_frontend_phase!(crate::server_auth::ServerAuthResponse => server_authentication::TokenResponse, server_authentication::TokenResponseExternalMessage);
305typed_frontend_phase!(crate::server_auth::ServerStartupReady => server_authentication::StartupReady, server_authentication::StartupReadyExternalMessage);
306typed_frontend_phase!(crate::server_session::ServerBuilding => backend::Building, backend::BuildingExternalMessage);
307typed_frontend_phase!(crate::server_session::ServerExtendedError => backend::ExtendedError, backend::ExtendedErrorExternalMessage);
308typed_frontend_phase!(crate::server_session::ServerCopyIn<crate::server_session::CopySimple> => backend::SimpleCopyIn, backend::SimpleCopyInExternalMessage);
309typed_frontend_phase!(crate::server_session::ServerCopyIn<crate::server_session::CopyExtended> => backend::ExtendedCopyIn, backend::ExtendedCopyInExternalMessage);
310typed_frontend_phase!(crate::server_session::ServerCopyBoth<crate::server_session::CopySimple, crate::server_session::BothOpen> => backend::SimpleCopyBoth, backend::SimpleCopyBothExternalMessage);
311typed_frontend_phase!(crate::server_session::ServerCopyBoth<crate::server_session::CopyExtended, crate::server_session::BothOpen> => backend::ExtendedCopyBoth, backend::ExtendedCopyBothExternalMessage);
312typed_frontend_phase!(crate::server_session::ServerCopyBoth<crate::server_session::CopySimple, crate::server_session::BothServerDone> => backend::SimpleCopyBothServerDone, backend::SimpleCopyBothServerDoneExternalMessage);
313typed_frontend_phase!(crate::server_session::ServerCopyBoth<crate::server_session::CopyExtended, crate::server_session::BothServerDone> => backend::ExtendedCopyBothServerDone, backend::ExtendedCopyBothServerDoneExternalMessage);
314
315pub trait TypedMiddleware<Role, Phase, Message, State> {
322 type Error;
324
325 fn intercept_typed(
331 &mut self,
332 state: &mut State,
333 message: Message,
334 ) -> Result<Message, Self::Error>;
335}
336
337pub struct WireAdapter<Wire, Handler> {
344 handler: Handler,
345 _wire: PhantomData<fn(Wire) -> Wire>,
346}
347
348impl<Wire, Handler> WireAdapter<Wire, Handler> {
349 pub const fn new(handler: Handler) -> Self {
351 Self {
352 handler,
353 _wire: PhantomData,
354 }
355 }
356
357 pub fn into_inner(self) -> Handler {
359 self.handler
360 }
361}
362
363#[derive(Clone, Debug, Eq, PartialEq)]
365pub enum WireAdapterError<Error, Wire> {
366 Middleware(Error),
368 IllegalReplacement(Wire),
370}
371
372impl<Role, Phase, Message, State, Wire, Handler> TypedMiddleware<Role, Phase, Message, State>
373 for WireAdapter<Wire, Handler>
374where
375 Message: Into<Wire> + TryFrom<Wire, Error = Wire>,
376 Handler: MessageMiddleware<Wire, State>,
377{
378 type Error = WireAdapterError<Handler::Error, Wire>;
379
380 fn intercept_typed(
381 &mut self,
382 state: &mut State,
383 message: Message,
384 ) -> Result<Message, Self::Error> {
385 let message = self
386 .handler
387 .intercept(state, message.into())
388 .map_err(WireAdapterError::Middleware)?;
389 Message::try_from(message).map_err(WireAdapterError::IllegalReplacement)
390 }
391}
392
393impl<Role, Phase, Message, State, Error, F> TypedMiddleware<Role, Phase, Message, State> for F
394where
395 F: FnMut(&mut State, Message) -> Result<Message, Error>,
396{
397 type Error = Error;
398
399 fn intercept_typed(
400 &mut self,
401 state: &mut State,
402 message: Message,
403 ) -> Result<Message, Self::Error> {
404 self(state, message)
405 }
406}
407
408pub trait MessageMiddlewareExt: Sized {
410 fn then<Next>(self, next: Next) -> Then<Self, Next> {
413 Then {
414 first: self,
415 second: next,
416 }
417 }
418}
419
420impl<Handler> MessageMiddlewareExt for Handler {}
421
422impl<Message, State, Error, F> MessageMiddleware<Message, State> for F
423where
424 F: FnMut(&mut State, Message) -> Result<Message, Error>,
425{
426 type Error = Error;
427
428 fn intercept(&mut self, state: &mut State, message: Message) -> Result<Message, Self::Error> {
429 self(state, message)
430 }
431}
432
433#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
435pub struct Identity;
436
437impl<Message, State> MessageMiddleware<Message, State> for Identity {
438 type Error = Infallible;
439
440 fn intercept(&mut self, _state: &mut State, message: Message) -> Result<Message, Self::Error> {
441 Ok(message)
442 }
443}
444
445impl<Role, Phase, Message, State> TypedMiddleware<Role, Phase, Message, State> for Identity {
446 type Error = Infallible;
447
448 fn intercept_typed(
449 &mut self,
450 _state: &mut State,
451 message: Message,
452 ) -> Result<Message, Self::Error> {
453 Ok(message)
454 }
455}
456
457#[derive(Clone, Copy, Debug, Eq, PartialEq)]
459pub struct Then<First, Second> {
460 first: First,
461 second: Second,
462}
463
464impl<Message, State, First, Second> MessageMiddleware<Message, State> for Then<First, Second>
465where
466 First: MessageMiddleware<Message, State>,
467 Second: MessageMiddleware<Message, State>,
468{
469 type Error = ChainError<First::Error, Second::Error>;
470
471 fn intercept(&mut self, state: &mut State, message: Message) -> Result<Message, Self::Error> {
472 let message = self
473 .first
474 .intercept(state, message)
475 .map_err(ChainError::First)?;
476 self.second
477 .intercept(state, message)
478 .map_err(ChainError::Second)
479 }
480}
481
482impl<Role, Phase, Message, State, First, Second> TypedMiddleware<Role, Phase, Message, State>
483 for Then<First, Second>
484where
485 First: TypedMiddleware<Role, Phase, Message, State>,
486 Second: TypedMiddleware<Role, Phase, Message, State>,
487{
488 type Error = ChainError<First::Error, Second::Error>;
489
490 fn intercept_typed(
491 &mut self,
492 state: &mut State,
493 message: Message,
494 ) -> Result<Message, Self::Error> {
495 let message = self
496 .first
497 .intercept_typed(state, message)
498 .map_err(ChainError::First)?;
499 self.second
500 .intercept_typed(state, message)
501 .map_err(ChainError::Second)
502 }
503}
504
505#[derive(Clone, Copy, Debug, Eq, PartialEq)]
507pub enum ChainError<First, Second> {
508 First(First),
510 Second(Second),
512}
513
514#[derive(Clone, Copy, Debug, Eq, PartialEq)]
516pub enum InterceptError<Error, Message> {
517 Middleware(Error),
519 Invalid(Message),
521}
522
523#[derive(Debug)]
525pub enum ReceiveError<Error, Message> {
526 Io(io::Error),
528 Intercept(InterceptError<Error, Message>),
530}
531
532#[derive(Debug)]
534pub enum TypedReceiveError<Error, Wire> {
535 Io(io::Error),
537 Illegal(Wire),
539 Middleware(Error),
541 InvalidWire(Wire),
543}
544
545#[derive(Clone, Copy, Debug, Eq, PartialEq)]
547pub struct Middleware<State, Handler> {
548 state: State,
549 handler: Handler,
550}
551
552impl<State, Handler> Middleware<State, Handler> {
553 pub const fn new(state: State, handler: Handler) -> Self {
555 Self { state, handler }
556 }
557
558 pub const fn state(&self) -> &State {
560 &self.state
561 }
562
563 pub const fn state_mut(&mut self) -> &mut State {
565 &mut self.state
566 }
567
568 pub const fn handler(&self) -> &Handler {
570 &self.handler
571 }
572
573 pub const fn handler_mut(&mut self) -> &mut Handler {
575 &mut self.handler
576 }
577
578 pub fn into_parts(self) -> (State, Handler) {
580 (self.state, self.handler)
581 }
582
583 pub fn intercept<Message>(&mut self, message: Message) -> Result<Message, Handler::Error>
589 where
590 Handler: MessageMiddleware<Message, State>,
591 {
592 self.handler.intercept(&mut self.state, message)
593 }
594
595 pub fn intercept_typed<Role, Phase, Message>(
606 &mut self,
607 message: Message,
608 ) -> Result<Message, Handler::Error>
609 where
610 Handler: TypedMiddleware<Role, Phase, Message, State>,
611 {
612 self.handler.intercept_typed(&mut self.state, message)
613 }
614
615 pub fn intercept_checked<Message, ProtocolState>(
630 &mut self,
631 protocol_state: &ProtocolState,
632 message: Message,
633 ) -> Result<Message, InterceptError<Handler::Error, Message>>
634 where
635 Message: ReconstructableMessage,
636 Handler: MessageMiddleware<Message, State>,
637 ProtocolState: AcceptsMessage<Message>,
638 {
639 let message = self
640 .intercept(message)
641 .map_err(InterceptError::Middleware)?;
642 if message.is_reconstructable() && protocol_state.accepts(&message) {
643 Ok(message)
644 } else {
645 Err(InterceptError::Invalid(message))
646 }
647 }
648}
649
650#[cfg(test)]
651mod tests {
652 use std::convert::Infallible;
653
654 use bytes::Bytes;
655
656 use super::{
657 AcceptsMessage as _, ChainError, ClientRole, Identity, InterceptError,
658 MessageMiddlewareExt as _, Middleware, WireAdapter,
659 };
660 use crate::{
661 codec::{FrontendMessage, Parse},
662 grammar::{backend, server_authentication, server_pre_startup},
663 pre_startup::PreStartupMessage,
664 };
665
666 #[test]
667 fn identity_is_a_no_op() {
668 let mut middleware = Middleware::new((), Identity);
669 assert_eq!(
670 middleware.intercept(String::from("message")),
671 Ok(String::from("message"))
672 );
673 }
674
675 #[test]
676 fn closure_can_replace_message_and_accumulate_state() {
677 let mut middleware =
678 Middleware::new(Vec::new(), |seen: &mut Vec<String>, message: String| {
679 seen.push(message.clone());
680 Ok::<_, &'static str>(message.to_uppercase())
681 });
682
683 assert_eq!(
684 middleware.intercept(String::from("hello")),
685 Ok(String::from("HELLO"))
686 );
687 assert_eq!(middleware.state(), &[String::from("hello")]);
688 }
689
690 #[test]
691 fn typed_closure_replaces_only_within_its_role_and_phase() {
692 let handler = |seen: &mut usize, _message: backend::ReadyExternalMessage| {
693 *seen += 1;
694 backend::ReadyExternalMessage::try_from(FrontendMessage::Terminate)
695 .map_err(|_| "terminate must be legal while ready")
696 };
697 let mut middleware = Middleware::new(0, handler);
698 let Ok(input) = backend::ReadyExternalMessage::try_from(FrontendMessage::Query(
699 Bytes::from_static(b"select 1"),
700 )) else {
701 panic!("query must be legal while ready");
702 };
703
704 let output = middleware
705 .intercept_typed::<ClientRole, backend::Ready, _>(input)
706 .expect("middleware accepts the message");
707
708 assert_eq!(output.event(), backend::Event::Terminate);
709 assert!(matches!(output.into_wire(), FrontendMessage::Terminate));
710 assert_eq!(*middleware.state(), 1);
711 }
712
713 #[test]
714 fn typed_chain_is_ordered_and_threads_shared_state() {
715 let first = |order: &mut Vec<&'static str>, message: backend::ReadyExternalMessage| {
716 order.push("first");
717 Ok::<_, Infallible>(message)
718 };
719 let second = |order: &mut Vec<&'static str>, message: backend::ReadyExternalMessage| {
720 order.push("second");
721 Ok::<_, Infallible>(message)
722 };
723 let mut middleware = Middleware::new(Vec::new(), first.then(second));
724 let Ok(input) = backend::ReadyExternalMessage::try_from(FrontendMessage::Terminate) else {
725 panic!("terminate must be legal while ready");
726 };
727
728 let output = middleware
729 .intercept_typed::<ClientRole, backend::Ready, _>(input)
730 .expect("both typed stages accept the message");
731
732 assert_eq!(output.event(), backend::Event::Terminate);
733 assert_eq!(middleware.state(), &["first", "second"]);
734 }
735
736 #[test]
737 fn wire_adapter_passes_unhandled_families_through_multiple_phases() {
738 let handler = |seen: &mut usize, message: FrontendMessage| {
739 *seen += 1;
740 Ok::<_, Infallible>(message)
741 };
742 let mut middleware = Middleware::new(0, WireAdapter::new(handler));
743
744 let Ok(ready) = backend::ReadyExternalMessage::try_from(FrontendMessage::Terminate) else {
745 panic!("terminate must be legal while ready");
746 };
747 middleware
748 .intercept_typed::<ClientRole, backend::Ready, _>(ready)
749 .expect("ready pass-through");
750
751 let Ok(building) = backend::BuildingExternalMessage::try_from(FrontendMessage::Sync) else {
752 panic!("sync must be legal while building");
753 };
754 middleware
755 .intercept_typed::<ClientRole, backend::Building, _>(building)
756 .expect("building pass-through");
757
758 assert_eq!(*middleware.state(), 2);
759 }
760
761 #[test]
762 fn chain_passes_replacement_to_next_stage_in_order() {
763 let first = |order: &mut Vec<&'static str>, mut message: String| {
764 order.push("first");
765 message.push('1');
766 Ok::<_, &'static str>(message)
767 };
768 let second = |order: &mut Vec<&'static str>, mut message: String| {
769 order.push("second");
770 message.push('2');
771 Ok::<_, u8>(message)
772 };
773 let mut middleware = Middleware::new(Vec::new(), first.then(second));
774
775 assert_eq!(
776 middleware.intercept(String::from("m")),
777 Ok(String::from("m12"))
778 );
779 assert_eq!(middleware.state(), &["first", "second"]);
780 }
781
782 #[test]
783 fn chain_stops_after_first_error() {
784 let first = |calls: &mut usize, _message: String| {
785 *calls += 1;
786 Err::<String, _>("rejected")
787 };
788 let second = |calls: &mut usize, message: String| {
789 *calls += 1;
790 Ok::<_, u8>(message)
791 };
792 let mut middleware = Middleware::new(0, first.then(second));
793
794 assert_eq!(
795 middleware.intercept(String::from("message")),
796 Err(ChainError::First("rejected"))
797 );
798 assert_eq!(*middleware.state(), 1);
799 }
800
801 #[test]
802 fn checked_interception_accepts_a_legal_replacement() {
803 let mut middleware = Middleware::new((), |_state: &mut (), _message: FrontendMessage| {
804 Ok::<_, Infallible>(FrontendMessage::Terminate)
805 });
806
807 assert_eq!(
808 middleware.intercept_checked(
809 &backend::RuntimeState::Ready,
810 FrontendMessage::Query(Bytes::from_static(b"select 1")),
811 ),
812 Ok(FrontendMessage::Terminate)
813 );
814 }
815
816 #[test]
817 fn checked_interception_returns_an_illegal_replacement() {
818 let replacement = FrontendMessage::Parse(Parse {
819 statement: Bytes::new(),
820 query: Bytes::from_static(b"select 2"),
821 parameter_types: Vec::new(),
822 });
823 let expected = replacement.clone();
824 let mut middleware =
825 Middleware::new((), move |_state: &mut (), _message: FrontendMessage| {
826 Ok::<_, Infallible>(replacement.clone())
827 });
828
829 assert_eq!(
830 middleware.intercept_checked(
831 &backend::RuntimeState::Simple,
832 FrontendMessage::Query(Bytes::from_static(b"select 1")),
833 ),
834 Err(InterceptError::Invalid(expected))
835 );
836 }
837
838 #[test]
839 fn generated_states_cover_authentication_extended_query_copy_and_replication() {
840 let password = FrontendMessage::PasswordResponse(Bytes::from_static(b"secret"));
841 assert!(server_authentication::RuntimeState::PasswordResponse.accepts(&password));
842 assert!(
843 !server_authentication::RuntimeState::PasswordResponse
844 .accepts(&FrontendMessage::Query(Bytes::from_static(b"select 1")))
845 );
846
847 let parse = FrontendMessage::Parse(Parse {
848 statement: Bytes::from_static(b"statement"),
849 query: Bytes::from_static(b"select 1"),
850 parameter_types: Vec::new(),
851 });
852 assert!(backend::RuntimeState::Building.accepts(&parse));
853 assert!(
854 !backend::RuntimeState::Building
855 .accepts(&FrontendMessage::Query(Bytes::from_static(b"select 1")))
856 );
857 assert!(backend::RuntimeState::ExtendedError.accepts(&parse));
858 assert!(backend::RuntimeState::ExtendedError.accepts(&FrontendMessage::Sync));
859
860 let copy = FrontendMessage::CopyData(Bytes::from_static(b"data"));
861 assert!(backend::RuntimeState::SimpleCopyIn.accepts(©));
862 assert!(backend::RuntimeState::ExtendedCopyBoth.accepts(©));
863 assert!(
864 !backend::RuntimeState::ExtendedCopyBoth
865 .accepts(&FrontendMessage::Query(Bytes::from_static(b"select 1")))
866 );
867
868 assert!(
869 server_pre_startup::RuntimeState::PreStartup.accepts(&PreStartupMessage::SslRequest)
870 );
871 assert!(
872 !server_pre_startup::RuntimeState::SslDecision.accepts(&PreStartupMessage::SslRequest)
873 );
874 }
875
876 #[test]
877 fn checked_interception_rejects_an_unencodable_message() {
878 let invalid = FrontendMessage::Parse(Parse {
879 statement: Bytes::from_static(b"invalid\0name"),
880 query: Bytes::from_static(b"select 1"),
881 parameter_types: Vec::new(),
882 });
883 let expected = invalid.clone();
884 let mut middleware = Middleware::new((), move |_state: &mut (), _message| {
885 Ok::<_, Infallible>(invalid.clone())
886 });
887
888 assert_eq!(
889 middleware.intercept_checked(&backend::RuntimeState::Ready, FrontendMessage::Terminate),
890 Err(InterceptError::Invalid(expected))
891 );
892 }
893}