1#![allow(clippy::mutable_key_type)]
20
21use std::{collections::HashMap, fmt, slice::Iter, str::FromStr};
24
25use bytes::Bytes;
26use serde::{Deserialize, Deserializer, Serialize, Serializer};
27
28#[derive(Clone, PartialEq, Eq, Debug, Default)]
48pub struct HeaderMap {
49 inner: HashMap<HeaderName, Vec<HeaderValue>>,
50}
51
52#[derive(Deserialize)]
56#[serde(untagged)]
57enum HeaderMapHelper {
58 Legacy {
60 inner: HashMap<HeaderName, Vec<HeaderValue>>,
61 },
62 Current(HashMap<HeaderName, Vec<HeaderValue>>),
64}
65
66impl<'de> Deserialize<'de> for HeaderMap {
67 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
68 where
69 D: Deserializer<'de>,
70 {
71 let helper = HeaderMapHelper::deserialize(deserializer)?;
73
74 Ok(match helper {
75 HeaderMapHelper::Legacy { inner } => HeaderMap { inner },
76 HeaderMapHelper::Current(inner) => HeaderMap { inner },
77 })
78 }
79}
80
81impl Serialize for HeaderMap {
82 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
83 where
84 S: Serializer,
85 {
86 self.inner.serialize(serializer)
88 }
89}
90
91impl FromIterator<(HeaderName, HeaderValue)> for HeaderMap {
92 fn from_iter<T: IntoIterator<Item = (HeaderName, HeaderValue)>>(iter: T) -> Self {
93 let mut header_map = HeaderMap::new();
94 for (key, value) in iter {
95 header_map.insert(key, value);
96 }
97 header_map
98 }
99}
100
101impl HeaderMap {
102 pub fn iter(&self) -> std::collections::hash_map::Iter<'_, HeaderName, Vec<HeaderValue>> {
103 self.inner.iter()
104 }
105}
106
107pub struct GetAll<'a, T> {
108 inner: Iter<'a, T>,
109}
110
111impl<'a, T> Iterator for GetAll<'a, T> {
112 type Item = &'a T;
113
114 fn next(&mut self) -> Option<Self::Item> {
115 self.inner.next()
116 }
117}
118
119impl HeaderMap {
120 pub fn new() -> Self {
131 HeaderMap::default()
132 }
133
134 pub fn is_empty(&self) -> bool {
150 self.inner.is_empty()
151 }
152
153 pub fn len(&self) -> usize {
154 self.inner.len()
155 }
156}
157
158impl HeaderMap {
159 pub fn insert<K: IntoHeaderName, V: IntoHeaderValue>(&mut self, name: K, value: V) {
170 self.inner
171 .insert(name.into_header_name(), vec![value.into_header_value()]);
172 }
173
174 pub fn append<K: IntoHeaderName, V: IntoHeaderValue>(&mut self, name: K, value: V) {
186 let key = name.into_header_name();
187 let v = self.inner.get_mut(&key);
188 match v {
189 Some(v) => {
190 v.push(value.into_header_value());
191 }
192 None => {
193 self.insert(key, value.into_header_value());
194 }
195 }
196 }
197
198 pub fn get<K: IntoHeaderName>(&self, key: K) -> Option<&HeaderValue> {
210 self.inner
211 .get(&key.into_header_name())
212 .and_then(|x| x.first())
213 }
214
215 pub fn get_last<K: IntoHeaderName>(&self, key: K) -> Option<&HeaderValue> {
227 self.inner
228 .get(&key.into_header_name())
229 .and_then(|x| x.last())
230 }
231
232 pub fn get_all<K: IntoHeaderName>(&self, key: K) -> GetAll<'_, HeaderValue> {
247 let inner = self
248 .inner
249 .get(&key.into_header_name())
250 .map(|x| x.iter())
251 .unwrap_or([].iter());
252
253 GetAll { inner }
254 }
255
256 pub(crate) fn to_bytes(&self) -> Vec<u8> {
257 let mut buf = vec![];
258 buf.extend_from_slice(b"NATS/1.0\r\n");
259 for (k, vs) in &self.inner {
260 for v in vs.iter() {
261 buf.extend_from_slice(k.as_str().as_bytes());
262 buf.extend_from_slice(b": ");
263 buf.extend_from_slice(v.inner.as_bytes());
264 buf.extend_from_slice(b"\r\n");
265 }
266 }
267 buf.extend_from_slice(b"\r\n");
268 buf
269 }
270}
271
272#[derive(Clone, PartialEq, Eq, Debug, Default, Serialize, Deserialize)]
284#[serde(transparent)]
285pub struct HeaderValue {
286 inner: String,
287}
288
289impl fmt::Display for HeaderValue {
290 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
291 fmt::Display::fmt(&self.as_str(), f)
292 }
293}
294
295impl AsRef<[u8]> for HeaderValue {
296 fn as_ref(&self) -> &[u8] {
297 self.inner.as_ref()
298 }
299}
300
301impl AsRef<str> for HeaderValue {
302 fn as_ref(&self) -> &str {
303 self.as_str()
304 }
305}
306
307impl From<i16> for HeaderValue {
308 fn from(v: i16) -> Self {
309 Self {
310 inner: v.to_string(),
311 }
312 }
313}
314
315impl From<i32> for HeaderValue {
316 fn from(v: i32) -> Self {
317 Self {
318 inner: v.to_string(),
319 }
320 }
321}
322
323impl From<i64> for HeaderValue {
324 fn from(v: i64) -> Self {
325 Self {
326 inner: v.to_string(),
327 }
328 }
329}
330
331impl From<isize> for HeaderValue {
332 fn from(v: isize) -> Self {
333 Self {
334 inner: v.to_string(),
335 }
336 }
337}
338
339impl From<u16> for HeaderValue {
340 fn from(v: u16) -> Self {
341 Self {
342 inner: v.to_string(),
343 }
344 }
345}
346
347impl From<u32> for HeaderValue {
348 fn from(v: u32) -> Self {
349 Self {
350 inner: v.to_string(),
351 }
352 }
353}
354
355impl From<u64> for HeaderValue {
356 fn from(v: u64) -> Self {
357 Self {
358 inner: v.to_string(),
359 }
360 }
361}
362
363impl From<usize> for HeaderValue {
364 fn from(v: usize) -> Self {
365 Self {
366 inner: v.to_string(),
367 }
368 }
369}
370
371impl FromStr for HeaderValue {
372 type Err = ParseHeaderValueError;
373
374 fn from_str(s: &str) -> Result<Self, Self::Err> {
375 if s.contains(['\r', '\n']) {
376 return Err(ParseHeaderValueError);
377 }
378
379 Ok(HeaderValue {
380 inner: s.to_string(),
381 })
382 }
383}
384
385impl From<&str> for HeaderValue {
386 fn from(v: &str) -> Self {
387 assert!(
388 !v.contains(['\r', '\n']),
389 "invalid header value: cannot contain '\\r' or '\\n'"
390 );
391 Self {
392 inner: v.to_string(),
393 }
394 }
395}
396
397impl From<String> for HeaderValue {
398 fn from(inner: String) -> Self {
399 assert!(
400 !inner.contains(['\r', '\n']),
401 "invalid header value: cannot contain '\\r' or '\\n'"
402 );
403 Self { inner }
404 }
405}
406
407impl HeaderValue {
408 pub fn new() -> Self {
409 HeaderValue::default()
410 }
411
412 pub fn as_str(&self) -> &str {
413 self.inner.as_str()
414 }
415}
416
417#[derive(Debug, Clone)]
418pub struct ParseHeaderValueError;
419
420impl fmt::Display for ParseHeaderValueError {
421 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
422 write!(
423 f,
424 r#"invalid character found in header value (value cannot contain '\r' or '\n')"#
425 )
426 }
427}
428
429impl std::error::Error for ParseHeaderValueError {}
430
431pub trait IntoHeaderName {
432 fn into_header_name(self) -> HeaderName;
433}
434
435impl IntoHeaderName for &str {
436 fn into_header_name(self) -> HeaderName {
437 assert!(
438 !self.contains(|c: char| c == ':' || (c as u8) < 33 || (c as u8) > 126),
439 "invalid header name: cannot contain control characters, non-ASCII, or ':'"
440 );
441 match StandardHeader::from_bytes(self.as_bytes()) {
442 Some(v) => HeaderName {
443 inner: HeaderRepr::Standard(v),
444 },
445 None => HeaderName {
446 inner: HeaderRepr::Custom(self.into()),
447 },
448 }
449 }
450}
451
452impl IntoHeaderName for String {
453 fn into_header_name(self) -> HeaderName {
454 assert!(
455 !self.contains(|c: char| c == ':' || (c as u8) < 33 || (c as u8) > 126),
456 "invalid header name: cannot contain control characters, non-ASCII, or ':'"
457 );
458 match StandardHeader::from_bytes(self.as_bytes()) {
459 Some(v) => HeaderName {
460 inner: HeaderRepr::Standard(v),
461 },
462 None => HeaderName {
463 inner: HeaderRepr::Custom(self.into()),
464 },
465 }
466 }
467}
468
469impl IntoHeaderName for HeaderName {
470 fn into_header_name(self) -> HeaderName {
471 self
472 }
473}
474
475pub trait IntoHeaderValue {
476 fn into_header_value(self) -> HeaderValue;
477}
478
479impl IntoHeaderValue for &str {
480 fn into_header_value(self) -> HeaderValue {
481 HeaderValue::from(self)
482 }
483}
484
485impl IntoHeaderValue for String {
486 fn into_header_value(self) -> HeaderValue {
487 HeaderValue::from(self)
488 }
489}
490
491impl IntoHeaderValue for HeaderValue {
492 fn into_header_value(self) -> HeaderValue {
493 self
494 }
495}
496
497macro_rules! standard_headers {
498 (
499 $(
500 $(#[$docs:meta])*
501 ($variant:ident, $constant:ident, $bytes:literal);
502 )+
503 ) => {
504 #[allow(clippy::enum_variant_names)]
505 #[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
506 enum StandardHeader {
507 $(
508 $variant,
509 )+
510 }
511
512 $(
513 $(#[$docs])*
514 pub const $constant: HeaderName = HeaderName {
515 inner: HeaderRepr::Standard(StandardHeader::$variant),
516 };
517 )+
518
519 impl StandardHeader {
520 #[inline]
521 fn as_str(&self) -> &'static str {
522 match *self {
523 $(
524 StandardHeader::$variant => unsafe { std::str::from_utf8_unchecked( $bytes ) },
525 )+
526 }
527 }
528
529 const fn from_bytes(bytes: &[u8]) -> Option<StandardHeader> {
530 match bytes {
531 $(
532 $bytes => Some(StandardHeader::$variant),
533 )+
534 _ => None,
535 }
536 }
537 }
538
539 #[cfg(test)]
540 mod standard_header_tests {
541 use super::HeaderName;
542 use std::str::{self, FromStr};
543
544 const TEST_HEADERS: &'static [(&'static HeaderName, &'static [u8])] = &[
545 $(
546 (&super::$constant, $bytes),
547 )+
548 ];
549
550 #[test]
551 fn from_str() {
552 for &(header, bytes) in TEST_HEADERS {
553 let utf8 = str::from_utf8(bytes).expect("string constants isn't utf8");
554 assert_eq!(HeaderName::from_str(utf8).unwrap(), *header);
555 }
556 }
557 }
558 }
559}
560
561standard_headers! {
563 (NatsStream, NATS_STREAM, b"Nats-Stream");
565 (NatsSequence, NATS_SEQUENCE, b"Nats-Sequence");
567 (NatsTimeStamp, NATS_TIME_STAMP, b"Nats-Time-Stamp");
569 (NatsSubject, NATS_SUBJECT, b"Nats-Subject");
571 (NatsMessageId, NATS_MESSAGE_ID, b"Nats-Msg-Id");
573 (NatsLastStream, NATS_LAST_STREAM, b"Nats-Last-Stream");
575 (NatsLastConsumer, NATS_LAST_CONSUMER, b"Nats-Last-Consumer");
577 (NatsLastSequence, NATS_LAST_SEQUENCE, b"Nats-Last-Sequence");
579 (NatsExpectedLastSubjectSequence, NATS_EXPECTED_LAST_SUBJECT_SEQUENCE, b"Nats-Expected-Last-Subject-Sequence");
581 (NatsExpectedLastMessageId, NATS_EXPECTED_LAST_MESSAGE_ID, b"Nats-Expected-Last-Msg-Id");
583 (NatsExpectedLastSequence, NATS_EXPECTED_LAST_SEQUENCE, b"Nats-Expected-Last-Sequence");
585 (NatsExpectedStream, NATS_EXPECTED_STREAM, b"Nats-Expected-Stream");
587 (NatsMessageTtl, NATS_MESSAGE_TTL, b"Nats-TTL");
589 (NatsMarkerReason, NATS_MARKER_REASON, b"Nats-Marker-Reason");
591}
592
593#[derive(Debug, Hash, PartialEq, Eq, Clone)]
594struct CustomHeader {
595 bytes: Bytes,
596}
597
598impl CustomHeader {
599 #[inline]
600 pub(crate) const fn from_static(value: &'static str) -> CustomHeader {
601 CustomHeader {
602 bytes: Bytes::from_static(value.as_bytes()),
603 }
604 }
605
606 #[inline]
607 pub(crate) fn as_str(&self) -> &str {
608 unsafe { std::str::from_utf8_unchecked(self.bytes.as_ref()) }
609 }
610}
611
612impl From<String> for CustomHeader {
613 #[inline]
614 fn from(value: String) -> CustomHeader {
615 CustomHeader {
616 bytes: Bytes::from(value),
617 }
618 }
619}
620
621impl<'a> From<&'a str> for CustomHeader {
622 #[inline]
623 fn from(value: &'a str) -> CustomHeader {
624 CustomHeader {
625 bytes: Bytes::copy_from_slice(value.as_bytes()),
626 }
627 }
628}
629
630#[derive(Debug, Hash, PartialEq, Eq, Clone)]
631enum HeaderRepr {
632 Standard(StandardHeader),
633 Custom(CustomHeader),
634}
635
636#[derive(Clone, PartialEq, Eq, Hash, Debug)]
646pub struct HeaderName {
647 inner: HeaderRepr,
648}
649
650impl HeaderName {
651 #[inline]
653 pub const fn from_static(value: &'static str) -> HeaderName {
654 if let Some(standard) = StandardHeader::from_bytes(value.as_bytes()) {
655 return HeaderName {
656 inner: HeaderRepr::Standard(standard),
657 };
658 }
659
660 HeaderName {
661 inner: HeaderRepr::Custom(CustomHeader::from_static(value)),
662 }
663 }
664
665 #[inline]
667 fn as_str(&self) -> &str {
668 match self.inner {
669 HeaderRepr::Standard(v) => v.as_str(),
670 HeaderRepr::Custom(ref v) => v.as_str(),
671 }
672 }
673}
674
675impl FromStr for HeaderName {
676 type Err = ParseHeaderNameError;
677
678 fn from_str(s: &str) -> Result<Self, Self::Err> {
679 if s.contains(|c: char| c == ':' || (c as u8) < 33 || (c as u8) > 126) {
680 return Err(ParseHeaderNameError);
681 }
682
683 match StandardHeader::from_bytes(s.as_ref()) {
684 Some(v) => Ok(HeaderName {
685 inner: HeaderRepr::Standard(v),
686 }),
687 None => Ok(HeaderName {
688 inner: HeaderRepr::Custom(CustomHeader::from(s)),
689 }),
690 }
691 }
692}
693
694impl fmt::Display for HeaderName {
695 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
696 fmt::Display::fmt(&self.as_str(), f)
697 }
698}
699
700impl AsRef<[u8]> for HeaderName {
701 fn as_ref(&self) -> &[u8] {
702 self.as_str().as_bytes()
703 }
704}
705
706impl AsRef<str> for HeaderName {
707 fn as_ref(&self) -> &str {
708 self.as_str()
709 }
710}
711
712impl Serialize for HeaderName {
713 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
714 where
715 S: serde::Serializer,
716 {
717 serializer.serialize_str(self.as_str())
718 }
719}
720
721impl<'de> Deserialize<'de> for HeaderName {
722 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
723 where
724 D: serde::Deserializer<'de>,
725 {
726 String::deserialize(deserializer)?
727 .parse()
728 .map_err(serde::de::Error::custom)
729 }
730}
731
732#[derive(Debug, Clone)]
733pub struct ParseHeaderNameError;
734
735impl std::fmt::Display for ParseHeaderNameError {
736 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
737 write!(f, "invalid header name (name cannot contain non-ascii alphanumeric characters other than '-')")
738 }
739}
740
741impl std::error::Error for ParseHeaderNameError {}
742
743#[cfg(test)]
744mod tests {
745 use super::{HeaderMap, HeaderName, HeaderValue, IntoHeaderName, IntoHeaderValue};
746 use std::str::{from_utf8, FromStr};
747
748 #[test]
749 fn try_from() {
750 let mut headers = HeaderMap::new();
751 headers.insert("name", "something".parse::<HeaderValue>().unwrap());
752 headers.insert("name", "something2");
753 }
754
755 #[test]
756 fn append() {
757 let mut headers = HeaderMap::new();
758 headers.append("Key", "value");
759 headers.append("Key", "second_value");
760
761 let mut result = headers.get_all("Key");
762
763 assert_eq!(
764 result.next().unwrap(),
765 &HeaderValue::from_str("value").unwrap()
766 );
767
768 assert_eq!(
769 result.next().unwrap(),
770 &HeaderValue::from_str("second_value").unwrap()
771 );
772
773 assert_eq!(result.next(), None);
774 }
775
776 #[test]
777 fn get_string() {
778 let mut headers = HeaderMap::new();
779 headers.append("Key", "value");
780 headers.append("Key", "other");
781
782 assert_eq!(headers.get("Key").unwrap().to_string(), "value");
783
784 let key: String = headers.get("Key").unwrap().as_str().into();
785 assert_eq!(key, "value".to_string());
786
787 let key: String = headers.get("Key").unwrap().as_str().to_owned();
788 assert_eq!(key, "value".to_string());
789
790 assert_eq!(headers.get("Key").unwrap().as_str(), "value");
791
792 let key: String = headers.get_last("Key").unwrap().as_str().into();
793 assert_eq!(key, "other".to_string());
794 }
795
796 #[test]
797 fn insert() {
798 let mut headers = HeaderMap::new();
799 headers.insert("Key", "Value");
800
801 let mut result = headers.get_all("Key");
802
803 assert_eq!(
804 result.next().unwrap(),
805 &HeaderValue::from_str("Value").unwrap()
806 );
807 assert_eq!(result.next(), None);
808 }
809
810 #[test]
811 fn serialize() {
812 let mut headers = HeaderMap::new();
813 headers.append("Key", "value");
814 headers.append("Key", "second_value");
815 headers.insert("Second", "SecondValue");
816
817 let bytes = headers.to_bytes();
818
819 println!("bytes: {:?}", from_utf8(&bytes));
820 }
821
822 #[test]
823 fn is_empty() {
824 let mut headers = HeaderMap::new();
825 assert!(headers.is_empty());
826
827 headers.append("Key", "value");
828 headers.append("Key", "second_value");
829 headers.insert("Second", "SecondValue");
830 assert!(!headers.is_empty());
831 }
832
833 #[test]
834 fn parse_value() {
835 assert!("Foo\r".parse::<HeaderValue>().is_err());
836 assert!("Foo\n".parse::<HeaderValue>().is_err());
837 assert!("Foo\r\n".parse::<HeaderValue>().is_err());
838 }
839
840 #[test]
841 fn valid_header_name() {
842 let valid_header_name = "X-Custom-Header";
843 let parsed_header = HeaderName::from_str(valid_header_name);
844
845 assert!(
846 parsed_header.is_ok(),
847 "Expected Ok(HeaderName), but got an error: {:?}",
848 parsed_header.err()
849 );
850 }
851
852 #[test]
853 fn dollar_header_name() {
854 let valid_header_name = "$X_Custom_Header";
855 let parsed_header = HeaderName::from_str(valid_header_name);
856
857 assert!(
858 parsed_header.is_ok(),
859 "Expected Ok(HeaderName), but got an error: {:?}",
860 parsed_header.err()
861 );
862 }
863
864 #[test]
865 fn invalid_header_name_with_space() {
866 let invalid_header_name = "X Custom Header";
867 let parsed_header = HeaderName::from_str(invalid_header_name);
868
869 assert!(
870 parsed_header.is_err(),
871 "Expected Err(InvalidHeaderNameError), but got Ok: {:?}",
872 parsed_header.ok()
873 );
874 }
875
876 #[test]
877 fn invalid_header_name_with_special_chars() {
878 let invalid_header_name = "X-Header:";
879 let parsed_header = HeaderName::from_str(invalid_header_name);
880
881 assert!(
882 parsed_header.is_err(),
883 "Expected Err(InvalidHeaderNameError), but got Ok: {:?}",
884 parsed_header.ok()
885 );
886 }
887
888 #[test]
889 fn from_static_eq() {
890 let a = HeaderName::from_static("NATS-Stream");
891 let b = HeaderName::from_static("NATS-Stream");
892
893 assert_eq!(a, b);
894 }
895
896 #[test]
897 fn header_name_serde() {
898 let raw = "Nats-Stream";
899 let raw_json = "\"Nats-Stream\"";
900 let header = HeaderName::from_static(raw);
901
902 assert_eq!(serde_json::to_string(&header).unwrap(), raw_json);
904 assert_eq!(
905 serde_json::from_str::<HeaderName>(raw_json).unwrap(),
906 header
907 );
908 }
909
910 #[test]
911 fn header_name_from_string() {
912 let string = "NATS-Stream".to_string();
913 let name = string.into_header_name();
914
915 assert_eq!("NATS-Stream", name.as_str());
916 }
917
918 #[test]
919 fn header_value_from_string_with_trait() {
920 let string = "some value".to_string();
921
922 let value = string.into_header_value();
923
924 assert_eq!("some value", value.as_str());
925 }
926
927 #[test]
928 fn header_value_from_string() {
929 let string = "some value".to_string();
930
931 let value: HeaderValue = string.into();
932
933 assert_eq!("some value", value.as_str());
934 }
935
936 #[test]
937 fn header_map_backward_compatible_deserialization() {
938 let new_format_json =
940 r#"{"Content-Type": ["application/json"], "Authorization": ["Bearer token"]}"#;
941 let header_map: HeaderMap = serde_json::from_str(new_format_json).unwrap();
942
943 assert_eq!(
944 header_map.get("Content-Type").unwrap().as_str(),
945 "application/json"
946 );
947 assert_eq!(
948 header_map.get("Authorization").unwrap().as_str(),
949 "Bearer token"
950 );
951
952 let legacy_format_json = r#"{"inner": {"Content-Type": ["application/json"], "Authorization": ["Bearer token"]}}"#;
954 let header_map_legacy: HeaderMap = serde_json::from_str(legacy_format_json).unwrap();
955
956 assert_eq!(
957 header_map_legacy.get("Content-Type").unwrap().as_str(),
958 "application/json"
959 );
960 assert_eq!(
961 header_map_legacy.get("Authorization").unwrap().as_str(),
962 "Bearer token"
963 );
964
965 assert_eq!(header_map, header_map_legacy);
967 }
968
969 #[test]
970 fn header_map_serialization_new_format() {
971 let mut headers = HeaderMap::new();
973 headers.insert("Content-Type", "application/json");
974 headers.insert("Authorization", "Bearer token");
975
976 let serialized = serde_json::to_string(&headers).unwrap();
977
978 assert!(!serialized.contains("inner"));
980
981 let deserialized: HeaderMap = serde_json::from_str(&serialized).unwrap();
983 assert_eq!(headers, deserialized);
984 }
985
986 #[test]
987 fn header_map_roundtrip_compatibility() {
988 let mut original = HeaderMap::new();
990 original.insert("X-Custom-Header", "custom-value");
991 original.append("Multi-Value", "value1");
992 original.append("Multi-Value", "value2");
993
994 let new_serialized = serde_json::to_string(&original).unwrap();
996 let new_deserialized: HeaderMap = serde_json::from_str(&new_serialized).unwrap();
997 assert_eq!(original, new_deserialized);
998
999 let legacy_json = format!(r#"{{"inner": {}}}"#, new_serialized);
1001 let legacy_deserialized: HeaderMap = serde_json::from_str(&legacy_json).unwrap();
1002 assert_eq!(original, legacy_deserialized);
1003 }
1004
1005 #[test]
1006 fn header_map_invalid_format_error() {
1007 let invalid_json = r#"{"not_inner_or_direct": {"Content-Type": ["application/json"]}}"#;
1009 let result = serde_json::from_str::<HeaderMap>(invalid_json);
1010 assert!(result.is_err());
1011
1012 let error_message = result.unwrap_err().to_string();
1013 assert!(error_message.contains("did not match any variant"));
1015 }
1016
1017 #[test]
1018 fn header_map_empty_cases() {
1019 let empty = HeaderMap::new();
1021 let serialized = serde_json::to_string(&empty).unwrap();
1022 assert_eq!(serialized, "{}");
1023
1024 let deserialized: HeaderMap = serde_json::from_str("{}").unwrap();
1025 assert!(deserialized.is_empty());
1026
1027 let legacy_empty = r#"{"inner": {}}"#;
1029 let legacy_deserialized: HeaderMap = serde_json::from_str(legacy_empty).unwrap();
1030 assert!(legacy_deserialized.is_empty());
1031 }
1032
1033 #[test]
1034 fn header_map_mixed_legacy_detection() {
1035 let json_with_inner_header =
1038 r#"{"inner": ["some-value"], "Other-Header": ["other-value"]}"#;
1039 let header_map: HeaderMap = serde_json::from_str(json_with_inner_header).unwrap();
1040
1041 assert_eq!(header_map.len(), 2);
1043 assert_eq!(header_map.get("inner").unwrap().as_str(), "some-value");
1044 assert_eq!(
1045 header_map.get("Other-Header").unwrap().as_str(),
1046 "other-value"
1047 );
1048 }
1049
1050 #[test]
1051 #[should_panic(expected = "invalid header value")]
1052 fn header_value_from_str_rejects_cr() {
1053 let _: HeaderValue = "value\rwith\rcr".into();
1054 }
1055
1056 #[test]
1057 #[should_panic(expected = "invalid header value")]
1058 fn header_value_from_str_rejects_lf() {
1059 let _: HeaderValue = "value\nwith\nlf".into();
1060 }
1061
1062 #[test]
1063 #[should_panic(expected = "invalid header value")]
1064 fn header_value_from_string_rejects_crlf() {
1065 let _: HeaderValue = "injected\r\nPUB attack 0\r\n\r\n".to_string().into();
1066 }
1067
1068 #[test]
1069 #[should_panic(expected = "invalid header value")]
1070 fn header_value_into_trait_rejects_crlf() {
1071 let mut headers = HeaderMap::new();
1072 headers.insert("Key", "value\r\nPUB attack 0\r\n\r\n");
1073 }
1074
1075 #[test]
1076 #[should_panic(expected = "invalid header name")]
1077 fn header_name_into_trait_rejects_cr() {
1078 let mut headers = HeaderMap::new();
1079 headers.insert("Bad\rName", "value");
1080 }
1081
1082 #[test]
1083 #[should_panic(expected = "invalid header name")]
1084 fn header_name_into_trait_rejects_lf() {
1085 let mut headers = HeaderMap::new();
1086 headers.insert("Bad\nName", "value");
1087 }
1088
1089 #[test]
1090 #[should_panic(expected = "invalid header name")]
1091 fn header_name_into_trait_rejects_space() {
1092 let mut headers = HeaderMap::new();
1093 headers.insert("Bad Name", "value");
1094 }
1095
1096 #[test]
1097 #[should_panic(expected = "invalid header name")]
1098 fn header_name_into_trait_rejects_colon() {
1099 let mut headers = HeaderMap::new();
1100 headers.insert("Bad:Name", "value");
1101 }
1102
1103 #[test]
1104 #[should_panic(expected = "invalid header name")]
1105 fn header_name_from_string_rejects_control_chars() {
1106 let name = "Bad\x00Name".to_string();
1107 name.into_header_name();
1108 }
1109
1110 #[test]
1111 fn valid_header_values_still_work() {
1112 let _: HeaderValue = "normal value".into();
1113 let _: HeaderValue = "value with special chars !@#$%^&*()".into();
1114 let _: HeaderValue = "".into();
1115 let _: HeaderValue = String::from("string value").into();
1116 }
1117
1118 #[test]
1119 fn valid_header_names_still_work() {
1120 let mut headers = HeaderMap::new();
1121 headers.insert("X-Custom-Header", "value");
1122 headers.insert("Another-Header", "value");
1123 headers.insert("$dollar", "value");
1124 headers.insert("Nats-Stream", "value");
1125 assert_eq!(headers.get("Nats-Stream").unwrap().as_str(), "value");
1126 }
1127
1128 #[test]
1129 fn header_map_large_headers() {
1130 let mut headers = HeaderMap::new();
1132 for i in 0..100 {
1133 headers.insert(format!("Header-{}", i), format!("Value-{}", i));
1134 }
1135
1136 let serialized = serde_json::to_string(&headers).unwrap();
1137 let deserialized: HeaderMap = serde_json::from_str(&serialized).unwrap();
1138
1139 assert_eq!(headers.len(), deserialized.len());
1140 for i in 0..100 {
1141 assert_eq!(
1142 deserialized
1143 .get(format!("Header-{}", i).as_str())
1144 .unwrap()
1145 .as_str(),
1146 format!("Value-{}", i)
1147 );
1148 }
1149 }
1150}