1use crate::body::RequestBody;
4use crate::extensions::Extensions;
5use bytes::Bytes;
6use serde::{Deserialize, Serialize};
7use std::collections::HashMap;
8use std::sync::Arc;
9
10#[derive(Debug, Clone)]
15pub struct HttpRequest {
16 pub method: String,
17 pub path: String,
18 pub headers: HashMap<String, String>,
19 pub body: Vec<u8>,
24 pub path_params: HashMap<String, String>,
25 pub query_params: HashMap<String, String>,
26 pub extensions: Extensions,
31 body_bytes: Option<Bytes>,
34}
35
36impl HttpRequest {
37 pub fn new(method: String, path: String) -> Self {
38 Self {
39 method,
40 path,
41 headers: HashMap::new(),
42 body: Vec::new(),
43 path_params: HashMap::new(),
44 query_params: HashMap::new(),
45 extensions: Extensions::new(),
46 body_bytes: None,
47 }
48 }
49
50 #[inline]
52 pub fn with_extensions_capacity(method: String, path: String, capacity: usize) -> Self {
53 Self {
54 method,
55 path,
56 headers: HashMap::new(),
57 body: Vec::new(),
58 path_params: HashMap::new(),
59 query_params: HashMap::new(),
60 extensions: Extensions::with_capacity(capacity),
61 body_bytes: None,
62 }
63 }
64
65 #[inline]
70 pub fn with_bytes_body(method: String, path: String, body: Bytes) -> Self {
71 Self {
72 method,
73 path,
74 headers: HashMap::new(),
75 body: Vec::new(), path_params: HashMap::new(),
77 query_params: HashMap::new(),
78 extensions: Extensions::new(),
79 body_bytes: Some(body),
80 }
81 }
82
83 #[inline]
87 pub fn set_body_bytes(&mut self, bytes: Bytes) {
88 self.body_bytes = Some(bytes);
89 self.body.clear(); }
91
92 #[inline]
98 pub fn body_bytes(&self) -> Bytes {
99 if let Some(ref bytes) = self.body_bytes {
100 bytes.clone() } else {
102 Bytes::copy_from_slice(&self.body)
103 }
104 }
105
106 #[inline]
110 pub fn body_ref(&self) -> &[u8] {
111 if let Some(ref bytes) = self.body_bytes {
112 bytes.as_ref()
113 } else {
114 &self.body
115 }
116 }
117
118 #[inline]
120 pub fn request_body(&self) -> RequestBody {
121 RequestBody::from_bytes(self.body_bytes())
122 }
123
124 #[inline]
126 pub fn has_bytes_body(&self) -> bool {
127 self.body_bytes.is_some()
128 }
129
130 #[inline]
132 pub fn set_body(&mut self, body: Vec<u8>) {
133 self.body = body;
134 self.body_bytes = None;
135 }
136
137 #[inline]
139 pub fn from_parts(
140 method: String,
141 path: String,
142 headers: HashMap<String, String>,
143 body: Vec<u8>,
144 path_params: HashMap<String, String>,
145 query_params: HashMap<String, String>,
146 ) -> Self {
147 Self {
148 method,
149 path,
150 headers,
151 body,
152 path_params,
153 query_params,
154 extensions: Extensions::new(),
155 body_bytes: None,
156 }
157 }
158
159 #[inline]
170 pub fn insert_extension<T: Send + Sync + 'static>(&mut self, value: T) {
171 self.extensions.insert(value);
172 }
173
174 #[inline]
178 pub fn insert_extension_arc<T: Send + Sync + 'static>(&mut self, value: Arc<T>) {
179 self.extensions.insert_arc(value);
180 }
181
182 #[inline]
186 pub fn extension<T: Send + Sync + 'static>(&self) -> Option<&T> {
187 self.extensions.get::<T>()
188 }
189
190 #[inline]
192 pub fn extension_arc<T: Send + Sync + 'static>(&self) -> Option<Arc<T>> {
193 self.extensions.get_arc::<T>()
194 }
195
196 #[inline]
207 pub fn json<T: for<'de> Deserialize<'de>>(&self) -> Result<T, crate::Error> {
208 crate::json::from_slice(self.body_ref())
209 .map_err(|e| crate::Error::Deserialization(e.to_string()))
210 }
211
212 pub fn form<T: for<'de> Deserialize<'de>>(&self) -> Result<T, crate::Error> {
214 crate::form::parse_form(self.body_ref())
215 }
216
217 pub fn form_map(&self) -> Result<HashMap<String, String>, crate::Error> {
219 crate::form::parse_form_map(self.body_ref())
220 }
221
222 pub fn multipart(&self) -> Result<Vec<crate::form::FormField>, crate::Error> {
224 let content_type = self
225 .headers
226 .get("Content-Type")
227 .or_else(|| self.headers.get("content-type"))
228 .ok_or_else(|| crate::Error::BadRequest("Missing Content-Type header".to_string()))?;
229
230 let parser = crate::form::MultipartParser::from_content_type(content_type)?;
231 parser.parse(self.body_ref())
232 }
233
234 pub fn param(&self, name: &str) -> Option<&String> {
236 self.path_params.get(name)
237 }
238
239 pub fn query(&self, name: &str) -> Option<&String> {
241 self.query_params.get(name)
242 }
243}
244
245#[derive(Debug, Clone, Default)]
250pub struct LazyHeaders {
251 inner: Option<HashMap<String, String>>,
252}
253
254impl LazyHeaders {
255 #[inline(always)]
257 pub const fn new() -> Self {
258 Self { inner: None }
259 }
260
261 #[inline]
263 pub fn with_capacity(cap: usize) -> Self {
264 Self {
265 inner: Some(HashMap::with_capacity(cap)),
266 }
267 }
268
269 #[inline]
271 pub fn insert(&mut self, key: String, value: String) -> Option<String> {
272 self.inner
273 .get_or_insert_with(HashMap::new)
274 .insert(key, value)
275 }
276
277 #[inline]
279 pub fn get(&self, key: &str) -> Option<&String> {
280 self.inner.as_ref()?.get(key)
281 }
282
283 #[inline]
285 pub fn contains_key(&self, key: &str) -> bool {
286 self.inner.as_ref().is_some_and(|m| m.contains_key(key))
287 }
288
289 #[inline]
291 pub fn len(&self) -> usize {
292 self.inner.as_ref().map_or(0, |m| m.len())
293 }
294
295 #[inline]
297 pub fn is_empty(&self) -> bool {
298 self.inner.as_ref().is_none_or(|m| m.is_empty())
299 }
300
301 #[inline]
303 pub fn iter(&self) -> impl Iterator<Item = (&String, &String)> {
304 self.inner.iter().flat_map(|m| m.iter())
305 }
306
307 #[inline]
309 pub fn to_hashmap(&self) -> HashMap<String, String> {
310 self.inner.clone().unwrap_or_default()
311 }
312
313 #[inline]
315 pub fn remove(&mut self, key: &str) -> Option<String> {
316 self.inner.as_mut()?.remove(key)
317 }
318
319 #[inline]
321 pub fn entry(&mut self, key: String) -> std::collections::hash_map::Entry<'_, String, String> {
322 self.inner.get_or_insert_with(HashMap::new).entry(key)
323 }
324
325 #[inline]
327 pub fn extend<I: IntoIterator<Item = (String, String)>>(&mut self, iter: I) {
328 let map = self.inner.get_or_insert_with(HashMap::new);
329 map.extend(iter);
330 }
331
332 #[inline]
334 pub fn clear(&mut self) {
335 if let Some(ref mut map) = self.inner {
336 map.clear();
337 }
338 }
339
340 #[inline]
342 pub fn clone_inner(&self) -> Option<HashMap<String, String>> {
343 self.inner.clone()
344 }
345}
346
347impl From<HashMap<String, String>> for LazyHeaders {
348 #[inline]
349 fn from(map: HashMap<String, String>) -> Self {
350 Self { inner: Some(map) }
351 }
352}
353
354impl From<LazyHeaders> for HashMap<String, String> {
355 #[inline]
356 fn from(lazy: LazyHeaders) -> Self {
357 lazy.inner.unwrap_or_default()
358 }
359}
360
361impl<'a> IntoIterator for &'a LazyHeaders {
363 type Item = (&'a String, &'a String);
364 type IntoIter = std::iter::Flatten<std::option::Iter<'a, HashMap<String, String>>>;
365
366 fn into_iter(self) -> Self::IntoIter {
367 self.inner.iter().flatten()
368 }
369}
370
371#[derive(Debug)]
383pub struct HttpResponse {
384 pub status: u16,
385 pub headers: LazyHeaders,
387 pub body: Vec<u8>,
389 body_bytes: Option<Bytes>,
392}
393
394pub const DEFAULT_RESPONSE_CAPACITY: usize = 512;
396
397impl HttpResponse {
398 #[inline(always)]
404 pub fn new(status: u16) -> Self {
405 Self {
406 status,
407 headers: LazyHeaders::new(),
408 body: Vec::new(),
409 body_bytes: None,
410 }
411 }
412
413 #[inline]
425 pub fn with_capacity(status: u16, capacity: usize) -> Self {
426 Self {
427 status,
428 headers: LazyHeaders::with_capacity(8),
429 body: Vec::with_capacity(capacity),
430 body_bytes: None,
431 }
432 }
433
434 #[inline(always)]
436 pub fn ok() -> Self {
437 Self::new(200)
438 }
439
440 #[inline]
442 pub fn ok_preallocated() -> Self {
443 Self::with_capacity(200, DEFAULT_RESPONSE_CAPACITY)
444 }
445
446 #[inline(always)]
448 pub fn created() -> Self {
449 Self::new(201)
450 }
451
452 #[inline(always)]
454 pub fn no_content() -> Self {
455 Self::new(204)
456 }
457
458 #[inline(always)]
460 pub fn bad_request() -> Self {
461 Self::new(400)
462 }
463
464 #[inline(always)]
466 pub fn not_found() -> Self {
467 Self::new(404)
468 }
469
470 #[inline(always)]
472 pub fn internal_server_error() -> Self {
473 Self::new(500)
474 }
475
476 pub fn with_body(mut self, body: Vec<u8>) -> Self {
477 self.body = body;
478 self.body_bytes = None;
479 self
480 }
481
482 #[inline]
487 pub fn with_bytes_body(mut self, bytes: Bytes) -> Self {
488 self.body_bytes = Some(bytes);
489 self.body.clear();
490 self
491 }
492
493 #[inline]
495 pub fn with_static_body(mut self, body: &'static [u8]) -> Self {
496 self.body_bytes = Some(Bytes::from_static(body));
497 self.body.clear();
498 self
499 }
500
501 #[inline]
507 pub fn body_bytes(&self) -> Bytes {
508 if let Some(ref bytes) = self.body_bytes {
509 bytes.clone() } else {
511 Bytes::copy_from_slice(&self.body)
512 }
513 }
514
515 #[inline]
520 pub fn into_body_bytes(self) -> Bytes {
521 if let Some(bytes) = self.body_bytes {
522 bytes
523 } else {
524 Bytes::from(self.body)
525 }
526 }
527
528 #[inline]
530 pub fn body_ref(&self) -> &[u8] {
531 if let Some(ref bytes) = self.body_bytes {
532 bytes.as_ref()
533 } else {
534 &self.body
535 }
536 }
537
538 #[inline]
540 pub fn body_len(&self) -> usize {
541 if let Some(ref bytes) = self.body_bytes {
542 bytes.len()
543 } else {
544 self.body.len()
545 }
546 }
547
548 #[inline]
550 pub fn has_bytes_body(&self) -> bool {
551 self.body_bytes.is_some()
552 }
553
554 #[inline]
567 pub fn with_json<T: Serialize>(mut self, value: &T) -> Result<Self, crate::Error> {
568 let vec =
569 crate::json::to_vec(value).map_err(|e| crate::Error::Serialization(e.to_string()))?;
570 self.body_bytes = Some(Bytes::from(vec));
571 self.body.clear();
572 self.headers
573 .insert("Content-Type".to_string(), "application/json".to_string());
574 Ok(self)
575 }
576
577 pub fn with_header(mut self, key: String, value: String) -> Self {
578 self.headers.insert(key, value);
579 self
580 }
581
582 #[inline]
584 pub fn with_headers(mut self, headers: HashMap<String, String>) -> Self {
585 self.headers = LazyHeaders::from(headers);
586 self
587 }
588
589 #[inline]
591 pub fn with_status_and_headers(status: u16, headers: HashMap<String, String>) -> Self {
592 Self {
593 status,
594 headers: LazyHeaders::from(headers),
595 body: Vec::new(),
596 body_bytes: None,
597 }
598 }
599
600 #[inline]
604 pub fn from_parts(status: u16, headers: HashMap<String, String>, body: Vec<u8>) -> Self {
605 Self {
606 status,
607 headers: LazyHeaders::from(headers),
608 body,
609 body_bytes: None,
610 }
611 }
612
613 pub fn accepted() -> Self {
626 Self::new(202)
627 }
628
629 pub fn unauthorized() -> Self {
638 Self::new(401)
639 }
640
641 pub fn forbidden() -> Self {
650 Self::new(403)
651 }
652
653 pub fn conflict() -> Self {
662 Self::new(409)
663 }
664
665 pub fn service_unavailable() -> Self {
674 Self::new(503)
675 }
676
677 pub fn json<T: Serialize>(value: &T) -> Result<Self, crate::Error> {
688 Self::ok().with_json(value)
689 }
690
691 pub fn html(content: impl Into<String>) -> Self {
701 Self::ok()
702 .with_header(
703 "Content-Type".to_string(),
704 "text/html; charset=utf-8".to_string(),
705 )
706 .with_body(content.into().into_bytes())
707 }
708
709 pub fn text(content: impl Into<String>) -> Self {
719 Self::ok()
720 .with_header(
721 "Content-Type".to_string(),
722 "text/plain; charset=utf-8".to_string(),
723 )
724 .with_body(content.into().into_bytes())
725 }
726
727 pub fn redirect(url: impl Into<String>) -> Self {
737 Self::new(302).with_header("Location".to_string(), url.into())
738 }
739
740 pub fn redirect_permanent(url: impl Into<String>) -> Self {
749 Self::new(301).with_header("Location".to_string(), url.into())
750 }
751
752 pub fn see_other(url: impl Into<String>) -> Self {
762 Self::new(303).with_header("Location".to_string(), url.into())
763 }
764
765 pub fn empty() -> Self {
774 Self::no_content()
775 }
776
777 pub fn content_type(self, content_type: impl Into<String>) -> Self {
786 self.with_header("Content-Type".to_string(), content_type.into())
787 }
788
789 pub fn cache_control(self, directive: impl Into<String>) -> Self {
797 self.with_header("Cache-Control".to_string(), directive.into())
798 }
799
800 pub fn no_cache(self) -> Self {
808 self.cache_control("no-store, no-cache, must-revalidate")
809 }
810
811 pub fn cookie(self, name: impl Into<String>, value: impl Into<String>) -> Self {
819 self.with_header(
820 "Set-Cookie".to_string(),
821 format!("{}={}", name.into(), value.into()),
822 )
823 }
824
825 pub fn body_string(&self) -> String {
827 String::from_utf8_lossy(self.body_ref()).to_string()
828 }
829
830 pub fn is_success(&self) -> bool {
832 (200..300).contains(&self.status)
833 }
834
835 pub fn is_redirect(&self) -> bool {
837 (300..400).contains(&self.status)
838 }
839
840 pub fn is_client_error(&self) -> bool {
842 (400..500).contains(&self.status)
843 }
844
845 pub fn is_server_error(&self) -> bool {
847 (500..600).contains(&self.status)
848 }
849}
850
851#[derive(Debug)]
853pub struct Json<T: Serialize>(pub T);
854
855impl<T: Serialize> Json<T> {
856 pub fn into_response(self) -> Result<HttpResponse, crate::Error> {
857 HttpResponse::ok().with_json(&self.0)
858 }
859}
860
861#[cfg(test)]
862mod tests {
863 use super::*;
864
865 #[test]
866 fn test_http_request_new() {
867 let req = HttpRequest::new("GET".to_string(), "/test".to_string());
868 assert_eq!(req.method, "GET");
869 assert_eq!(req.path, "/test");
870 assert!(req.headers.is_empty());
871 assert!(req.body.is_empty());
872 }
873
874 #[test]
875 fn test_http_request_with_body() {
876 let mut req = HttpRequest::new("POST".to_string(), "/api".to_string());
877 req.body = vec![1, 2, 3, 4];
878 assert_eq!(req.body.len(), 4);
879 }
880
881 #[test]
882 fn test_http_request_json_deserialization() {
883 #[derive(Deserialize, Debug, PartialEq)]
884 struct TestData {
885 name: String,
886 age: u32,
887 }
888
889 let mut req = HttpRequest::new("POST".to_string(), "/api".to_string());
890 req.body = serde_json::to_vec(&serde_json::json!({
891 "name": "John",
892 "age": 30
893 }))
894 .unwrap();
895
896 let data: TestData = req.json().unwrap();
897 assert_eq!(data.name, "John");
898 assert_eq!(data.age, 30);
899 }
900
901 #[test]
902 fn test_http_request_param() {
903 let mut req = HttpRequest::new("GET".to_string(), "/users/123".to_string());
904 req.path_params.insert("id".to_string(), "123".to_string());
905
906 assert_eq!(req.param("id"), Some(&"123".to_string()));
907 assert_eq!(req.param("name"), None);
908 }
909
910 #[test]
911 fn test_http_request_query() {
912 let mut req = HttpRequest::new("GET".to_string(), "/users".to_string());
913 req.query_params
914 .insert("sort".to_string(), "asc".to_string());
915
916 assert_eq!(req.query("sort"), Some(&"asc".to_string()));
917 assert_eq!(req.query("limit"), None);
918 }
919
920 #[test]
921 fn test_http_request_clone() {
922 let req1 = HttpRequest::new("GET".to_string(), "/test".to_string());
923 let req2 = req1.clone();
924
925 assert_eq!(req1.method, req2.method);
926 assert_eq!(req1.path, req2.path);
927 }
928
929 #[test]
930 fn test_http_response_ok() {
931 let res = HttpResponse::ok();
932 assert_eq!(res.status, 200);
933 }
934
935 #[test]
936 fn test_http_response_created() {
937 let res = HttpResponse::created();
938 assert_eq!(res.status, 201);
939 }
940
941 #[test]
942 fn test_http_response_no_content() {
943 let res = HttpResponse::no_content();
944 assert_eq!(res.status, 204);
945 }
946
947 #[test]
948 fn test_http_response_bad_request() {
949 let res = HttpResponse::bad_request();
950 assert_eq!(res.status, 400);
951 }
952
953 #[test]
954 fn test_http_response_not_found() {
955 let res = HttpResponse::not_found();
956 assert_eq!(res.status, 404);
957 }
958
959 #[test]
960 fn test_http_response_internal_server_error() {
961 let res = HttpResponse::internal_server_error();
962 assert_eq!(res.status, 500);
963 }
964
965 #[test]
966 fn test_http_response_with_body() {
967 let body = b"Hello, World!".to_vec();
968 let res = HttpResponse::ok().with_body(body.clone());
969 assert_eq!(res.body, body);
970 }
971
972 #[test]
973 fn test_http_response_with_json() {
974 #[derive(Serialize)]
975 struct TestData {
976 message: String,
977 }
978
979 let data = TestData {
980 message: "test".to_string(),
981 };
982
983 let res = HttpResponse::ok().with_json(&data).unwrap();
984 assert!(!res.body_ref().is_empty());
985 assert_eq!(
986 res.headers.get("Content-Type"),
987 Some(&"application/json".to_string())
988 );
989 }
990
991 #[test]
992 fn test_http_response_with_header() {
993 let res = HttpResponse::ok().with_header("X-Custom".to_string(), "value".to_string());
994
995 assert_eq!(res.headers.get("X-Custom"), Some(&"value".to_string()));
996 }
997
998 #[test]
999 fn test_http_response_multiple_headers() {
1000 let res = HttpResponse::ok()
1001 .with_header("X-Header-1".to_string(), "value1".to_string())
1002 .with_header("X-Header-2".to_string(), "value2".to_string());
1003
1004 assert_eq!(res.headers.len(), 2);
1005 }
1006
1007 #[test]
1008 fn test_json_helper() {
1009 #[derive(Serialize)]
1010 struct Data {
1011 value: i32,
1012 }
1013
1014 let json = Json(Data { value: 42 });
1015 let response = json.into_response().unwrap();
1016
1017 assert_eq!(response.status, 200);
1018 assert!(!response.body_ref().is_empty());
1019 }
1020
1021 #[test]
1022 fn test_http_request_with_headers() {
1023 let mut req = HttpRequest::new("GET".to_string(), "/api".to_string());
1024 req.headers
1025 .insert("Authorization".to_string(), "Bearer token".to_string());
1026 req.headers
1027 .insert("Content-Type".to_string(), "application/json".to_string());
1028
1029 assert_eq!(req.headers.len(), 2);
1030 }
1031
1032 #[test]
1033 fn test_http_request_json_invalid() {
1034 #[derive(Deserialize)]
1035 #[allow(dead_code)]
1036 struct TestData {
1037 name: String,
1038 }
1039
1040 let mut req = HttpRequest::new("POST".to_string(), "/api".to_string());
1041 req.body = b"invalid json".to_vec();
1042
1043 let result: Result<TestData, crate::Error> = req.json();
1044 assert!(result.is_err());
1045 }
1046
1047 #[test]
1048 fn test_http_response_new_custom_status() {
1049 let res = HttpResponse::new(418); assert_eq!(res.status, 418);
1051 }
1052
1053 #[test]
1054 fn test_http_response_with_json_complex() {
1055 #[derive(Serialize)]
1056 struct ComplexData {
1057 nested: Vec<HashMap<String, i32>>,
1058 }
1059
1060 let mut map = HashMap::new();
1061 map.insert("key".to_string(), 123);
1062
1063 let data = ComplexData { nested: vec![map] };
1064
1065 let res = HttpResponse::ok().with_json(&data);
1066 assert!(res.is_ok());
1067 }
1068}