Skip to main content

warp/
route.rs

1use scoped_tls::scoped_thread_local;
2use std::cell::RefCell;
3use std::mem;
4use std::net::SocketAddr;
5
6use crate::addr::RemoteAddr;
7use crate::{bodyt::Body, Request};
8
9scoped_thread_local!(static ROUTE: RefCell<Route>);
10
11pub(crate) fn set<F, U>(r: &RefCell<Route>, func: F) -> U
12where
13    F: FnOnce() -> U,
14{
15    ROUTE.set(r, func)
16}
17
18pub(crate) fn is_set() -> bool {
19    ROUTE.is_set()
20}
21
22pub(crate) fn with<F, R>(func: F) -> R
23where
24    F: FnOnce(&mut Route) -> R,
25{
26    ROUTE.with(move |route| func(&mut *route.borrow_mut()))
27}
28
29#[derive(Debug)]
30pub(crate) struct Route {
31    body: BodyState,
32    req: Request,
33    segments_index: usize,
34}
35
36#[derive(Debug)]
37enum BodyState {
38    Ready,
39    Taken,
40}
41
42impl Route {
43    pub(crate) fn new(req: http::Request<Body>) -> RefCell<Route> {
44        let segments_index = if req.uri().path().starts_with('/') {
45            // Skip the beginning slash.
46            1
47        } else {
48            0
49        };
50
51        RefCell::new(Route {
52            body: BodyState::Ready,
53            req,
54            segments_index,
55        })
56    }
57
58    pub(crate) fn method(&self) -> &http::Method {
59        self.req.method()
60    }
61
62    pub(crate) fn headers(&self) -> &http::HeaderMap {
63        self.req.headers()
64    }
65
66    pub(crate) fn version(&self) -> http::Version {
67        self.req.version()
68    }
69
70    pub(crate) fn extensions(&self) -> &http::Extensions {
71        self.req.extensions()
72    }
73
74    #[cfg(feature = "websocket")]
75    pub(crate) fn extensions_mut(&mut self) -> &mut http::Extensions {
76        self.req.extensions_mut()
77    }
78
79    pub(crate) fn uri(&self) -> &http::Uri {
80        self.req.uri()
81    }
82
83    pub(crate) fn path(&self) -> &str {
84        &self.req.uri().path()[self.segments_index..]
85    }
86
87    pub(crate) fn full_path(&self) -> &str {
88        self.req.uri().path()
89    }
90
91    pub(crate) fn set_unmatched_path(&mut self, index: usize) {
92        let index = self.segments_index + index;
93        let path = self.req.uri().path();
94        if path.is_empty() {
95            // malformed path
96            return;
97        } else if path.len() == index {
98            self.segments_index = index;
99        } else {
100            debug_assert_eq!(path.as_bytes()[index], b'/');
101            self.segments_index = index + 1;
102        }
103    }
104
105    pub(crate) fn query(&self) -> Option<&str> {
106        self.req.uri().query()
107    }
108
109    pub(crate) fn matched_path_index(&self) -> usize {
110        self.segments_index
111    }
112
113    pub(crate) fn reset_matched_path_index(&mut self, index: usize) {
114        debug_assert!(
115            index <= self.segments_index,
116            "reset_match_path_index should not be bigger: current={}, arg={}",
117            self.segments_index,
118            index,
119        );
120        self.segments_index = index;
121    }
122
123    pub(crate) fn remote_addr(&self) -> Option<SocketAddr> {
124        self.req
125            .extensions()
126            .get::<RemoteAddr>()
127            .map(|RemoteAddr(addr)| *addr)
128    }
129
130    pub(crate) fn take_body(&mut self) -> Option<Body> {
131        match self.body {
132            BodyState::Ready => {
133                let body = mem::replace(self.req.body_mut(), Body::empty());
134                self.body = BodyState::Taken;
135                Some(body)
136            }
137            BodyState::Taken => None,
138        }
139    }
140}