1#![cfg_attr(feature = "docs", feature(doc_cfg))]
39#![deny(unsafe_code)]
40#![deny(missing_debug_implementations, nonstandard_style)]
41#![warn(missing_docs, unreachable_pub, future_incompatible, rust_2018_idioms)]
42#![doc(test(attr(deny(warnings))))]
43#![doc(test(attr(allow(unused_extern_crates, unused_variables))))]
44#![doc(html_favicon_url = "https://yoshuawuyts.com/assets/http-rs/favicon.ico")]
45#![doc(html_logo_url = "https://yoshuawuyts.com/assets/http-rs/logo-rounded.png")]
46
47use std::cmp::Ordering;
48use std::collections::{btree_map, BTreeMap};
49use std::ops::Index;
50
51use crate::nfa::{CharacterClass, NFA};
52
53#[doc(hidden)]
54pub mod nfa;
55
56#[derive(Clone, Eq, Debug)]
57struct Metadata {
58 statics: u32,
59 dynamics: u32,
60 wildcards: u32,
61 param_names: Vec<String>,
62}
63
64impl Metadata {
65 pub(crate) fn new() -> Self {
66 Self {
67 statics: 0,
68 dynamics: 0,
69 wildcards: 0,
70 param_names: Vec::new(),
71 }
72 }
73}
74
75impl Ord for Metadata {
76 fn cmp(&self, other: &Self) -> Ordering {
77 if self.statics > other.statics {
78 Ordering::Greater
79 } else if self.statics < other.statics {
80 Ordering::Less
81 } else if self.dynamics > other.dynamics {
82 Ordering::Greater
83 } else if self.dynamics < other.dynamics {
84 Ordering::Less
85 } else if self.wildcards > other.wildcards {
86 Ordering::Greater
87 } else if self.wildcards < other.wildcards {
88 Ordering::Less
89 } else {
90 Ordering::Equal
91 }
92 }
93}
94
95impl PartialOrd for Metadata {
96 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
97 Some(self.cmp(other))
98 }
99}
100
101impl PartialEq for Metadata {
102 fn eq(&self, other: &Self) -> bool {
103 self.statics == other.statics
104 && self.dynamics == other.dynamics
105 && self.wildcards == other.wildcards
106 }
107}
108
109#[derive(PartialEq, Clone, Debug, Default)]
111pub struct Params {
112 map: BTreeMap<String, String>,
113}
114
115impl Params {
116 pub fn new() -> Self {
118 Self {
119 map: BTreeMap::new(),
120 }
121 }
122
123 pub fn insert(&mut self, key: String, value: String) {
125 self.map.insert(key, value);
126 }
127
128 pub fn find(&self, key: &str) -> Option<&str> {
130 self.map.get(key).map(|s| &s[..])
131 }
132
133 pub fn iter(&self) -> Iter<'_> {
137 Iter(self.map.iter())
138 }
139}
140
141impl Index<&str> for Params {
142 type Output = String;
143 fn index(&self, index: &str) -> &String {
144 match self.map.get(index) {
145 None => panic!("params[{}] did not exist", index),
146 Some(s) => s,
147 }
148 }
149}
150
151impl<'a> IntoIterator for &'a Params {
152 type IntoIter = Iter<'a>;
153 type Item = (&'a str, &'a str);
154
155 fn into_iter(self) -> Iter<'a> {
156 self.iter()
157 }
158}
159
160#[derive(Debug)]
162pub struct Iter<'a>(btree_map::Iter<'a, String, String>);
163
164impl<'a> Iterator for Iter<'a> {
165 type Item = (&'a str, &'a str);
166
167 #[inline]
168 fn next(&mut self) -> Option<(&'a str, &'a str)> {
169 self.0.next().map(|(k, v)| (&**k, &**v))
170 }
171
172 fn size_hint(&self) -> (usize, Option<usize>) {
173 self.0.size_hint()
174 }
175}
176
177#[derive(Debug)]
179pub struct Match<T> {
180 handler: T,
182 params: Params,
184}
185
186impl<T> Match<T> {
187 pub fn new(handler: T, params: Params) -> Self {
189 Self { handler, params }
190 }
191
192 pub fn handler(&self) -> &T {
194 &self.handler
195 }
196
197 pub fn handler_mut(&mut self) -> &mut T {
199 &mut self.handler
200 }
201
202 pub fn params(&self) -> &Params {
204 &self.params
205 }
206
207 pub fn params_mut(&mut self) -> &mut Params {
209 &mut self.params
210 }
211}
212
213#[derive(Clone, Debug)]
215pub struct Router<T> {
216 nfa: NFA<Metadata>,
217 handlers: BTreeMap<usize, T>,
218}
219
220fn segments(route: &str) -> Vec<(Option<char>, &str)> {
221 let predicate = |c| c == '.' || c == '/';
222
223 let mut segments = vec![];
224 let mut segment_start = 0;
225
226 while segment_start < route.len() {
227 let segment_end = route[segment_start + 1..]
228 .find(predicate)
229 .map(|i| i + segment_start + 1)
230 .unwrap_or_else(|| route.len());
231 let potential_sep = route.chars().nth(segment_start);
232 let sep_and_segment = match potential_sep {
233 Some(sep) if predicate(sep) => (Some(sep), &route[segment_start + 1..segment_end]),
234 _ => (None, &route[segment_start..segment_end]),
235 };
236
237 segments.push(sep_and_segment);
238 segment_start = segment_end;
239 }
240
241 segments
242}
243
244impl<T> Router<T> {
245 pub fn new() -> Self {
247 Self {
248 nfa: NFA::new(),
249 handlers: BTreeMap::new(),
250 }
251 }
252
253 pub fn add(&mut self, mut route: &str, dest: T) {
255 if !route.is_empty() && route.as_bytes()[0] == b'/' {
256 route = &route[1..];
257 }
258
259 let nfa = &mut self.nfa;
260 let mut state = 0;
261 let mut metadata = Metadata::new();
262
263 for (separator, segment) in segments(route) {
264 if let Some(separator) = separator {
265 state = nfa.put(state, CharacterClass::valid_char(separator));
266 }
267
268 if !segment.is_empty() && segment.as_bytes()[0] == b':' {
269 state = process_dynamic_segment(nfa, state);
270 metadata.dynamics += 1;
271 metadata.param_names.push(segment[1..].to_string());
272 } else if !segment.is_empty() && segment.as_bytes()[0] == b'*' {
273 state = process_star_state(nfa, state);
274 metadata.wildcards += 1;
275 metadata.param_names.push(segment[1..].to_string());
276 } else {
277 state = process_static_segment(segment, nfa, state);
278 metadata.statics += 1;
279 }
280 }
281
282 nfa.acceptance(state);
283 nfa.metadata(state, metadata);
284 self.handlers.insert(state, dest);
285 }
286
287 pub fn recognize(&self, mut path: &str) -> Result<Match<&T>, String> {
289 if !path.is_empty() && path.as_bytes()[0] == b'/' {
290 path = &path[1..];
291 }
292
293 let nfa = &self.nfa;
294 let result = nfa.process(path, |index| nfa.get(index).metadata.as_ref().unwrap());
295
296 match result {
297 Ok(nfa_match) => {
298 let mut map = Params::new();
299 let state = &nfa.get(nfa_match.state);
300 let metadata = state.metadata.as_ref().unwrap();
301 let param_names = metadata.param_names.clone();
302
303 for (i, capture) in nfa_match.captures.iter().enumerate() {
304 if !param_names[i].is_empty() {
305 map.insert(param_names[i].to_string(), capture.to_string());
306 }
307 }
308
309 let handler = self.handlers.get(&nfa_match.state).unwrap();
310 Ok(Match::new(handler, map))
311 }
312 Err(str) => Err(str),
313 }
314 }
315}
316
317impl<T> Default for Router<T> {
318 fn default() -> Self {
319 Self::new()
320 }
321}
322
323fn process_static_segment<T>(segment: &str, nfa: &mut NFA<T>, mut state: usize) -> usize {
324 for char in segment.chars() {
325 state = nfa.put(state, CharacterClass::valid_char(char));
326 }
327
328 state
329}
330
331fn process_dynamic_segment<T>(nfa: &mut NFA<T>, mut state: usize) -> usize {
332 state = nfa.put(state, CharacterClass::invalid_char('/'));
333 nfa.put_state(state, state);
334 nfa.start_capture(state);
335 nfa.end_capture(state);
336
337 state
338}
339
340fn process_star_state<T>(nfa: &mut NFA<T>, mut state: usize) -> usize {
341 state = nfa.put(state, CharacterClass::any());
342 nfa.put_state(state, state);
343 nfa.start_capture(state);
344 nfa.end_capture(state);
345
346 state
347}
348
349#[cfg(test)]
350mod tests {
351 use super::{Params, Router};
352
353 #[test]
354 fn basic_router() {
355 let mut router = Router::new();
356
357 router.add("/thomas", "Thomas".to_string());
358 router.add("/tom", "Tom".to_string());
359 router.add("/wycats", "Yehuda".to_string());
360
361 let m = router.recognize("/thomas").unwrap();
362
363 assert_eq!(*m.handler, "Thomas".to_string());
364 assert_eq!(m.params, Params::new());
365 }
366
367 #[test]
368 fn root_router() {
369 let mut router = Router::new();
370 router.add("/", 10);
371 assert_eq!(*router.recognize("/").unwrap().handler, 10)
372 }
373
374 #[test]
375 fn empty_path() {
376 let mut router = Router::new();
377 router.add("/", 12);
378 assert_eq!(*router.recognize("").unwrap().handler, 12)
379 }
380
381 #[test]
382 fn empty_route() {
383 let mut router = Router::new();
384 router.add("", 12);
385 assert_eq!(*router.recognize("/").unwrap().handler, 12)
386 }
387
388 #[test]
389 fn ambiguous_router() {
390 let mut router = Router::new();
391
392 router.add("/posts/new", "new".to_string());
393 router.add("/posts/:id", "id".to_string());
394
395 let id = router.recognize("/posts/1").unwrap();
396
397 assert_eq!(*id.handler, "id".to_string());
398 assert_eq!(id.params, params("id", "1"));
399
400 let new = router.recognize("/posts/new").unwrap();
401 assert_eq!(*new.handler, "new".to_string());
402 assert_eq!(new.params, Params::new());
403 }
404
405 #[test]
406 fn ambiguous_router_b() {
407 let mut router = Router::new();
408
409 router.add("/posts/:id", "id".to_string());
410 router.add("/posts/new", "new".to_string());
411
412 let id = router.recognize("/posts/1").unwrap();
413
414 assert_eq!(*id.handler, "id".to_string());
415 assert_eq!(id.params, params("id", "1"));
416
417 let new = router.recognize("/posts/new").unwrap();
418 assert_eq!(*new.handler, "new".to_string());
419 assert_eq!(new.params, Params::new());
420 }
421
422 #[test]
423 fn multiple_params() {
424 let mut router = Router::new();
425
426 router.add("/posts/:post_id/comments/:id", "comment".to_string());
427 router.add("/posts/:post_id/comments", "comments".to_string());
428
429 let com = router.recognize("/posts/12/comments/100").unwrap();
430 let coms = router.recognize("/posts/12/comments").unwrap();
431
432 assert_eq!(*com.handler, "comment".to_string());
433 assert_eq!(com.params, two_params("post_id", "12", "id", "100"));
434
435 assert_eq!(*coms.handler, "comments".to_string());
436 assert_eq!(coms.params, params("post_id", "12"));
437 assert_eq!(coms.params["post_id"], "12".to_string());
438 }
439
440 #[test]
441 fn wildcard() {
442 let mut router = Router::new();
443
444 router.add("*foo", "test".to_string());
445 router.add("/bar/*foo", "test2".to_string());
446
447 let m = router.recognize("/test").unwrap();
448 assert_eq!(*m.handler, "test".to_string());
449 assert_eq!(m.params, params("foo", "test"));
450
451 let m = router.recognize("/foo/bar").unwrap();
452 assert_eq!(*m.handler, "test".to_string());
453 assert_eq!(m.params, params("foo", "foo/bar"));
454
455 let m = router.recognize("/bar/foo").unwrap();
456 assert_eq!(*m.handler, "test2".to_string());
457 assert_eq!(m.params, params("foo", "foo"));
458 }
459
460 #[test]
461 fn wildcard_colon() {
462 let mut router = Router::new();
463
464 router.add("/a/*b", "ab".to_string());
465 router.add("/a/*b/c", "abc".to_string());
466 router.add("/a/*b/c/:d", "abcd".to_string());
467
468 let m = router.recognize("/a/foo").unwrap();
469 assert_eq!(*m.handler, "ab".to_string());
470 assert_eq!(m.params, params("b", "foo"));
471
472 let m = router.recognize("/a/foo/bar").unwrap();
473 assert_eq!(*m.handler, "ab".to_string());
474 assert_eq!(m.params, params("b", "foo/bar"));
475
476 let m = router.recognize("/a/foo/c").unwrap();
477 assert_eq!(*m.handler, "abc".to_string());
478 assert_eq!(m.params, params("b", "foo"));
479
480 let m = router.recognize("/a/foo/bar/c").unwrap();
481 assert_eq!(*m.handler, "abc".to_string());
482 assert_eq!(m.params, params("b", "foo/bar"));
483
484 let m = router.recognize("/a/foo/c/baz").unwrap();
485 assert_eq!(*m.handler, "abcd".to_string());
486 assert_eq!(m.params, two_params("b", "foo", "d", "baz"));
487
488 let m = router.recognize("/a/foo/bar/c/baz").unwrap();
489 assert_eq!(*m.handler, "abcd".to_string());
490 assert_eq!(m.params, two_params("b", "foo/bar", "d", "baz"));
491
492 let m = router.recognize("/a/foo/bar/c/baz/bay").unwrap();
493 assert_eq!(*m.handler, "ab".to_string());
494 assert_eq!(m.params, params("b", "foo/bar/c/baz/bay"));
495 }
496
497 #[test]
498 fn unnamed_parameters() {
499 let mut router = Router::new();
500
501 router.add("/foo/:/bar", "test".to_string());
502 router.add("/foo/:bar/*", "test2".to_string());
503 let m = router.recognize("/foo/test/bar").unwrap();
504 assert_eq!(*m.handler, "test");
505 assert_eq!(m.params, Params::new());
506
507 let m = router.recognize("/foo/test/blah").unwrap();
508 assert_eq!(*m.handler, "test2");
509 assert_eq!(m.params, params("bar", "test"));
510 }
511
512 fn params(key: &str, val: &str) -> Params {
513 let mut map = Params::new();
514 map.insert(key.to_string(), val.to_string());
515 map
516 }
517
518 fn two_params(k1: &str, v1: &str, k2: &str, v2: &str) -> Params {
519 let mut map = Params::new();
520 map.insert(k1.to_string(), v1.to_string());
521 map.insert(k2.to_string(), v2.to_string());
522 map
523 }
524
525 #[test]
526 fn dot() {
527 let mut router = Router::new();
528 router.add("/1/baz.:wibble", ());
529 router.add("/2/:bar.baz", ());
530 router.add("/3/:dynamic.:extension", ());
531 router.add("/4/static.static", ());
532
533 let m = router.recognize("/1/baz.jpg").unwrap();
534 assert_eq!(m.params, params("wibble", "jpg"));
535
536 let m = router.recognize("/2/test.baz").unwrap();
537 assert_eq!(m.params, params("bar", "test"));
538
539 let m = router.recognize("/3/any.thing").unwrap();
540 assert_eq!(m.params, two_params("dynamic", "any", "extension", "thing"));
541
542 let m = router.recognize("/3/this.performs.a.greedy.match").unwrap();
543 assert_eq!(
544 m.params,
545 two_params("dynamic", "this.performs.a.greedy", "extension", "match")
546 );
547
548 let m = router.recognize("/4/static.static").unwrap();
549 assert_eq!(m.params, Params::new());
550
551 let m = router.recognize("/4/static/static");
552 assert!(m.is_err());
553
554 let m = router.recognize("/4.static.static");
555 assert!(m.is_err());
556 }
557
558 #[test]
559 fn test_chinese() {
560 let mut router = Router::new();
561 router.add("/crates/:foo/:bar", "Hello".to_string());
562
563 let m = router.recognize("/crates/实打实打算/d's'd").unwrap();
564 assert_eq!(m.handler().as_str(), "Hello");
565 assert_eq!(m.params().find("foo"), Some("实打实打算"));
566 assert_eq!(m.params().find("bar"), Some("d's'd"));
567 }
568}