1#![deny(unsafe_code)]
12#![deny(missing_debug_implementations)]
13#![warn(missing_docs)]
14
15pub mod normalize;
16
17pub const MAX_PATH_LEN: usize = 1024;
23
24pub const MAX_QUERY_LEN: usize = 1024;
26
27pub const MAX_AUTHORITY_LEN: usize = 256;
29
30pub const MAX_HEADER_COUNT: usize = 32;
32
33pub const MAX_HEADER_NAME_LEN: usize = 64;
35
36pub const MAX_HEADER_VALUE_LEN: usize = 256;
39
40pub const MAX_BODY_LEN: usize = 4096;
43
44#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
50pub enum Protocol {
51 Http1,
53 Http2,
55 Http3,
57 Tcp,
59 Udp,
61 Quic,
63}
64
65#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
67pub enum Transport {
68 Plaintext,
70 Tls13,
72}
73
74#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
76pub enum Method {
77 Get,
79 Post,
81 Put,
83 Delete,
85 Patch,
87 Head,
89 Options,
91 Connect,
93 Trace,
95}
96
97impl Method {
98 #[inline]
100 pub fn as_str(&self) -> &'static str {
101 match self {
102 Method::Get => "GET",
103 Method::Post => "POST",
104 Method::Put => "PUT",
105 Method::Delete => "DELETE",
106 Method::Patch => "PATCH",
107 Method::Head => "HEAD",
108 Method::Options => "OPTIONS",
109 Method::Connect => "CONNECT",
110 Method::Trace => "TRACE",
111 }
112 }
113}
114
115#[derive(Debug, Clone, PartialEq, Eq)]
117pub struct MethodParseError(());
118
119impl std::fmt::Display for MethodParseError {
120 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
121 f.write_str("invalid HTTP method")
122 }
123}
124
125impl std::error::Error for MethodParseError {}
126
127impl std::str::FromStr for Method {
128 type Err = MethodParseError;
129
130 #[inline]
136 fn from_str(s: &str) -> Result<Self, Self::Err> {
137 Ok(match s {
139 "GET" => Method::Get,
140 "POST" => Method::Post,
141 "PUT" => Method::Put,
142 "DELETE" => Method::Delete,
143 "PATCH" => Method::Patch,
144 "HEAD" => Method::Head,
145 "OPTIONS" => Method::Options,
146 "CONNECT" => Method::Connect,
147 "TRACE" => Method::Trace,
148 _ => return Err(MethodParseError(())),
149 })
150 }
151}
152
153#[derive(Debug, Clone, Copy)]
161pub struct CanonicalHeader {
162 pub name: [u8; MAX_HEADER_NAME_LEN],
164 pub name_len: u8,
166 pub value: [u8; MAX_HEADER_VALUE_LEN],
168 pub value_len: u16,
170}
171
172impl CanonicalHeader {
173 #[inline]
175 pub const fn empty() -> Self {
176 Self {
177 name: [0u8; MAX_HEADER_NAME_LEN],
178 name_len: 0,
179 value: [0u8; MAX_HEADER_VALUE_LEN],
180 value_len: 0,
181 }
182 }
183
184 #[inline]
187 pub fn reset(&mut self) {
188 self.name_len = 0;
190 self.value_len = 0;
191 }
192
193 pub fn from_bytes(name: &[u8], value: &[u8]) -> Option<Self> {
203 if name.len() > MAX_HEADER_NAME_LEN || value.len() > MAX_HEADER_VALUE_LEN {
204 return None;
205 }
206 let mut hdr = Self::empty();
207 let name_len = name.len() as u8;
208 hdr.name[..name.len()].copy_from_slice(name);
209 hdr.name_len = name_len;
210
211 let value_len = value.len() as u16;
212 hdr.value[..value.len()].copy_from_slice(value);
213 hdr.value_len = value_len;
214 Some(hdr)
215 }
216
217 #[inline]
219 pub fn name_str(&self) -> &str {
220 core::str::from_utf8(&self.name[..self.name_len as usize]).unwrap_or("")
221 }
222
223 #[inline]
225 pub fn value_str(&self) -> &str {
226 core::str::from_utf8(&self.value[..self.value_len as usize]).unwrap_or("")
227 }
228
229 #[inline]
231 pub fn is_empty(&self) -> bool {
232 self.name_len == 0
233 }
234}
235
236#[derive(Debug)]
244pub struct BodyStream<'a> {
245 data: &'a [u8],
247 consumed: bool,
249}
250
251impl<'a> BodyStream<'a> {
252 #[inline]
254 pub fn new(data: &'a [u8]) -> Self {
255 Self {
256 data,
257 consumed: false,
258 }
259 }
260
261 #[inline]
267 pub fn get_data(&mut self) -> Option<&'a [u8]> {
268 if self.consumed || self.data.is_empty() {
269 return None;
270 }
271 self.consumed = true;
272 Some(self.data)
273 }
274
275 #[inline]
277 pub fn is_consumed(&self) -> bool {
278 self.consumed
279 }
280
281 #[inline]
283 pub fn len(&self) -> usize {
284 self.data.len()
285 }
286
287 #[inline]
289 pub fn is_empty(&self) -> bool {
290 self.data.is_empty()
291 }
292}
293
294#[derive(Debug, Clone)]
312pub struct CanonicalRequest {
313 pub method: Method,
315 scheme: [u8; 8],
317 scheme_len: u8,
319 authority: [u8; MAX_AUTHORITY_LEN],
321 authority_len: u16,
323 normalized_path: [u8; MAX_PATH_LEN],
325 path_len: u16,
327 normalized_query: [u8; MAX_QUERY_LEN],
329 query_len: u32,
331 headers: [CanonicalHeader; MAX_HEADER_COUNT],
333 header_count: u8,
335 pub protocol: Protocol,
337 pub transport: Transport,
339 pub generation: u64,
341 pub deadline_ms: u64,
343 pub cancelled: bool,
345 pub resource_lease: u64,
347 body_buffer: [u8; MAX_BODY_LEN],
349 body_len: u32,
351 body_overflow: Option<Vec<u8>>,
353}
354
355impl CanonicalRequest {
356 pub const fn empty() -> Self {
358 Self {
359 method: Method::Get,
360 scheme: [0u8; 8],
361 scheme_len: 0,
362 authority: [0u8; MAX_AUTHORITY_LEN],
363 authority_len: 0,
364 normalized_path: [0u8; MAX_PATH_LEN],
365 path_len: 0,
366 normalized_query: [0u8; MAX_QUERY_LEN],
367 query_len: 0,
368 headers: [CanonicalHeader::empty(); MAX_HEADER_COUNT],
369 header_count: 0,
370 protocol: Protocol::Http1,
371 transport: Transport::Plaintext,
372 generation: 0,
373 deadline_ms: 0,
374 cancelled: false,
375 resource_lease: 0,
376 body_buffer: [0u8; MAX_BODY_LEN],
377 body_len: 0,
378 body_overflow: None,
379 }
380 }
381
382 #[inline]
385 pub fn reset(&mut self) {
386 self.method = Method::Get;
387 self.scheme_len = 0;
388 self.authority_len = 0;
389 self.path_len = 0;
390 self.query_len = 0;
391 for i in 0..self.header_count as usize {
393 self.headers[i].reset();
394 }
395 self.header_count = 0;
396 self.protocol = Protocol::Http1;
397 self.transport = Transport::Plaintext;
398 self.generation = 0;
399 self.deadline_ms = 0;
400 self.cancelled = false;
401 self.resource_lease = 0;
402 self.body_len = 0;
404 self.body_overflow = None;
405 }
406
407 pub fn set_body(&mut self, body: impl Into<Vec<u8>>) {
413 let body = body.into();
414 if body.len() <= MAX_BODY_LEN {
415 self.body_overflow = None;
416 self.body_buffer[..body.len()].copy_from_slice(&body);
417 self.body_len = body.len() as u32;
418 } else {
419 self.body_overflow = Some(body);
420 self.body_len = self
421 .body_overflow
422 .as_ref()
423 .map(|v| v.len())
424 .unwrap_or(0) as u32;
425 }
426 }
427
428 #[inline]
430 pub fn body(&self) -> &[u8] {
431 if let Some(ref overflow) = self.body_overflow {
432 overflow.as_slice()
433 } else {
434 &self.body_buffer[..self.body_len as usize]
435 }
436 }
437
438 #[inline]
440 pub fn scheme_str(&self) -> &str {
441 core::str::from_utf8(&self.scheme[..self.scheme_len as usize]).unwrap_or("")
442 }
443
444 #[must_use]
451 pub fn set_scheme(&mut self, scheme: &str) -> bool {
452 if scheme.len() > 8 {
453 return false;
454 }
455 let len = scheme.len() as u8;
456 self.scheme[..scheme.len()].copy_from_slice(scheme.as_bytes());
457 self.scheme_len = len;
458 true
459 }
460
461 #[inline]
463 pub fn authority_str(&self) -> &str {
464 core::str::from_utf8(&self.authority[..self.authority_len as usize]).unwrap_or("")
465 }
466
467 #[must_use]
473 pub fn set_authority(&mut self, authority: &str) -> bool {
474 if authority.len() > MAX_AUTHORITY_LEN {
475 return false;
476 }
477 let len = authority.len() as u16;
478 self.authority[..authority.len()].copy_from_slice(authority.as_bytes());
479 self.authority_len = len;
480 true
481 }
482
483 #[inline]
485 pub fn path_str(&self) -> &str {
486 core::str::from_utf8(&self.normalized_path[..self.path_len as usize]).unwrap_or("")
487 }
488
489 #[inline]
491 pub fn path_bytes(&self) -> &[u8] {
492 &self.normalized_path[..self.path_len as usize]
493 }
494
495 #[must_use]
506 pub fn set_path(&mut self, path: &str) -> bool {
507 let (path_part, query_part) = match path.find('?') {
509 Some(pos) => (&path[..pos], Some(&path[pos + 1..])),
510 None => (path, None),
511 };
512 if path_part.len() > MAX_PATH_LEN {
514 return false;
515 }
516 if let Some(query) = query_part
517 && query.len() > MAX_QUERY_LEN
518 {
519 return false;
520 }
521 self.normalized_path[..path_part.len()].copy_from_slice(path_part.as_bytes());
522 self.path_len = path_part.len() as u16;
523 if let Some(query) = query_part {
524 let _ = self.set_query(query);
526 }
527 true
528 }
529
530 #[inline]
532 pub fn query_str(&self) -> &str {
533 core::str::from_utf8(&self.normalized_query[..self.query_len as usize]).unwrap_or("")
534 }
535
536 #[must_use]
542 pub fn set_query(&mut self, query: &str) -> bool {
543 if query.len() > MAX_QUERY_LEN {
544 return false;
545 }
546 let len = query.len() as u32;
547 self.normalized_query[..query.len()].copy_from_slice(query.as_bytes());
548 self.query_len = len;
549 true
550 }
551
552 #[inline]
554 pub fn header_count(&self) -> u8 {
555 self.header_count
556 }
557
558 #[inline]
560 pub fn get_header(&self, idx: usize) -> Option<&CanonicalHeader> {
561 if idx < self.header_count as usize {
562 Some(&self.headers[idx])
563 } else {
564 None
565 }
566 }
567
568 #[inline]
573 pub fn find_header(&self, name: &str) -> Option<&CanonicalHeader> {
574 let name_bytes = name.as_bytes();
575 for i in 0..self.header_count as usize {
576 let hdr = &self.headers[i];
577 if hdr.name_len as usize == name_bytes.len()
578 && hdr.name[..hdr.name_len as usize].eq_ignore_ascii_case(name_bytes)
579 {
580 return Some(hdr);
581 }
582 }
583 None
584 }
585
586 pub fn add_header(&mut self, name: &[u8], value: &[u8]) -> Result<(), &'static str> {
592 if self.header_count as usize >= MAX_HEADER_COUNT {
593 return Err("header count exceeded");
594 }
595 if name.len() > MAX_HEADER_NAME_LEN {
597 return Err("header name too long");
598 }
599 if value.len() > MAX_HEADER_VALUE_LEN {
600 return Err("header value too long");
601 }
602 if name.contains(&b'\r') || name.contains(&b'\n') {
604 return Err("header name contains CRLF");
605 }
606 if value.contains(&b'\r') || value.contains(&b'\n') {
607 return Err("header value contains CRLF");
608 }
609 let idx = self.header_count as usize;
610 self.headers[idx] = match CanonicalHeader::from_bytes(name, value) {
612 Some(hdr) => hdr,
613 None => return Err("header name or value too long"),
614 };
615 self.header_count += 1;
616 Ok(())
617 }
618
619 #[inline]
621 pub fn headers_iter(&self) -> &[CanonicalHeader] {
622 &self.headers[..self.header_count as usize]
623 }
624
625 #[inline]
627 pub fn cancel(&mut self) {
628 self.cancelled = true;
629 }
630
631 #[inline]
633 pub fn is_cancelled(&self) -> bool {
634 self.cancelled
635 }
636}
637
638#[derive(Debug, Clone)]
650pub struct CanonicalResponse {
651 pub status_code: u16,
653 headers: [CanonicalHeader; MAX_HEADER_COUNT],
655 header_count: u8,
657 body_buffer: [u8; MAX_BODY_LEN],
659 body_len: u32,
661 body_overflow: Option<Vec<u8>>,
663}
664
665impl CanonicalResponse {
666 #[inline]
668 pub const fn new(status_code: u16) -> Self {
669 Self {
670 status_code,
671 headers: [CanonicalHeader::empty(); MAX_HEADER_COUNT],
672 header_count: 0,
673 body_buffer: [0u8; MAX_BODY_LEN],
674 body_len: 0,
675 body_overflow: None,
676 }
677 }
678
679 #[inline]
681 pub const fn ok() -> Self {
682 Self::new(200)
683 }
684
685 #[inline]
687 pub const fn error(status_code: u16) -> Self {
688 Self::new(status_code)
689 }
690
691 #[inline]
694 pub fn reset(&mut self) {
695 for i in 0..self.header_count as usize {
697 self.headers[i].reset();
698 }
699 self.header_count = 0;
700 self.body_len = 0;
702 self.body_overflow = None;
703 }
704
705 #[inline]
707 pub fn header_count(&self) -> u8 {
708 self.header_count
709 }
710
711 pub fn add_header(&mut self, name: &[u8], value: &[u8]) -> Result<(), &'static str> {
716 if self.header_count as usize >= MAX_HEADER_COUNT {
717 return Err("header count exceeded");
718 }
719 if name.contains(&b'\r') || name.contains(&b'\n') {
721 return Err("header name contains CRLF");
722 }
723 if value.contains(&b'\r') || value.contains(&b'\n') {
724 return Err("header value contains CRLF");
725 }
726 let idx = self.header_count as usize;
727 self.headers[idx] = CanonicalHeader::from_bytes(name, value)
729 .ok_or("header name/value too long")?;
730 self.header_count += 1;
731 Ok(())
732 }
733
734 pub fn set_body(&mut self, body: impl Into<Vec<u8>>) {
740 let body = body.into();
741 if body.len() <= MAX_BODY_LEN {
742 self.body_overflow = None;
743 self.body_buffer[..body.len()].copy_from_slice(&body);
744 self.body_len = body.len() as u32;
745 } else {
746 self.body_overflow = Some(body);
747 self.body_len = self.body_overflow.as_ref().map(|v| v.len()).unwrap_or(0) as u32;
748 }
749 }
750
751 #[inline]
753 pub fn body(&self) -> &[u8] {
754 if let Some(ref overflow) = self.body_overflow {
755 overflow
756 } else {
757 &self.body_buffer[..self.body_len as usize]
758 }
759 }
760
761 #[inline]
763 pub fn headers_iter(&self) -> &[CanonicalHeader] {
764 &self.headers[..self.header_count as usize]
765 }
766
767 #[inline]
769 pub fn find_header(&self, name: &str) -> Option<&CanonicalHeader> {
770 let name_bytes = name.as_bytes();
771 for i in 0..self.header_count as usize {
772 let hdr = &self.headers[i];
773 if hdr.name_len as usize == name_bytes.len()
774 && hdr.name[..hdr.name_len as usize].eq_ignore_ascii_case(name_bytes)
775 {
776 return Some(hdr);
777 }
778 }
779 None
780 }
781}
782
783impl Default for CanonicalRequest {
784 #[inline]
785 fn default() -> Self {
786 Self::empty()
787 }
788}
789
790impl Default for CanonicalResponse {
791 #[inline]
792 fn default() -> Self {
793 Self::new(200)
794 }
795}
796
797pub trait Service: Send + Sync + 'static {
803 fn handle(&self, request: CanonicalRequest) -> CanonicalResponse;
805}
806
807pub trait ServiceFactory: Send + Sync + 'static {
809 fn create(&self) -> Box<dyn Service>;
811}
812
813#[cfg(test)]
818mod tests {
819 use super::*;
820
821 #[test]
822 fn test_method_from_str() {
823 use std::str::FromStr;
824 assert_eq!(Method::from_str("GET"), Ok(Method::Get));
825 assert_eq!(Method::from_str("POST"), Ok(Method::Post));
826 assert!(Method::from_str("post").is_err());
828 assert!(Method::from_str("Get").is_err());
829 assert!(Method::from_str("INVALID").is_err());
830 }
831
832 #[test]
833 fn test_method_as_str() {
834 assert_eq!(Method::Get.as_str(), "GET");
835 assert_eq!(Method::Post.as_str(), "POST");
836 }
837
838 #[test]
839 fn test_canonical_header_creation() {
840 let hdr = CanonicalHeader::from_bytes(b"content-type", b"application/json").unwrap();
841 assert_eq!(hdr.name_str(), "content-type");
842 assert_eq!(hdr.value_str(), "application/json");
843 assert_eq!(hdr.name_len, 12);
844 assert_eq!(hdr.value_len, 16);
845 }
846
847 #[test]
848 fn test_canonical_header_overlong_rejected() {
849 let long_name = b"this-is-a-very-long-header-name-that-should-exceed-the-maximum-sixty-four-bytes-limit-and-test-truncation";
851 assert!(long_name.len() > MAX_HEADER_NAME_LEN);
852 assert!(CanonicalHeader::from_bytes(long_name, b"value").is_none());
853
854 let exact_name = vec![b'n'; MAX_HEADER_NAME_LEN];
856 let hdr = CanonicalHeader::from_bytes(&exact_name, b"value").unwrap();
857 assert_eq!(hdr.name_len, MAX_HEADER_NAME_LEN as u8);
858 }
859
860 #[test]
861 fn test_canonical_request_creation() {
862 let mut request = CanonicalRequest::empty();
863 request.method = Method::Get;
864 assert!(request.set_scheme("https"));
865 assert!(request.set_authority("example.com"));
866 assert!(request.set_path("/api/test"));
867 assert!(request.set_query("key=value"));
868 request.protocol = Protocol::Http1;
869 request.transport = Transport::Tls13;
870
871 assert_eq!(request.method, Method::Get);
872 assert_eq!(request.scheme_str(), "https");
873 assert_eq!(request.authority_str(), "example.com");
874 assert_eq!(request.path_str(), "/api/test");
875 assert_eq!(request.query_str(), "key=value");
876 }
877
878 #[test]
879 fn test_canonical_request_headers() {
880 let mut request = CanonicalRequest::empty();
881 request
882 .add_header(b"content-type", b"application/json")
883 .unwrap();
884 request
885 .add_header(b"accept", b"text/html")
886 .unwrap();
887
888 assert_eq!(request.header_count(), 2);
889 assert!(request.find_header("content-type").is_some());
890 assert!(request.find_header("non-existent").is_none());
891
892 let hdr = request.find_header("accept").unwrap();
893 assert_eq!(hdr.value_str(), "text/html");
894 }
895
896 #[test]
897 fn test_canonical_request_header_limit() {
898 let mut request = CanonicalRequest::empty();
899 for i in 0..MAX_HEADER_COUNT {
900 let name = format!("header-{}", i);
901 request.add_header(name.as_bytes(), b"value").unwrap();
902 }
903 assert_eq!(request.header_count(), MAX_HEADER_COUNT as u8);
904
905 let result = request.add_header(b"overflow", b"value");
907 assert!(result.is_err());
908 }
909
910 #[test]
911 fn test_body_stream() {
912 let data = b"test body data";
913 let mut stream = BodyStream::new(data);
914
915 assert!(!stream.is_consumed());
916 assert_eq!(stream.len(), 14);
917 assert!(!stream.is_empty());
918
919 let result = stream.get_data();
920 assert_eq!(result, Some(&data[..]));
921 assert!(stream.is_consumed());
922
923 let result2 = stream.get_data();
925 assert!(result2.is_none());
926 }
927
928 #[test]
929 fn test_body_stream_empty() {
930 let mut stream = BodyStream::new(b"");
931 assert!(stream.is_empty());
932 let result = stream.get_data();
933 assert!(result.is_none());
934 }
935
936 #[test]
937 fn test_governance_fields() {
938 let mut request = CanonicalRequest::empty();
939 request.generation = 42;
940 request.deadline_ms = 5000;
941 request.resource_lease = 100;
942
943 assert_eq!(request.generation, 42);
944 assert_eq!(request.deadline_ms, 5000);
945
946 request.cancel();
947 assert!(request.is_cancelled());
948 }
949
950 #[test]
951 fn test_canonical_response() {
952 let mut response = CanonicalResponse::new(200);
953 assert_eq!(response.status_code, 200);
954
955 response
956 .add_header(b"content-type", b"text/plain")
957 .unwrap();
958 assert_eq!(response.header_count(), 1);
959
960 response.set_body(b"Hello".to_vec());
961 assert_eq!(response.body(), b"Hello");
962 }
963
964 #[test]
965 fn test_canonical_response_helpers() {
966 let ok = CanonicalResponse::ok();
967 assert_eq!(ok.status_code, 200);
968
969 let error = CanonicalResponse::error(404);
970 assert_eq!(error.status_code, 404);
971 }
972
973 #[test]
974 fn test_request_copy_semantics() {
975 let mut request = CanonicalRequest::empty();
976 request.method = Method::Post;
977 assert!(request.set_path("/test"));
978 request.generation = 1;
979
980 let cloned = request.clone();
982 assert_eq!(cloned.method, Method::Post);
983 assert_eq!(cloned.path_str(), "/test");
984 assert_eq!(cloned.generation, 1);
985
986 request.method = Method::Get;
988 assert_ne!(request.method, cloned.method);
989 }
990
991 #[test]
996 fn test_method_all_variants_as_str() {
997 assert_eq!(Method::Get.as_str(), "GET");
998 assert_eq!(Method::Post.as_str(), "POST");
999 assert_eq!(Method::Put.as_str(), "PUT");
1000 assert_eq!(Method::Delete.as_str(), "DELETE");
1001 assert_eq!(Method::Patch.as_str(), "PATCH");
1002 assert_eq!(Method::Head.as_str(), "HEAD");
1003 assert_eq!(Method::Options.as_str(), "OPTIONS");
1004 assert_eq!(Method::Connect.as_str(), "CONNECT");
1005 assert_eq!(Method::Trace.as_str(), "TRACE");
1006 }
1007
1008 #[test]
1009 fn test_method_from_str_all_variants() {
1010 use std::str::FromStr;
1011 assert_eq!(Method::from_str("GET"), Ok(Method::Get));
1012 assert_eq!(Method::from_str("POST"), Ok(Method::Post));
1013 assert_eq!(Method::from_str("PUT"), Ok(Method::Put));
1014 assert_eq!(Method::from_str("DELETE"), Ok(Method::Delete));
1015 assert_eq!(Method::from_str("PATCH"), Ok(Method::Patch));
1016 assert_eq!(Method::from_str("HEAD"), Ok(Method::Head));
1017 assert_eq!(Method::from_str("OPTIONS"), Ok(Method::Options));
1018 assert_eq!(Method::from_str("CONNECT"), Ok(Method::Connect));
1019 assert_eq!(Method::from_str("TRACE"), Ok(Method::Trace));
1020 }
1021
1022 #[test]
1023 fn test_method_from_str_case_sensitive_strict() {
1024 use std::str::FromStr;
1027 assert!(Method::from_str("get").is_err());
1028 assert!(Method::from_str("Get").is_err());
1029 assert!(Method::from_str("gEt").is_err());
1030 assert!(Method::from_str("post").is_err());
1031 assert!(Method::from_str("Post").is_err());
1032 assert!(Method::from_str("delete").is_err());
1033 assert!(Method::from_str(" GET").is_err());
1034 assert!(Method::from_str("GET ").is_err());
1035 }
1036
1037 #[test]
1038 fn test_method_from_str_invalid() {
1039 use std::str::FromStr;
1040 assert!(Method::from_str("").is_err());
1041 assert!(Method::from_str("UNKNOWN").is_err());
1042 assert!(Method::from_str("GET ").is_err());
1043 assert!(Method::from_str(" GET").is_err());
1044 assert!(Method::from_str("123").is_err());
1045 }
1046
1047 #[test]
1048 fn test_method_parse_error_display() {
1049 use std::str::FromStr;
1050 let err = Method::from_str("INVALID").unwrap_err();
1051 assert_eq!(format!("{}", err), "invalid HTTP method");
1052 assert!(format!("{:?}", err).contains("MethodParseError"));
1053 }
1054
1055 #[test]
1060 fn test_protocol_variants() {
1061 let protocols = [
1062 Protocol::Http1,
1063 Protocol::Http2,
1064 Protocol::Http3,
1065 Protocol::Tcp,
1066 Protocol::Udp,
1067 Protocol::Quic,
1068 ];
1069 for (i, p) in protocols.iter().enumerate() {
1070 for (j, q) in protocols.iter().enumerate() {
1071 if i == j {
1072 assert_eq!(p, q);
1073 } else {
1074 assert_ne!(p, q);
1075 }
1076 }
1077 }
1078 }
1079
1080 #[test]
1081 fn test_transport_variants() {
1082 assert_eq!(Transport::Plaintext, Transport::Plaintext);
1083 assert_eq!(Transport::Tls13, Transport::Tls13);
1084 assert_ne!(Transport::Plaintext, Transport::Tls13);
1085 }
1086
1087 #[test]
1092 fn test_canonical_header_empty() {
1093 let hdr = CanonicalHeader::empty();
1094 assert!(hdr.is_empty());
1095 assert_eq!(hdr.name_len, 0);
1096 assert_eq!(hdr.value_len, 0);
1097 assert_eq!(hdr.name_str(), "");
1098 assert_eq!(hdr.value_str(), "");
1099 }
1100
1101 #[test]
1102 fn test_canonical_header_value_overlong_rejected() {
1103 let long_value = vec![b'x'; MAX_HEADER_VALUE_LEN + 100];
1105 assert!(CanonicalHeader::from_bytes(b"name", &long_value).is_none());
1106
1107 let exact_value = vec![b'x'; MAX_HEADER_VALUE_LEN];
1109 let hdr = CanonicalHeader::from_bytes(b"name", &exact_value).unwrap();
1110 assert_eq!(hdr.value_len, MAX_HEADER_VALUE_LEN as u16);
1111 assert_eq!(hdr.value_str().len(), MAX_HEADER_VALUE_LEN);
1112 }
1113
1114 #[test]
1115 fn test_canonical_header_zero_length() {
1116 let hdr = CanonicalHeader::from_bytes(b"", b"").unwrap();
1117 assert!(hdr.is_empty());
1118 assert_eq!(hdr.name_str(), "");
1119 assert_eq!(hdr.value_str(), "");
1120 }
1121
1122 #[test]
1123 fn test_canonical_header_invalid_utf8() {
1124 let invalid_utf8 = [0xFF, 0xFE, 0xFD];
1125 let hdr = CanonicalHeader::from_bytes(&invalid_utf8, b"value").unwrap();
1126 assert_eq!(hdr.name_str(), "");
1128 }
1129
1130 #[test]
1135 fn test_canonical_request_full_fields() {
1136 let mut req = CanonicalRequest::empty();
1137 req.method = Method::Put;
1138 assert!(req.set_scheme("https"));
1139 assert!(req.set_authority("api.example.com:8443"));
1140 assert!(req.set_path("/api/v1/users/42"));
1141 assert!(req.set_query("id=42&name=test&verbose=true"));
1142 req.protocol = Protocol::Http2;
1143 req.transport = Transport::Tls13;
1144 req.generation = 12345;
1145 req.deadline_ms = 30000;
1146 req.cancelled = false;
1147 req.resource_lease = 999;
1148
1149 assert_eq!(req.method, Method::Put);
1150 assert_eq!(req.scheme_str(), "https");
1151 assert_eq!(req.authority_str(), "api.example.com:8443");
1152 assert_eq!(req.path_str(), "/api/v1/users/42");
1153 assert_eq!(req.query_str(), "id=42&name=test&verbose=true");
1154 assert_eq!(req.protocol, Protocol::Http2);
1155 assert_eq!(req.transport, Transport::Tls13);
1156 assert_eq!(req.generation, 12345);
1157 assert_eq!(req.deadline_ms, 30000);
1158 assert!(!req.is_cancelled());
1159 assert_eq!(req.resource_lease, 999);
1160 }
1161
1162 #[test]
1163 fn test_canonical_request_scheme_overlong_rejected() {
1164 let mut req = CanonicalRequest::empty();
1166 assert!(req.set_scheme("https"));
1167 assert!(!req.set_scheme("https-and-more"));
1168 assert_eq!(req.scheme_str(), "https");
1170
1171 let mut req2 = CanonicalRequest::empty();
1173 assert!(req2.set_scheme("12345678"));
1174 assert_eq!(req2.scheme_str(), "12345678");
1175 }
1176
1177 #[test]
1178 fn test_canonical_request_path_overlong_rejected() {
1179 let mut req = CanonicalRequest::empty();
1181 assert!(req.set_path("/original"));
1182 let long_path = "a".repeat(MAX_PATH_LEN + 100);
1183 assert!(!req.set_path(&long_path));
1184 assert_eq!(req.path_str(), "/original");
1185
1186 let exact_path = "a".repeat(MAX_PATH_LEN);
1188 assert!(req.set_path(&exact_path));
1189 assert_eq!(req.path_str().len(), MAX_PATH_LEN);
1190 }
1191
1192 #[test]
1193 fn test_set_path_splits_query() {
1194 let mut req = CanonicalRequest::empty();
1195 assert!(req.set_path("/api/users?id=42&verbose=true"));
1198 assert_eq!(req.path_str(), "/api/users");
1199 assert_eq!(req.query_str(), "id=42&verbose=true");
1200
1201 let mut req2 = CanonicalRequest::empty();
1203 assert!(req2.set_query("keep=1"));
1204 assert!(req2.set_path("/plain/path"));
1205 assert_eq!(req2.path_str(), "/plain/path");
1206 assert_eq!(req2.query_str(), "keep=1");
1207
1208 let mut req3 = CanonicalRequest::empty();
1210 assert!(req3.set_path("/api?"));
1211 assert_eq!(req3.path_str(), "/api");
1212 assert_eq!(req3.query_str(), "");
1213 }
1214
1215 #[test]
1216 fn test_set_path_overlong_split_query_atomic_rejected() {
1217 let mut req = CanonicalRequest::empty();
1219 assert!(req.set_query("keep=1"));
1220 let long_target = format!("/ok?{}", "a".repeat(MAX_QUERY_LEN + 1));
1221 assert!(!req.set_path(&long_target));
1222 assert_eq!(req.path_str(), "");
1223 assert_eq!(req.query_str(), "keep=1");
1224 }
1225
1226 #[test]
1227 fn test_add_header_overlong_rejected() {
1228 let mut req = CanonicalRequest::empty();
1229
1230 let long_name = vec![b'n'; MAX_HEADER_NAME_LEN + 1];
1232 let result = req.add_header(&long_name, b"value");
1233 assert_eq!(result, Err("header name too long"));
1234
1235 let long_value = vec![b'v'; MAX_HEADER_VALUE_LEN + 1];
1237 let result = req.add_header(b"name", &long_value);
1238 assert_eq!(result, Err("header value too long"));
1239
1240 assert_eq!(req.header_count(), 0);
1242
1243 let exact_name = vec![b'n'; MAX_HEADER_NAME_LEN];
1245 let exact_value = vec![b'v'; MAX_HEADER_VALUE_LEN];
1246 assert!(req.add_header(&exact_name, &exact_value).is_ok());
1247 assert_eq!(req.header_count(), 1);
1248 }
1249
1250 #[test]
1251 fn test_response_add_header_overlong_rejected() {
1252 let mut resp = CanonicalResponse::new(200);
1253
1254 let long_name = vec![b'n'; MAX_HEADER_NAME_LEN + 1];
1255 assert!(resp.add_header(&long_name, b"value").is_err());
1256
1257 let long_value = vec![b'v'; MAX_HEADER_VALUE_LEN + 1];
1258 assert!(resp.add_header(b"name", &long_value).is_err());
1259
1260 assert_eq!(resp.header_count(), 0);
1261 }
1262
1263 #[test]
1264 fn test_canonical_request_query_overlong_rejected() {
1265 let mut req = CanonicalRequest::empty();
1267 assert!(req.set_query("keep=1"));
1268 let long_query = "a".repeat(MAX_QUERY_LEN + 100);
1269 assert!(!req.set_query(&long_query));
1270 assert_eq!(req.query_str(), "keep=1");
1271
1272 let exact_query = "a".repeat(MAX_QUERY_LEN);
1274 assert!(req.set_query(&exact_query));
1275 assert_eq!(req.query_str().len(), MAX_QUERY_LEN);
1276 }
1277
1278 #[test]
1279 fn test_canonical_request_authority_overlong_rejected() {
1280 let mut req = CanonicalRequest::empty();
1282 assert!(req.set_authority("example.com"));
1283 let long_auth = "a".repeat(MAX_AUTHORITY_LEN + 100);
1284 assert!(!req.set_authority(&long_auth));
1285 assert_eq!(req.authority_str(), "example.com");
1286
1287 let exact_auth = "a".repeat(MAX_AUTHORITY_LEN);
1289 assert!(req.set_authority(&exact_auth));
1290 assert_eq!(req.authority_str().len(), MAX_AUTHORITY_LEN);
1291 }
1292
1293 #[test]
1294 fn test_canonical_request_empty_strings() {
1295 let mut req = CanonicalRequest::empty();
1296 assert!(req.set_scheme(""));
1297 assert!(req.set_authority(""));
1298 assert!(req.set_path(""));
1299 assert!(req.set_query(""));
1300
1301 assert_eq!(req.scheme_str(), "");
1302 assert_eq!(req.authority_str(), "");
1303 assert_eq!(req.path_str(), "");
1304 assert_eq!(req.query_str(), "");
1305 }
1306
1307 #[test]
1312 fn test_canonical_request_get_header_boundary() {
1313 let mut req = CanonicalRequest::empty();
1314 req.add_header(b"h1", b"v1").unwrap();
1315 req.add_header(b"h2", b"v2").unwrap();
1316
1317 assert!(req.get_header(0).is_some());
1318 assert!(req.get_header(1).is_some());
1319 assert!(req.get_header(2).is_none());
1320 assert!(req.get_header(100).is_none());
1321 }
1322
1323 #[test]
1324 fn test_canonical_request_find_header_case_insensitive() {
1325 let mut req = CanonicalRequest::empty();
1326 req.add_header(b"Content-Type", b"application/json").unwrap();
1327
1328 assert!(req.find_header("Content-Type").is_some());
1330 assert!(req.find_header("content-type").is_some());
1331 assert!(req.find_header("CONTENT-TYPE").is_some());
1332 assert!(req.find_header("cOnTeNt-tYpE").is_some());
1333 assert!(req.find_header("content-length").is_none());
1335 }
1336
1337 #[test]
1338 fn test_canonical_request_headers_iter() {
1339 let mut req = CanonicalRequest::empty();
1340 req.add_header(b"a", b"1").unwrap();
1341 req.add_header(b"b", b"2").unwrap();
1342 req.add_header(b"c", b"3").unwrap();
1343
1344 let headers = req.headers_iter();
1345 assert_eq!(headers.len(), 3);
1346 assert_eq!(headers[0].name_str(), "a");
1347 assert_eq!(headers[1].name_str(), "b");
1348 assert_eq!(headers[2].name_str(), "c");
1349 }
1350
1351 #[test]
1352 fn test_canonical_request_headers_iter_empty() {
1353 let req = CanonicalRequest::empty();
1354 assert!(req.headers_iter().is_empty());
1355 }
1356
1357 #[test]
1362 fn test_canonical_request_cancel() {
1363 let mut req = CanonicalRequest::empty();
1364 assert!(!req.is_cancelled());
1365 req.cancel();
1366 assert!(req.is_cancelled());
1367 req.cancel();
1369 assert!(req.is_cancelled());
1370 }
1371
1372 #[test]
1373 fn test_canonical_request_deadline_zero() {
1374 let mut req = CanonicalRequest::empty();
1375 assert_eq!(req.deadline_ms, 0);
1376 req.deadline_ms = 0;
1377 assert_eq!(req.deadline_ms, 0);
1378 }
1379
1380 #[test]
1381 fn test_canonical_request_resource_lease() {
1382 let mut req = CanonicalRequest::empty();
1383 assert_eq!(req.resource_lease, 0);
1384 req.resource_lease = u64::MAX;
1385 assert_eq!(req.resource_lease, u64::MAX);
1386 }
1387
1388 #[test]
1393 fn test_body_stream_single_use() {
1394 let data = b"hello";
1395 let mut stream = BodyStream::new(data);
1396 assert_eq!(stream.get_data(), Some(&data[..]));
1397 assert!(stream.is_consumed());
1398 assert!(stream.get_data().is_none());
1399 assert!(stream.get_data().is_none());
1400 }
1401
1402 #[test]
1403 fn test_body_stream_len_unchanged_after_consume() {
1404 let data = b"test data";
1405 let mut stream = BodyStream::new(data);
1406 assert_eq!(stream.len(), 9);
1407 let _ = stream.get_data();
1408 assert_eq!(stream.len(), 9);
1409 }
1410
1411 #[test]
1412 fn test_body_stream_empty_data_never_consumable() {
1413 let mut stream = BodyStream::new(b"");
1414 assert!(stream.is_empty());
1415 assert!(!stream.is_consumed());
1416 assert!(stream.get_data().is_none());
1418 assert!(!stream.is_consumed());
1420 }
1421
1422 #[test]
1423 fn test_body_stream_large_data() {
1424 let large_data = vec![b'x'; 10000];
1425 let mut stream = BodyStream::new(&large_data);
1426 assert_eq!(stream.len(), 10000);
1427 assert!(!stream.is_empty());
1428 let result = stream.get_data().unwrap();
1429 assert_eq!(result.len(), 10000);
1430 }
1431
1432 #[test]
1437 fn test_canonical_response_full_fields() {
1438 let mut resp = CanonicalResponse::new(418);
1439 resp.add_header(b"content-type", b"text/plain").unwrap();
1440 resp.add_header(b"x-custom", b"value").unwrap();
1441 resp.set_body(b"I'm a teapot".to_vec());
1442
1443 assert_eq!(resp.status_code, 418);
1444 assert_eq!(resp.header_count(), 2);
1445 assert_eq!(resp.body(), b"I'm a teapot");
1446 }
1447
1448 #[test]
1449 fn test_canonical_response_header_limit() {
1450 let mut resp = CanonicalResponse::new(200);
1451 for i in 0..MAX_HEADER_COUNT {
1452 let name = format!("h{}", i);
1453 resp.add_header(name.as_bytes(), b"v").unwrap();
1454 }
1455 assert_eq!(resp.header_count(), MAX_HEADER_COUNT as u8);
1456 assert!(resp.add_header(b"overflow", b"v").is_err());
1457 }
1458
1459 #[test]
1460 fn test_canonical_response_find_header() {
1461 let mut resp = CanonicalResponse::new(200);
1462 resp.add_header(b"Server", b"zenith").unwrap();
1463 resp.add_header(b"Date", b"today").unwrap();
1464
1465 assert!(resp.find_header("Server").is_some());
1466 assert!(resp.find_header("Date").is_some());
1467 assert!(resp.find_header("server").is_some());
1469 assert!(resp.find_header("DATE").is_some());
1470 assert!(resp.find_header("X-Missing").is_none());
1471 }
1472
1473 #[test]
1474 fn test_canonical_response_headers_iter() {
1475 let mut resp = CanonicalResponse::new(200);
1476 resp.add_header(b"a", b"1").unwrap();
1477 resp.add_header(b"b", b"2").unwrap();
1478
1479 let headers = resp.headers_iter();
1480 assert_eq!(headers.len(), 2);
1481 }
1482
1483 #[test]
1484 fn test_canonical_response_body_empty() {
1485 let resp = CanonicalResponse::new(204);
1486 assert!(resp.body().is_empty());
1487 }
1488
1489 #[test]
1490 fn test_canonical_response_body_replace() {
1491 let mut resp = CanonicalResponse::new(200);
1492 resp.set_body(b"first".to_vec());
1493 assert_eq!(resp.body(), b"first");
1494 resp.set_body(b"second".to_vec());
1495 assert_eq!(resp.body(), b"second");
1496 }
1497
1498 struct EchoService;
1503
1504 impl Service for EchoService {
1505 fn handle(&self, request: CanonicalRequest) -> CanonicalResponse {
1506 let mut resp = CanonicalResponse::ok();
1507 resp.set_body(request.path_str().as_bytes().to_vec());
1508 resp
1509 }
1510 }
1511
1512 struct EchoServiceFactory;
1513
1514 impl ServiceFactory for EchoServiceFactory {
1515 fn create(&self) -> Box<dyn Service> {
1516 Box::new(EchoService)
1517 }
1518 }
1519
1520 #[test]
1521 fn test_service_trait_object() {
1522 let service: Box<dyn Service> = Box::new(EchoService);
1523 let mut req = CanonicalRequest::empty();
1524 assert!(req.set_path("/hello"));
1525 let resp = service.handle(req);
1526 assert_eq!(resp.status_code, 200);
1527 assert_eq!(resp.body(), b"/hello");
1528 }
1529
1530 #[test]
1531 fn test_service_factory_trait() {
1532 let factory = EchoServiceFactory;
1533 let service = factory.create();
1534 let mut req = CanonicalRequest::empty();
1535 assert!(req.set_path("/test"));
1536 let resp = service.handle(req);
1537 assert_eq!(resp.body(), b"/test");
1538 }
1539
1540 #[test]
1545 fn test_add_header_rejects_crlf() {
1546 let mut req = CanonicalRequest::empty();
1547
1548 assert_eq!(
1550 req.add_header(b"bad\rname", b"v"),
1551 Err("header name contains CRLF")
1552 );
1553 assert_eq!(
1554 req.add_header(b"bad\nname", b"v"),
1555 Err("header name contains CRLF")
1556 );
1557 assert_eq!(
1558 req.add_header(b"bad\r\nname", b"v"),
1559 Err("header name contains CRLF")
1560 );
1561
1562 assert_eq!(
1564 req.add_header(b"name", b"bad\rvalue"),
1565 Err("header value contains CRLF")
1566 );
1567 assert_eq!(
1568 req.add_header(b"name", b"bad\nvalue"),
1569 Err("header value contains CRLF")
1570 );
1571 assert!(req.add_header(b"name", b"ok\r\nEvil: x").is_err());
1573
1574 assert_eq!(req.header_count(), 0);
1576
1577 let mut resp = CanonicalResponse::new(200);
1579 assert_eq!(
1580 resp.add_header(b"bad\rname", b"v"),
1581 Err("header name contains CRLF")
1582 );
1583 assert_eq!(
1584 resp.add_header(b"name", b"bad\nvalue"),
1585 Err("header value contains CRLF")
1586 );
1587 assert_eq!(resp.header_count(), 0);
1588 }
1589
1590 #[test]
1595 fn test_request_set_body_overflow_heap_path() {
1596 let mut req = CanonicalRequest::empty();
1597
1598 let big = vec![b'x'; 5000];
1600 assert!(big.len() > MAX_BODY_LEN);
1601 req.set_body(big.clone());
1602 assert!(req.body_overflow.is_some());
1604 assert_eq!(req.body().len(), 5000);
1605 assert_eq!(req.body(), &big[..]);
1606
1607 req.set_body(b"small".to_vec());
1609 assert!(req.body_overflow.is_none());
1610 assert_eq!(req.body(), b"small");
1611 }
1612}