1use std::fmt;
25use std::marker::PhantomData;
26use std::sync::OnceLock;
27
28use aws_smithy_eventstream::error::Error;
29use aws_smithy_eventstream::frame::{
30 write_message_to, MarshallMessage, NoOpSigner, UnmarshallMessage, UnmarshalledMessage,
31};
32use aws_smithy_eventstream::smithy as expect_fns;
33use aws_smithy_http::event_stream::{EventStreamSender, InitialMessageType};
34use aws_smithy_schema::serde::{SerdeError, SerializableStruct, ShapeDeserializer, ShapeSerializer};
35use aws_smithy_schema::{intern_header_name, Schema, ShapeType};
36use aws_smithy_types::event_stream::{Header, HeaderValue, Message};
37use aws_smithy_types::str_bytes::StrBytes;
38use aws_smithy_types::{BigDecimal, BigInteger, Blob, DateTime, Document};
39use bytes::Bytes;
40
41use crate::body::{boxed, BoxBody};
42use crate::schema::{DeserializeError, EventStreamFraming, SharedServerProtocol};
43
44pub async fn apply_initial_request<Fut, Err>(
60 recv_initial: impl FnOnce(InitialMessageType) -> Fut,
61 protocol: &SharedServerProtocol,
62 apply: impl FnOnce(&mut dyn ShapeDeserializer) -> Result<(), SerdeError>,
63) -> Result<(), DeserializeError>
64where
65 Fut: std::future::Future<Output = Result<Option<Message>, Err>>,
66 Err: fmt::Display,
67{
68 let capability = protocol
69 .event_stream_framing()
70 .ok_or_else(|| DeserializeError::Serde(SerdeError::custom(NO_EVENT_STREAM_SUPPORT)))?;
71 if !capability.initial_messages_in_frames {
72 return Ok(());
73 }
74 match recv_initial(InitialMessageType::Request).await {
75 Ok(Some(initial)) => {
76 let mut deser = capability.payload_codec.create_deserializer(&initial.payload()[..]);
77 apply(&mut *deser)?;
78 Ok(())
79 }
80 Ok(None) => Ok(()),
81 Err(err) => Err(DeserializeError::InitialRequestFrame(err.to_string())),
82 }
83}
84
85#[non_exhaustive]
89#[derive(Clone, Copy, Debug, PartialEq, Eq)]
90pub enum InitialResponsePolicy {
91 Send,
93 Omit,
95}
96
97pub fn event_stream_response_body<T, E>(
106 output_schema: &Schema<'_>,
107 output: &dyn SerializableStruct,
108 events: EventStreamSender<T, E>,
109 marshaller: impl MarshallMessage<Input = T> + Send + Sync + 'static,
110 error_marshaller: impl MarshallMessage<Input = E> + Send + Sync + 'static,
111 protocol: &SharedServerProtocol,
112 initial_response: InitialResponsePolicy,
113) -> Result<BoxBody, SerdeError>
114where
115 T: Send + Sync + 'static,
116 E: std::error::Error + Send + Sync + 'static,
117{
118 let capability = protocol
119 .event_stream_framing()
120 .ok_or_else(|| SerdeError::custom(NO_EVENT_STREAM_SUPPORT))?;
121 let signer = NoOpSigner {};
122 if initial_response == InitialResponsePolicy::Send {
123 use futures_util::StreamExt;
124 let payload = if capability.initial_messages_in_frames {
125 let mut ser = capability.payload_codec.create_serializer();
126 ser.write_struct(output_schema, output)?;
127 Bytes::from(ser.finish_boxed())
128 } else {
129 Bytes::from_static(capability.unset_initial_response_payload)
130 };
131 let initial_message = Message::new_from_parts(
132 vec![
133 Header::new(":message-type", HeaderValue::String("event".into())),
134 Header::new(":event-type", HeaderValue::String("initial-response".into())),
135 Header::new(
136 ":content-type",
137 HeaderValue::String(capability.media_type.to_string().into()),
138 ),
139 ],
140 payload,
141 );
142 let mut initial_frame = Vec::new();
146 write_message_to(&initial_message, &mut initial_frame)
147 .map_err(|err| SerdeError::custom(format!("failed to write the initial-response frame: {err}")))?;
148 let initial = futures_util::stream::iter([Ok(http_body::Frame::data(Bytes::from(initial_frame)))]);
149 let adapter = events.into_body_stream(marshaller, error_marshaller, signer);
150 Ok(boxed(http_body_util::StreamBody::new(initial.chain(adapter))))
151 } else {
152 let adapter = events.into_body_stream(marshaller, error_marshaller, signer);
153 Ok(boxed(http_body_util::StreamBody::new(adapter)))
154 }
155}
156
157pub struct SchemaEventMarshaller<T> {
166 protocol: SharedServerProtocol,
167 variants: OnceLock<Box<[OnceLock<FrameStrings>]>>,
170 _phantom: PhantomData<fn() -> T>,
171}
172
173impl<T> SchemaEventMarshaller<T> {
174 pub fn new(protocol: SharedServerProtocol) -> Self {
176 Self {
177 protocol,
178 variants: OnceLock::new(),
179 _phantom: PhantomData,
180 }
181 }
182}
183
184impl<T> fmt::Debug for SchemaEventMarshaller<T> {
185 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
186 f.debug_struct("SchemaEventMarshaller")
187 .field("protocol", &self.protocol)
188 .finish()
189 }
190}
191
192impl<T: SerializableStruct> MarshallMessage for SchemaEventMarshaller<T> {
193 type Input = T;
194
195 fn marshall(&self, input: Self::Input) -> Result<Message, Error> {
196 let variants = match self.variants.get() {
199 Some(variants) => variants,
200 None => {
201 capability_or_marshalling_error(&self.protocol)?;
202 self.variants
203 .get_or_init(|| input.schema().members().iter().map(|_| OnceLock::new()).collect())
204 }
205 };
206 let mut serializer = UnionVariantSerializer {
207 framing: Framing::Deferred(&self.protocol),
208 kind: FrameKind::Event,
209 variants,
210 message: None,
211 };
212 input
213 .serialize_members(&mut serializer)
214 .map_err(|err| Error::marshalling(format!("{err}")))?;
215 serializer
216 .message
217 .ok_or_else(|| Error::marshalling("event stream union serialized no variant".to_owned()))
218 }
219}
220
221pub trait SerializableEventError {
226 fn variant(&self) -> (&'static str, &Schema<'_>, &dyn SerializableStruct);
228}
229
230pub struct SchemaEventErrorMarshaller<E> {
232 protocol: SharedServerProtocol,
233 _phantom: PhantomData<fn() -> E>,
234}
235
236impl<E> SchemaEventErrorMarshaller<E> {
237 pub fn new(protocol: SharedServerProtocol) -> Self {
239 Self {
240 protocol,
241 _phantom: PhantomData,
242 }
243 }
244}
245
246impl<E> fmt::Debug for SchemaEventErrorMarshaller<E> {
247 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
248 f.debug_struct("SchemaEventErrorMarshaller")
249 .field("protocol", &self.protocol)
250 .finish()
251 }
252}
253
254impl<E: SerializableEventError> MarshallMessage for SchemaEventErrorMarshaller<E> {
255 type Input = E;
256
257 fn marshall(&self, input: Self::Input) -> Result<Message, Error> {
258 let capability = capability_or_marshalling_error(&self.protocol)?;
259 let (exception_type, schema, value) = input.variant();
260 build_frame(
261 Framing::Known(capability),
262 exception_type,
263 schema,
264 value,
265 FrameKind::Exception,
266 None,
267 )
268 .map_err(|err| Error::marshalling(format!("{err}")))
269 }
270}
271
272#[derive(Debug)]
277pub struct NoModeledEventErrorMarshaller {
278 protocol: SharedServerProtocol,
279}
280
281impl NoModeledEventErrorMarshaller {
282 pub fn new(protocol: SharedServerProtocol) -> Self {
285 Self { protocol }
286 }
287}
288
289impl MarshallMessage for NoModeledEventErrorMarshaller {
290 type Input = aws_smithy_http::event_stream::MessageStreamError;
291
292 fn marshall(&self, _input: Self::Input) -> Result<Message, Error> {
293 capability_or_marshalling_error(&self.protocol)?;
294 let headers = vec![Header::new(":message-type", HeaderValue::String("exception".into()))];
295 Ok(Message::new_from_parts(headers, Bytes::new()))
296 }
297}
298
299pub trait DeserializableEventStream: Sized {
309 type Error;
313
314 fn deserialize_event(event_type: &str, frame: &EventFrame<'_>) -> Result<Option<Self>, Error>;
316
317 fn deserialize_error(exception_type: &str, frame: &EventFrame<'_>) -> Result<Option<Self::Error>, Error>;
319}
320
321pub struct SchemaEventUnmarshaller<T> {
323 protocol: SharedServerProtocol,
324 _phantom: PhantomData<fn() -> T>,
325}
326
327impl<T> SchemaEventUnmarshaller<T> {
328 pub fn new(protocol: SharedServerProtocol) -> Self {
330 Self {
331 protocol,
332 _phantom: PhantomData,
333 }
334 }
335}
336
337impl<T> fmt::Debug for SchemaEventUnmarshaller<T> {
338 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
339 f.debug_struct("SchemaEventUnmarshaller")
340 .field("protocol", &self.protocol)
341 .finish()
342 }
343}
344
345impl<T: DeserializableEventStream> UnmarshallMessage for SchemaEventUnmarshaller<T> {
346 type Output = T;
347 type Error = T::Error;
348
349 fn unmarshall(&self, message: &Message) -> Result<UnmarshalledMessage<Self::Output, Self::Error>, Error> {
350 let capability = self
351 .protocol
352 .event_stream_framing()
353 .ok_or_else(|| Error::unmarshalling(NO_EVENT_STREAM_SUPPORT))?;
354 let response_headers = expect_fns::parse_response_headers(message)?;
355 let kind = match response_headers.message_type.as_str() {
356 "event" => FrameKind::Event,
357 "exception" => FrameKind::Exception,
358 value => return Err(Error::unmarshalling(format!("unrecognized :message-type: {value}"))),
359 };
360 let frame = EventFrame {
361 message,
362 capability,
363 kind,
364 content_type: response_headers.content_type,
365 };
366 match kind {
367 FrameKind::Event => {
368 let event_type = response_headers.smithy_type.as_str();
369 match T::deserialize_event(event_type, &frame)? {
370 Some(event) => Ok(UnmarshalledMessage::Event(event)),
371 None => Err(Error::unmarshalling(format!("unrecognized :event-type: {event_type}"))),
372 }
373 }
374 FrameKind::Exception => {
375 let exception_type = response_headers.smithy_type.as_str();
376 match T::deserialize_error(exception_type, &frame)? {
377 Some(error) => Ok(UnmarshalledMessage::Error(error)),
378 None => Err(Error::unmarshalling(format!(
379 "unrecognized exception: {exception_type}"
380 ))),
381 }
382 }
383 }
384 }
385}
386
387pub struct EventFrame<'a> {
389 message: &'a Message,
390 capability: EventStreamFraming<'a>,
391 kind: FrameKind,
392 content_type: Option<&'a StrBytes>,
393}
394
395impl<'a> EventFrame<'a> {
396 pub fn new(message: &'a Message, capability: EventStreamFraming<'a>) -> Self {
401 let last_string_header = |name: &str| {
402 message
403 .headers()
404 .iter()
405 .rfind(|header| header.name().as_str() == name)
406 .and_then(|header| header.value().as_string().ok())
407 };
408 let kind = match last_string_header(":message-type").map(StrBytes::as_str) {
409 Some("exception") => FrameKind::Exception,
410 _ => FrameKind::Event,
411 };
412 Self {
413 message,
414 capability,
415 kind,
416 content_type: last_string_header(":content-type"),
417 }
418 }
419
420 pub fn deserializer(&self) -> EventFrameDeserializer<'a> {
423 EventFrameDeserializer {
424 message: self.message,
425 capability: self.capability,
426 kind: self.kind,
427 content_type: self.content_type,
428 }
429 }
430}
431
432pub struct EventFrameDeserializer<'a> {
438 message: &'a Message,
439 capability: EventStreamFraming<'a>,
440 kind: FrameKind,
441 content_type: Option<&'a StrBytes>,
442}
443
444impl EventFrameDeserializer<'_> {
445 fn check_content_type(&self, expected: &str) -> Result<(), SerdeError> {
446 let content_type = self.content_type.map(StrBytes::as_str).unwrap_or_default();
447 if content_type != expected {
448 return Err(SerdeError::custom(format!(
449 "expected :content-type to be '{expected}', but was '{content_type}'"
450 )));
451 }
452 Ok(())
453 }
454}
455
456fn wrapped_xml_error_element(payload: &[u8]) -> Result<&[u8], SerdeError> {
460 let mut document =
461 aws_smithy_xml::decode::Document::try_from(payload).map_err(|err| SerdeError::custom(err.to_string()))?;
462 let root = document
463 .next_start_element()
464 .ok_or_else(|| SerdeError::custom("no root found searching for an Error"))?;
465 if !root.matches("ErrorResponse") {
466 return Err(SerdeError::custom("expected ErrorResponse as root"));
467 }
468 aws_smithy_xml::codec::find_depth2_element_slice_by(payload, |name| name == "Error")
469 .ok_or_else(|| SerdeError::custom("no error found inside of ErrorResponse"))
470}
471
472fn unwrapped_xml_error_element(payload: &[u8]) -> Result<&[u8], SerdeError> {
475 let mut document =
476 aws_smithy_xml::decode::Document::try_from(payload).map_err(|err| SerdeError::custom(err.to_string()))?;
477 let root = document
478 .root_element()
479 .map_err(|err| SerdeError::custom(err.to_string()))?;
480 if !root.start_el().matches("Error") {
481 return Err(SerdeError::custom("expected error as root"));
482 }
483 Ok(payload)
484}
485
486macro_rules! frames_deserialize_structs {
487 ($($fn_name:ident() -> $result_type:ty,)+) => {
488 $(fn $fn_name(&mut self, _schema: &Schema<'_>) -> Result<$result_type, SerdeError> {
489 Err(SerdeError::unsupported(
490 "an event stream frame deserializes a structure",
491 ))
492 })+
493 };
494}
495
496impl ShapeDeserializer for EventFrameDeserializer<'_> {
497 fn read_struct(
498 &mut self,
499 schema: &Schema<'_>,
500 state: &mut dyn FnMut(&Schema<'_>, &mut dyn ShapeDeserializer) -> Result<(), SerdeError>,
501 ) -> Result<(), SerdeError> {
502 let members = schema.members();
503 if members.is_empty() {
507 return Ok(());
508 }
509 if let Some(codec) = self
510 .capability
511 .xml_exception_codec
512 .filter(|_| matches!(self.kind, FrameKind::Exception))
513 {
514 let payload = &self.message.payload()[..];
517 if payload.is_empty() {
518 return Ok(());
519 }
520 let error = if self.capability.xml_exceptions_wrapped {
521 wrapped_xml_error_element(payload)?
522 } else {
523 unwrapped_xml_error_element(payload)?
524 };
525 return codec.create_deserializer(error).read_struct(schema, state);
526 }
527 let payload_member = members.iter().copied().find(|m| m.event_payload().is_some());
528 let has_header_members = members.iter().any(|m| m.event_header().is_some());
529 if payload_member.is_none() && !has_header_members {
530 let mut deser = self
532 .capability
533 .payload_codec
534 .create_deserializer(&self.message.payload()[..]);
535 return deser.read_struct(schema, state);
536 }
537
538 if has_header_members {
539 for header in self.message.headers() {
540 let name = header.name().as_str();
541 let member = members
542 .iter()
543 .copied()
544 .find(|m| m.event_header().is_some() && m.member_name() == Some(name));
545 match member {
546 Some(member) => {
547 state(member, &mut EventHeaderDeserializer { header })?;
548 }
549 None if !name.starts_with(':') => {
551 tracing::trace!("Unrecognized event stream message header: {}", name);
552 }
553 None => {}
554 }
555 }
556 }
557
558 if let Some(member) = payload_member {
559 match member.shape_type() {
560 ShapeType::Blob => {
561 self.check_content_type("application/octet-stream")?;
562 state(
563 member,
564 &mut RawPayloadDeserializer {
565 payload: self.message.payload(),
566 },
567 )?;
568 }
569 ShapeType::String => {
570 self.check_content_type("text/plain")?;
571 state(
572 member,
573 &mut RawPayloadDeserializer {
574 payload: self.message.payload(),
575 },
576 )?;
577 }
578 _ => {
579 let mut deser = self
580 .capability
581 .payload_codec
582 .create_deserializer(&self.message.payload()[..]);
583 state(member, &mut *deser)?;
584 }
585 }
586 } else if members
587 .iter()
588 .any(|m| m.event_header().is_none() && m.event_payload().is_none())
589 {
590 if self.message.payload().is_empty() {
593 return Ok(());
594 }
595 let mut deser = self
599 .capability
600 .payload_codec
601 .create_deserializer(&self.message.payload()[..]);
602 deser.read_struct(schema, state)?;
603 }
604 Ok(())
605 }
606
607 fn read_list(
608 &mut self,
609 _schema: &Schema<'_>,
610 _state: &mut dyn FnMut(&mut dyn ShapeDeserializer) -> Result<(), SerdeError>,
611 ) -> Result<(), SerdeError> {
612 Err(SerdeError::unsupported(
613 "an event stream frame deserializes a structure",
614 ))
615 }
616
617 fn read_map(
618 &mut self,
619 _schema: &Schema<'_>,
620 _state: &mut dyn FnMut(String, &mut dyn ShapeDeserializer) -> Result<(), SerdeError>,
621 ) -> Result<(), SerdeError> {
622 Err(SerdeError::unsupported(
623 "an event stream frame deserializes a structure",
624 ))
625 }
626
627 frames_deserialize_structs!(
628 read_boolean() -> bool,
629 read_byte() -> i8,
630 read_short() -> i16,
631 read_integer() -> i32,
632 read_long() -> i64,
633 read_float() -> f32,
634 read_double() -> f64,
635 read_big_integer() -> BigInteger,
636 read_big_decimal() -> BigDecimal,
637 read_string() -> String,
638 read_blob() -> Blob,
639 read_timestamp() -> DateTime,
640 read_document() -> Document,
641 );
642
643 fn is_null(&self) -> bool {
644 false
645 }
646
647 fn container_size(&self) -> Option<usize> {
648 None
649 }
650}
651
652const NO_EVENT_STREAM_SUPPORT: &str = "protocol does not support event streams";
653
654fn capability_or_marshalling_error(protocol: &SharedServerProtocol) -> Result<EventStreamFraming<'_>, Error> {
655 protocol
656 .event_stream_framing()
657 .ok_or_else(|| Error::marshalling(NO_EVENT_STREAM_SUPPORT.to_owned()))
658}
659
660#[derive(Clone, Copy)]
665enum Framing<'a> {
666 Known(EventStreamFraming<'a>),
667 Deferred(&'a SharedServerProtocol),
668}
669
670impl<'a> Framing<'a> {
671 fn get(self) -> Result<EventStreamFraming<'a>, SerdeError> {
672 match self {
673 Self::Known(capability) => Ok(capability),
674 Self::Deferred(protocol) => protocol
675 .event_stream_framing()
676 .ok_or_else(|| SerdeError::custom(NO_EVENT_STREAM_SUPPORT)),
677 }
678 }
679}
680
681#[derive(Clone, Copy)]
682enum FrameKind {
683 Event,
684 Exception,
685}
686
687fn content_type(payload_type: Option<ShapeType>, media_type: &str) -> StrBytes {
690 match payload_type {
691 Some(ShapeType::Blob) => "application/octet-stream".into(),
692 Some(ShapeType::String) => "text/plain".into(),
693 _ => media_type.to_owned().into(),
694 }
695}
696
697struct FrameStrings {
704 event_type: &'static str,
705 content_type: &'static str,
706 header_names: Box<[Option<&'static str>]>,
708}
709
710impl FrameStrings {
711 fn new(event_type: &str, schema: &Schema<'_>, capability: EventStreamFraming<'_>) -> Self {
712 let members = schema.members();
713 let payload_type = members
714 .iter()
715 .find(|m| m.event_payload().is_some())
716 .map(|m| m.shape_type());
717 let mut header_names = vec![None; members.len()];
718 for member in members.iter().filter(|m| m.event_header().is_some()) {
719 if let (Some(index), Some(name)) = (member.member_index(), member.member_name()) {
720 if let Some(slot) = header_names.get_mut(index) {
721 *slot = Some(intern_header_name(name));
722 }
723 }
724 }
725 Self {
726 event_type: intern_header_name(event_type),
727 content_type: intern_header_name(content_type(payload_type, capability.media_type).as_str()),
728 header_names: header_names.into(),
729 }
730 }
731}
732
733fn push_static_header(headers: &mut Vec<Header>, name: &'static str, value: &'static str) {
739 headers.push(Header::new(name, HeaderValue::String(value.into())));
740}
741
742#[inline]
746fn build_frame(
747 framing: Framing<'_>,
748 event_type: &str,
749 schema: &Schema<'_>,
750 value: &dyn SerializableStruct,
751 kind: FrameKind,
752 strings: Option<&FrameStrings>,
753) -> Result<Message, SerdeError> {
754 let (message_type, type_header) = match kind {
755 FrameKind::Event => ("event", ":event-type"),
756 FrameKind::Exception => ("exception", ":exception-type"),
757 };
758 let mut headers = Vec::with_capacity(4);
761 headers.push(Header::new(":message-type", HeaderValue::String(message_type.into())));
762 match strings {
763 Some(strings) if strings.event_type == event_type => {
764 push_static_header(&mut headers, type_header, strings.event_type)
765 }
766 _ => headers.push(Header::new(
767 type_header,
768 HeaderValue::String(StrBytes::copy_from_str(event_type)),
769 )),
770 }
771 let push_content_type = |headers: &mut Vec<Header>, payload_type| -> Result<(), SerdeError> {
772 match strings {
773 Some(strings) => push_static_header(headers, ":content-type", strings.content_type),
774 None => headers.push(Header::new(
775 ":content-type",
776 HeaderValue::String(content_type(payload_type, framing.get()?.media_type)),
777 )),
778 }
779 Ok(())
780 };
781 let payload_member = schema.members().iter().copied().find(|m| m.event_payload().is_some());
782 let has_header_members = schema.members().iter().any(|m| m.event_header().is_some());
783
784 if payload_member.is_none() && !has_header_members {
785 let capability = framing.get()?;
788 push_content_type(&mut headers, None)?;
789 let framed = capability
790 .exception_discriminator
791 .filter(|_| matches!(kind, FrameKind::Exception))
792 .map(|discriminator| discriminator.frame(schema, value));
793 let value = framed
794 .as_ref()
795 .map(|framed| framed as &dyn SerializableStruct)
796 .unwrap_or(value);
797 let projected = ExceptionBody(value);
798 let value = if capability.exception_http_bindings && matches!(kind, FrameKind::Exception) {
799 &projected as &dyn SerializableStruct
800 } else {
801 value
802 };
803 let mut ser = capability.payload_codec.create_serializer();
804 ser.write_struct(schema, value)?;
805 let payload = Bytes::from(ser.finish_boxed());
806 return Ok(Message::new_from_parts(headers, payload));
807 }
808
809 let mut payload = None;
810 {
811 let mut member_ser = EventMemberSerializer {
812 framing,
813 header_names: strings.map(|strings| &strings.header_names[..]).unwrap_or_default(),
814 headers: &mut headers,
815 payload: &mut payload,
816 };
817 value.serialize_members(&mut member_ser)?;
818 }
819 match payload_member {
820 Some(member) => {
821 push_content_type(&mut headers, Some(member.shape_type()))?;
824 Ok(Message::new_from_parts(headers, payload.unwrap_or_default()))
825 }
826 None => Ok(Message::new_from_parts(headers, Bytes::new())),
829 }
830}
831
832struct ExceptionBody<'a>(&'a dyn SerializableStruct);
834impl SerializableStruct for ExceptionBody<'_> {
835 fn schema(&self) -> &Schema<'_> {
836 self.0.schema()
837 }
838 fn serialize_members(&self, serializer: &mut dyn ShapeSerializer) -> Result<(), SerdeError> {
839 self.0.serialize_members(&mut ExceptionBodySerializer(serializer))
840 }
841}
842struct ExceptionBodySerializer<'a>(&'a mut dyn ShapeSerializer);
843macro_rules! exception_body_members {
844 ($($method:ident($($argument:ident: $ty:ty),*);)*) => {
845 $(fn $method(&mut self, schema: &Schema<'_>, $($argument: $ty),*) -> Result<(), SerdeError> {
846 if schema.http_header().is_some() || schema.http_prefix_headers().is_some() || schema.http_response_code().is_some() {
847 Ok(())
848 } else {
849 self.0.$method(schema, $($argument),*)
850 }
851 })*
852 };
853}
854impl ShapeSerializer for ExceptionBodySerializer<'_> {
855 exception_body_members! {
856 write_struct(value: &dyn SerializableStruct);
857 write_list(elements: &dyn Fn(&mut dyn ShapeSerializer) -> Result<(), SerdeError>);
858 write_map(entries: &dyn Fn(&mut dyn ShapeSerializer) -> Result<(), SerdeError>);
859 write_boolean(value: bool);
860 write_byte(value: i8);
861 write_short(value: i16);
862 write_integer(value: i32);
863 write_long(value: i64);
864 write_float(value: f32);
865 write_double(value: f64);
866 write_big_integer(value: &BigInteger);
867 write_big_decimal(value: &BigDecimal);
868 write_string(value: &str);
869 write_blob(value: Blob);
870 write_timestamp(value: &DateTime);
871 write_document(value: &Document);
872 write_null();
873 }
874}
875
876struct UnionVariantSerializer<'a> {
879 framing: Framing<'a>,
880 kind: FrameKind,
881 variants: &'a [OnceLock<FrameStrings>],
882 message: Option<Message>,
883}
884
885macro_rules! not_a_union_variant {
886 ($($fn_name:ident($value_type:ty),)+) => {
887 $(fn $fn_name(&mut self, _schema: &Schema<'_>, _value: $value_type) -> Result<(), SerdeError> {
888 Err(SerdeError::unsupported(
889 "an event stream union serializes exactly one structure variant",
890 ))
891 })+
892 };
893}
894
895impl ShapeSerializer for UnionVariantSerializer<'_> {
896 fn write_struct(&mut self, schema: &Schema<'_>, value: &dyn SerializableStruct) -> Result<(), SerdeError> {
897 let event_type = schema
898 .member_name()
899 .ok_or_else(|| SerdeError::unsupported("event stream union variant schema has no member name"))?;
900 let strings = match schema.member_index().and_then(|index| self.variants.get(index)) {
901 Some(slot) => Some(match slot.get() {
902 Some(strings) => strings,
903 None => {
904 let capability = self.framing.get()?;
905 slot.get_or_init(|| FrameStrings::new(event_type, value.schema(), capability))
906 }
907 }),
908 None => None,
909 };
910 self.message = Some(build_frame(
911 self.framing,
912 event_type,
913 value.schema(),
914 value,
915 self.kind,
916 strings,
917 )?);
918 Ok(())
919 }
920
921 fn write_list(
922 &mut self,
923 _schema: &Schema<'_>,
924 _write_elements: &dyn Fn(&mut dyn ShapeSerializer) -> Result<(), SerdeError>,
925 ) -> Result<(), SerdeError> {
926 Err(SerdeError::unsupported(
927 "an event stream union serializes exactly one structure variant",
928 ))
929 }
930
931 fn write_map(
932 &mut self,
933 _schema: &Schema<'_>,
934 _write_entries: &dyn Fn(&mut dyn ShapeSerializer) -> Result<(), SerdeError>,
935 ) -> Result<(), SerdeError> {
936 Err(SerdeError::unsupported(
937 "an event stream union serializes exactly one structure variant",
938 ))
939 }
940
941 not_a_union_variant!(
942 write_boolean(bool),
943 write_byte(i8),
944 write_short(i16),
945 write_integer(i32),
946 write_long(i64),
947 write_float(f32),
948 write_double(f64),
949 write_big_integer(&BigInteger),
950 write_big_decimal(&BigDecimal),
951 write_string(&str),
952 write_blob(Blob),
953 write_timestamp(&DateTime),
954 write_document(&Document),
955 );
956
957 fn write_null(&mut self, _schema: &Schema<'_>) -> Result<(), SerdeError> {
958 Err(SerdeError::unsupported(
959 "an event stream union serializes exactly one structure variant",
960 ))
961 }
962}
963
964struct EventMemberSerializer<'a> {
969 framing: Framing<'a>,
970 header_names: &'a [Option<&'static str>],
972 headers: &'a mut Vec<Header>,
973 payload: &'a mut Option<Bytes>,
974}
975
976enum MemberRole {
977 Header,
978 Payload,
979 Dropped,
980}
981
982fn member_role(schema: &Schema<'_>) -> MemberRole {
983 if schema.event_header().is_some() {
984 MemberRole::Header
985 } else if schema.event_payload().is_some() {
986 MemberRole::Payload
987 } else {
988 MemberRole::Dropped
989 }
990}
991
992impl EventMemberSerializer<'_> {
993 #[inline]
994 fn push_header(&mut self, schema: &Schema<'_>, value: HeaderValue) -> Result<(), SerdeError> {
995 let name = schema
996 .member_name()
997 .ok_or_else(|| SerdeError::unsupported("event header schema has no member name"))?;
998 let cached = schema
999 .member_index()
1000 .and_then(|index| *self.header_names.get(index)?)
1001 .filter(|&cached| cached == name);
1002 match cached {
1003 Some(cached) => self.headers.push(Header::new(cached, value)),
1004 None => self.headers.push(Header::new(StrBytes::copy_from_str(name), value)),
1005 }
1006 Ok(())
1007 }
1008
1009 fn unsupported(&self, what: &str, schema: &Schema<'_>) -> SerdeError {
1010 SerdeError::unsupported(format!(
1011 "unsupported event stream {what} type: {:?}",
1012 schema.shape_type()
1013 ))
1014 }
1015}
1016
1017macro_rules! header_only_member {
1018 ($($fn_name:ident($value_type:ty) => $header_value:expr,)+) => {
1019 $(fn $fn_name(&mut self, schema: &Schema<'_>, value: $value_type) -> Result<(), SerdeError> {
1020 match member_role(schema) {
1021 MemberRole::Header => {
1022 #[allow(clippy::redundant_closure_call)]
1023 self.push_header(schema, ($header_value)(value))
1024 }
1025 MemberRole::Payload => Err(self.unsupported("payload", schema)),
1026 MemberRole::Dropped => Ok(()),
1027 }
1028 })+
1029 };
1030}
1031
1032macro_rules! dropped_only_member {
1033 ($($fn_name:ident($value_type:ty),)+) => {
1034 $(fn $fn_name(&mut self, schema: &Schema<'_>, _value: $value_type) -> Result<(), SerdeError> {
1035 match member_role(schema) {
1036 MemberRole::Header => Err(self.unsupported("header", schema)),
1037 MemberRole::Payload => Err(self.unsupported("payload", schema)),
1038 MemberRole::Dropped => Ok(()),
1039 }
1040 })+
1041 };
1042}
1043
1044impl ShapeSerializer for EventMemberSerializer<'_> {
1045 fn write_struct(&mut self, schema: &Schema<'_>, value: &dyn SerializableStruct) -> Result<(), SerdeError> {
1046 match member_role(schema) {
1047 MemberRole::Header => Err(self.unsupported("header", schema)),
1048 MemberRole::Payload => {
1049 let mut ser = self.framing.get()?.payload_codec.create_serializer();
1050 ser.write_struct(value.schema(), value)?;
1051 *self.payload = Some(Bytes::from(ser.finish_boxed()));
1052 Ok(())
1053 }
1054 MemberRole::Dropped => Ok(()),
1055 }
1056 }
1057
1058 fn write_list(
1059 &mut self,
1060 schema: &Schema<'_>,
1061 _write_elements: &dyn Fn(&mut dyn ShapeSerializer) -> Result<(), SerdeError>,
1062 ) -> Result<(), SerdeError> {
1063 match member_role(schema) {
1064 MemberRole::Header => Err(self.unsupported("header", schema)),
1065 MemberRole::Payload => Err(self.unsupported("payload", schema)),
1066 MemberRole::Dropped => Ok(()),
1067 }
1068 }
1069
1070 fn write_map(
1071 &mut self,
1072 schema: &Schema<'_>,
1073 _write_entries: &dyn Fn(&mut dyn ShapeSerializer) -> Result<(), SerdeError>,
1074 ) -> Result<(), SerdeError> {
1075 match member_role(schema) {
1076 MemberRole::Header => Err(self.unsupported("header", schema)),
1077 MemberRole::Payload => Err(self.unsupported("payload", schema)),
1078 MemberRole::Dropped => Ok(()),
1079 }
1080 }
1081
1082 fn write_string(&mut self, schema: &Schema<'_>, value: &str) -> Result<(), SerdeError> {
1083 match member_role(schema) {
1084 MemberRole::Header => self.push_header(schema, HeaderValue::String(value.to_owned().into())),
1085 MemberRole::Payload => {
1086 *self.payload = Some(Bytes::from(value.to_owned().into_bytes()));
1087 Ok(())
1088 }
1089 MemberRole::Dropped => Ok(()),
1090 }
1091 }
1092
1093 fn write_blob(&mut self, schema: &Schema<'_>, value: Blob) -> Result<(), SerdeError> {
1094 match member_role(schema) {
1095 MemberRole::Header => self.push_header(schema, HeaderValue::ByteArray(value.into_bytes())),
1096 MemberRole::Payload => {
1097 *self.payload = Some(value.into_bytes());
1098 Ok(())
1099 }
1100 MemberRole::Dropped => Ok(()),
1101 }
1102 }
1103
1104 header_only_member!(
1107 write_boolean(bool) => HeaderValue::Bool,
1108 write_byte(i8) => HeaderValue::Byte,
1109 write_short(i16) => HeaderValue::Int16,
1110 write_integer(i32) => HeaderValue::Int32,
1111 write_long(i64) => HeaderValue::Int64,
1112 );
1113
1114 fn write_timestamp(&mut self, schema: &Schema<'_>, value: &DateTime) -> Result<(), SerdeError> {
1115 match member_role(schema) {
1116 MemberRole::Header => self.push_header(schema, HeaderValue::Timestamp(*value)),
1117 MemberRole::Payload => Err(self.unsupported("payload", schema)),
1118 MemberRole::Dropped => Ok(()),
1119 }
1120 }
1121
1122 dropped_only_member!(
1123 write_float(f32),
1124 write_double(f64),
1125 write_big_integer(&BigInteger),
1126 write_big_decimal(&BigDecimal),
1127 write_document(&Document),
1128 );
1129
1130 fn write_null(&mut self, _schema: &Schema<'_>) -> Result<(), SerdeError> {
1131 Ok(())
1132 }
1133}
1134
1135struct EventHeaderDeserializer<'a> {
1137 header: &'a Header,
1138}
1139
1140fn header_error(err: Error) -> SerdeError {
1141 SerdeError::custom(format!("{err}"))
1142}
1143
1144macro_rules! typed_header_reads {
1145 ($($fn_name:ident($expect_fn:ident) -> $result_type:ty,)+) => {
1146 $(fn $fn_name(&mut self, _schema: &Schema<'_>) -> Result<$result_type, SerdeError> {
1147 expect_fns::$expect_fn(self.header).map_err(header_error)
1148 })+
1149 };
1150}
1151
1152macro_rules! not_a_header_type {
1153 ($($fn_name:ident() -> $result_type:ty,)+) => {
1154 $(fn $fn_name(&mut self, _schema: &Schema<'_>) -> Result<$result_type, SerdeError> {
1155 Err(SerdeError::unsupported(
1156 "unsupported event stream header type",
1157 ))
1158 })+
1159 };
1160}
1161
1162impl ShapeDeserializer for EventHeaderDeserializer<'_> {
1163 fn read_struct(
1164 &mut self,
1165 _schema: &Schema<'_>,
1166 _state: &mut dyn FnMut(&Schema<'_>, &mut dyn ShapeDeserializer) -> Result<(), SerdeError>,
1167 ) -> Result<(), SerdeError> {
1168 Err(SerdeError::unsupported("unsupported event stream header type"))
1169 }
1170
1171 fn read_list(
1172 &mut self,
1173 _schema: &Schema<'_>,
1174 _state: &mut dyn FnMut(&mut dyn ShapeDeserializer) -> Result<(), SerdeError>,
1175 ) -> Result<(), SerdeError> {
1176 Err(SerdeError::unsupported("unsupported event stream header type"))
1177 }
1178
1179 fn read_map(
1180 &mut self,
1181 _schema: &Schema<'_>,
1182 _state: &mut dyn FnMut(String, &mut dyn ShapeDeserializer) -> Result<(), SerdeError>,
1183 ) -> Result<(), SerdeError> {
1184 Err(SerdeError::unsupported("unsupported event stream header type"))
1185 }
1186
1187 typed_header_reads!(
1188 read_boolean(expect_bool) -> bool,
1189 read_byte(expect_byte) -> i8,
1190 read_short(expect_int16) -> i16,
1191 read_integer(expect_int32) -> i32,
1192 read_long(expect_int64) -> i64,
1193 read_string(expect_string) -> String,
1194 read_blob(expect_byte_array) -> Blob,
1195 read_timestamp(expect_timestamp) -> DateTime,
1196 );
1197
1198 not_a_header_type!(
1199 read_float() -> f32,
1200 read_double() -> f64,
1201 read_big_integer() -> BigInteger,
1202 read_big_decimal() -> BigDecimal,
1203 read_document() -> Document,
1204 );
1205
1206 fn is_null(&self) -> bool {
1207 false
1208 }
1209
1210 fn container_size(&self) -> Option<usize> {
1211 None
1212 }
1213}
1214
1215struct RawPayloadDeserializer<'a> {
1217 payload: &'a Bytes,
1218}
1219
1220macro_rules! not_a_raw_payload_type {
1221 ($($fn_name:ident() -> $result_type:ty,)+) => {
1222 $(fn $fn_name(&mut self, _schema: &Schema<'_>) -> Result<$result_type, SerdeError> {
1223 Err(SerdeError::unsupported(
1224 "an event stream payload is a blob or a string",
1225 ))
1226 })+
1227 };
1228}
1229
1230impl ShapeDeserializer for RawPayloadDeserializer<'_> {
1231 fn read_struct(
1232 &mut self,
1233 _schema: &Schema<'_>,
1234 _state: &mut dyn FnMut(&Schema<'_>, &mut dyn ShapeDeserializer) -> Result<(), SerdeError>,
1235 ) -> Result<(), SerdeError> {
1236 Err(SerdeError::unsupported("an event stream payload is a blob or a string"))
1237 }
1238
1239 fn read_list(
1240 &mut self,
1241 _schema: &Schema<'_>,
1242 _state: &mut dyn FnMut(&mut dyn ShapeDeserializer) -> Result<(), SerdeError>,
1243 ) -> Result<(), SerdeError> {
1244 Err(SerdeError::unsupported("an event stream payload is a blob or a string"))
1245 }
1246
1247 fn read_map(
1248 &mut self,
1249 _schema: &Schema<'_>,
1250 _state: &mut dyn FnMut(String, &mut dyn ShapeDeserializer) -> Result<(), SerdeError>,
1251 ) -> Result<(), SerdeError> {
1252 Err(SerdeError::unsupported("an event stream payload is a blob or a string"))
1253 }
1254
1255 fn read_string(&mut self, _schema: &Schema<'_>) -> Result<String, SerdeError> {
1256 Ok(std::str::from_utf8(self.payload)
1257 .map_err(|_| SerdeError::custom("message payload is not valid UTF-8"))?
1258 .to_owned())
1259 }
1260
1261 fn read_blob(&mut self, _schema: &Schema<'_>) -> Result<Blob, SerdeError> {
1262 Ok(Blob::from_maybe_shared(self.payload.clone()))
1263 }
1264
1265 not_a_raw_payload_type!(
1266 read_boolean() -> bool,
1267 read_byte() -> i8,
1268 read_short() -> i16,
1269 read_integer() -> i32,
1270 read_long() -> i64,
1271 read_float() -> f32,
1272 read_double() -> f64,
1273 read_big_integer() -> BigInteger,
1274 read_big_decimal() -> BigDecimal,
1275 read_timestamp() -> DateTime,
1276 read_document() -> Document,
1277 );
1278
1279 fn is_null(&self) -> bool {
1280 false
1281 }
1282
1283 fn container_size(&self) -> Option<usize> {
1284 None
1285 }
1286}
1287
1288#[cfg(test)]
1289mod tests {
1290 use super::*;
1291 use crate::schema::protocol::RestJson1;
1292 use crate::schema::protocol::RpcV2Cbor;
1293 use aws_smithy_http::event_stream::Receiver;
1294 use aws_smithy_schema::ShapeId;
1295
1296 fn json_protocol() -> SharedServerProtocol {
1297 SharedServerProtocol::metadata_routed(RestJson1::default())
1298 }
1299
1300 fn cbor_protocol() -> SharedServerProtocol {
1301 SharedServerProtocol::metadata_routed(RpcV2Cbor::default())
1302 }
1303
1304 fn header<'a>(message: &'a Message, name: &str) -> Option<&'a HeaderValue> {
1305 message
1306 .headers()
1307 .iter()
1308 .find(|h| h.name().as_str() == name)
1309 .map(|h| h.value())
1310 }
1311
1312 fn string_header<'a>(message: &'a Message, name: &str) -> Option<&'a str> {
1313 header(message, name).map(|v| v.as_string().unwrap().as_str())
1314 }
1315
1316 macro_rules! member_schema {
1317 ($name:ident, $shape:literal, $member:literal, $shape_type:expr, $index:literal $(, $with:ident)*) => {
1318 static $name: Schema<'static> = Schema::new_member(
1319 ShapeId::from_parts(
1320 concat!("test#", $shape, "$", $member),
1321 "test",
1322 $shape,
1323 ),
1324 $shape_type,
1325 $member,
1326 $index,
1327 )$(.$with())*;
1328 };
1329 }
1330
1331 macro_rules! struct_schema {
1332 ($name:ident, $shape:literal, [$($member:ident),*]) => {
1333 static $name: Schema<'static> = Schema::new_struct(
1334 ShapeId::from_parts(concat!("test#", $shape), "test", $shape),
1335 ShapeType::Structure,
1336 &[$(&$member),*],
1337 );
1338 };
1339 }
1340
1341 member_schema!(AH_BOOL, "AllHeaders", "flag", ShapeType::Boolean, 0, with_event_header);
1344 member_schema!(AH_BYTE, "AllHeaders", "small", ShapeType::Byte, 1, with_event_header);
1345 member_schema!(AH_SHORT, "AllHeaders", "short", ShapeType::Short, 2, with_event_header);
1346 member_schema!(AH_INT, "AllHeaders", "int", ShapeType::Integer, 3, with_event_header);
1347 member_schema!(AH_LONG, "AllHeaders", "long", ShapeType::Long, 4, with_event_header);
1348 member_schema!(AH_BLOB, "AllHeaders", "bin", ShapeType::Blob, 5, with_event_header);
1349 member_schema!(AH_STRING, "AllHeaders", "name", ShapeType::String, 6, with_event_header);
1350 member_schema!(AH_TIME, "AllHeaders", "at", ShapeType::Timestamp, 7, with_event_header);
1351 member_schema!(
1352 AH_SKIPPED,
1353 "AllHeaders",
1354 "skipped",
1355 ShapeType::String,
1356 8,
1357 with_event_header
1358 );
1359 member_schema!(AH_EXTRA, "AllHeaders", "extra", ShapeType::String, 9);
1360 struct_schema!(
1361 ALL_HEADERS_SCHEMA,
1362 "AllHeaders",
1363 [AH_BOOL, AH_BYTE, AH_SHORT, AH_INT, AH_LONG, AH_BLOB, AH_STRING, AH_TIME, AH_SKIPPED, AH_EXTRA]
1364 );
1365
1366 #[derive(Debug, Default, PartialEq)]
1367 struct AllHeaders {
1368 flag: Option<bool>,
1369 small: Option<i8>,
1370 short: Option<i16>,
1371 int: Option<i32>,
1372 long: Option<i64>,
1373 bin: Option<Blob>,
1374 name: Option<String>,
1375 at: Option<DateTime>,
1376 skipped: Option<String>,
1377 extra: Option<String>,
1378 }
1379
1380 impl SerializableStruct for AllHeaders {
1381 fn schema(&self) -> &Schema<'_> {
1382 &ALL_HEADERS_SCHEMA
1383 }
1384
1385 fn serialize_members(&self, ser: &mut dyn ShapeSerializer) -> Result<(), SerdeError> {
1386 if let Some(v) = self.flag {
1387 ser.write_boolean(&AH_BOOL, v)?;
1388 }
1389 if let Some(v) = self.small {
1390 ser.write_byte(&AH_BYTE, v)?;
1391 }
1392 if let Some(v) = self.short {
1393 ser.write_short(&AH_SHORT, v)?;
1394 }
1395 if let Some(v) = self.int {
1396 ser.write_integer(&AH_INT, v)?;
1397 }
1398 if let Some(v) = self.long {
1399 ser.write_long(&AH_LONG, v)?;
1400 }
1401 if let Some(ref v) = self.bin {
1402 ser.write_blob(&AH_BLOB, v.clone())?;
1403 }
1404 if let Some(ref v) = self.name {
1405 ser.write_string(&AH_STRING, v)?;
1406 }
1407 if let Some(ref v) = self.at {
1408 ser.write_timestamp(&AH_TIME, v)?;
1409 }
1410 if let Some(ref v) = self.skipped {
1411 ser.write_string(&AH_SKIPPED, v)?;
1412 }
1413 if let Some(ref v) = self.extra {
1414 ser.write_string(&AH_EXTRA, v)?;
1415 }
1416 Ok(())
1417 }
1418 }
1419
1420 impl AllHeaders {
1421 fn deserialize(deser: &mut dyn ShapeDeserializer) -> Result<Self, SerdeError> {
1422 let mut out = AllHeaders::default();
1423 deser.read_struct(&ALL_HEADERS_SCHEMA, &mut |member, d| {
1424 match member.member_index() {
1425 Some(0) => out.flag = Some(d.read_boolean(member)?),
1426 Some(1) => out.small = Some(d.read_byte(member)?),
1427 Some(2) => out.short = Some(d.read_short(member)?),
1428 Some(3) => out.int = Some(d.read_integer(member)?),
1429 Some(4) => out.long = Some(d.read_long(member)?),
1430 Some(5) => out.bin = Some(d.read_blob(member)?),
1431 Some(6) => out.name = Some(d.read_string(member)?),
1432 Some(7) => out.at = Some(d.read_timestamp(member)?),
1433 Some(8) => out.skipped = Some(d.read_string(member)?),
1434 Some(9) => {
1435 if d.is_null() {
1436 d.read_null()?;
1437 } else {
1438 out.extra = Some(d.read_string(member)?);
1439 }
1440 }
1441 _ => {}
1442 }
1443 Ok(())
1444 })?;
1445 Ok(out)
1446 }
1447 }
1448
1449 member_schema!(FH_RATE, "FloatHeader", "rate", ShapeType::Float, 0, with_event_header);
1451 struct_schema!(FLOAT_HEADER_SCHEMA, "FloatHeader", [FH_RATE]);
1452
1453 #[derive(Debug)]
1454 struct FloatHeader {
1455 rate: f32,
1456 }
1457
1458 impl SerializableStruct for FloatHeader {
1459 fn schema(&self) -> &Schema<'_> {
1460 &FLOAT_HEADER_SCHEMA
1461 }
1462
1463 fn serialize_members(&self, ser: &mut dyn ShapeSerializer) -> Result<(), SerdeError> {
1464 ser.write_float(&FH_RATE, self.rate)
1465 }
1466 }
1467
1468 member_schema!(
1470 TEXT_VALUE,
1471 "TextEvent",
1472 "value",
1473 ShapeType::String,
1474 0,
1475 with_event_payload
1476 );
1477 struct_schema!(TEXT_EVENT_SCHEMA, "TextEvent", [TEXT_VALUE]);
1478
1479 #[derive(Debug, Default, PartialEq)]
1480 struct TextEvent {
1481 value: Option<String>,
1482 }
1483
1484 impl SerializableStruct for TextEvent {
1485 fn schema(&self) -> &Schema<'_> {
1486 &TEXT_EVENT_SCHEMA
1487 }
1488
1489 fn serialize_members(&self, ser: &mut dyn ShapeSerializer) -> Result<(), SerdeError> {
1490 if let Some(ref v) = self.value {
1491 ser.write_string(&TEXT_VALUE, v)?;
1492 }
1493 Ok(())
1494 }
1495 }
1496
1497 impl TextEvent {
1498 fn deserialize(deser: &mut dyn ShapeDeserializer) -> Result<Self, SerdeError> {
1499 let mut out = TextEvent::default();
1500 deser.read_struct(&TEXT_EVENT_SCHEMA, &mut |member, d| {
1501 if member.member_index() == Some(0) {
1502 out.value = Some(d.read_string(member)?);
1503 }
1504 Ok(())
1505 })?;
1506 Ok(out)
1507 }
1508 }
1509
1510 member_schema!(BIN_VALUE, "BinEvent", "value", ShapeType::Blob, 0, with_event_payload);
1511 struct_schema!(BIN_EVENT_SCHEMA, "BinEvent", [BIN_VALUE]);
1512
1513 #[derive(Debug, Default, PartialEq)]
1514 struct BinEvent {
1515 value: Option<Blob>,
1516 }
1517
1518 impl SerializableStruct for BinEvent {
1519 fn schema(&self) -> &Schema<'_> {
1520 &BIN_EVENT_SCHEMA
1521 }
1522
1523 fn serialize_members(&self, ser: &mut dyn ShapeSerializer) -> Result<(), SerdeError> {
1524 if let Some(ref v) = self.value {
1525 ser.write_blob(&BIN_VALUE, v.clone())?;
1526 }
1527 Ok(())
1528 }
1529 }
1530
1531 impl BinEvent {
1532 fn deserialize(deser: &mut dyn ShapeDeserializer) -> Result<Self, SerdeError> {
1533 let mut out = BinEvent::default();
1534 deser.read_struct(&BIN_EVENT_SCHEMA, &mut |member, d| {
1535 if member.member_index() == Some(0) {
1536 out.value = Some(d.read_blob(member)?);
1537 }
1538 Ok(())
1539 })?;
1540 Ok(out)
1541 }
1542 }
1543
1544 member_schema!(BODY_TEXT, "MessageBody", "text", ShapeType::String, 0);
1546 struct_schema!(MESSAGE_BODY_SCHEMA, "MessageBody", [BODY_TEXT]);
1547
1548 #[derive(Debug, Default, PartialEq)]
1549 struct MessageBody {
1550 text: Option<String>,
1551 }
1552
1553 impl SerializableStruct for MessageBody {
1554 fn schema(&self) -> &Schema<'_> {
1555 &MESSAGE_BODY_SCHEMA
1556 }
1557
1558 fn serialize_members(&self, ser: &mut dyn ShapeSerializer) -> Result<(), SerdeError> {
1559 if let Some(ref v) = self.text {
1560 ser.write_string(&BODY_TEXT, v)?;
1561 }
1562 Ok(())
1563 }
1564 }
1565
1566 impl MessageBody {
1567 fn deserialize(deser: &mut dyn ShapeDeserializer) -> Result<Self, SerdeError> {
1568 let mut out = MessageBody::default();
1569 deser.read_struct(&MESSAGE_BODY_SCHEMA, &mut |member, d| {
1570 if member.member_index() == Some(0) {
1571 out.text = Some(d.read_string(member)?);
1572 }
1573 Ok(())
1574 })?;
1575 Ok(out)
1576 }
1577 }
1578
1579 member_schema!(
1580 STRUCT_FROM,
1581 "StructEvent",
1582 "from",
1583 ShapeType::String,
1584 0,
1585 with_event_header
1586 );
1587 member_schema!(
1588 STRUCT_BODY,
1589 "StructEvent",
1590 "body",
1591 ShapeType::Structure,
1592 1,
1593 with_event_payload
1594 );
1595 struct_schema!(STRUCT_EVENT_SCHEMA, "StructEvent", [STRUCT_FROM, STRUCT_BODY]);
1596
1597 #[derive(Debug, Default, PartialEq)]
1598 struct StructEvent {
1599 from: Option<String>,
1600 body: Option<MessageBody>,
1601 }
1602
1603 impl SerializableStruct for StructEvent {
1604 fn schema(&self) -> &Schema<'_> {
1605 &STRUCT_EVENT_SCHEMA
1606 }
1607
1608 fn serialize_members(&self, ser: &mut dyn ShapeSerializer) -> Result<(), SerdeError> {
1609 if let Some(ref v) = self.from {
1610 ser.write_string(&STRUCT_FROM, v)?;
1611 }
1612 if let Some(ref v) = self.body {
1613 ser.write_struct(&STRUCT_BODY, v)?;
1614 }
1615 Ok(())
1616 }
1617 }
1618
1619 impl StructEvent {
1620 fn deserialize(deser: &mut dyn ShapeDeserializer) -> Result<Self, SerdeError> {
1621 let mut out = StructEvent::default();
1622 deser.read_struct(&STRUCT_EVENT_SCHEMA, &mut |member, d| {
1623 match member.member_index() {
1624 Some(0) => out.from = Some(d.read_string(member)?),
1625 Some(1) => out.body = Some(MessageBody::deserialize(d)?),
1626 _ => {}
1627 }
1628 Ok(())
1629 })?;
1630 Ok(out)
1631 }
1632 }
1633
1634 struct_schema!(EMPTY_EVENT_SCHEMA, "EmptyEvent", []);
1636
1637 #[derive(Debug, Default, PartialEq)]
1638 struct EmptyEvent;
1639
1640 impl SerializableStruct for EmptyEvent {
1641 fn schema(&self) -> &Schema<'_> {
1642 &EMPTY_EVENT_SCHEMA
1643 }
1644
1645 fn serialize_members(&self, _ser: &mut dyn ShapeSerializer) -> Result<(), SerdeError> {
1646 Ok(())
1647 }
1648 }
1649
1650 member_schema!(PLAIN_TEXT, "PlainEvent", "text", ShapeType::String, 0);
1652 struct_schema!(PLAIN_EVENT_SCHEMA, "PlainEvent", [PLAIN_TEXT]);
1653
1654 #[derive(Debug, Default, PartialEq)]
1655 struct PlainEvent {
1656 text: Option<String>,
1657 }
1658
1659 impl SerializableStruct for PlainEvent {
1660 fn schema(&self) -> &Schema<'_> {
1661 &PLAIN_EVENT_SCHEMA
1662 }
1663
1664 fn serialize_members(&self, ser: &mut dyn ShapeSerializer) -> Result<(), SerdeError> {
1665 if let Some(ref v) = self.text {
1666 ser.write_string(&PLAIN_TEXT, v)?;
1667 }
1668 Ok(())
1669 }
1670 }
1671
1672 impl PlainEvent {
1673 fn deserialize(deser: &mut dyn ShapeDeserializer) -> Result<Self, SerdeError> {
1674 let mut out = PlainEvent::default();
1675 deser.read_struct(&PLAIN_EVENT_SCHEMA, &mut |member, d| {
1676 if member.member_index() == Some(0) {
1677 out.text = Some(d.read_string(member)?);
1678 }
1679 Ok(())
1680 })?;
1681 Ok(out)
1682 }
1683 }
1684
1685 member_schema!(EV_ALL_HEADERS, "TestEvents", "allHeaders", ShapeType::Structure, 0);
1687 member_schema!(EV_FLOAT_HEADER, "TestEvents", "floatHeader", ShapeType::Structure, 1);
1688 member_schema!(EV_TEXT, "TestEvents", "text", ShapeType::Structure, 2);
1689 member_schema!(EV_BIN, "TestEvents", "bin", ShapeType::Structure, 3);
1690 member_schema!(EV_STRUCTURED, "TestEvents", "structured", ShapeType::Structure, 4);
1691 member_schema!(EV_EMPTY, "TestEvents", "empty", ShapeType::Structure, 5);
1692 member_schema!(EV_PLAIN, "TestEvents", "plain", ShapeType::Structure, 6);
1693
1694 #[derive(Debug, PartialEq)]
1695 enum TestEvents {
1696 AllHeaders(AllHeaders),
1697 FloatHeader(FloatHeader),
1698 Text(TextEvent),
1699 Bin(BinEvent),
1700 Structured(StructEvent),
1701 Empty(EmptyEvent),
1702 Plain(PlainEvent),
1703 }
1704
1705 impl PartialEq for FloatHeader {
1706 fn eq(&self, other: &Self) -> bool {
1707 self.rate == other.rate
1708 }
1709 }
1710
1711 static TEST_EVENTS_SCHEMA: Schema<'static> = Schema::new_struct(
1712 ShapeId::from_parts("test#TestEvents", "test", "TestEvents"),
1713 ShapeType::Union,
1714 &[
1715 &EV_ALL_HEADERS,
1716 &EV_FLOAT_HEADER,
1717 &EV_TEXT,
1718 &EV_BIN,
1719 &EV_STRUCTURED,
1720 &EV_EMPTY,
1721 &EV_PLAIN,
1722 ],
1723 )
1724 .with_streaming();
1725
1726 impl SerializableStruct for TestEvents {
1727 fn schema(&self) -> &Schema<'_> {
1728 &TEST_EVENTS_SCHEMA
1729 }
1730
1731 fn serialize_members(&self, ser: &mut dyn ShapeSerializer) -> Result<(), SerdeError> {
1732 match self {
1733 Self::AllHeaders(v) => ser.write_struct(&EV_ALL_HEADERS, v),
1734 Self::FloatHeader(v) => ser.write_struct(&EV_FLOAT_HEADER, v),
1735 Self::Text(v) => ser.write_struct(&EV_TEXT, v),
1736 Self::Bin(v) => ser.write_struct(&EV_BIN, v),
1737 Self::Structured(v) => ser.write_struct(&EV_STRUCTURED, v),
1738 Self::Empty(v) => ser.write_struct(&EV_EMPTY, v),
1739 Self::Plain(v) => ser.write_struct(&EV_PLAIN, v),
1740 }
1741 }
1742 }
1743
1744 #[derive(Debug)]
1745 enum TestEventsError {
1746 Boom(BoomError),
1747 }
1748
1749 impl fmt::Display for TestEventsError {
1750 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1751 write!(f, "boom")
1752 }
1753 }
1754
1755 impl std::error::Error for TestEventsError {}
1756
1757 member_schema!(BOOM_MESSAGE, "BoomError", "message", ShapeType::String, 0);
1758 struct_schema!(BOOM_ERROR_SCHEMA, "BoomError", [BOOM_MESSAGE]);
1759
1760 #[derive(Debug, Default, PartialEq)]
1761 struct BoomError {
1762 message: Option<String>,
1763 }
1764
1765 impl SerializableStruct for BoomError {
1766 fn schema(&self) -> &Schema<'_> {
1767 &BOOM_ERROR_SCHEMA
1768 }
1769
1770 fn serialize_members(&self, ser: &mut dyn ShapeSerializer) -> Result<(), SerdeError> {
1771 if let Some(ref v) = self.message {
1772 ser.write_string(&BOOM_MESSAGE, v)?;
1773 }
1774 Ok(())
1775 }
1776 }
1777
1778 impl BoomError {
1779 fn deserialize(deser: &mut dyn ShapeDeserializer) -> Result<Self, SerdeError> {
1780 let mut out = BoomError::default();
1781 deser.read_struct(&BOOM_ERROR_SCHEMA, &mut |member, d| {
1782 if member.member_index() == Some(0) {
1783 out.message = Some(d.read_string(member)?);
1784 }
1785 Ok(())
1786 })?;
1787 Ok(out)
1788 }
1789 }
1790
1791 impl SerializableEventError for TestEventsError {
1792 fn variant(&self) -> (&'static str, &Schema<'_>, &dyn SerializableStruct) {
1793 match self {
1794 Self::Boom(inner) => ("boom", &BOOM_ERROR_SCHEMA, inner),
1795 }
1796 }
1797 }
1798
1799 impl DeserializableEventStream for TestEvents {
1800 type Error = TestEventsError;
1801
1802 fn deserialize_event(event_type: &str, frame: &EventFrame<'_>) -> Result<Option<Self>, Error> {
1803 let mut deser = frame.deserializer();
1804 let wrap = |err: SerdeError| Error::unmarshalling(format!("failed to unmarshall {event_type}: {err}"));
1805 Ok(Some(match event_type {
1806 "allHeaders" => Self::AllHeaders(AllHeaders::deserialize(&mut deser).map_err(wrap)?),
1807 "text" => Self::Text(TextEvent::deserialize(&mut deser).map_err(wrap)?),
1808 "bin" => Self::Bin(BinEvent::deserialize(&mut deser).map_err(wrap)?),
1809 "structured" => Self::Structured(StructEvent::deserialize(&mut deser).map_err(wrap)?),
1810 "empty" => Self::Empty(EmptyEvent),
1811 "plain" => Self::Plain(PlainEvent::deserialize(&mut deser).map_err(wrap)?),
1812 _ => return Ok(None),
1813 }))
1814 }
1815
1816 fn deserialize_error(exception_type: &str, frame: &EventFrame<'_>) -> Result<Option<Self::Error>, Error> {
1817 match exception_type {
1818 "boom" => {
1819 let mut deser = frame.deserializer();
1820 let parsed = BoomError::deserialize(&mut deser)
1821 .map_err(|err| Error::unmarshalling(format!("failed to unmarshall exception: {err}")))?;
1822 Ok(Some(TestEventsError::Boom(parsed)))
1823 }
1824 _ => Ok(None),
1825 }
1826 }
1827 }
1828
1829 fn marshall(protocol: &SharedServerProtocol, event: TestEvents) -> Message {
1830 SchemaEventMarshaller::<TestEvents>::new(protocol.clone())
1831 .marshall(event)
1832 .expect("marshalls")
1833 }
1834
1835 fn unmarshall(
1836 protocol: &SharedServerProtocol,
1837 message: &Message,
1838 ) -> Result<UnmarshalledMessage<TestEvents, TestEventsError>, Error> {
1839 SchemaEventUnmarshaller::<TestEvents>::new(protocol.clone()).unmarshall(message)
1840 }
1841
1842 #[test]
1843 fn all_header_types_round_trip_and_keep_declaration_order() {
1844 let protocol = json_protocol();
1845 let event = AllHeaders {
1846 flag: Some(true),
1847 small: Some(-3),
1848 short: Some(-300),
1849 int: Some(70_000),
1850 long: Some(5_000_000_000),
1851 bin: Some(Blob::new(&b"\x00\xff"[..])),
1852 name: Some("ann".to_owned()),
1853 at: Some(DateTime::from_secs(1_700_000_000)),
1854 skipped: None,
1855 extra: Some("payload".to_owned()),
1856 };
1857 let message = marshall(&protocol, TestEvents::AllHeaders(event));
1858
1859 let names: Vec<_> = message.headers().iter().map(|h| h.name().as_str()).collect();
1860 assert_eq!(
1862 names,
1863 [
1864 ":message-type",
1865 ":event-type",
1866 "flag",
1867 "small",
1868 "short",
1869 "int",
1870 "long",
1871 "bin",
1872 "name",
1873 "at"
1874 ]
1875 );
1876 assert_eq!(string_header(&message, ":event-type"), Some("allHeaders"));
1877 assert!(message.payload().is_empty());
1878 assert!(matches!(header(&message, "flag"), Some(HeaderValue::Bool(true))));
1879 assert!(matches!(header(&message, "small"), Some(HeaderValue::Byte(-3))));
1880 assert!(matches!(header(&message, "short"), Some(HeaderValue::Int16(-300))));
1881 assert!(matches!(header(&message, "int"), Some(HeaderValue::Int32(70_000))));
1882 assert!(matches!(
1883 header(&message, "long"),
1884 Some(HeaderValue::Int64(5_000_000_000))
1885 ));
1886 assert!(matches!(header(&message, "bin"), Some(HeaderValue::ByteArray(b)) if &b[..] == b"\x00\xff"));
1887 assert!(matches!(header(&message, "at"), Some(HeaderValue::Timestamp(_))));
1888
1889 match unmarshall(&protocol, &message).expect("unmarshalls") {
1890 UnmarshalledMessage::Event(TestEvents::AllHeaders(parsed)) => {
1891 assert_eq!(parsed.flag, Some(true));
1892 assert_eq!(parsed.small, Some(-3));
1893 assert_eq!(parsed.short, Some(-300));
1894 assert_eq!(parsed.int, Some(70_000));
1895 assert_eq!(parsed.long, Some(5_000_000_000));
1896 assert_eq!(parsed.bin.as_ref().map(|b| b.as_ref()), Some(&b"\x00\xff"[..]));
1897 assert_eq!(parsed.name.as_deref(), Some("ann"));
1898 assert_eq!(parsed.at, Some(DateTime::from_secs(1_700_000_000)));
1899 assert_eq!(parsed.skipped, None);
1900 assert_eq!(parsed.extra, None);
1901 }
1902 other => panic!("unexpected result: {other:?}"),
1903 }
1904 }
1905
1906 #[test]
1907 fn headers_without_explicit_payload_omit_ordinary_members() {
1908 static HEADER: Schema<'static> = Schema::new_member(
1909 ShapeId::from_parts("test#Implicit$header", "test", "Implicit"),
1910 ShapeType::String,
1911 "header",
1912 0,
1913 )
1914 .with_event_header();
1915 static DATA: Schema<'static> = Schema::new_member(
1916 ShapeId::from_parts("test#Implicit$data", "test", "Implicit"),
1917 ShapeType::String,
1918 "data",
1919 1,
1920 )
1921 .with_json_name("wireData")
1922 .with_xml_name("WireData");
1923 static SCHEMA: Schema<'static> = Schema::new_struct(
1924 ShapeId::from_parts("test#Implicit", "test", "Implicit"),
1925 ShapeType::Structure,
1926 &[&HEADER, &DATA],
1927 )
1928 .with_xml_name("WireEvent")
1929 .with_xml_namespace("urn:test", None);
1930 struct Implicit;
1931 impl SerializableStruct for Implicit {
1932 fn schema(&self) -> &Schema<'_> {
1933 &SCHEMA
1934 }
1935
1936 fn serialize_members(&self, ser: &mut dyn ShapeSerializer) -> Result<(), SerdeError> {
1937 ser.write_string(&HEADER, "ann")?;
1938 ser.write_string(&DATA, "hi")
1939 }
1940 }
1941 for (protocol, _media_type, expected) in [
1942 (json_protocol(), "application/json", br#"{"wireData":"hi"}"#.as_slice()),
1943 (
1944 cbor_protocol(),
1945 "application/cbor",
1946 b"\xbf\x64data\x62hi\xff".as_slice(),
1947 ),
1948 (
1949 SharedServerProtocol::metadata_routed(crate::schema::protocol::RestXml::default()),
1950 "application/xml",
1951 br#"<WireEvent xmlns="urn:test"><WireData>hi</WireData></WireEvent>"#.as_slice(),
1952 ),
1953 ] {
1954 let capability = protocol.event_stream_framing().unwrap();
1955 let message = build_frame(
1956 Framing::Known(capability),
1957 "implicit",
1958 &SCHEMA,
1959 &Implicit,
1960 FrameKind::Event,
1961 None,
1962 )
1963 .unwrap();
1964 assert_eq!(string_header(&message, "header"), Some("ann"));
1965 assert_eq!(string_header(&message, ":content-type"), None);
1966 assert!(message.payload().is_empty());
1967 let message = Message::new_from_parts(message.headers().to_vec(), Bytes::copy_from_slice(expected));
1969 let mut values = [None, None];
1970 EventFrame::new(&message, capability)
1971 .deserializer()
1972 .read_struct(&SCHEMA, &mut |member, d| {
1973 values[member.member_index().unwrap()] = Some(d.read_string(member)?);
1974 Ok(())
1975 })
1976 .unwrap();
1977 assert_eq!(values, [Some("ann".to_owned()), Some("hi".to_owned())]);
1978 }
1979 }
1980
1981 #[test]
1982 fn header_only_event_has_no_payload_or_content_type() {
1983 member_schema!(
1984 HEADER_NAME,
1985 "HeaderOnly",
1986 "name",
1987 ShapeType::String,
1988 0,
1989 with_event_header
1990 );
1991 static SCHEMA: Schema<'static> = Schema::new_struct(
1992 ShapeId::from_parts("test#HeaderOnly", "test", "HeaderOnly"),
1993 ShapeType::Structure,
1994 &[&HEADER_NAME],
1995 );
1996 struct HeaderOnly;
1997 impl SerializableStruct for HeaderOnly {
1998 fn schema(&self) -> &Schema<'_> {
1999 &SCHEMA
2000 }
2001
2002 fn serialize_members(&self, ser: &mut dyn ShapeSerializer) -> Result<(), SerdeError> {
2003 ser.write_string(&HEADER_NAME, "ann")
2004 }
2005 }
2006 let protocol = json_protocol();
2007 let capability = protocol.event_stream_framing().unwrap();
2008 let message = build_frame(
2009 Framing::Known(capability),
2010 "headerOnly",
2011 &SCHEMA,
2012 &HeaderOnly,
2013 FrameKind::Event,
2014 None,
2015 )
2016 .unwrap();
2017 assert_eq!(string_header(&message, "name"), Some("ann"));
2018 assert_eq!(string_header(&message, ":content-type"), None);
2019 assert!(message.payload().is_empty());
2020 }
2021
2022 #[test]
2023 fn absent_implicit_members_do_not_form_a_payload_document() {
2024 for protocol in [
2025 json_protocol(),
2026 cbor_protocol(),
2027 SharedServerProtocol::metadata_routed(crate::schema::protocol::RestXml::default()),
2028 ] {
2029 for name in [None, Some("ann".to_owned())] {
2030 for extra in [None, Some("omitted".to_owned())] {
2031 let message = marshall(
2032 &protocol,
2033 TestEvents::AllHeaders(AllHeaders {
2034 name: name.clone(),
2035 extra,
2036 ..Default::default()
2037 }),
2038 );
2039 assert!(message.payload().is_empty());
2040 assert_eq!(string_header(&message, ":content-type"), None);
2041 match unmarshall(&protocol, &message).unwrap() {
2042 UnmarshalledMessage::Event(TestEvents::AllHeaders(parsed)) => {
2043 assert_eq!(parsed.name, name);
2044 assert_eq!(parsed.extra, None);
2045 }
2046 other => panic!("unexpected result: {other:?}"),
2047 }
2048 }
2049 }
2050 }
2051 }
2052
2053 #[test]
2054 fn implicit_xml_payloads_still_validate_headers_and_nonempty_documents() {
2055 let protocol = SharedServerProtocol::metadata_routed(crate::schema::protocol::RestXml::default());
2056 let message = marshall(
2057 &protocol,
2058 TestEvents::AllHeaders(AllHeaders {
2059 name: Some("ann".to_owned()),
2060 ..Default::default()
2061 }),
2062 );
2063 for payload in [b" ".as_slice(), b"<", b"not XML"] {
2064 let malformed = Message::new_from_parts(message.headers().to_vec(), Bytes::copy_from_slice(payload));
2065 assert!(unmarshall(&protocol, &malformed).is_err());
2066 }
2067 let headers = message
2068 .headers()
2069 .iter()
2070 .map(|header| {
2071 if header.name().as_str() == "name" {
2072 Header::new("name", HeaderValue::Int32(42))
2073 } else {
2074 header.clone()
2075 }
2076 })
2077 .collect();
2078 let invalid_header = Message::new_from_parts(headers, Bytes::new());
2079 assert!(unmarshall(&protocol, &invalid_header).is_err());
2080 }
2081
2082 #[test]
2083 fn float_header_fails_to_marshall() {
2084 let err = SchemaEventMarshaller::<TestEvents>::new(json_protocol())
2085 .marshall(TestEvents::FloatHeader(FloatHeader { rate: 1.5 }))
2086 .expect_err("floats are not event stream header types");
2087 assert!(err.to_string().contains("unsupported event stream header type"));
2088 }
2089
2090 #[test]
2091 fn string_payload_is_raw_text() {
2092 let protocol = json_protocol();
2093 let message = marshall(
2094 &protocol,
2095 TestEvents::Text(TextEvent {
2096 value: Some("raw string".to_owned()),
2097 }),
2098 );
2099 assert_eq!(string_header(&message, ":content-type"), Some("text/plain"));
2100 assert_eq!(&message.payload()[..], b"raw string");
2101 match unmarshall(&protocol, &message).expect("unmarshalls") {
2102 UnmarshalledMessage::Event(TestEvents::Text(parsed)) => {
2103 assert_eq!(parsed.value.as_deref(), Some("raw string"));
2104 }
2105 other => panic!("unexpected result: {other:?}"),
2106 }
2107 }
2108
2109 #[test]
2110 fn optional_string_payload_none_is_empty_with_content_type() {
2111 let message = marshall(&json_protocol(), TestEvents::Text(TextEvent { value: None }));
2112 assert_eq!(string_header(&message, ":content-type"), Some("text/plain"));
2113 assert!(message.payload().is_empty());
2114 }
2115
2116 #[test]
2117 fn blob_payload_is_raw_bytes() {
2118 let protocol = json_protocol();
2119 let message = marshall(
2120 &protocol,
2121 TestEvents::Bin(BinEvent {
2122 value: Some(Blob::new(&b"\x00\xff"[..])),
2123 }),
2124 );
2125 assert_eq!(
2126 string_header(&message, ":content-type"),
2127 Some("application/octet-stream")
2128 );
2129 assert_eq!(&message.payload()[..], b"\x00\xff");
2130 match unmarshall(&protocol, &message).expect("unmarshalls") {
2131 UnmarshalledMessage::Event(TestEvents::Bin(parsed)) => {
2132 assert_eq!(parsed.value.as_ref().map(|b| b.as_ref()), Some(&b"\x00\xff"[..]));
2133 }
2134 other => panic!("unexpected result: {other:?}"),
2135 }
2136 }
2137
2138 #[test]
2139 fn structured_payload_goes_through_the_selected_codec() {
2140 for (protocol, media_type) in [
2141 (json_protocol(), "application/json"),
2142 (cbor_protocol(), "application/cbor"),
2143 ] {
2144 let message = marshall(
2145 &protocol,
2146 TestEvents::Structured(StructEvent {
2147 from: Some("ann".to_owned()),
2148 body: Some(MessageBody {
2149 text: Some("hi".to_owned()),
2150 }),
2151 }),
2152 );
2153 let names: Vec<_> = message.headers().iter().map(|h| h.name().as_str()).collect();
2155 assert_eq!(names, [":message-type", ":event-type", "from", ":content-type"]);
2156 assert_eq!(string_header(&message, ":content-type"), Some(media_type));
2157 if media_type == "application/json" {
2158 assert_eq!(&message.payload()[..], br#"{"text":"hi"}"#);
2159 }
2160 match unmarshall(&protocol, &message).expect("unmarshalls") {
2161 UnmarshalledMessage::Event(TestEvents::Structured(parsed)) => {
2162 assert_eq!(parsed.from.as_deref(), Some("ann"));
2163 assert_eq!(parsed.body.and_then(|b| b.text).as_deref(), Some("hi"));
2164 }
2165 other => panic!("unexpected result: {other:?}"),
2166 }
2167 }
2168 }
2169
2170 #[test]
2171 fn optional_structured_payload_none_is_empty_with_content_type() {
2172 let message = marshall(
2173 &json_protocol(),
2174 TestEvents::Structured(StructEvent {
2175 from: Some("ann".to_owned()),
2176 body: None,
2177 }),
2178 );
2179 assert_eq!(string_header(&message, ":content-type"), Some("application/json"));
2180 assert!(message.payload().is_empty());
2181 }
2182
2183 #[test]
2184 fn no_event_traits_serializes_the_whole_struct_as_payload() {
2185 let protocol = json_protocol();
2186 let message = marshall(
2187 &protocol,
2188 TestEvents::Plain(PlainEvent {
2189 text: Some("hi".to_owned()),
2190 }),
2191 );
2192 assert_eq!(string_header(&message, ":content-type"), Some("application/json"));
2193 assert_eq!(&message.payload()[..], br#"{"text":"hi"}"#);
2194 match unmarshall(&protocol, &message).expect("unmarshalls") {
2195 UnmarshalledMessage::Event(TestEvents::Plain(parsed)) => {
2196 assert_eq!(parsed.text.as_deref(), Some("hi"));
2197 }
2198 other => panic!("unexpected result: {other:?}"),
2199 }
2200 }
2201
2202 #[test]
2203 fn empty_struct_serializes_as_codec_payload_and_skips_it_on_read() {
2204 let protocol = json_protocol();
2205 let message = marshall(&protocol, TestEvents::Empty(EmptyEvent));
2206 assert_eq!(string_header(&message, ":content-type"), Some("application/json"));
2207 assert_eq!(&message.payload()[..], br#"{}"#);
2208 let garbage = Message::new_from_parts(message.headers().to_vec(), Bytes::from_static(b"!!"));
2210 assert!(matches!(
2211 unmarshall(&protocol, &garbage).expect("unmarshalls"),
2212 UnmarshalledMessage::Event(TestEvents::Empty(_))
2213 ));
2214 }
2215
2216 #[test]
2217 fn untraited_members_alongside_headers_are_read_from_the_payload() {
2218 let protocol = json_protocol();
2220 let message = Message::new_from_parts(
2221 vec![
2222 Header::new(":message-type", HeaderValue::String("event".into())),
2223 Header::new(":event-type", HeaderValue::String("allHeaders".into())),
2224 Header::new("name", HeaderValue::String("ann".into())),
2225 Header::new("unknown", HeaderValue::String("traced, not fatal".into())),
2226 ],
2227 Bytes::from_static(br#"{"extra":"from payload"}"#),
2228 );
2229 match unmarshall(&protocol, &message).expect("unmarshalls") {
2230 UnmarshalledMessage::Event(TestEvents::AllHeaders(parsed)) => {
2231 assert_eq!(parsed.name.as_deref(), Some("ann"));
2232 assert_eq!(parsed.extra.as_deref(), Some("from payload"));
2233 }
2234 other => panic!("unexpected result: {other:?}"),
2235 }
2236 }
2237
2238 #[test]
2239 fn implicit_payload_overwrites_event_headers() {
2240 let protocol = json_protocol();
2242 let message = Message::new_from_parts(
2243 vec![
2244 Header::new(":message-type", HeaderValue::String("event".into())),
2245 Header::new(":event-type", HeaderValue::String("allHeaders".into())),
2246 Header::new("name", HeaderValue::String("ann".into())),
2247 ],
2248 Bytes::from_static(br#"{"name":"bob","extra":"from payload"}"#),
2249 );
2250 match unmarshall(&protocol, &message).expect("unmarshalls") {
2251 UnmarshalledMessage::Event(TestEvents::AllHeaders(parsed)) => {
2252 assert_eq!(parsed.name.as_deref(), Some("bob"));
2253 assert_eq!(parsed.extra.as_deref(), Some("from payload"));
2254 }
2255 other => panic!("unexpected result: {other:?}"),
2256 }
2257 }
2258
2259 #[test]
2260 fn implicit_payloads_validate_event_header_types_for_every_codec() {
2261 let cases: [(SharedServerProtocol, &[u8]); 3] = [
2262 (
2263 json_protocol(),
2264 br#"{"name":{"extra":"decoy"},"flag":"not a boolean","extra":"from payload"}"#,
2265 ),
2266 (
2267 cbor_protocol(),
2268 b"\xa3\x64name\xa1\x65extra\x65decoy\x64flag\x6dnot a boolean\x65extra\x6cfrom payload",
2270 ),
2271 (
2272 SharedServerProtocol::metadata_routed(crate::schema::protocol::RestXml::default()),
2273 b"<AllHeaders><name><extra>decoy</extra></name><flag>not a boolean</flag>\
2274 <extra>from payload</extra></AllHeaders>",
2275 ),
2276 ];
2277 for (protocol, payload) in cases {
2278 let message = Message::new_from_parts(
2279 vec![
2280 Header::new(":message-type", HeaderValue::String("event".into())),
2281 Header::new(":event-type", HeaderValue::String("allHeaders".into())),
2282 Header::new("name", HeaderValue::String("ann".into())),
2283 Header::new("flag", HeaderValue::Bool(false)),
2284 ],
2285 Bytes::copy_from_slice(payload),
2286 );
2287 assert!(unmarshall(&protocol, &message).is_err());
2288 }
2289 }
2290
2291 #[test]
2295 fn rest_xml_exception_frames_read_the_legacy_error_envelope() {
2296 let protocol = SharedServerProtocol::metadata_routed(crate::schema::protocol::RestXml::default());
2297 let decoded = |payload: &'static [u8]| {
2298 let message = Message::new_from_parts(
2299 vec![
2300 Header::new(":message-type", HeaderValue::String("exception".into())),
2301 Header::new(":exception-type", HeaderValue::String("boom".into())),
2302 Header::new(":content-type", HeaderValue::String("application/xml".into())),
2303 ],
2304 Bytes::from_static(payload),
2305 );
2306 match unmarshall(&protocol, &message) {
2307 Ok(UnmarshalledMessage::Error(TestEventsError::Boom(error))) => Ok(error),
2308 Ok(_) => panic!("an exception frame decodes as an error"),
2309 Err(err) => Err(err.to_string()),
2310 }
2311 };
2312 let failed = BoomError {
2313 message: Some("failed".to_owned()),
2314 };
2315 assert_eq!(
2316 decoded(b"<ErrorResponse><Error><message>failed</message></Error></ErrorResponse>"),
2317 Ok(failed)
2318 );
2319 assert_eq!(
2320 decoded(b"<ErrorResponse><RequestId>r</RequestId><Error><message>m</message></Error></ErrorResponse>"),
2321 Ok(BoomError {
2322 message: Some("m".to_owned())
2323 })
2324 );
2325 assert_eq!(decoded(b""), Ok(BoomError::default()));
2326 for bare in [
2327 &b"<BoomError><message>failed</message></BoomError>"[..],
2328 b"<Error><message>failed</message></Error>",
2329 ] {
2330 let bare: &'static [u8] = bare;
2331 assert!(decoded(bare).unwrap_err().contains("expected ErrorResponse as root"));
2332 }
2333 assert!(decoded(b"<ErrorResponse><Other/></ErrorResponse>")
2334 .unwrap_err()
2335 .contains("no error found inside of ErrorResponse"));
2336 }
2337
2338 #[test]
2342 fn rest_xml_no_error_wrapping_exception_frames_are_rooted_at_error() {
2343 use crate::schema::protocol::RestXml;
2344 use crate::schema::traits::RestXmlTrait;
2345 use crate::schema::{MetadataRoutedProtocol, ProtocolBuildContext, ServiceSchema};
2346
2347 static TRAITS: std::sync::LazyLock<aws_smithy_schema::TraitMap> = std::sync::LazyLock::new(|| {
2348 let mut traits = aws_smithy_schema::TraitMap::new();
2349 traits.insert(Box::new(RestXmlTrait::new().with_no_error_wrapping(true)));
2350 traits
2351 });
2352 static SERVICE: ServiceSchema<'static> = ServiceSchema::new(
2353 aws_smithy_schema::shape_id!("test", "Service"),
2354 None,
2355 &[RestXmlTrait::TRAIT_ID],
2356 &[],
2357 )
2358 .with_traits(&TRAITS);
2359 let protocol = SharedServerProtocol::metadata_routed(
2360 RestXml::from_build_context(&ProtocolBuildContext::new(&SERVICE)).unwrap(),
2361 );
2362 let decoded = |payload: &'static [u8]| {
2363 let message = Message::new_from_parts(
2364 vec![
2365 Header::new(":message-type", HeaderValue::String("exception".into())),
2366 Header::new(":exception-type", HeaderValue::String("boom".into())),
2367 Header::new(":content-type", HeaderValue::String("application/xml".into())),
2368 ],
2369 Bytes::from_static(payload),
2370 );
2371 match unmarshall(&protocol, &message) {
2372 Ok(UnmarshalledMessage::Error(TestEventsError::Boom(error))) => Ok(error),
2373 Ok(_) => panic!("an exception frame decodes as an error"),
2374 Err(err) => Err(err.to_string()),
2375 }
2376 };
2377 assert_eq!(
2378 decoded(b"<Error><message>failed</message></Error>"),
2379 Ok(BoomError {
2380 message: Some("failed".to_owned())
2381 })
2382 );
2383 assert_eq!(decoded(b""), Ok(BoomError::default()));
2384 assert!(
2385 decoded(b"<ErrorResponse><Error><message>failed</message></Error></ErrorResponse>")
2386 .unwrap_err()
2387 .contains("expected error as root")
2388 );
2389 assert!(decoded(b"<BoomError><message>failed</message></BoomError>")
2390 .unwrap_err()
2391 .contains("expected error as root"));
2392 }
2393
2394 #[test]
2395 fn duplicate_message_types_share_dispatch_and_xml_payload_kind() {
2396 let protocol = SharedServerProtocol::metadata_routed(crate::schema::protocol::RestXml::default());
2397 for payload in [
2398 "",
2399 "hello",
2400 "<ErrorResponse><Error><value>hello</value></Error></ErrorResponse>",
2401 ] {
2402 let message = Message::new_from_parts(
2403 vec![
2404 Header::new(":message-type", HeaderValue::String("exception".into())),
2405 Header::new(":message-type", HeaderValue::String("event".into())),
2406 Header::new(":event-type", HeaderValue::String("text".into())),
2407 Header::new(":content-type", HeaderValue::String("text/plain".into())),
2408 ],
2409 Bytes::copy_from_slice(payload.as_bytes()),
2410 );
2411 let expected = TextEvent {
2412 value: Some(payload.to_owned()),
2413 };
2414 match unmarshall(&protocol, &message).unwrap() {
2415 UnmarshalledMessage::Event(TestEvents::Text(event)) => assert_eq!(event, expected),
2416 other => panic!("expected a text event, got {other:?}"),
2417 }
2418 let frame = EventFrame::new(&message, protocol.event_stream_framing().unwrap());
2419 assert_eq!(TextEvent::deserialize(&mut frame.deserializer()).unwrap(), expected);
2420 }
2421
2422 let message = Message::new_from_parts(
2423 vec![
2424 Header::new(":message-type", HeaderValue::String("event".into())),
2425 Header::new(":message-type", HeaderValue::String("exception".into())),
2426 Header::new(":exception-type", HeaderValue::String("boom".into())),
2427 ],
2428 Bytes::from_static(b"<ErrorResponse><Error><message>failed</message></Error></ErrorResponse>"),
2429 );
2430 match unmarshall(&protocol, &message).unwrap() {
2431 UnmarshalledMessage::Error(TestEventsError::Boom(error)) => {
2432 assert_eq!(error.message.as_deref(), Some("failed"));
2433 }
2434 other => panic!("expected an exception, got {other:?}"),
2435 }
2436 let frame = EventFrame::new(&message, protocol.event_stream_framing().unwrap());
2437 assert_eq!(
2438 BoomError::deserialize(&mut frame.deserializer())
2439 .unwrap()
2440 .message
2441 .as_deref(),
2442 Some("failed")
2443 );
2444 }
2445
2446 #[test]
2447 fn duplicate_content_types_validate_the_last_value() {
2448 for protocol in [
2449 json_protocol(),
2450 cbor_protocol(),
2451 SharedServerProtocol::metadata_routed(crate::schema::protocol::RestXml::default()),
2452 ] {
2453 for event in [
2454 TestEvents::Text(TextEvent {
2455 value: Some("hello".to_owned()),
2456 }),
2457 TestEvents::Bin(BinEvent {
2458 value: Some(Blob::new(b"hello")),
2459 }),
2460 ] {
2461 let original = marshall(&protocol, event);
2462 for incorrect in [HeaderValue::String("application/json".into()), HeaderValue::Int32(123)] {
2463 for incorrect_is_last in [false, true] {
2464 let mut headers = original.headers().to_vec();
2465 let duplicate = Header::new(":content-type", incorrect.clone());
2466 if incorrect_is_last {
2467 headers.push(duplicate);
2468 } else {
2469 headers.insert(0, duplicate);
2470 }
2471 let message = Message::new_from_parts(headers, original.payload().clone());
2472 let result = unmarshall(&protocol, &message);
2473 if incorrect_is_last {
2474 assert!(result.is_err(), "the final content type must be validated");
2475 } else {
2476 let parsed = match result.unwrap() {
2477 UnmarshalledMessage::Event(event) => event,
2478 other => panic!("expected an event, got {other:?}"),
2479 };
2480 let baseline = match unmarshall(&protocol, &original).unwrap() {
2481 UnmarshalledMessage::Event(event) => event,
2482 other => panic!("expected an event, got {other:?}"),
2483 };
2484 assert_eq!(parsed, baseline);
2485 }
2486 let frame = EventFrame::new(&message, protocol.event_stream_framing().unwrap());
2488 let result = match string_header(&original, ":event-type").unwrap() {
2489 "text" => TextEvent::deserialize(&mut frame.deserializer()).map(|_| ()),
2490 "bin" => BinEvent::deserialize(&mut frame.deserializer()).map(|_| ()),
2491 _ => unreachable!(),
2492 };
2493 assert_eq!(result.is_err(), incorrect_is_last);
2494 }
2495 }
2496 }
2497 }
2498 }
2499
2500 #[test]
2501 fn duplicate_protocol_type_headers_validate_only_the_selected_value() {
2502 let protocol = json_protocol();
2503 for (name, selected, message_type) in [
2504 (":message-type", "event", "event"),
2505 (":event-type", "text", "event"),
2506 (":exception-type", "boom", "exception"),
2507 ] {
2508 for incorrect_is_last in [false, true] {
2509 let mut headers = vec![
2510 Header::new(":message-type", HeaderValue::String(message_type.into())),
2511 Header::new(":event-type", HeaderValue::String("text".into())),
2512 Header::new(":exception-type", HeaderValue::String("boom".into())),
2513 Header::new(":content-type", HeaderValue::String("text/plain".into())),
2514 ];
2515 headers.retain(|header| header.name().as_str() != name);
2516 let mut duplicates = vec![
2517 Header::new(name, HeaderValue::Int32(123)),
2518 Header::new(name, HeaderValue::String(selected.into())),
2519 ];
2520 if incorrect_is_last {
2521 duplicates.reverse();
2522 }
2523 headers.extend(duplicates);
2524 let payload = if message_type == "event" {
2525 Bytes::from_static(b"hello")
2526 } else {
2527 Bytes::from_static(br#"{"message":"failed"}"#)
2528 };
2529 let message = Message::new_from_parts(headers, payload);
2530 let result = unmarshall(&protocol, &message);
2531 if incorrect_is_last {
2532 assert!(result.unwrap_err().to_string().contains(name));
2533 } else {
2534 match result.unwrap() {
2535 UnmarshalledMessage::Event(TestEvents::Text(event)) => {
2536 assert_eq!(event.value.as_deref(), Some("hello"));
2537 }
2538 UnmarshalledMessage::Error(TestEventsError::Boom(error)) => {
2539 assert_eq!(error.message.as_deref(), Some("failed"));
2540 }
2541 other => panic!("unexpected result: {other:?}"),
2542 }
2543 }
2544 }
2545 }
2546 }
2547
2548 #[test]
2549 fn duplicate_modeled_headers_validate_every_value_before_overwriting() {
2550 let protocol = json_protocol();
2551 let headers = vec![
2552 Header::new(":message-type", HeaderValue::String("event".into())),
2553 Header::new(":event-type", HeaderValue::String("allHeaders".into())),
2554 Header::new("name", HeaderValue::String("first".into())),
2555 Header::new("name", HeaderValue::String("last".into())),
2556 ];
2557 let message = Message::new_from_parts(headers.clone(), Bytes::new());
2558 match unmarshall(&protocol, &message).unwrap() {
2559 UnmarshalledMessage::Event(TestEvents::AllHeaders(event)) => {
2560 assert_eq!(event.name.as_deref(), Some("last"));
2561 }
2562 other => panic!("expected an event, got {other:?}"),
2563 }
2564 for index in [2, 3] {
2565 let mut headers = headers.clone();
2566 headers[index] = Header::new("name", HeaderValue::Int32(123));
2567 let message = Message::new_from_parts(headers, Bytes::new());
2568 assert!(unmarshall(&protocol, &message).is_err());
2569 }
2570 }
2571
2572 #[test]
2573 fn unmarshalling_error_strings() {
2574 let protocol = json_protocol();
2575
2576 let bogus_message_type = Message::new_from_parts(
2577 vec![
2578 Header::new(":message-type", HeaderValue::String("bogus".into())),
2579 Header::new(":event-type", HeaderValue::String("text".into())),
2580 ],
2581 Bytes::new(),
2582 );
2583 assert_eq!(
2586 unmarshall(&protocol, &bogus_message_type).unwrap_err().to_string(),
2587 "failed to unmarshall message: unrecognized `:message-type`: bogus"
2588 );
2589
2590 let unknown_event = Message::new_from_parts(
2591 vec![
2592 Header::new(":message-type", HeaderValue::String("event".into())),
2593 Header::new(":event-type", HeaderValue::String("nope".into())),
2594 ],
2595 Bytes::new(),
2596 );
2597 assert_eq!(
2598 unmarshall(&protocol, &unknown_event).unwrap_err().to_string(),
2599 "failed to unmarshall message: unrecognized :event-type: nope"
2600 );
2601
2602 let unknown_exception = Message::new_from_parts(
2603 vec![
2604 Header::new(":message-type", HeaderValue::String("exception".into())),
2605 Header::new(":exception-type", HeaderValue::String("nope".into())),
2606 ],
2607 Bytes::new(),
2608 );
2609 assert_eq!(
2610 unmarshall(&protocol, &unknown_exception).unwrap_err().to_string(),
2611 "failed to unmarshall message: unrecognized exception: nope"
2612 );
2613
2614 let wrong_content_type = Message::new_from_parts(
2615 vec![
2616 Header::new(":message-type", HeaderValue::String("event".into())),
2617 Header::new(":event-type", HeaderValue::String("text".into())),
2618 Header::new(":content-type", HeaderValue::String("application/json".into())),
2619 ],
2620 Bytes::from_static(b"raw"),
2621 );
2622 assert!(unmarshall(&protocol, &wrong_content_type)
2623 .unwrap_err()
2624 .to_string()
2625 .contains("expected :content-type to be 'text/plain', but was 'application/json'"));
2626
2627 let invalid_utf8 = Message::new_from_parts(
2628 vec![
2629 Header::new(":message-type", HeaderValue::String("event".into())),
2630 Header::new(":event-type", HeaderValue::String("text".into())),
2631 Header::new(":content-type", HeaderValue::String("text/plain".into())),
2632 ],
2633 Bytes::from_static(b"\xff\xfe"),
2634 );
2635 assert!(unmarshall(&protocol, &invalid_utf8)
2636 .unwrap_err()
2637 .to_string()
2638 .contains("message payload is not valid UTF-8"));
2639 }
2640
2641 #[test]
2642 fn modeled_error_marshals_as_exception_frame() {
2643 let protocol = json_protocol();
2644 let marshaller = SchemaEventErrorMarshaller::<TestEventsError>::new(protocol.clone());
2645 let message = marshaller
2646 .marshall(TestEventsError::Boom(BoomError {
2647 message: Some("failure".to_owned()),
2648 }))
2649 .expect("marshalls");
2650 assert_eq!(string_header(&message, ":message-type"), Some("exception"));
2651 assert_eq!(string_header(&message, ":exception-type"), Some("boom"));
2652 assert_eq!(string_header(&message, ":content-type"), Some("application/json"));
2653 match unmarshall(&protocol, &message).expect("unmarshalls") {
2654 UnmarshalledMessage::Error(TestEventsError::Boom(parsed)) => {
2655 assert_eq!(parsed.message.as_deref(), Some("failure"));
2656 }
2657 other => panic!("unexpected result: {other:?}"),
2658 }
2659 }
2660
2661 #[test]
2662 fn aws_json_exception_frames_include_the_protocol_discriminator() {
2663 use crate::schema::protocol::{AwsJson1_0, AwsJson1_1};
2664 for (protocol, expected) in [
2665 (
2666 SharedServerProtocol::metadata_routed(AwsJson1_0::default()),
2667 "test#BoomError",
2668 ),
2669 (
2670 SharedServerProtocol::metadata_routed(AwsJson1_1::default()),
2671 "BoomError",
2672 ),
2673 ] {
2674 let marshaller = SchemaEventErrorMarshaller::<TestEventsError>::new(protocol.clone());
2675 let message = marshaller
2676 .marshall(TestEventsError::Boom(BoomError {
2677 message: Some("failure".into()),
2678 }))
2679 .unwrap();
2680 assert_eq!(
2681 message.payload().as_ref(),
2682 format!(r#"{{"message":"failure","__type":"{expected}"}}"#).as_bytes()
2683 );
2684 assert!(matches!(
2685 unmarshall(&protocol, &message).unwrap(),
2686 UnmarshalledMessage::Error(TestEventsError::Boom(_))
2687 ));
2688 }
2689 }
2690
2691 #[test]
2692 fn unmodeled_error_marshaller_emits_a_bare_exception_frame() {
2693 let marshaller = NoModeledEventErrorMarshaller::new(json_protocol());
2694 let message = marshaller
2695 .marshall(aws_smithy_http::event_stream::MessageStreamError::unhandled(
2696 std::io::Error::other("boom"),
2697 ))
2698 .expect("marshalls");
2699 let names: Vec<_> = message.headers().iter().map(|h| h.name().as_str()).collect();
2700 assert_eq!(names, [":message-type"]);
2701 assert_eq!(string_header(&message, ":message-type"), Some("exception"));
2702 assert!(message.payload().is_empty());
2703 }
2704
2705 #[test]
2707 fn protocols_without_event_stream_support_are_rejected() {
2708 #[derive(Debug)]
2709 struct HttpOnly;
2710 impl crate::schema::ServerProtocol for HttpOnly {
2711 fn serialize_runtime_error(&self, error: crate::runtime_error::RuntimeError) -> crate::response::Response {
2712 panic!("unexpected extractor runtime error: {error}")
2713 }
2714
2715 fn protocol_id(&self) -> &'static ShapeId<'static> {
2716 static ID: ShapeId<'static> = aws_smithy_schema::shape_id!("test", "HttpOnly");
2717 &ID
2718 }
2719 fn deserialize_request<'a>(
2720 &'a self,
2721 _: &Schema<'_>,
2722 _: &'a aws_smithy_runtime_api::http::Request<bytes::Bytes>,
2723 ) -> Result<Box<dyn ShapeDeserializer + 'a>, DeserializeError> {
2724 unreachable!()
2725 }
2726 fn serialize_response(&self, _: &Schema<'_>, _: &dyn SerializableStruct) -> crate::response::Response {
2727 unreachable!()
2728 }
2729 fn serialize_streaming_response(
2730 &self,
2731 _: &Schema<'_>,
2732 _: &dyn SerializableStruct,
2733 _streaming_member: &Schema<'_>,
2734 _: Option<BoxBody>,
2735 ) -> crate::response::Response {
2736 unreachable!()
2737 }
2738 fn serialize_error(&self, _: &dyn crate::schema::HttpModeledError) -> crate::response::Response {
2739 unreachable!()
2740 }
2741 fn serialize_rejection(&self, _: DeserializeError) -> crate::response::Response {
2742 unreachable!()
2743 }
2744 }
2745
2746 let protocol = SharedServerProtocol::serde_only(HttpOnly);
2747 assert!(SchemaEventMarshaller::<TestEvents>::new(protocol.clone())
2748 .marshall(TestEvents::Empty(EmptyEvent))
2749 .is_err());
2750 assert!(SchemaEventMarshaller::<TestEvents>::new(protocol.clone())
2751 .marshall(TestEvents::Text(TextEvent {
2752 value: Some("raw".to_owned())
2753 }))
2754 .is_err());
2755 assert!(SchemaEventErrorMarshaller::<TestEventsError>::new(protocol.clone())
2756 .marshall(TestEventsError::Boom(BoomError { message: None }))
2757 .is_err());
2758 assert!(NoModeledEventErrorMarshaller::new(protocol.clone())
2759 .marshall(aws_smithy_http::event_stream::MessageStreamError::unhandled(
2760 std::io::Error::other("boom"),
2761 ))
2762 .is_err());
2763 assert!(SchemaEventUnmarshaller::<TestEvents>::new(protocol)
2764 .unmarshall(&Message::new(Bytes::new()))
2765 .is_err());
2766 }
2767
2768 fn write_frame(message: &Message, out: &mut Vec<u8>) {
2771 aws_smithy_eventstream::frame::write_message_to(message, out).expect("writes");
2772 }
2773
2774 fn initial_request_frame(payload: &'static [u8], content_type: &str) -> Message {
2775 Message::new_from_parts(
2776 vec![
2777 Header::new(":message-type", HeaderValue::String("event".into())),
2778 Header::new(":event-type", HeaderValue::String("initial-request".into())),
2779 Header::new(":content-type", HeaderValue::String(content_type.to_owned().into())),
2780 ],
2781 Bytes::from_static(payload),
2782 )
2783 }
2784
2785 #[tokio::test]
2786 async fn apply_initial_request_reads_the_initial_frame() {
2787 let protocol = cbor_protocol();
2788 let mut body = Vec::new();
2790 write_frame(
2791 &initial_request_frame(b"\xa1\x64text\x62hi", "application/cbor"),
2792 &mut body,
2793 );
2794 write_frame(
2795 &marshall(
2796 &protocol,
2797 TestEvents::Text(TextEvent {
2798 value: Some("evt".to_owned()),
2799 }),
2800 ),
2801 &mut body,
2802 );
2803 let unmarshaller = SchemaEventUnmarshaller::<TestEvents>::new(protocol.clone());
2804 let mut receiver = Receiver::new(unmarshaller, aws_smithy_types::body::SdkBody::from(body));
2805 let mut applied = None;
2806 apply_initial_request(
2807 |mt| receiver.try_recv_initial(mt),
2808 &protocol,
2809 |deser| {
2810 applied = Some(PlainEvent::deserialize(deser)?);
2811 Ok(())
2812 },
2813 )
2814 .await
2815 .expect("applies");
2816 assert_eq!(applied.and_then(|p| p.text).as_deref(), Some("hi"));
2817 let event = receiver.recv().await.expect("a frame").expect("an event");
2819 assert_eq!(
2820 event,
2821 TestEvents::Text(TextEvent {
2822 value: Some("evt".to_owned())
2823 })
2824 );
2825 }
2826
2827 #[tokio::test]
2828 async fn apply_initial_request_preserves_a_first_ordinary_event() {
2829 let protocol = cbor_protocol();
2830 let mut body = Vec::new();
2831 write_frame(
2832 &marshall(
2833 &protocol,
2834 TestEvents::Text(TextEvent {
2835 value: Some("evt".to_owned()),
2836 }),
2837 ),
2838 &mut body,
2839 );
2840 let unmarshaller = SchemaEventUnmarshaller::<TestEvents>::new(protocol.clone());
2841 let mut receiver = Receiver::new(unmarshaller, aws_smithy_types::body::SdkBody::from(body));
2842 apply_initial_request(
2843 |mt| receiver.try_recv_initial(mt),
2844 &protocol,
2845 |_| panic!("no initial frame to apply"),
2846 )
2847 .await
2848 .expect("no initial frame is fine");
2849 let event = receiver.recv().await.expect("a frame").expect("an event");
2850 assert_eq!(
2851 event,
2852 TestEvents::Text(TextEvent {
2853 value: Some("evt".to_owned())
2854 })
2855 );
2856 }
2857
2858 #[tokio::test]
2859 async fn apply_initial_request_skips_protocols_without_initial_frames() {
2860 let protocol = json_protocol();
2861 let unmarshaller = SchemaEventUnmarshaller::<TestEvents>::new(protocol.clone());
2862 let mut receiver = Receiver::new(unmarshaller, aws_smithy_types::body::SdkBody::from(Vec::<u8>::new()));
2863 apply_initial_request(
2864 |mt| receiver.try_recv_initial(mt),
2865 &protocol,
2866 |_| panic!("restJson1 carries no initial frames"),
2867 )
2868 .await
2869 .expect("nothing to do");
2870 }
2871
2872 #[tokio::test]
2873 async fn apply_initial_request_reports_malformed_frames() {
2874 let protocol = cbor_protocol();
2875 let unmarshaller = SchemaEventUnmarshaller::<TestEvents>::new(protocol.clone());
2876 let mut receiver = Receiver::new(
2877 unmarshaller,
2878 aws_smithy_types::body::SdkBody::from(&b"malformed frame"[..]),
2879 );
2880 let err = apply_initial_request(|mt| receiver.try_recv_initial(mt), &protocol, |_| Ok(()))
2881 .await
2882 .expect_err("malformed frame");
2883 assert!(matches!(&err, DeserializeError::InitialRequestFrame(_)));
2884 assert!(err.to_string().contains("failed to read the initial-request frame"));
2885 }
2886
2887 async fn collect_frames(body: BoxBody) -> Vec<Message> {
2888 use http_body_util::BodyExt;
2889 let mut bytes = body.collect().await.expect("collects").to_bytes();
2890 let mut frames = Vec::new();
2891 while !bytes.is_empty() {
2892 frames.push(aws_smithy_eventstream::frame::read_message_from(&mut bytes).expect("valid frame"));
2893 }
2894 frames
2895 }
2896
2897 fn response_body_for(
2898 protocol: &SharedServerProtocol,
2899 initial_response: InitialResponsePolicy,
2900 ) -> Result<BoxBody, SerdeError> {
2901 let events: EventStreamSender<TestEvents, TestEventsError> =
2902 futures_util::stream::iter([Ok(TestEvents::Text(TextEvent {
2903 value: Some("evt".to_owned()),
2904 }))])
2905 .into();
2906 let output = PlainEvent {
2908 text: Some("topic".to_owned()),
2909 };
2910 event_stream_response_body(
2911 &PLAIN_EVENT_SCHEMA,
2912 &output,
2913 events,
2914 SchemaEventMarshaller::<TestEvents>::new(protocol.clone()),
2915 SchemaEventErrorMarshaller::<TestEventsError>::new(protocol.clone()),
2916 protocol,
2917 initial_response,
2918 )
2919 }
2920
2921 #[tokio::test]
2922 async fn response_body_prepends_the_initial_response_frame_when_asked() {
2923 let body = response_body_for(&cbor_protocol(), InitialResponsePolicy::Send).expect("builds");
2924 let frames = collect_frames(body).await;
2925 assert_eq!(frames.len(), 2);
2926 assert_eq!(string_header(&frames[0], ":event-type"), Some("initial-response"));
2927 assert_eq!(string_header(&frames[0], ":content-type"), Some("application/cbor"));
2928 assert_eq!(string_header(&frames[1], ":event-type"), Some("text"));
2929 }
2930
2931 #[tokio::test]
2932 async fn response_body_rpc_initial_response_preserves_output_members() {
2933 use crate::schema::protocol::{AwsJson1_0, AwsJson1_1};
2934 for protocol in [
2935 cbor_protocol(),
2936 SharedServerProtocol::metadata_routed(AwsJson1_0::default()),
2937 SharedServerProtocol::metadata_routed(AwsJson1_1::default()),
2938 ] {
2939 let frames = collect_frames(response_body_for(&protocol, InitialResponsePolicy::Send).unwrap()).await;
2940 assert_eq!(frames.len(), 2);
2941 assert_eq!(string_header(&frames[0], ":event-type"), Some("initial-response"));
2942 let capability = protocol.event_stream_framing().unwrap();
2943 assert!(capability.initial_messages_in_frames);
2944 let mut deser = capability.payload_codec.create_deserializer(frames[0].payload());
2945 assert_eq!(
2946 PlainEvent::deserialize(&mut *deser).unwrap(),
2947 PlainEvent {
2948 text: Some("topic".to_owned())
2949 }
2950 );
2951 }
2952 }
2953
2954 #[tokio::test]
2955 async fn response_body_omits_the_initial_response_frame_when_disabled() {
2956 let body = response_body_for(&cbor_protocol(), InitialResponsePolicy::Omit).expect("builds");
2957 let frames = collect_frames(body).await;
2958 assert_eq!(frames.len(), 1);
2959 assert_eq!(string_header(&frames[0], ":event-type"), Some("text"));
2960 }
2961
2962 #[tokio::test]
2963 async fn response_body_rest_initial_response_frames_match_legacy() {
2964 for (protocol, media_type, payload) in [
2967 (json_protocol(), "application/json", &b"{}"[..]),
2968 (
2969 SharedServerProtocol::metadata_routed(crate::schema::protocol::RestXml::default()),
2970 "application/xml",
2971 &b""[..],
2972 ),
2973 ] {
2974 assert!(!protocol.event_stream_framing().unwrap().initial_messages_in_frames);
2975 let frames = collect_frames(response_body_for(&protocol, InitialResponsePolicy::Send).unwrap()).await;
2976 assert_eq!(frames.len(), 2);
2977 assert_eq!(string_header(&frames[0], ":message-type"), Some("event"));
2978 assert_eq!(string_header(&frames[0], ":event-type"), Some("initial-response"));
2979 assert_eq!(string_header(&frames[0], ":content-type"), Some(media_type));
2980 assert_eq!(frames[0].payload().as_ref(), payload);
2981 assert_eq!(string_header(&frames[1], ":event-type"), Some("text"));
2982
2983 let omitted = collect_frames(response_body_for(&protocol, InitialResponsePolicy::Omit).unwrap()).await;
2984 assert_eq!(omitted.len(), 1);
2985 assert_eq!(omitted[0], frames[1]);
2986 }
2987 }
2988
2989 #[tokio::test]
2990 async fn response_body_rest_initial_response_does_not_poll_application_events() {
2991 use http_body_util::BodyExt;
2992 for protocol in [
2993 json_protocol(),
2994 SharedServerProtocol::metadata_routed(crate::schema::protocol::RestXml::default()),
2995 ] {
2996 let events: EventStreamSender<TestEvents, TestEventsError> = futures_util::stream::poll_fn(|_| {
2997 panic!("the initial response must arrive before polling application events");
2998 #[allow(unreachable_code)]
2999 std::task::Poll::Ready(None)
3000 })
3001 .into();
3002 let output = PlainEvent {
3003 text: Some("topic".to_owned()),
3004 };
3005 let mut body = event_stream_response_body(
3006 &PLAIN_EVENT_SCHEMA,
3007 &output,
3008 events,
3009 SchemaEventMarshaller::<TestEvents>::new(protocol.clone()),
3010 SchemaEventErrorMarshaller::<TestEventsError>::new(protocol.clone()),
3011 &protocol,
3012 InitialResponsePolicy::Send,
3013 )
3014 .unwrap();
3015 let bytes = tokio::time::timeout(std::time::Duration::from_secs(1), body.frame())
3016 .await
3017 .expect("initial response arrives on an idle stream")
3018 .unwrap()
3019 .unwrap()
3020 .into_data()
3021 .unwrap();
3022 let mut bytes = bytes.as_ref();
3023 let frame = aws_smithy_eventstream::frame::read_message_from(&mut bytes).unwrap();
3024 assert_eq!(string_header(&frame, ":event-type"), Some("initial-response"));
3025 assert!(bytes.is_empty());
3026 }
3027 }
3028
3029 #[tokio::test]
3030 async fn response_body_carries_modeled_errors_as_exception_frames() {
3031 let protocol = json_protocol();
3032 let events: EventStreamSender<TestEvents, TestEventsError> =
3033 futures_util::stream::iter([Err(TestEventsError::Boom(BoomError {
3034 message: Some("failure".to_owned()),
3035 }))])
3036 .into();
3037 let output = PlainEvent { text: None };
3038 let body = event_stream_response_body(
3039 &PLAIN_EVENT_SCHEMA,
3040 &output,
3041 events,
3042 SchemaEventMarshaller::<TestEvents>::new(protocol.clone()),
3043 SchemaEventErrorMarshaller::<TestEventsError>::new(protocol.clone()),
3044 &protocol,
3045 InitialResponsePolicy::Omit,
3046 )
3047 .expect("builds");
3048 let frames = collect_frames(body).await;
3049 assert_eq!(frames.len(), 1);
3050 assert_eq!(string_header(&frames[0], ":message-type"), Some("exception"));
3051 assert_eq!(string_header(&frames[0], ":exception-type"), Some("boom"));
3052 }
3053}