1use crate::{
61 Request, Response,
62 header::{HeaderName, HeaderValue},
63};
64use rama_core::{
65 Layer, Service,
66 extensions::{Extension, ExtensionsRef},
67 telemetry::tracing,
68};
69use rama_utils::macros::define_inner_service_accessors;
70use rama_utils::str::smol_str::ToSmolStr as _;
71
72use rand::RngExt as _;
73use uuid::Uuid;
74
75pub(crate) const REQUEST_ID: HeaderName = HeaderName::from_static("request-id");
77
78pub(crate) const X_REQUEST_ID: HeaderName = HeaderName::from_static("x-request-id");
79
80pub trait MakeRequestId: Send + Sync + 'static {
84 fn make_request_id<B>(&self, request: &Request<B>) -> Option<RequestId>;
86}
87
88#[derive(Debug, Clone, Extension)]
90#[extension(tags(http))]
91pub struct RequestId(HeaderValue);
92
93impl RequestId {
94 pub const fn new(header_value: HeaderValue) -> Self {
96 Self(header_value)
97 }
98
99 pub fn header_value(&self) -> &HeaderValue {
101 &self.0
102 }
103
104 pub fn into_header_value(self) -> HeaderValue {
106 self.0
107 }
108}
109
110impl From<HeaderValue> for RequestId {
111 fn from(value: HeaderValue) -> Self {
112 Self::new(value)
113 }
114}
115
116#[derive(Debug, Clone)]
122pub struct SetRequestIdLayer<M> {
123 header_name: HeaderName,
124 make_request_id: M,
125}
126
127impl<M> SetRequestIdLayer<M> {
128 pub const fn new(header_name: HeaderName, make_request_id: M) -> Self
130 where
131 M: MakeRequestId,
132 {
133 Self {
134 header_name,
135 make_request_id,
136 }
137 }
138
139 pub const fn request_id(make_request_id: M) -> Self
141 where
142 M: MakeRequestId,
143 {
144 Self::new(REQUEST_ID, make_request_id)
145 }
146
147 pub const fn x_request_id(make_request_id: M) -> Self
149 where
150 M: MakeRequestId,
151 {
152 Self::new(X_REQUEST_ID, make_request_id)
153 }
154}
155
156impl<S, M> Layer<S> for SetRequestIdLayer<M>
157where
158 M: Clone + MakeRequestId,
159{
160 type Service = SetRequestId<S, M>;
161
162 fn layer(&self, inner: S) -> Self::Service {
163 SetRequestId::new(
164 inner,
165 self.header_name.clone(),
166 self.make_request_id.clone(),
167 )
168 }
169
170 fn into_layer(self, inner: S) -> Self::Service {
171 SetRequestId::new(inner, self.header_name, self.make_request_id)
172 }
173}
174
175#[derive(Debug, Clone)]
185pub struct SetRequestId<S, M> {
186 inner: S,
187 header_name: HeaderName,
188 make_request_id: M,
189}
190
191impl<S, M> SetRequestId<S, M> {
192 pub const fn new(inner: S, header_name: HeaderName, make_request_id: M) -> Self
194 where
195 M: MakeRequestId,
196 {
197 Self {
198 inner,
199 header_name,
200 make_request_id,
201 }
202 }
203
204 pub const fn request_id(inner: S, make_request_id: M) -> Self
206 where
207 M: MakeRequestId,
208 {
209 Self::new(inner, REQUEST_ID, make_request_id)
210 }
211
212 pub const fn x_request_id(inner: S, make_request_id: M) -> Self
214 where
215 M: MakeRequestId,
216 {
217 Self::new(inner, X_REQUEST_ID, make_request_id)
218 }
219
220 define_inner_service_accessors!();
221}
222
223impl<S, M, ReqBody, ResBody> Service<Request<ReqBody>> for SetRequestId<S, M>
224where
225 S: Service<Request<ReqBody>, Output = Response<ResBody>>,
226 M: MakeRequestId,
227 ReqBody: Send + 'static,
228 ResBody: Send + 'static,
229{
230 type Output = S::Output;
231 type Error = S::Error;
232
233 async fn serve(&self, mut req: Request<ReqBody>) -> Result<Self::Output, Self::Error> {
234 if let Some(request_id) = req.headers().get(&self.header_name) {
235 if req.extensions().get_ref::<RequestId>().is_none() {
236 let request_id = request_id.clone();
237 req.extensions().insert(RequestId::new(request_id));
238 }
239 } else if let Some(request_id) = self.make_request_id.make_request_id(&req) {
240 req.extensions().insert(request_id.clone());
241 req.headers_mut()
242 .insert(self.header_name.clone(), request_id.0);
243 }
244
245 self.inner.serve(req).await
246 }
247}
248
249#[derive(Debug, Clone)]
255pub struct PropagateRequestIdLayer {
256 header_name: HeaderName,
257}
258
259impl PropagateRequestIdLayer {
260 pub const fn new(header_name: HeaderName) -> Self {
262 Self { header_name }
263 }
264
265 pub const fn request_id() -> Self {
267 Self::new(REQUEST_ID)
268 }
269
270 pub const fn x_request_id() -> Self {
272 Self::new(X_REQUEST_ID)
273 }
274}
275
276impl<S> Layer<S> for PropagateRequestIdLayer {
277 type Service = PropagateRequestId<S>;
278
279 fn layer(&self, inner: S) -> Self::Service {
280 PropagateRequestId::new(inner, self.header_name.clone())
281 }
282}
283
284#[derive(Debug, Clone)]
291pub struct PropagateRequestId<S> {
292 inner: S,
293 header_name: HeaderName,
294}
295
296impl<S> PropagateRequestId<S> {
297 pub const fn new(inner: S, header_name: HeaderName) -> Self {
299 Self { inner, header_name }
300 }
301
302 pub const fn request_id(inner: S) -> Self {
304 Self::new(inner, REQUEST_ID)
305 }
306
307 pub const fn x_request_id(inner: S) -> Self {
309 Self::new(inner, X_REQUEST_ID)
310 }
311
312 define_inner_service_accessors!();
313}
314
315impl<S, ReqBody, ResBody> Service<Request<ReqBody>> for PropagateRequestId<S>
316where
317 S: Service<Request<ReqBody>, Output = Response<ResBody>>,
318 ReqBody: Send + 'static,
319 ResBody: Send + 'static,
320{
321 type Output = S::Output;
322 type Error = S::Error;
323
324 async fn serve(&self, req: Request<ReqBody>) -> Result<Self::Output, Self::Error> {
325 let request_id = req
326 .headers()
327 .get(&self.header_name)
328 .cloned()
329 .map(RequestId::new);
330
331 let mut response = self.inner.serve(req).await?;
332
333 if let Some(current_id) = response.headers().get(&self.header_name) {
334 if response.extensions().get_ref::<RequestId>().is_none() {
335 let current_id = current_id.clone();
336 response.extensions().insert(RequestId::new(current_id));
337 }
338 } else if let Some(request_id) = request_id {
339 response
340 .headers_mut()
341 .insert(self.header_name.clone(), request_id.0.clone());
342 response.extensions().insert(request_id);
343 }
344
345 Ok(response)
346 }
347}
348
349#[derive(Debug, Clone, Copy, Default)]
351pub struct MakeRequestUuid;
352
353impl MakeRequestId for MakeRequestUuid {
354 fn make_request_id<B>(&self, _request: &Request<B>) -> Option<RequestId> {
355 let request_id = Uuid::new_v4()
356 .to_smolstr()
357 .parse()
358 .inspect_err(|err| {
359 tracing::debug!("failed to parse UUID4 as RequestId: {err}");
360 })
361 .ok()?;
362 Some(RequestId::new(request_id))
363 }
364}
365
366#[derive(Debug, Clone, Copy, Default)]
368pub struct MakeRequestNanoid;
369
370impl MakeRequestId for MakeRequestNanoid {
371 fn make_request_id<B>(&self, _request: &Request<B>) -> Option<RequestId> {
372 let request_id = make_nano_id();
373 Some(RequestId::new(request_id))
374 }
375}
376
377fn make_nano_id() -> HeaderValue {
378 const ALPHABET_LEN: usize = 64;
379 const ALPHABET: [u8; ALPHABET_LEN] =
380 *b"_-0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
381 const ID_LEN: usize = 21;
382 const STEP: usize = 8 * ID_LEN / 5;
383 const MASK: usize = (ALPHABET_LEN * 2) - 1;
384
385 let mut id = [0u8; ID_LEN];
386
387 let mut index = 0;
388 loop {
389 let input: [u8; STEP] = rand::rng().random();
395 for byte in input {
396 let byte = byte as usize & MASK;
397
398 if ALPHABET_LEN > byte {
399 id[index] = ALPHABET[byte];
400 index += 1;
401 if index == ID_LEN {
402 return unsafe { HeaderValue::from_maybe_shared_unchecked(id) };
403 }
404 }
405 }
406 }
407}
408
409#[cfg(test)]
410mod tests {
411 use crate::layer::set_header;
412 use crate::{Body, Response};
413 use rama_core::Layer;
414 use rama_core::service::service_fn;
415 use std::{
416 convert::Infallible,
417 sync::{
418 Arc,
419 atomic::{AtomicU64, Ordering},
420 },
421 };
422
423 use super::*;
424
425 #[tokio::test]
426 async fn basic() {
427 let svc = (
428 SetRequestIdLayer::x_request_id(Counter::default()),
429 PropagateRequestIdLayer::x_request_id(),
430 )
431 .into_layer(service_fn(handler));
432
433 let req = Request::builder().body(Body::empty()).unwrap();
435 let res = svc.serve(req).await.unwrap();
436 assert_eq!(res.headers()["x-request-id"], "0");
437
438 let req = Request::builder().body(Body::empty()).unwrap();
439 let res = svc.serve(req).await.unwrap();
440 assert_eq!(res.headers()["x-request-id"], "1");
441
442 let req = Request::builder()
444 .header("x-request-id", "foo")
445 .body(Body::empty())
446 .unwrap();
447 let res = svc.serve(req).await.unwrap();
448 assert_eq!(res.headers()["x-request-id"], "foo");
449
450 let req = Request::builder().body(Body::empty()).unwrap();
452 let res = svc.serve(req).await.unwrap();
453 assert_eq!(res.extensions().get_ref::<RequestId>().unwrap().0, "2");
454 }
455
456 #[tokio::test]
457 async fn basic_with_request_id() {
458 let svc = (
459 SetRequestIdLayer::request_id(Counter::default()),
460 PropagateRequestIdLayer::request_id(),
461 )
462 .into_layer(service_fn(handler));
463
464 let req = Request::builder().body(Body::empty()).unwrap();
466 let res = svc.serve(req).await.unwrap();
467 assert_eq!(res.headers()["request-id"], "0");
468
469 let req = Request::builder().body(Body::empty()).unwrap();
470 let res = svc.serve(req).await.unwrap();
471 assert_eq!(res.headers()["request-id"], "1");
472
473 let req = Request::builder()
475 .header("request-id", "foo")
476 .body(Body::empty())
477 .unwrap();
478 let res = svc.serve(req).await.unwrap();
479 assert_eq!(res.headers()["request-id"], "foo");
480
481 let req = Request::builder().body(Body::empty()).unwrap();
483 let res = svc.serve(req).await.unwrap();
484 assert_eq!(res.extensions().get_ref::<RequestId>().unwrap().0, "2");
485 }
486
487 #[tokio::test]
488 async fn other_middleware_setting_request_id_on_response() {
489 let svc = (
490 SetRequestIdLayer::x_request_id(Counter::default()),
491 PropagateRequestIdLayer::x_request_id(),
492 set_header::SetResponseHeaderLayer::overriding(
493 HeaderName::from_static("x-request-id"),
494 HeaderValue::from_static("foo"),
495 ),
496 )
497 .into_layer(service_fn(handler));
498
499 let req = Request::builder()
500 .header("x-request-id", "foo")
501 .body(Body::empty())
502 .unwrap();
503 let res = svc.serve(req).await.unwrap();
504 assert_eq!(res.headers()["x-request-id"], "foo");
505 assert_eq!(res.extensions().get_ref::<RequestId>().unwrap().0, "foo");
506 }
507
508 #[derive(Clone, Default)]
509 struct Counter(Arc<AtomicU64>);
510
511 impl MakeRequestId for Counter {
512 fn make_request_id<B>(&self, _request: &Request<B>) -> Option<RequestId> {
513 let id =
514 HeaderValue::from_str(&self.0.fetch_add(1, Ordering::AcqRel).to_string()).unwrap();
515 Some(RequestId::new(id))
516 }
517 }
518
519 async fn handler(_: Request<Body>) -> Result<Response<Body>, Infallible> {
520 Ok(Response::new(Body::empty()))
521 }
522
523 #[tokio::test]
524 async fn uuid() {
525 let svc = (
526 SetRequestIdLayer::x_request_id(MakeRequestUuid),
527 PropagateRequestIdLayer::x_request_id(),
528 )
529 .into_layer(service_fn(handler));
530
531 let req = Request::builder().body(Body::empty()).unwrap();
533 let mut res = svc.serve(req).await.unwrap();
534 let id = res.headers_mut().remove("x-request-id").unwrap();
535 id.to_str().unwrap().parse::<Uuid>().unwrap();
536 }
537
538 #[tokio::test]
539 async fn nanoid() {
540 let svc = (
541 SetRequestIdLayer::x_request_id(MakeRequestNanoid),
542 PropagateRequestIdLayer::x_request_id(),
543 )
544 .into_layer(service_fn(handler));
545
546 let req = Request::builder().body(Body::empty()).unwrap();
548 let mut res = svc.serve(req).await.unwrap();
549 let id = res.headers_mut().remove("x-request-id").unwrap();
550 assert_eq!(id.to_str().unwrap().chars().count(), 21);
551 }
552
553 #[test]
562 fn nanoid_no_intra_id_mirror() {
563 fn has_mirror(id: &[u8]) -> bool {
564 (11..=16).any(|k| id[k..21] == id[0..21 - k])
565 }
566
567 use ahash::HashSet;
568 let samples = 2_000;
569 let mut mirrors = 0;
570 let mut ids: HashSet<Vec<u8>> = HashSet::default();
571 for _ in 0..samples {
572 let hv = make_nano_id();
573 let id = hv.as_bytes();
574 assert_eq!(id.len(), 21);
575 if has_mirror(id) {
576 mirrors += 1;
577 }
578 ids.insert(id.to_vec());
579 }
580 assert!(
584 mirrors < 5,
585 "{mirrors}/{samples} ids exhibit the entropy-bug mirror pattern",
586 );
587 assert_eq!(ids.len(), samples, "duplicate ids generated");
589 }
590}