1use std::{
41 collections::HashMap,
42 fmt::{Debug, Display},
43 marker::PhantomData,
44};
45
46use crate::{shared::HttpVersion, HttpMethod};
47
48const CARRIAGE_RETURN_LINE_FEED: &[u8; 2] = b"\r\n";
49const CARRIAGE_RETURN_LINE_FEED_TWICE: &[u8; 4] = b"\r\n\r\n";
50const WHITESPACE_BYTE: u8 = 32;
51const COLON_BYTE: u8 = 58;
52
53const MAX_NUM_HEADERS: usize = 1000;
54
55#[derive(Debug)]
57pub struct HttpRequest<'a> {
58 method: HttpMethod,
59 uri: Uri<'a>,
60 version: HttpVersion,
61 headers: Headers<'a>,
62 body: &'a str,
63}
64
65unsafe impl Send for HttpRequest<'_> {}
67
68impl Display for HttpRequest<'_> {
69 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
70 f.write_str(&format!(
71 "Method: {:?}\nUri: {:?}\nVersion: {:?}\nHeaders: {:?}\nBody: {:?}",
72 self.method,
73 self.uri.0,
74 self.version,
75 self.headers
76 .keys
77 .iter()
78 .zip(self.headers.values.iter())
79 .take(self.headers.num)
80 .map(|(key, value)| (key.unwrap(), value.unwrap()))
81 .collect::<HashMap<&str, &str>>(),
82 self.body
83 ))
84 }
85}
86
87impl<'a> HttpRequest<'a> {
88 pub fn from_bytes(bytes: &'a [u8]) -> Self {
90 let request_line = Self::get_request_line(bytes);
91 let http_method = Self::extract_http_method(request_line);
92 let http_version = Self::extract_http_version(request_line);
93 let uri = Self::extract_request_uri(request_line);
94 let header_bytes = Self::get_headers(bytes);
95 let headers = Self::extract_headers(header_bytes);
96 let body = Self::get_body(bytes);
97
98 Self {
99 method: http_method,
100 uri,
101 version: http_version,
102 headers,
103 body,
104 }
105 }
106
107 pub fn uri(&self) -> &Uri {
109 &self.uri
110 }
111
112 pub fn method(&self) -> HttpMethod {
114 self.method
115 }
116
117 fn get_request_line(bytes: &[u8]) -> &[u8] {
119 let idx = bytes
120 .windows(CARRIAGE_RETURN_LINE_FEED.len())
121 .position(|window| window == CARRIAGE_RETURN_LINE_FEED)
122 .unwrap();
123
124 &bytes[..idx]
125 }
126
127 fn get_headers(bytes: &[u8]) -> &[u8] {
129 let idx = bytes
130 .windows(CARRIAGE_RETURN_LINE_FEED.len())
131 .position(|window| window == CARRIAGE_RETURN_LINE_FEED)
132 .map(|idx| idx + CARRIAGE_RETURN_LINE_FEED.len())
133 .unwrap();
134
135 let header_bytes_idx = bytes[idx..]
136 .windows(CARRIAGE_RETURN_LINE_FEED_TWICE.len())
137 .position(|window| window == CARRIAGE_RETURN_LINE_FEED_TWICE)
138 .unwrap();
139
140 &bytes[idx..header_bytes_idx + idx]
141 }
142
143 fn get_body(bytes: &[u8]) -> &str {
145 let idx = bytes
146 .windows(CARRIAGE_RETURN_LINE_FEED_TWICE.len())
147 .position(|window| window == CARRIAGE_RETURN_LINE_FEED_TWICE)
148 .map(|idx| idx + CARRIAGE_RETURN_LINE_FEED_TWICE.len())
149 .unwrap();
150
151 std::str::from_utf8(&bytes[idx..]).unwrap()
152 }
153
154 fn extract_http_method(bytes: &[u8]) -> HttpMethod {
156 bytes
157 .split(|b| *b == WHITESPACE_BYTE)
158 .next()
159 .unwrap()
160 .into()
161 }
162
163 fn extract_request_uri(bytes: &[u8]) -> Uri {
165 let mut uri_bytes_split = bytes.split(|b| *b == WHITESPACE_BYTE);
166 uri_bytes_split.next().unwrap();
167 let uri_bytes = uri_bytes_split.next().unwrap();
168 Uri(std::str::from_utf8(uri_bytes).unwrap())
169 }
170
171 fn extract_http_version(bytes: &[u8]) -> HttpVersion {
173 let mut http_version_bytes_split = bytes.split(|b| *b == WHITESPACE_BYTE);
174 http_version_bytes_split.next().unwrap();
175 http_version_bytes_split.next().unwrap();
176 http_version_bytes_split.next().unwrap().into()
177 }
178
179 fn extract_headers(bytes: &[u8]) -> Headers {
181 let mut headers = Headers::new();
182 let mut start_idx = 0;
183
184 loop {
185 let Some(carriage_return_idx) = bytes[start_idx..]
186 .windows(CARRIAGE_RETURN_LINE_FEED.len())
187 .position(|window| window == CARRIAGE_RETURN_LINE_FEED)
188 else {
189 break;
190 };
191
192 let (key, value) = HttpRequest::get_header_key_and_value(
193 &bytes[start_idx..carriage_return_idx + start_idx],
194 );
195
196 headers.add_key_value(key, value);
197
198 start_idx += carriage_return_idx + CARRIAGE_RETURN_LINE_FEED.len();
199 }
200
201 let (key, value) = HttpRequest::get_header_key_and_value(&bytes[start_idx..]);
202 headers.add_key_value(key, value);
203
204 headers
205 }
206
207 fn get_header_key_and_value(bytes: &'a [u8]) -> (&'a str, &'a str) {
209 let colon_idx = bytes.iter().position(|byte| *byte == COLON_BYTE).unwrap();
210 let key = std::str::from_utf8(&bytes[..colon_idx]);
211 let whitespace_offset = (bytes[colon_idx + 1] == WHITESPACE_BYTE) as usize;
212 let value = std::str::from_utf8(&bytes[colon_idx + 1 + whitespace_offset..]);
213 (key.unwrap(), value.unwrap())
214 }
215}
216
217struct Cursor {
219 idx: usize,
221 start_idx: usize,
223}
224
225impl Cursor {
226 fn increment(&mut self) {
228 self.idx += 1;
229 }
230
231 fn get(&self) -> usize {
233 self.idx
234 }
235
236 fn get_start(&self) -> usize {
238 self.start_idx
239 }
240
241 fn set_start_to_idx(&mut self) {
243 self.start_idx = self.idx;
244 }
245}
246
247#[derive(Debug, Copy, Clone, PartialEq, Eq)]
249pub struct PathSegment;
250
251#[derive(Debug, Copy, Clone, PartialEq, Eq)]
253pub struct QuerySegment;
254
255#[derive(Debug, Copy, Clone, PartialEq, Eq)]
257pub struct Params<'a> {
258 path_segment: Segment<'a, PathSegment>,
259 query_fragment: Segment<'a, QuerySegment>,
260}
261
262impl Default for Params<'_> {
263 fn default() -> Self {
264 Self::new()
265 }
266}
267
268impl<'a> Params<'a> {
269 pub fn new() -> Self {
271 Self {
272 path_segment: Segment::<PathSegment>::new(),
273 query_fragment: Segment::<QuerySegment>::new(),
274 }
275 }
276
277 pub fn iter_path(&mut self) -> &mut Segment<'a, PathSegment> {
279 self.path_segment.iter()
280 }
281
282 pub fn iter_query(&mut self) -> &mut Segment<'a, QuerySegment> {
284 self.query_fragment.iter()
285 }
286
287 pub fn path_segment(&self) -> &Segment<'_, PathSegment> {
289 &self.path_segment
290 }
291
292 pub fn query_segment(&self) -> &Segment<'_, QuerySegment> {
294 &self.query_fragment
295 }
296}
297
298#[derive(Debug, Copy, Clone, PartialEq, Eq)]
301pub struct Segment<'a, T>
302where
303 T: Copy + Debug + PartialEq + Eq + Clone,
304{
305 key: [Option<&'a str>; 1024],
307 value: [Option<&'a str>; 1024],
309 num: usize,
311 iter_cnt: usize,
313 marker: PhantomData<T>,
315}
316
317impl<'a, T> Segment<'a, T>
318where
319 T: Copy + Debug + PartialEq + Eq + Clone,
320{
321 pub fn new() -> Self {
323 Self {
324 key: [None; 1024],
325 value: [None; 1024],
326 num: 0,
327 iter_cnt: 0,
328 marker: PhantomData,
329 }
330 }
331
332 pub fn insert_key_value(&mut self, key: &'a str, value: Option<&'a str>) {
334 self.key[self.num] = Some(key);
335 self.value[self.num] = value;
336 self.num += 1;
337 }
338
339 pub fn insert_key(&mut self, key: &'a str) {
341 self.key[self.num] = Some(key);
342 }
343
344 pub fn insert_value(&mut self, value: Option<&'a str>) {
346 self.value[self.num] = value;
347 self.num += 1;
348 }
349
350 pub fn size(&self) -> usize {
352 self.num
353 }
354
355 pub fn iter(&mut self) -> &mut Self {
357 self.iter_cnt = 0;
358 self
359 }
360}
361
362impl<'a> Iterator for Segment<'a, PathSegment> {
364 type Item = (Key<'a>, Value<'a>);
365
366 fn next(&mut self) -> Option<Self::Item> {
367 if self.iter_cnt >= self.num {
368 return None;
369 }
370 let items = (
371 Key(self.key[self.iter_cnt].unwrap()),
372 Value(self.value[self.iter_cnt].unwrap()),
373 );
374 self.iter_cnt += 1;
375 Some(items)
376 }
377}
378
379impl<'a> Iterator for Segment<'a, QuerySegment> {
381 type Item = (Key<'a>, Option<Value<'a>>);
382
383 fn next(&mut self) -> Option<Self::Item> {
384 if self.iter_cnt >= self.num {
385 return None;
386 }
387 let items = (
388 Key(self.key[self.iter_cnt].unwrap()),
389 self.value[self.iter_cnt].map(Value),
390 );
391 self.iter_cnt += 1;
392 Some(items)
393 }
394}
395
396#[derive(Debug, PartialEq)]
398pub struct Key<'a>(&'a str);
399
400impl AsRef<str> for Key<'_> {
401 fn as_ref(&self) -> &str {
402 self.0
403 }
404}
405
406#[derive(Debug, PartialEq)]
408pub struct Value<'a>(&'a str);
409
410impl AsRef<str> for Value<'_> {
411 fn as_ref(&self) -> &str {
412 self.0
413 }
414}
415
416#[derive(Debug, Copy, Clone, PartialEq, Eq)]
418pub struct Uri<'a>(&'a str);
419
420impl AsRef<str> for Uri<'_> {
421 fn as_ref(&self) -> &str {
422 self.0
423 }
424}
425
426impl<'a> Uri<'a> {
427 pub fn is_match(&self, cmp_uri: &'a str) -> Option<Params<'a>> {
429 if self.0 == cmp_uri {
434 return Some(Params {
435 path_segment: Segment::<PathSegment>::new(),
436 query_fragment: Segment::<QuerySegment>::new(),
437 });
438 }
439 if self.0.split('/').count() != cmp_uri.split('/').count() {
440 return None;
441 }
442 let mut path_segment = Segment::<PathSegment>::new();
445
446 let mut start_idx = 0;
448 let mut bracket_hit = false;
449 let mut bracket_hit_idx = 0;
450 let mut record_uri_char = false;
451 let mut end_with_value = false;
452
453 let mut cursor_uri = Cursor {
455 idx: 0,
456 start_idx: 0,
457 };
458 let mut cursor_cmp_uri = Cursor {
459 idx: 0,
460 start_idx: 0,
461 };
462
463 for (idx, c) in cmp_uri.char_indices() {
465 if record_uri_char {
466 end_with_value = false;
468 cursor_cmp_uri.set_start_to_idx();
469
470 let start_idx_uri = cursor_uri.get();
471 let mut c_iter = self.0.chars().skip(cursor_uri.get());
472 let Some(mut c_uri) = c_iter.next() else {
473 break;
474 };
475
476 while c_uri != c {
477 let Some(c_uri_next) = c_iter.next() else {
478 break;
479 };
480 c_uri = c_uri_next;
481 cursor_uri.increment();
482 }
483
484 let end_idx_uri = cursor_uri.get();
485 path_segment.insert_value(Some(&self.0[start_idx_uri..end_idx_uri]));
486 cursor_uri.set_start_to_idx();
487 record_uri_char = false;
488 }
489
490 if c == '{' {
491 if cmp_uri[cursor_cmp_uri.get_start()..cursor_cmp_uri.get()]
493 != self.0[cursor_uri.get_start()..cursor_uri.get()]
494 {
495 return None;
496 } else {
497 bracket_hit = true;
498 bracket_hit_idx = idx;
499 }
500 }
501
502 if bracket_hit {
503 if c == '}' {
504 bracket_hit = false;
506 start_idx = idx + 1;
507 record_uri_char = true;
508 end_with_value = true;
509 path_segment.insert_key(&cmp_uri[bracket_hit_idx + 1..idx]);
510 cursor_cmp_uri.set_start_to_idx();
511 }
512 cursor_cmp_uri.increment();
513 continue;
514 }
515
516 cursor_uri.increment();
518 if !bracket_hit {
519 cursor_cmp_uri.increment();
520 }
521 }
522
523 let mut params: Option<Params> = None;
524
525 if self.0.contains('?') {
527 if let Some(query_fragment) = self.0.split('?').last() {
528 let query_segment = Uri::parse_segment(query_fragment);
529 params.get_or_insert_default().query_fragment = query_segment;
530 }
531 }
532
533 if end_with_value {
535 let mut end_idx = self.0.len();
536 for (idx, char) in self.0.char_indices() {
537 if char == '?' {
538 end_idx = idx;
539 break;
540 }
541 }
542 path_segment.insert_value(Some(&self.0[cursor_uri.get()..end_idx]));
543 }
544
545 if path_segment.num > 0 {
547 params.get_or_insert_default().path_segment = path_segment;
548 }
549
550 if start_idx >= cmp_uri.len() {
552 return params;
553 }
554
555 if self.0[cursor_uri.get_start()..] != cmp_uri[cursor_cmp_uri.get_start()..] {
557 return params;
558 }
559
560 if params.is_none() {
562 params = Some(Params::default());
563 }
564 params
565 }
566
567 fn parse_segment(segment_part: &'a str) -> Segment<'a, QuerySegment> {
569 let mut segment: Segment<'a, QuerySegment> = Segment::new();
570
571 segment_part.split('&').for_each(|inner_split| {
572 let mut iter = inner_split.splitn(2, '=');
573 let Some(key) = iter.next() else { return };
574 let value = iter.next();
575 segment.insert_key_value(key, value);
576 });
577
578 segment
579 }
580}
581
582#[derive(Debug, Copy, Clone, PartialEq, Eq)]
584pub struct Headers<'a> {
585 keys: [Option<&'a str>; MAX_NUM_HEADERS],
586 values: [Option<&'a str>; MAX_NUM_HEADERS],
587 num: usize,
589}
590
591impl Default for Headers<'_> {
592 fn default() -> Self {
593 Self::new()
594 }
595}
596
597impl<'a> Headers<'a> {
598 pub fn new() -> Self {
600 Self {
601 keys: [None; MAX_NUM_HEADERS],
602 values: [None; MAX_NUM_HEADERS],
603 num: 0,
604 }
605 }
606
607 fn add_key_value(&mut self, key: &'a str, value: &'a str) {
609 self.keys[self.num] = Some(key);
610 self.values[self.num] = Some(value);
611 self.num += 1;
612 }
613}
614
615#[cfg(test)]
616mod tests {
617 use super::*;
618
619 fn get_test_post_request() -> &'static [u8] {
620 b"POST /user HTTP/1.1\r\n\
621 Host: localhost:8080\r\n\
622 User-Agent: curl/7.81.0\r\n\
623 Accept: */*\r\n\
624 Content-Type: application/json\r\n\
625 Content-Length: 26\r\n\
626 \r\n\
627 {\"message\": \"hello world\"}"
628 }
629
630 fn get_test_post_request_no_headers() -> &'static [u8] {
631 b"POST /user HTTP/1.1\r\n\
632 \r\n\
633 {\"message\": \"hello world\"}"
634 }
635
636 #[test]
637 fn get_request_line() {
638 let request = get_test_post_request();
639 let expected = [
641 80, 79, 83, 84, 32, 47, 117, 115, 101, 114, 32, 72, 84, 84, 80, 47, 49, 46, 49,
642 ];
643 let actual = HttpRequest::get_request_line(request);
644
645 assert_eq!(actual, expected);
646 }
647
648 #[test]
649 fn extract_http_method() {
650 let request_line = [
651 80, 79, 83, 84, 32, 47, 117, 115, 101, 114, 32, 72, 84, 84, 80, 47, 49, 46, 49,
652 ];
653
654 let expected = HttpMethod::POST;
655
656 let actual = HttpRequest::extract_http_method(&request_line);
657
658 assert_eq!(actual, expected);
659 }
660
661 #[test]
662 fn bytes_to_http_method() {
663 let get = [71, 69, 84];
664 let actual: HttpMethod = get.as_slice().into();
665
666 assert_eq!(actual, HttpMethod::GET);
667
668 let head = [72, 69, 65, 68];
669 let actual: HttpMethod = head.as_slice().into();
670 assert_eq!(actual, HttpMethod::HEAD);
671
672 let options = [79, 80, 84, 73, 79, 78, 83];
673 let actual: HttpMethod = options.as_slice().into();
674 assert_eq!(actual, HttpMethod::OPTIONS);
675
676 let post = [80, 79, 83, 84];
677 let actual: HttpMethod = post.as_slice().into();
678 assert_eq!(actual, HttpMethod::POST);
679
680 let put = [80, 85, 84];
681 let actual: HttpMethod = put.as_slice().into();
682 assert_eq!(actual, HttpMethod::PUT);
683
684 let patch = [80, 65, 84, 67, 72];
685 let actual: HttpMethod = patch.as_slice().into();
686 assert_eq!(actual, HttpMethod::PATCH);
687
688 let delete = [68, 69, 76, 69, 84, 69];
689 let actual: HttpMethod = delete.as_slice().into();
690 assert_eq!(actual, HttpMethod::DELETE);
691 }
692
693 #[test]
694 fn extract_request_uri() {
695 let request_line = [
696 80, 79, 83, 84, 32, 47, 117, 115, 101, 114, 32, 72, 84, 84, 80, 47, 49, 46, 49,
697 ];
698
699 let actual = HttpRequest::extract_request_uri(&request_line);
700 let expected = Uri("/user");
701
702 assert_eq!(actual, expected);
703 }
704
705 #[test]
706 fn extract_http_version() {
707 let request_line = [
708 80, 79, 83, 84, 32, 47, 117, 115, 101, 114, 32, 72, 84, 84, 80, 47, 49, 46, 49,
709 ];
710
711 let expected = HttpVersion::OnePointOne;
712
713 let actual = HttpRequest::extract_http_version(&request_line);
714
715 assert_eq!(actual, expected);
716 }
717
718 #[test]
719 fn get_headers() {
720 let request = get_test_post_request();
721
722 let actual = HttpRequest::get_headers(request);
723
724 let expected = b"Host: localhost:8080\r\n\
725 User-Agent: curl/7.81.0\r\n\
726 Accept: */*\r\n\
727 Content-Type: application/json\r\n\
728 Content-Length: 26";
729
730 assert_eq!(actual, expected);
731 }
732
733 #[test]
734 fn extract_headers() {
735 let headers = b"Host: localhost:8080\r\n\
736 User-Agent: curl/7.81.0\r\n\
737 Accept:*/*\r\n\
738 Content-Type:application/json\r\n\
739 Content-Length: 26";
740
741 let actual = HttpRequest::extract_headers(headers);
742
743 let mut expected_keys = [None; MAX_NUM_HEADERS];
744 let mut expected_values = [None; MAX_NUM_HEADERS];
745 let expected_num_headers = 5;
746
747 expected_keys[0] = Some("Host");
748 expected_keys[1] = Some("User-Agent");
749 expected_keys[2] = Some("Accept");
750 expected_keys[3] = Some("Content-Type");
751 expected_keys[4] = Some("Content-Length");
752
753 expected_values[0] = Some("localhost:8080");
754 expected_values[1] = Some("curl/7.81.0");
755 expected_values[2] = Some("*/*");
756 expected_values[3] = Some("application/json");
757 expected_values[4] = Some("26");
758
759 let expected = Headers {
760 keys: expected_keys,
761 values: expected_values,
762 num: expected_num_headers,
763 };
764
765 assert_eq!(actual, expected);
766 }
767
768 #[test]
769 fn get_body() {
770 let request = get_test_post_request();
771
772 let actual = HttpRequest::get_body(request);
773
774 let expected = "{\"message\": \"hello world\"}";
775
776 assert_eq!(actual, expected);
777
778 let request = get_test_post_request_no_headers();
779
780 let actual = HttpRequest::get_body(request);
781
782 let expected = "{\"message\": \"hello world\"}";
783
784 assert_eq!(actual, expected);
785 }
786
787 #[test]
788 fn uri_is_match_home_path() {
789 let uri = Uri("/");
790
791 let expected_params = Params {
792 path_segment: Segment::<PathSegment>::new(),
793 query_fragment: Segment::<QuerySegment>::new(),
794 };
795
796 assert_eq!(uri.is_match("/"), Some(expected_params))
797 }
798
799 #[test]
800 fn uri_is_match_home_path_no_parameters() {
801 let uri = Uri("/");
802
803 let actual = uri.is_match("/{something}");
804
805 let mut path_segment = Segment::<PathSegment>::new();
806 path_segment.key[0] = Some("something");
807 path_segment.value[0] = Some("");
808 path_segment.num = 1;
809
810 let expected_params = Params {
811 path_segment,
812 query_fragment: Segment::<QuerySegment>::new(),
813 };
814
815 assert_eq!(actual, Some(expected_params))
816 }
817
818 #[test]
819 fn uri_is_match_no_parameterized() {
820 let uri = Uri("/uri");
821
822 let expected_params = Params {
823 path_segment: Segment::<PathSegment>::new(),
824 query_fragment: Segment::<QuerySegment>::new(),
825 };
826
827 assert_eq!(uri.is_match("/uri"), Some(expected_params))
828 }
829
830 #[test]
831 fn uri_is_match_parameterized_single_arg() {
832 let uri = Uri("/1244r2");
833
834 let mut path_segment = Segment::<PathSegment>::new();
835 path_segment.key[0] = Some("id");
836 path_segment.value[0] = Some("1244r2");
837 path_segment.num = 1;
838
839 let expected_params = Params {
840 path_segment,
841 query_fragment: Segment::<QuerySegment>::new(),
842 };
843 assert_eq!(uri.is_match("/{id}"), Some(expected_params))
844 }
845
846 #[test]
847 fn uri_is_match_parameterized_invalid_comparison() {
848 let uri = Uri("/");
849 assert!(uri.is_match("/what/{mate}").is_none())
850 }
851
852 #[test]
853 fn uri_is_match_parameterized_and_query() {
854 let uri = Uri("/orders/123?status=hello_matey&include=details");
855 let mut path_segment = Segment::<PathSegment>::new();
856
857 path_segment.key[0] = Some("orders_param");
858 path_segment.value[0] = Some("orders");
859 path_segment.num = 1;
860
861 let mut query_segment = Segment::<QuerySegment>::new();
862 query_segment.key[0] = Some("status");
863 query_segment.value[0] = Some("hello_matey");
864 query_segment.key[1] = Some("include");
865 query_segment.value[1] = Some("details");
866 query_segment.num = 2;
867
868 let params = Params {
869 path_segment,
870 query_fragment: query_segment,
871 };
872
873 assert_eq!(uri.is_match("/{orders_param}/123"), Some(params))
874 }
875
876 #[test]
877 fn uri_is_match_parameterized_multi_args() {
878 let uri = Uri("/orders/status/123?status=shipped&include=details");
879
880 let mut path_segment = Segment::<PathSegment>::new();
881 path_segment.key[0] = Some("orders_param");
882 path_segment.value[0] = Some("orders");
883 path_segment.key[1] = Some("field");
884 path_segment.value[1] = Some("status");
885 path_segment.num = 2;
886
887 let mut query_segment = Segment::<QuerySegment>::new();
888 query_segment.key[0] = Some("status");
889 query_segment.value[0] = Some("shipped");
890 query_segment.key[1] = Some("include");
891 query_segment.value[1] = Some("details");
892 query_segment.num = 2;
893
894 assert_eq!(
895 uri.is_match("/{orders_param}/{field}/123"),
896 Some(Params {
897 path_segment,
898 query_fragment: query_segment,
899 })
900 )
901 }
902
903 #[test]
904 fn uri_is_match_parameterized_multi_args2() {
905 let uri = Uri("/what/hello?this=value&is");
906
907 let mut path_segment = Segment::<PathSegment>::new();
908 path_segment.key[0] = Some("mate");
909 path_segment.value[0] = Some("hello");
910 path_segment.num = 1;
911
912 let mut query_segment = Segment::<QuerySegment>::new();
913 query_segment.key[0] = Some("this");
914 query_segment.value[0] = Some("value");
915 query_segment.key[1] = Some("is");
916 query_segment.value[1] = None;
917 query_segment.num = 2;
918
919 assert_eq!(
920 uri.is_match("/what/{mate}"),
921 Some(Params {
922 path_segment,
923 query_fragment: query_segment,
924 })
925 )
926 }
927
928 #[test]
929 fn uri_query_segment_params_parsing() {
930 let segment = "q=rust&&limit=10&debug&sort=asc";
931
932 let actual = Uri::parse_segment(segment);
933
934 let mut expected = Segment::new();
935 expected.key[0] = Some("q");
936 expected.key[1] = Some("");
937 expected.key[2] = Some("limit");
938 expected.key[3] = Some("debug");
939 expected.key[4] = Some("sort");
940 expected.value[0] = Some("rust");
941 expected.value[1] = None;
942 expected.value[2] = Some("10");
943 expected.value[3] = None;
944 expected.value[4] = Some("asc");
945 expected.num = 5;
946
947 assert_eq!(actual, expected)
948 }
949
950 #[test]
951 fn path_segment_iter() {
952 let mut path_segment = Segment::<PathSegment>::new();
953 path_segment.key[0] = Some("id");
954 path_segment.value[0] = Some("123");
955 path_segment.key[1] = Some("name");
956 path_segment.value[1] = Some("hello");
957 path_segment.num = 2;
958
959 let iter = path_segment.iter();
960
961 assert_eq!(iter.next(), Some((Key("id"), Value("123"))));
962 assert_eq!(iter.next(), Some((Key("name"), Value("hello"))));
963 assert_eq!(iter.next(), None);
964 }
965
966 #[test]
967 fn query_segment_iter() {
968 let mut query_segment = Segment::<QuerySegment>::new();
969 query_segment.key[0] = Some("id");
970 query_segment.value[0] = Some("123");
971 query_segment.key[1] = Some("name");
972 query_segment.value[1] = None;
973 query_segment.num = 2;
974
975 let iter = query_segment.iter();
976 assert_eq!(iter.next(), Some((Key("id"), Some(Value("123")))));
977 assert_eq!(iter.next(), Some((Key("name"), None)));
978 assert_eq!(iter.next(), None);
979 }
980}