1use std::collections::{BTreeSet, HashMap};
7use std::sync::Arc;
8
9use crate::{
10 common::{Method, StatusCode},
11 headers::header_keys,
12 request::Request,
13 response::Response,
14};
15
16pub trait Handler: Send + Sync + 'static {
18 fn handle(&self, request: Request) -> Response;
21}
22
23impl<F> Handler for F
24where
25 F: Fn(Request) -> Response + Send + Sync + 'static,
26{
27 fn handle(&self, request: Request) -> Response {
28 (self)(request)
29 }
30}
31
32type SharedHandler = Arc<dyn Handler>;
33
34pub struct RouterBuilder {
36 routes: HashMap<String, RouteEntry>,
37 auto_head: bool,
38}
39
40impl Default for RouterBuilder {
41 fn default() -> Self {
42 Self {
43 routes: HashMap::new(),
44 auto_head: true,
45 }
46 }
47}
48
49impl RouterBuilder {
50 pub fn new() -> Self {
52 Self::default()
53 }
54
55 pub fn auto_head(mut self, enabled: bool) -> Self {
57 self.auto_head = enabled;
58 self
59 }
60
61 pub fn route<H>(mut self, method: Method, path: impl Into<String>, handler: H) -> Self
63 where
64 H: Handler,
65 {
66 let shared: SharedHandler = Arc::new(handler);
67 self.insert_route(method, path.into(), shared);
68 self
69 }
70
71 pub fn get<H>(self, path: impl Into<String>, handler: H) -> Self
73 where
74 H: Handler,
75 {
76 self.route(Method::Get, path, handler)
77 }
78
79 pub fn head<H>(self, path: impl Into<String>, handler: H) -> Self
81 where
82 H: Handler,
83 {
84 self.route(Method::Head, path, handler)
85 }
86
87 pub fn post<H>(self, path: impl Into<String>, handler: H) -> Self
89 where
90 H: Handler,
91 {
92 self.route(Method::Post, path, handler)
93 }
94
95 pub fn put<H>(self, path: impl Into<String>, handler: H) -> Self
97 where
98 H: Handler,
99 {
100 self.route(Method::Put, path, handler)
101 }
102
103 pub fn delete<H>(self, path: impl Into<String>, handler: H) -> Self
105 where
106 H: Handler,
107 {
108 self.route(Method::Delete, path, handler)
109 }
110
111 pub fn options<H>(self, path: impl Into<String>, handler: H) -> Self
113 where
114 H: Handler,
115 {
116 self.route(Method::Options, path, handler)
117 }
118
119 pub fn trace<H>(self, path: impl Into<String>, handler: H) -> Self
121 where
122 H: Handler,
123 {
124 self.route(Method::Trace, path, handler)
125 }
126
127 pub fn patch<H>(self, path: impl Into<String>, handler: H) -> Self
129 where
130 H: Handler,
131 {
132 self.route(Method::Patch, path, handler)
133 }
134
135 pub fn build(self) -> Router {
137 Router {
138 routes: self.routes,
139 auto_head: self.auto_head,
140 }
141 }
142
143 fn insert_route(&mut self, method: Method, path: String, handler: SharedHandler) {
144 let entry = self.routes.entry(path).or_insert_with(RouteEntry::default);
145 entry.insert(method, handler);
146 }
147}
148
149pub fn router() -> RouterBuilder {
151 RouterBuilder::default()
152}
153
154pub struct Router {
156 routes: HashMap<String, RouteEntry>,
157 auto_head: bool,
158}
159
160impl Handler for Router {
161 fn handle(&self, request: Request) -> Response {
162 let method_token = request.method().as_str().to_owned();
163 let target_key = target_key(&request);
164
165 if let Some(route) = self.routes.get(&target_key) {
166 match route.resolve(&method_token, self.auto_head) {
167 RouteMatch::Matched {
168 handler,
169 head_fallback,
170 } => {
171 let mut response = handler.handle(request);
172 if head_fallback {
173 response.strip_body_for_head();
174 }
175 response
176 }
177 RouteMatch::MethodNotAllowed { allow } => {
178 if matches!(request.method(), Method::Extension(_)) {
179 not_implemented()
180 } else {
181 method_not_allowed(allow)
182 }
183 }
184 }
185 } else if matches!(request.method(), Method::Extension(_)) {
186 not_implemented()
187 } else {
188 not_found()
189 }
190 }
191}
192
193pub struct DefaultRouter;
195
196impl Handler for DefaultRouter {
197 fn handle(&self, _request: Request) -> Response {
198 Response::new(StatusCode::NOT_IMPLEMENTED)
199 }
200}
201
202#[derive(Default)]
203struct RouteEntry {
204 handlers: HashMap<String, SharedHandler>,
205 methods: BTreeSet<String>,
206}
207
208impl RouteEntry {
209 fn insert(&mut self, method: Method, handler: SharedHandler) {
210 let token = method.as_str().to_owned();
211 self.handlers.insert(token.clone(), handler);
212 self.methods.insert(token);
213 }
214
215 fn resolve(&self, method: &str, auto_head: bool) -> RouteMatch {
216 if let Some(handler) = self.handlers.get(method) {
217 return RouteMatch::matched(handler, false);
218 }
219
220 if auto_head && method.eq_ignore_ascii_case("HEAD") {
221 if let Some(handler) = self.handlers.get("GET") {
222 return RouteMatch::matched(handler, true);
223 }
224 }
225
226 RouteMatch::method_not_allowed(self.allow_header(auto_head))
227 }
228
229 fn allow_header(&self, auto_head: bool) -> String {
230 let mut allowed = self.methods.clone();
231 if auto_head && allowed.contains("GET") {
232 allowed.insert(String::from("HEAD"));
233 }
234 allowed.into_iter().collect::<Vec<_>>().join(", ")
235 }
236}
237
238enum RouteMatch {
239 Matched {
240 handler: SharedHandler,
241 head_fallback: bool,
242 },
243 MethodNotAllowed {
244 allow: String,
245 },
246}
247
248impl RouteMatch {
249 fn matched(handler: &SharedHandler, head_fallback: bool) -> Self {
250 RouteMatch::Matched {
251 handler: Arc::clone(handler),
252 head_fallback,
253 }
254 }
255
256 fn method_not_allowed(allow: String) -> Self {
257 RouteMatch::MethodNotAllowed { allow }
258 }
259}
260
261fn target_key(request: &Request) -> String {
262 match request.target() {
263 crate::request::RequestTarget::Origin(path)
264 | crate::request::RequestTarget::Absolute(path)
265 | crate::request::RequestTarget::Authority(path) => path.clone(),
266 crate::request::RequestTarget::Asterisk => String::from("*"),
267 }
268}
269
270fn not_found() -> Response {
271 Response::new(StatusCode::NOT_FOUND)
272}
273
274fn method_not_allowed(allow: String) -> Response {
275 let mut response = Response::new(StatusCode::METHOD_NOT_ALLOWED);
276 response.headers_mut().insert(header_keys::ALLOW, allow);
277 response
278}
279
280fn not_implemented() -> Response {
281 Response::new(StatusCode::NOT_IMPLEMENTED)
282}