warp/
route.rs

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