1use aws_lambda_events::query_map::QueryMap;
4use http::request::Parts;
5use lambda_runtime::Context;
6
7use crate::request::RequestContext;
8
9#[derive(Clone)]
11pub(crate) struct QueryStringParameters(pub(crate) QueryMap);
12
13#[derive(Clone)]
17pub(crate) struct PathParameters(pub(crate) QueryMap);
18
19#[derive(Clone)]
24pub(crate) struct StageVariables(pub(crate) QueryMap);
25
26#[derive(Clone)]
28pub(crate) struct RawHttpPath(pub(crate) String);
29
30pub trait RequestExt {
38 fn raw_http_path(&self) -> &str;
40
41 fn with_raw_http_path<S>(self, path: S) -> Self
43 where
44 S: Into<String>;
45
46 fn query_string_parameters(&self) -> QueryMap;
57
58 fn query_string_parameters_ref(&self) -> Option<&QueryMap>;
70
71 fn with_query_string_parameters<Q>(self, parameters: Q) -> Self
75 where
76 Q: Into<QueryMap>;
77
78 fn path_parameters(&self) -> QueryMap;
85
86 fn path_parameters_ref(&self) -> Option<&QueryMap>;
93
94 fn with_path_parameters<P>(self, parameters: P) -> Self
98 where
99 P: Into<QueryMap>;
100
101 fn stage_variables(&self) -> QueryMap;
107
108 fn stage_variables_ref(&self) -> Option<&QueryMap>;
114
115 fn with_stage_variables<V>(self, variables: V) -> Self
119 where
120 V: Into<QueryMap>;
121
122 fn request_context(&self) -> RequestContext;
125
126 fn request_context_ref(&self) -> Option<&RequestContext>;
129
130 fn with_request_context(self, context: RequestContext) -> Self;
134
135 fn lambda_context(&self) -> Context;
138
139 fn lambda_context_ref(&self) -> Option<&Context>;
142
143 fn with_lambda_context(self, context: Context) -> Self;
145}
146
147impl RequestExt for http::Extensions {
148 fn raw_http_path(&self) -> &str {
149 self.get::<RawHttpPath>()
150 .map(|RawHttpPath(path)| path.as_str())
151 .unwrap_or_default()
152 }
153
154 fn with_raw_http_path<S>(self, path: S) -> Self
155 where
156 S: Into<String>,
157 {
158 let mut s = self;
159 s.insert(RawHttpPath(path.into()));
160 s
161 }
162
163 fn query_string_parameters(&self) -> QueryMap {
164 self.query_string_parameters_ref().cloned().unwrap_or_default()
165 }
166
167 fn query_string_parameters_ref(&self) -> Option<&QueryMap> {
168 self.get::<QueryStringParameters>().and_then(
169 |QueryStringParameters(params)| {
170 if params.is_empty() {
171 None
172 } else {
173 Some(params)
174 }
175 },
176 )
177 }
178
179 fn with_query_string_parameters<Q>(self, parameters: Q) -> Self
180 where
181 Q: Into<QueryMap>,
182 {
183 let mut s = self;
184 s.insert(QueryStringParameters(parameters.into()));
185 s
186 }
187
188 fn path_parameters(&self) -> QueryMap {
189 self.path_parameters_ref().cloned().unwrap_or_default()
190 }
191
192 fn path_parameters_ref(&self) -> Option<&QueryMap> {
193 self.get::<PathParameters>().and_then(
194 |PathParameters(params)| {
195 if params.is_empty() {
196 None
197 } else {
198 Some(params)
199 }
200 },
201 )
202 }
203
204 fn with_path_parameters<P>(self, parameters: P) -> Self
205 where
206 P: Into<QueryMap>,
207 {
208 let mut s = self;
209 s.insert(PathParameters(parameters.into()));
210 s
211 }
212
213 fn stage_variables(&self) -> QueryMap {
214 self.stage_variables_ref().cloned().unwrap_or_default()
215 }
216
217 fn stage_variables_ref(&self) -> Option<&QueryMap> {
218 self.get::<StageVariables>()
219 .and_then(|StageVariables(vars)| if vars.is_empty() { None } else { Some(vars) })
220 }
221
222 fn with_stage_variables<V>(self, variables: V) -> Self
223 where
224 V: Into<QueryMap>,
225 {
226 let mut s = self;
227 s.insert(StageVariables(variables.into()));
228 s
229 }
230
231 fn request_context(&self) -> RequestContext {
232 self.request_context_ref()
233 .cloned()
234 .expect("Request did not contain a request context")
235 }
236
237 fn request_context_ref(&self) -> Option<&RequestContext> {
238 self.get::<RequestContext>()
239 }
240
241 fn with_request_context(self, context: RequestContext) -> Self {
242 let mut s = self;
243 s.insert(context);
244 s
245 }
246
247 fn lambda_context(&self) -> Context {
248 self.lambda_context_ref()
249 .cloned()
250 .expect("Request did not contain a lambda context")
251 }
252
253 fn lambda_context_ref(&self) -> Option<&Context> {
254 self.get::<Context>()
255 }
256
257 fn with_lambda_context(self, context: Context) -> Self {
258 let mut s = self;
259 s.insert(context);
260 s
261 }
262}
263
264impl RequestExt for Parts {
265 fn raw_http_path(&self) -> &str {
266 self.extensions.raw_http_path()
267 }
268
269 fn with_raw_http_path<S>(self, path: S) -> Self
270 where
271 S: Into<String>,
272 {
273 let mut s = self;
274 s.extensions = s.extensions.with_raw_http_path(path);
275
276 s
277 }
278
279 fn query_string_parameters(&self) -> QueryMap {
280 self.extensions.query_string_parameters()
281 }
282
283 fn query_string_parameters_ref(&self) -> Option<&QueryMap> {
284 self.extensions.query_string_parameters_ref()
285 }
286
287 fn with_query_string_parameters<Q>(self, parameters: Q) -> Self
288 where
289 Q: Into<QueryMap>,
290 {
291 let mut s = self;
292 s.extensions = s.extensions.with_query_string_parameters(parameters);
293
294 s
295 }
296
297 fn path_parameters(&self) -> QueryMap {
298 self.extensions.path_parameters()
299 }
300
301 fn path_parameters_ref(&self) -> Option<&QueryMap> {
302 self.extensions.path_parameters_ref()
303 }
304
305 fn with_path_parameters<P>(self, parameters: P) -> Self
306 where
307 P: Into<QueryMap>,
308 {
309 let mut s = self;
310 s.extensions = s.extensions.with_path_parameters(parameters);
311
312 s
313 }
314
315 fn stage_variables(&self) -> QueryMap {
316 self.extensions.stage_variables()
317 }
318
319 fn stage_variables_ref(&self) -> Option<&QueryMap> {
320 self.extensions.stage_variables_ref()
321 }
322
323 fn with_stage_variables<V>(self, variables: V) -> Self
324 where
325 V: Into<QueryMap>,
326 {
327 let mut s = self;
328 s.extensions = s.extensions.with_stage_variables(variables);
329
330 s
331 }
332
333 fn request_context(&self) -> RequestContext {
334 self.extensions.request_context()
335 }
336
337 fn request_context_ref(&self) -> Option<&RequestContext> {
338 self.extensions.request_context_ref()
339 }
340
341 fn with_request_context(self, context: RequestContext) -> Self {
342 let mut s = self;
343 s.extensions = s.extensions.with_request_context(context);
344
345 s
346 }
347
348 fn lambda_context(&self) -> Context {
349 self.extensions.lambda_context()
350 }
351
352 fn lambda_context_ref(&self) -> Option<&Context> {
353 self.extensions.lambda_context_ref()
354 }
355
356 fn with_lambda_context(self, context: Context) -> Self {
357 let mut s = self;
358 s.extensions = s.extensions.with_lambda_context(context);
359
360 s
361 }
362}
363
364fn map_req_ext<B, F>(req: http::Request<B>, f: F) -> http::Request<B>
365where
366 F: FnOnce(http::Extensions) -> http::Extensions,
367{
368 let (mut parts, body) = req.into_parts();
369 parts.extensions = (f)(parts.extensions);
370
371 http::Request::from_parts(parts, body)
372}
373
374impl<B> RequestExt for http::Request<B> {
375 fn raw_http_path(&self) -> &str {
376 self.extensions().raw_http_path()
377 }
378
379 fn with_raw_http_path<S>(self, path: S) -> Self
380 where
381 S: Into<String>,
382 {
383 map_req_ext(self, |ext| ext.with_raw_http_path(path))
384 }
385
386 fn query_string_parameters(&self) -> QueryMap {
387 self.extensions().query_string_parameters()
388 }
389
390 fn query_string_parameters_ref(&self) -> Option<&QueryMap> {
391 self.extensions().query_string_parameters_ref()
392 }
393
394 fn with_query_string_parameters<Q>(self, parameters: Q) -> Self
395 where
396 Q: Into<QueryMap>,
397 {
398 map_req_ext(self, |ext| ext.with_query_string_parameters(parameters))
399 }
400
401 fn path_parameters(&self) -> QueryMap {
402 self.extensions().path_parameters()
403 }
404
405 fn path_parameters_ref(&self) -> Option<&QueryMap> {
406 self.extensions().path_parameters_ref()
407 }
408
409 fn with_path_parameters<P>(self, parameters: P) -> Self
410 where
411 P: Into<QueryMap>,
412 {
413 map_req_ext(self, |ext| ext.with_path_parameters(parameters))
414 }
415
416 fn stage_variables(&self) -> QueryMap {
417 self.extensions().stage_variables()
418 }
419
420 fn stage_variables_ref(&self) -> Option<&QueryMap> {
421 self.extensions().stage_variables_ref()
422 }
423
424 fn with_stage_variables<V>(self, variables: V) -> Self
425 where
426 V: Into<QueryMap>,
427 {
428 map_req_ext(self, |ext| ext.with_stage_variables(variables))
429 }
430
431 fn request_context(&self) -> RequestContext {
432 self.extensions().request_context()
433 }
434
435 fn request_context_ref(&self) -> Option<&RequestContext> {
436 self.extensions().request_context_ref()
437 }
438
439 fn with_request_context(self, context: RequestContext) -> Self {
440 map_req_ext(self, |ext| ext.with_request_context(context))
441 }
442
443 fn lambda_context(&self) -> Context {
444 self.extensions().lambda_context()
445 }
446
447 fn lambda_context_ref(&self) -> Option<&Context> {
448 self.extensions().lambda_context_ref()
449 }
450
451 fn with_lambda_context(self, context: Context) -> Self {
452 map_req_ext(self, |ext| ext.with_lambda_context(context))
453 }
454}
455
456#[cfg(test)]
457mod tests {
458 use aws_lambda_events::query_map::QueryMap;
459 use http::Extensions;
460
461 use crate::Request;
462
463 use super::RequestExt;
464
465 #[test]
466 fn extensions_can_mock_query_string_parameters_ext() {
467 let ext = Extensions::default();
468 assert_eq!(ext.query_string_parameters_ref(), None);
469 assert_eq!(ext.query_string_parameters(), QueryMap::default());
470
471 let mocked: QueryMap = hashmap! {
472 "foo".into() => vec!["bar".into()]
473 }
474 .into();
475
476 let ext = ext.with_query_string_parameters(mocked.clone());
477 assert_eq!(ext.query_string_parameters_ref(), Some(&mocked));
478 assert_eq!(ext.query_string_parameters(), mocked);
479 }
480
481 #[test]
482 fn parts_can_mock_query_string_parameters_ext() {
483 let (parts, _) = Request::default().into_parts();
484 assert_eq!(parts.query_string_parameters_ref(), None);
485 assert_eq!(parts.query_string_parameters(), QueryMap::default());
486
487 let mocked: QueryMap = hashmap! {
488 "foo".into() => vec!["bar".into()]
489 }
490 .into();
491
492 let parts = parts.with_query_string_parameters(mocked.clone());
493 assert_eq!(parts.query_string_parameters_ref(), Some(&mocked));
494 assert_eq!(parts.query_string_parameters(), mocked);
495 }
496
497 #[test]
498 fn requests_can_mock_query_string_parameters_ext() {
499 let request = Request::default();
500 assert_eq!(request.query_string_parameters_ref(), None);
501 assert_eq!(request.query_string_parameters(), QueryMap::default());
502
503 let mocked: QueryMap = hashmap! {
504 "foo".into() => vec!["bar".into()]
505 }
506 .into();
507
508 let request = request.with_query_string_parameters(mocked.clone());
509 assert_eq!(request.query_string_parameters_ref(), Some(&mocked));
510 assert_eq!(request.query_string_parameters(), mocked);
511 }
512
513 #[test]
514 fn extensions_can_mock_path_parameters_ext() {
515 let ext = Extensions::default();
516 assert_eq!(ext.path_parameters_ref(), None);
517 assert_eq!(ext.path_parameters(), QueryMap::default());
518
519 let mocked: QueryMap = hashmap! {
520 "foo".into() => vec!["bar".into()]
521 }
522 .into();
523
524 let ext = ext.with_path_parameters(mocked.clone());
525 assert_eq!(ext.path_parameters_ref(), Some(&mocked));
526 assert_eq!(ext.path_parameters(), mocked);
527 }
528
529 #[test]
530 fn parts_can_mock_path_parameters_ext() {
531 let (parts, _) = Request::default().into_parts();
532 assert_eq!(parts.path_parameters_ref(), None);
533 assert_eq!(parts.path_parameters(), QueryMap::default());
534
535 let mocked: QueryMap = hashmap! {
536 "foo".into() => vec!["bar".into()]
537 }
538 .into();
539
540 let parts = parts.with_path_parameters(mocked.clone());
541 assert_eq!(parts.path_parameters_ref(), Some(&mocked));
542 assert_eq!(parts.path_parameters(), mocked);
543 }
544
545 #[test]
546 fn requests_can_mock_path_parameters_ext() {
547 let request = Request::default();
548 assert_eq!(request.path_parameters_ref(), None);
549 assert_eq!(request.path_parameters(), QueryMap::default());
550
551 let mocked: QueryMap = hashmap! {
552 "foo".into() => vec!["bar".into()]
553 }
554 .into();
555
556 let request = request.with_path_parameters(mocked.clone());
557 assert_eq!(request.path_parameters_ref(), Some(&mocked));
558 assert_eq!(request.path_parameters(), mocked);
559 }
560
561 #[test]
562 fn extensions_can_mock_stage_variables_ext() {
563 let ext = Extensions::default();
564 assert_eq!(ext.stage_variables_ref(), None);
565 assert_eq!(ext.stage_variables(), QueryMap::default());
566
567 let mocked: QueryMap = hashmap! {
568 "foo".into() => vec!["bar".into()]
569 }
570 .into();
571
572 let ext = ext.with_stage_variables(mocked.clone());
573 assert_eq!(ext.stage_variables_ref(), Some(&mocked));
574 assert_eq!(ext.stage_variables(), mocked);
575 }
576
577 #[test]
578 fn parts_can_mock_stage_variables_ext() {
579 let (parts, _) = Request::default().into_parts();
580 assert_eq!(parts.stage_variables_ref(), None);
581 assert_eq!(parts.stage_variables(), QueryMap::default());
582
583 let mocked: QueryMap = hashmap! {
584 "foo".into() => vec!["bar".into()]
585 }
586 .into();
587
588 let parts = parts.with_stage_variables(mocked.clone());
589 assert_eq!(parts.stage_variables_ref(), Some(&mocked));
590 assert_eq!(parts.stage_variables(), mocked);
591 }
592
593 #[test]
594 fn requests_can_mock_stage_variables_ext() {
595 let request = Request::default();
596 assert_eq!(request.stage_variables_ref(), None);
597 assert_eq!(request.stage_variables(), QueryMap::default());
598
599 let mocked: QueryMap = hashmap! {
600 "foo".into() => vec!["bar".into()]
601 }
602 .into();
603
604 let request = request.with_stage_variables(mocked.clone());
605 assert_eq!(request.stage_variables_ref(), Some(&mocked));
606 assert_eq!(request.stage_variables(), mocked);
607 }
608
609 #[test]
610 fn extensions_can_mock_raw_http_path_ext() {
611 let ext = Extensions::default().with_raw_http_path("/raw-path");
612 assert_eq!("/raw-path", ext.raw_http_path());
613 }
614
615 #[test]
616 fn parts_can_mock_raw_http_path_ext() {
617 let (parts, _) = Request::default().into_parts();
618 let parts = parts.with_raw_http_path("/raw-path");
619 assert_eq!("/raw-path", parts.raw_http_path());
620 }
621
622 #[test]
623 fn requests_can_mock_raw_http_path_ext() {
624 let request = Request::default().with_raw_http_path("/raw-path");
625 assert_eq!("/raw-path", request.raw_http_path());
626 }
627}