aws_smithy_http_server/routing/
lambda_handler.rs1use http::uri;
7use lambda_http::{Request, RequestExt};
8use std::{
9 fmt::Debug,
10 task::{Context, Poll},
11};
12use tower::Service;
13
14type HyperRequest = http::Request<hyper::Body>;
15
16#[derive(Debug, Clone)]
25pub struct LambdaHandler<S> {
26 service: S,
27}
28
29impl<S> LambdaHandler<S> {
30 pub fn new(service: S) -> Self {
31 Self { service }
32 }
33}
34
35impl<S> Service<Request> for LambdaHandler<S>
36where
37 S: Service<HyperRequest>,
38{
39 type Error = S::Error;
40 type Response = S::Response;
41 type Future = S::Future;
42
43 #[inline]
44 fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
45 self.service.poll_ready(cx)
46 }
47
48 fn call(&mut self, event: Request) -> Self::Future {
49 self.service.call(convert_event(event))
50 }
51}
52
53fn convert_event(request: Request) -> HyperRequest {
61 let raw_path: &str = request.extensions().raw_http_path();
62 let path: &str = request.uri().path();
63
64 let (parts, body) = if !raw_path.is_empty() && raw_path != path {
65 let mut path = raw_path.to_owned(); let (mut parts, body) = request.into_parts();
67
68 let uri_parts: uri::Parts = parts.uri.into();
69 let path_and_query = uri_parts
70 .path_and_query
71 .expect("request URI does not have `PathAndQuery`");
72
73 if let Some(query) = path_and_query.query() {
74 path.push('?');
75 path.push_str(query);
76 }
77
78 parts.uri = uri::Uri::builder()
79 .authority(uri_parts.authority.expect("request URI does not have authority set"))
80 .scheme(uri_parts.scheme.expect("request URI does not have scheme set"))
81 .path_and_query(path)
82 .build()
83 .expect("unable to construct new URI");
84
85 (parts, body)
86 } else {
87 request.into_parts()
88 };
89
90 let body = match body {
91 lambda_http::Body::Empty => hyper::Body::empty(),
92 lambda_http::Body::Text(s) => hyper::Body::from(s),
93 lambda_http::Body::Binary(v) => hyper::Body::from(v),
94 };
95
96 http::Request::from_parts(parts, body)
97}
98
99#[cfg(test)]
100mod tests {
101 use super::*;
102 use lambda_http::RequestExt;
103
104 #[test]
105 fn traits() {
106 use crate::test_helpers::*;
107
108 assert_send::<LambdaHandler<()>>();
109 assert_sync::<LambdaHandler<()>>();
110 }
111
112 #[test]
113 fn raw_http_path() {
114 let event = http::Request::builder()
116 .uri("https://id.execute-api.us-east-1.amazonaws.com/prod/resources/1")
117 .body(())
118 .expect("unable to build Request");
119 let (parts, _) = event.into_parts();
120
121 let event =
123 lambda_http::Request::from_parts(parts, lambda_http::Body::Empty).with_raw_http_path("/resources/1");
124 let request = convert_event(event);
125
126 assert_eq!(request.uri().path(), "/resources/1")
127 }
128}