1use std::{
7 convert::Infallible,
8 future::{Future, Ready},
9 marker::PhantomData,
10 pin::Pin,
11 task::{Context, Poll},
12 time::Duration,
13};
14
15use futures_util::ready;
16use http::{header, StatusCode, Version};
17use pin_project_lite::pin_project;
18use tower::{util::Oneshot, Service, ServiceExt};
19use tracing::{debug, error, trace};
20
21use crate::{
22 body::{BoxBody, __private::HttpBody},
23 plugin::Plugin,
24 request::{FromParts, FromRequest},
25 response::IntoResponse,
26 runtime_error::InternalFailureException,
27 schema::{
28 collect_request_body, BodyDirective, DeserializableShape, DeserializeError, HttpModeledError, SelectedOperation,
29 },
30 service::ServiceShape,
31 settings::RequestBodyReadTimeoutConfig,
32};
33
34use super::{OperationShape, SchemaOperationShape, StreamingOperationShape};
35use aws_smithy_schema::serde::SerializableStruct;
36use aws_smithy_types::body::SdkBody;
37
38#[derive(Debug, Clone)]
43pub struct UpgradePlugin<Extractors> {
44 _extractors: PhantomData<Extractors>,
45 request_body_read_timeout: Option<RequestBodyReadTimeoutConfig>,
46}
47
48#[derive(Debug, Clone)]
50pub struct DynUpgradePlugin<Extractors> {
51 _extractors: PhantomData<Extractors>,
52}
53
54impl<Extractors> DynUpgradePlugin<Extractors> {
55 pub fn new() -> Self {
56 Self {
57 _extractors: PhantomData,
58 }
59 }
60}
61
62impl<Extractors> Default for DynUpgradePlugin<Extractors> {
63 fn default() -> Self {
64 Self::new()
65 }
66}
67
68impl<Ser, Op, T, Extractors> Plugin<Ser, Op, T> for DynUpgradePlugin<Extractors>
69where
70 Ser: ServiceShape,
71 Op: SchemaOperationShape,
72{
73 type Output = DynUpgrade<Ser::Protocol, Op, Extractors, T>;
74 fn apply(&self, inner: T) -> Self::Output {
75 DynUpgrade {
76 _protocol: PhantomData,
77 _operation: PhantomData,
78 _extractors: PhantomData,
79 inner,
80 }
81 }
82}
83
84pub struct DynUpgrade<P, Op, Extractors, S> {
91 _protocol: PhantomData<fn() -> P>,
93 _operation: PhantomData<Op>,
94 _extractors: PhantomData<Extractors>,
95 inner: S,
96}
97
98impl<P, Op, Extractors, S: Clone> Clone for DynUpgrade<P, Op, Extractors, S> {
99 fn clone(&self) -> Self {
100 Self {
101 _protocol: PhantomData,
102 _operation: PhantomData,
103 _extractors: PhantomData,
104 inner: self.inner.clone(),
105 }
106 }
107}
108
109enum SelectedOperationError {
110 Missing,
111 Mismatched(SelectedOperation),
112}
113
114impl SelectedOperationError {
115 fn into_response(self) -> http::Response<BoxBody> {
116 match self {
117 Self::Missing => empty_internal_server_error(),
118 Self::Mismatched(selected) => IntoResponse::<()>::into_response_with_protocol(
119 crate::runtime_error::RuntimeError::from(InternalFailureException),
120 &**selected.protocol(),
121 ),
122 }
123 }
124}
125
126fn selected_operation<Op: SchemaOperationShape>(
128 extensions: &http::Extensions,
129) -> Result<SelectedOperation, SelectedOperationError> {
130 let Some(selected) = SelectedOperation::get_from_extensions(extensions).cloned() else {
131 error!(operation = %Op::ID.absolute(), "selected protocol operation missing from request extensions");
132 return Err(SelectedOperationError::Missing);
133 };
134 if !std::ptr::eq(selected.operation(), Op::SCHEMA) {
135 error!(operation = %Op::ID.absolute(), "selected protocol operation is incompatible with the routed operation");
136 return Err(SelectedOperationError::Mismatched(selected));
137 }
138 Ok(selected)
139}
140
141pub(crate) fn convert_request<B>(
143 parts: http::request::Parts,
144 body: B,
145) -> Result<aws_smithy_runtime_api::http::Request<B>, DeserializeError> {
146 aws_smithy_runtime_api::http::Request::try_from(http::Request::from_parts(parts, body))
147 .map_err(|err| DeserializeError::Serde(aws_smithy_schema::serde::SerdeError::custom(err.to_string())))
148}
149
150impl<P, Op, Extractors, B, S> Service<http::Request<B>> for DynUpgrade<P, Op, Extractors, S>
151where
152 Op: SchemaOperationShape,
153 Op::Input: DeserializableShape + Send + 'static,
154 Op::Output: SerializableStruct + Send + 'static,
155 Extractors: FromParts<P> + Send + 'static,
156 <Extractors as FromParts<P>>::Rejection: std::fmt::Display + IntoResponse<P>,
157 B: HttpBody + Send + 'static,
158 B::Data: Send,
159 B::Error: std::error::Error + Send + Sync + 'static,
160 S: Service<(Op::Input, Extractors), Response = Op::Output> + Clone + Send + 'static,
161 S::Error: HttpModeledError,
162 S::Future: Send + 'static,
163{
164 type Response = http::Response<BoxBody>;
165 type Error = Infallible;
166 type Future = Pin<Box<dyn Future<Output = Result<Self::Response, Self::Error>> + Send>>;
167
168 fn poll_ready(&mut self, _cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
169 Poll::Ready(Ok(()))
170 }
171
172 fn call(&mut self, req: http::Request<B>) -> Self::Future {
173 let clone = self.inner.clone();
174 let service = std::mem::replace(&mut self.inner, clone);
175 Box::pin(async move {
176 let (mut parts, body) = req.into_parts();
177 let selected = match selected_operation::<Op>(&parts.extensions) {
178 Ok(selected) => selected,
179 Err(error) => return Ok(error.into_response()),
180 };
181 let protocol = selected.protocol();
182 let operation = selected.operation();
183 if operation.input().members().iter().any(|member| member.streaming()) {
184 error!("streaming operation routed through DynUpgrade");
185 return Ok(IntoResponse::<P>::into_response_with_protocol(
186 crate::runtime_error::RuntimeError::from(InternalFailureException),
187 &**protocol,
188 ));
189 }
190 let extractors = match Extractors::from_parts(&mut parts) {
191 Ok(value) => value,
192 Err(err) => {
193 error!(error = %err, operation = %operation.shape_id(), protocol = %protocol.protocol_id(),
196 "additional parameter for the handler function could not be constructed");
197 return Ok(err.into_response_with_protocol(&**protocol));
198 }
199 };
200 let mut request = match convert_request(parts, body) {
201 Ok(request) => request.map(Some),
202 Err(err) => {
203 debug!(error = %err, operation = %operation.shape_id(), protocol = %protocol.protocol_id(),
204 "failed to deserialize request into operation's input");
205 return Ok(protocol.serialize_rejection(err));
206 }
207 };
208 let body = request.body_mut().take().expect("request body is present");
209 if let Err(err) = protocol.validate_request_headers(operation, request.headers()) {
210 debug!(error = %err, operation = %operation.shape_id(), protocol = %protocol.protocol_id(),
211 "failed to deserialize request into operation's input");
212 return Ok(protocol.serialize_rejection(err));
213 }
214 let bytes = match protocol.request_body_requirement(operation) {
215 BodyDirective::Collect => match collect_request_body(body, &selected.request_body_config()).await {
216 Ok(bytes) => bytes,
217 Err(err) => {
218 debug!(error = %err, operation = %operation.shape_id(), protocol = %protocol.protocol_id(),
219 "failed to deserialize request into operation's input");
220 return Ok(crate::schema::body_collection_rejection(
221 &**protocol,
222 err.map_body_error(crate::Error::new),
223 ));
224 }
225 },
226 BodyDirective::Skip => bytes::Bytes::new(),
227 };
228 let request = request.map(|_| bytes.clone());
231 let input = {
232 let mut deserializer = match protocol.deserialize_request(operation.input(), &request) {
233 Ok(value) => value,
234 Err(err) => {
235 debug!(error = %err, operation = %operation.shape_id(), protocol = %protocol.protocol_id(),
236 "failed to deserialize request into operation's input");
237 return Ok(protocol.serialize_rejection(err));
238 }
239 };
240 match Op::Input::deserialize(&mut *deserializer) {
241 Ok(value) => value,
242 Err(err) => {
243 debug!(error = %err, operation = %operation.shape_id(), protocol = %protocol.protocol_id(),
244 "failed to deserialize request into operation's input");
245 return Ok(protocol.serialize_rejection(err));
246 }
247 }
248 };
249 match service.oneshot((input, extractors)).await {
250 Ok(output) => Ok(protocol.serialize_response(operation.output(), &output)),
251 Err(err) => Ok(protocol.serialize_error(&err)),
252 }
253 })
254 }
255}
256
257#[derive(Debug, Clone)]
265pub struct DynStreamingUpgradePlugin<Extractors> {
266 _extractors: PhantomData<Extractors>,
267}
268
269impl<Extractors> DynStreamingUpgradePlugin<Extractors> {
270 pub fn new() -> Self {
271 Self {
272 _extractors: PhantomData,
273 }
274 }
275}
276
277impl<Extractors> Default for DynStreamingUpgradePlugin<Extractors> {
278 fn default() -> Self {
279 Self::new()
280 }
281}
282
283impl<Ser, Op, T, Extractors> Plugin<Ser, Op, T> for DynStreamingUpgradePlugin<Extractors>
284where
285 Ser: ServiceShape,
286 Op: StreamingOperationShape,
287{
288 type Output = DynStreamingUpgrade<Ser::Protocol, Op, Extractors, T>;
289 fn apply(&self, inner: T) -> Self::Output {
290 DynStreamingUpgrade {
291 _protocol: PhantomData,
292 _operation: PhantomData,
293 _extractors: PhantomData,
294 inner,
295 }
296 }
297}
298
299pub struct DynStreamingUpgrade<P, Op, Extractors, S> {
306 _protocol: PhantomData<fn() -> P>,
308 _operation: PhantomData<Op>,
309 _extractors: PhantomData<Extractors>,
310 inner: S,
311}
312
313impl<P, Op, Extractors, S: Clone> Clone for DynStreamingUpgrade<P, Op, Extractors, S> {
314 fn clone(&self) -> Self {
315 Self {
316 _protocol: PhantomData,
317 _operation: PhantomData,
318 _extractors: PhantomData,
319 inner: self.inner.clone(),
320 }
321 }
322}
323
324impl<P, Op, Extractors, B, S> Service<http::Request<B>> for DynStreamingUpgrade<P, Op, Extractors, S>
325where
326 Op: StreamingOperationShape,
327 Op::Input: Send + 'static,
328 Op::Output: Send + 'static,
329 Extractors: FromParts<P> + Send + 'static,
330 <Extractors as FromParts<P>>::Rejection: std::fmt::Display + IntoResponse<P>,
331 B: HttpBody<Data = bytes::Bytes> + Send + Sync + 'static,
332 B::Error: std::error::Error + Send + Sync + 'static,
333 S: Service<(Op::Input, Extractors), Response = Op::Output> + Clone + Send + 'static,
334 S::Error: HttpModeledError,
335 S::Future: Send + 'static,
336{
337 type Response = http::Response<BoxBody>;
338 type Error = Infallible;
339 type Future = Pin<Box<dyn Future<Output = Result<Self::Response, Self::Error>> + Send>>;
340
341 fn poll_ready(&mut self, _cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
342 Poll::Ready(Ok(()))
343 }
344
345 fn call(&mut self, req: http::Request<B>) -> Self::Future {
346 let clone = self.inner.clone();
347 let service = std::mem::replace(&mut self.inner, clone);
348 Box::pin(async move {
349 let (mut parts, body) = req.into_parts();
350 let selected = match selected_operation::<Op>(&parts.extensions) {
351 Ok(selected) => selected,
352 Err(error) => return Ok(error.into_response()),
353 };
354 let protocol = selected.protocol();
355 let operation = selected.operation();
356 let has_event_stream = [operation.input(), operation.output()].iter().any(|schema| {
357 schema
358 .members()
359 .iter()
360 .any(|member| member.streaming() && member.shape_type() == aws_smithy_schema::ShapeType::Union)
361 });
362 if has_event_stream && protocol.event_stream_framing().is_none() {
363 trace!(operation = %operation.shape_id(), protocol = %protocol.protocol_id(),
364 "selected protocol does not support event streams");
365 return Ok(empty_not_implemented());
366 }
367
368 let extractors = match Extractors::from_parts(&mut parts) {
369 Ok(value) => value,
370 Err(err) => {
371 error!(error = %err, operation = %operation.shape_id(), protocol = %protocol.protocol_id(),
374 "additional parameter for the handler function could not be constructed");
375 return Ok(err.into_response_with_protocol(&**protocol));
376 }
377 };
378 let request = match convert_request(parts, crate::body::RequestBody::new(body)) {
379 Ok(request) => request,
380 Err(err) => {
381 debug!(error = %err, operation = %operation.shape_id(), protocol = %protocol.protocol_id(),
382 "failed to deserialize request into operation's input");
383 return Ok(protocol.serialize_rejection(err));
384 }
385 };
386 let future = Op::deserialize_streaming_input(request, protocol.clone());
387 let input = match future.await {
388 Ok(value) => value,
389 Err(err) => {
390 debug!(error = %err, operation = %operation.shape_id(), protocol = %protocol.protocol_id(),
391 "failed to deserialize request into operation's input");
392 return Ok(protocol.serialize_rejection(err));
393 }
394 };
395 match service.oneshot((input, extractors)).await {
396 Ok(output) => Ok(Op::serialize_streaming_output(output, protocol)),
397 Err(err) => Ok(protocol.serialize_error(&err)),
398 }
399 })
400 }
401}
402
403#[doc(hidden)]
408pub fn deserialize_streaming_request<I, F>(
409 operation: &'static crate::schema::OperationSchema<'static>,
410 request: aws_smithy_runtime_api::http::Request<crate::body::RequestBody>,
411 protocol: crate::schema::SharedServerProtocol,
412 deserialize: F,
413) -> super::StreamingInputFuture<I>
414where
415 I: Send + 'static,
416 F: FnOnce(
417 &mut dyn aws_smithy_schema::serde::ShapeDeserializer,
418 SdkBody,
419 crate::schema::SharedServerProtocol,
420 ) -> super::StreamingInputFuture<I>
421 + Send
422 + 'static,
423{
424 Box::pin(async move {
425 protocol.validate_request_headers(operation, request.headers())?;
426 let config = SelectedOperation::get_from_runtime_request(&request).map(SelectedOperation::request_body_config);
427 let mut request = request.map(Some);
428 let body = request.body_mut().take().expect("request body is present");
429 let directive = protocol.request_body_requirement(operation);
430 let input_streams = operation.input().members().iter().any(|member| {
431 member.streaming()
432 && (member.shape_type() == aws_smithy_schema::ShapeType::Union || directive != BodyDirective::Collect)
433 });
434 let (bytes, body) = if input_streams {
435 let body = crate::body::__private::wrap_streaming_body(body, config.unwrap_or_default().read_poll_budget);
436 (bytes::Bytes::new(), SdkBody::from_body_1_x(body))
437 } else if directive == BodyDirective::Collect {
438 let config = config.ok_or_else(|| {
441 DeserializeError::InternalFailure(crate::Error::new(std::io::Error::other(
442 "selected operation missing while preparing collected input",
443 )))
444 })?;
445 let bytes = collect_request_body(body, &config)
446 .await
447 .map_err(DeserializeError::from)?;
448 (bytes, SdkBody::empty())
449 } else {
450 (bytes::Bytes::new(), SdkBody::empty())
451 };
452 let request = request.map(|_| bytes.clone());
455 let future = {
456 let mut deserializer = protocol.deserialize_request(operation.input(), &request)?;
457 deserialize(&mut *deserializer, body, protocol.clone())
458 };
459 future.await
460 })
461}
462
463pub(crate) fn empty_not_implemented() -> http::Response<BoxBody> {
465 let mut response = http::Response::new(crate::body::empty());
466 *response.status_mut() = http::StatusCode::NOT_IMPLEMENTED;
467 response
468}
469
470#[doc(hidden)]
473pub fn empty_internal_server_error() -> http::Response<BoxBody> {
474 let mut response = http::Response::new(crate::body::empty());
475 *response.status_mut() = http::StatusCode::INTERNAL_SERVER_ERROR;
476 response
477}
478
479impl<Extractors> Default for UpgradePlugin<Extractors> {
480 fn default() -> Self {
481 Self {
482 _extractors: PhantomData,
483 request_body_read_timeout: None,
484 }
485 }
486}
487
488impl<Extractors> UpgradePlugin<Extractors> {
489 pub fn new() -> Self {
491 Self::default()
492 }
493
494 #[doc(hidden)]
496 pub fn with_default_request_body_read_timeout(mut self, payload: bool, operation: &'static str) -> Self {
497 self.request_body_read_timeout = RequestBodyReadTimeoutConfig::default_for_operation(payload, operation);
498 self
499 }
500
501 #[doc(hidden)]
505 pub fn with_request_body_read_timeout(mut self, timeout: Duration, operation: &'static str) -> Self {
506 self.request_body_read_timeout = RequestBodyReadTimeoutConfig::new(timeout, operation);
507 self
508 }
509}
510
511impl<Ser, Op, T, Extractors> Plugin<Ser, Op, T> for UpgradePlugin<Extractors>
512where
513 Ser: ServiceShape,
514 Op: OperationShape,
515{
516 type Output = Upgrade<Ser::Protocol, (Op::Input, Extractors), T>;
517
518 fn apply(&self, inner: T) -> Self::Output {
519 Upgrade {
520 _protocol: PhantomData,
521 _input: PhantomData,
522 inner,
523 request_body_read_timeout: self.request_body_read_timeout,
524 }
525 }
526}
527
528pub struct Upgrade<Protocol, Input, S> {
531 _protocol: PhantomData<Protocol>,
532 _input: PhantomData<Input>,
533 inner: S,
534 request_body_read_timeout: Option<RequestBodyReadTimeoutConfig>,
535}
536
537impl<P, Input, S> Clone for Upgrade<P, Input, S>
538where
539 S: Clone,
540{
541 fn clone(&self) -> Self {
542 Self {
543 _protocol: PhantomData,
544 _input: PhantomData,
545 inner: self.inner.clone(),
546 request_body_read_timeout: self.request_body_read_timeout,
547 }
548 }
549}
550
551struct RequestBodyReadTimeoutState {
552 sleep: Option<Pin<Box<tokio::time::Sleep>>>,
556 timeout: Duration,
557 version: Version,
558 operation: &'static str,
559 #[cfg(feature = "request-id")]
560 request_id: Option<String>,
561}
562
563impl RequestBodyReadTimeoutState {
564 fn is_expired(&mut self, cx: &mut Context<'_>) -> bool {
565 self.sleep.as_mut().is_some_and(|sleep| {
566 tokio::time::Instant::now() >= sleep.deadline() || sleep.as_mut().poll(cx).is_ready()
569 })
570 }
571
572 fn response(&self) -> http::Response<crate::body::BoxBody> {
573 #[cfg(feature = "request-id")]
574 if let Some(request_id) = self.request_id.as_deref() {
575 tracing::debug!(
576 operation = self.operation,
577 request_id,
578 timeout_millis = self.timeout.as_millis(),
579 "request body read timed out"
580 );
581 } else {
582 tracing::debug!(
583 operation = self.operation,
584 timeout_millis = self.timeout.as_millis(),
585 "request body read timed out"
586 );
587 }
588 #[cfg(not(feature = "request-id"))]
589 tracing::debug!(
590 operation = self.operation,
591 timeout_millis = self.timeout.as_millis(),
592 "request body read timed out"
593 );
594
595 let mut response = http::Response::builder().status(StatusCode::REQUEST_TIMEOUT);
596 if matches!(self.version, Version::HTTP_10 | Version::HTTP_11) {
597 response = response.header(header::CONNECTION, "close");
598 }
599 response.body(crate::body::empty()).expect("valid response")
600 }
601}
602
603#[cfg(feature = "request-id")]
604fn request_id<B>(req: &http::Request<B>) -> Option<String> {
605 req.extensions()
606 .get::<crate::request::request_id::ServerRequestId>()
607 .map(ToString::to_string)
608}
609
610pin_project! {
611 #[project = InnerProj]
612 #[project_replace = InnerProjReplace]
613 enum Inner<FromFut, HandlerFut> {
614 FromRequest {
615 #[pin]
616 inner: FromFut
617 },
618 Inner {
619 #[pin]
620 call: HandlerFut
621 }
622 }
623}
624
625type InnerAlias<Input, Protocol, B, S> = Inner<<Input as FromRequest<Protocol, B>>::Future, Oneshot<S, Input>>;
626
627pin_project! {
628 pub struct UpgradeFuture<Protocol, Input, B, S>
630 where
631 Input: FromRequest<Protocol, B>,
632 S: Service<Input>,
633 {
634 service: Option<S>,
635 #[pin]
636 inner: InnerAlias<Input, Protocol, B, S>,
637 request_body_read_timeout: Option<RequestBodyReadTimeoutState>,
638 }
639}
640
641impl<P, Input, B, S> Future for UpgradeFuture<P, Input, B, S>
642where
643 Input: FromRequest<P, B>,
644 <Input as FromRequest<P, B>>::Rejection: std::fmt::Display,
645 S: Service<Input>,
646 S::Response: IntoResponse<P>,
647 S::Error: IntoResponse<P>,
648{
649 type Output = Result<http::Response<crate::body::BoxBody>, Infallible>;
650
651 fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
652 loop {
653 let mut this = self.as_mut().project();
654 let this2 = this.inner.as_mut().project();
655
656 let call = match this2 {
657 InnerProj::FromRequest { inner } => {
658 if let Some(timeout) = this.request_body_read_timeout {
659 if timeout.is_expired(cx) {
660 return Poll::Ready(Ok(timeout.response()));
661 }
662 }
663 let result = inner.poll(cx);
664 if let Some(timeout) = this.request_body_read_timeout {
665 if result.is_pending() && timeout.sleep.is_none() {
666 timeout.sleep = Some(Box::pin(tokio::time::sleep(timeout.timeout)));
667 }
668 if timeout.is_expired(cx) {
671 return Poll::Ready(Ok(timeout.response()));
672 }
673 }
674 let result = match result {
675 Poll::Ready(result) => result,
676 Poll::Pending => return Poll::Pending,
677 };
678 *this.request_body_read_timeout = None;
679 match result {
680 Ok(ok) => this
681 .service
682 .take()
683 .expect("futures cannot be polled after completion")
684 .oneshot(ok),
685 Err(err) => {
686 tracing::trace!(error = %err, "parameter for the handler cannot be constructed");
690 return Poll::Ready(Ok(err.into_response()));
691 }
692 }
693 }
694 InnerProj::Inner { call } => {
695 let result = ready!(call.poll(cx));
696 let output = match result {
697 Ok(ok) => ok.into_response(),
698 Err(err) => err.into_response(),
699 };
700 return Poll::Ready(Ok(output));
701 }
702 };
703
704 this.inner.as_mut().project_replace(Inner::Inner { call });
705 }
706 }
707}
708
709impl<P, Input, B, S> Service<http::Request<B>> for Upgrade<P, Input, S>
710where
711 Input: FromRequest<P, B>,
712 <Input as FromRequest<P, B>>::Rejection: std::fmt::Display,
713 S: Service<Input> + Clone,
714 S::Response: IntoResponse<P>,
715 S::Error: IntoResponse<P>,
716{
717 type Response = http::Response<crate::body::BoxBody>;
718 type Error = Infallible;
719 type Future = UpgradeFuture<P, Input, B, S>;
720
721 fn poll_ready(&mut self, _cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
722 Poll::Ready(Ok(()))
725 }
726
727 fn call(&mut self, req: http::Request<B>) -> Self::Future {
728 let clone = self.inner.clone();
729 let service = std::mem::replace(&mut self.inner, clone);
730 let request_body_read_timeout = self.request_body_read_timeout.map(|config| {
731 debug_assert!(
732 !config.timeout.is_zero(),
733 "disabled request body read timeouts must be represented as None"
734 );
735 RequestBodyReadTimeoutState {
736 sleep: None,
737 timeout: config.timeout,
738 version: req.version(),
739 operation: config.operation,
740 #[cfg(feature = "request-id")]
741 request_id: request_id(&req),
742 }
743 });
744 UpgradeFuture {
745 service: Some(service),
746 inner: Inner::FromRequest {
747 inner: <Input as FromRequest<P, B>>::from_request(req),
748 },
749 request_body_read_timeout,
750 }
751 }
752}
753
754#[derive(Copy)]
756pub struct MissingFailure<P> {
757 _protocol: PhantomData<fn(P)>,
758}
759
760impl<P> Default for MissingFailure<P> {
761 fn default() -> Self {
762 Self { _protocol: PhantomData }
763 }
764}
765
766impl<P> Clone for MissingFailure<P> {
767 fn clone(&self) -> Self {
768 MissingFailure { _protocol: PhantomData }
769 }
770}
771
772impl<R, P> Service<R> for MissingFailure<P>
773where
774 InternalFailureException: IntoResponse<P>,
775{
776 type Response = http::Response<BoxBody>;
777 type Error = Infallible;
778 type Future = Ready<Result<Self::Response, Self::Error>>;
779
780 fn poll_ready(&mut self, _cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
781 Poll::Ready(Ok(()))
782 }
783
784 fn call(&mut self, _request: R) -> Self::Future {
785 error!("the operation has not been set");
786 std::future::ready(Ok(InternalFailureException.into_response()))
787 }
788}
789
790#[cfg(test)]
791mod tests;
792
793#[derive(Clone, Copy, Debug, Default)]
797pub struct SchemaMissingFailure;
798impl Service<http::Request<crate::body::Body>> for SchemaMissingFailure {
799 type Response = http::Response<BoxBody>;
800 type Error = Infallible;
801 type Future = Ready<Result<Self::Response, Self::Error>>;
802 fn poll_ready(&mut self, _: &mut Context<'_>) -> Poll<Result<(), Infallible>> {
803 Poll::Ready(Ok(()))
804 }
805 fn call(&mut self, request: http::Request<crate::body::Body>) -> Self::Future {
806 error!("the operation has not been set");
807 let Some(selected) = SelectedOperation::get_from_request(&request) else {
808 error!("request reached the missing-handler fallback without a selected protocol operation");
809 return std::future::ready(Ok(empty_internal_server_error()));
810 };
811 let rejection = crate::schema::DeserializeError::InternalFailure(crate::Error::new(String::from(
812 "the operation has not been set",
813 )));
814 std::future::ready(Ok(selected.protocol().serialize_rejection(rejection)))
815 }
816}
817
818#[cfg(test)]
819mod timeout_tests {
820 use super::*;
821 use std::sync::{
822 atomic::{AtomicUsize, Ordering},
823 Arc,
824 };
825 use std::task::Waker;
826 use tokio::sync::oneshot;
827
828 struct TestProtocol;
829 struct TestInput;
830 type InputResult = Result<TestInput, StatusCode>;
831 type ResponseFuture = Pin<Box<dyn Future<Output = Result<http::Response<BoxBody>, Infallible>>>>;
832
833 impl IntoResponse<TestProtocol> for StatusCode {
834 fn into_response(self) -> http::Response<BoxBody> {
835 http::Response::builder()
836 .status(self)
837 .body(crate::body::empty())
838 .unwrap()
839 }
840 }
841
842 impl FromRequest<TestProtocol, oneshot::Receiver<InputResult>> for TestInput {
843 type Rejection = StatusCode;
844 type Future = Pin<Box<dyn Future<Output = InputResult> + Send>>;
845
846 fn from_request(request: http::Request<oneshot::Receiver<InputResult>>) -> Self::Future {
847 Box::pin(async { request.into_body().await.expect("input sender must remain alive") })
848 }
849 }
850
851 fn request(
852 timeout: Option<Duration>,
853 version: Version,
854 handler_delay: Option<Duration>,
855 ) -> (ResponseFuture, oneshot::Sender<InputResult>, Arc<AtomicUsize>) {
856 let calls = Arc::new(AtomicUsize::new(0));
857 let handler_calls = calls.clone();
858 let mut upgrade = Upgrade::<TestProtocol, TestInput, _> {
859 _protocol: PhantomData,
860 _input: PhantomData,
861 inner: tower::service_fn(move |_input| {
862 handler_calls.fetch_add(1, Ordering::SeqCst);
863 async move {
864 if let Some(delay) = handler_delay {
865 tokio::time::sleep(delay).await;
866 }
867 Ok::<_, Infallible>(StatusCode::OK)
868 }
869 }),
870 request_body_read_timeout: timeout.map(|timeout| RequestBodyReadTimeoutConfig {
871 timeout,
872 operation: "test#Operation",
873 }),
874 };
875 let (sender, receiver) = oneshot::channel();
876 let request = http::Request::builder().version(version).body(receiver).unwrap();
877 (Box::pin(upgrade.call(request)), sender, calls)
878 }
879
880 fn assert_pending(future: &mut ResponseFuture) {
881 let mut cx = Context::from_waker(Waker::noop());
882 assert!(future.as_mut().poll(&mut cx).is_pending());
883 }
884
885 #[tokio::test(start_paused = true)]
886 async fn expired_deadline_rejects_ready_input() {
887 for version in [Version::HTTP_11, Version::HTTP_2] {
888 for succeeds in [true, false] {
889 let (mut response, sender, calls) = request(Some(Duration::from_millis(10)), version, None);
890 assert_pending(&mut response);
891 tokio::time::advance(Duration::from_millis(10)).await;
892 assert!(sender
895 .send(if succeeds {
896 Ok(TestInput)
897 } else {
898 Err(StatusCode::BAD_REQUEST)
899 })
900 .is_ok());
901 let response = response.await.unwrap();
902 assert_eq!(response.status(), StatusCode::REQUEST_TIMEOUT);
903 assert_eq!(calls.load(Ordering::SeqCst), 0);
904 if version == Version::HTTP_11 {
905 assert_eq!(response.headers()[header::CONNECTION], "close");
906 } else {
907 assert!(!response.headers().contains_key(header::CONNECTION));
908 }
909 }
910 }
911 }
912
913 #[tokio::test(start_paused = true)]
914 async fn input_ready_before_deadline_reaches_handler() {
915 let (mut response, sender, calls) = request(Some(Duration::from_millis(10)), Version::HTTP_11, None);
916 assert_pending(&mut response);
917 tokio::time::advance(Duration::from_millis(9)).await;
918 assert!(sender.send(Ok(TestInput)).is_ok());
919 assert_eq!(response.await.unwrap().status(), StatusCode::OK);
920 assert_eq!(calls.load(Ordering::SeqCst), 1);
921 }
922
923 #[tokio::test(start_paused = true)]
924 async fn body_deadline_does_not_time_out_handler() {
925 let (mut response, sender, calls) = request(
926 Some(Duration::from_millis(10)),
927 Version::HTTP_11,
928 Some(Duration::from_millis(20)),
929 );
930 assert_pending(&mut response);
931 tokio::time::advance(Duration::from_millis(9)).await;
932 assert!(sender.send(Ok(TestInput)).is_ok());
933 assert_pending(&mut response);
934 tokio::time::advance(Duration::from_millis(100)).await;
935 assert_eq!(response.await.unwrap().status(), StatusCode::OK);
936 assert_eq!(calls.load(Ordering::SeqCst), 1);
937 }
938
939 #[tokio::test(start_paused = true)]
940 async fn disabled_deadline_allows_late_input() {
941 let (mut response, sender, calls) = request(None, Version::HTTP_11, None);
942 assert_pending(&mut response);
943 tokio::time::advance(Duration::from_secs(60)).await;
944 assert!(sender.send(Ok(TestInput)).is_ok());
945 assert_eq!(response.await.unwrap().status(), StatusCode::OK);
946 assert_eq!(calls.load(Ordering::SeqCst), 1);
947 }
948
949 #[test]
950 fn immediately_ready_input_does_not_require_timer_driver() {
951 let (mut response, sender, calls) = request(Some(Duration::from_millis(10)), Version::HTTP_11, None);
952 assert!(sender.send(Ok(TestInput)).is_ok());
953 let mut cx = Context::from_waker(Waker::noop());
954 match response.as_mut().poll(&mut cx) {
955 Poll::Ready(Ok(response)) => assert_eq!(response.status(), StatusCode::OK),
956 _ => panic!("immediately ready input should complete without a timer driver"),
957 }
958 assert_eq!(calls.load(Ordering::SeqCst), 1);
959 }
960}