async_nats/
header.rs

1// Copyright 2020-2023 The NATS Authors
2// Licensed under the Apache License, Version 2.0 (the "License");
3// you may not use this file except in compliance with the License.
4// You may obtain a copy of the License at
5//
6// http://www.apache.org/licenses/LICENSE-2.0
7//
8// Unless required by applicable law or agreed to in writing, software
9// distributed under the License is distributed on an "AS IS" BASIS,
10// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11// See the License for the specific language governing permissions and
12// limitations under the License.
13
14// NOTE(thomastaylor312): This clippy lint is coming from serialize and deserialize and is likely a
15// false positive due to the bytes crate, see
16// https://rust-lang.github.io/rust-clippy/master/index.html#/mutable_key_type for more details.
17// Sorry to make this global to this module, rather than on the `HeaderMap` struct, but because it
18// is coming from the derive, it didn't work to set it on the struct.
19#![allow(clippy::mutable_key_type)]
20
21//! NATS [Message][crate::Message] headers, modeled loosely after the `http::header` crate.
22
23use std::{collections::HashMap, fmt, slice::Iter, str::FromStr};
24
25use bytes::Bytes;
26use serde::{Deserialize, Deserializer, Serialize, Serializer};
27
28/// A struct for handling NATS headers.
29/// Has a similar API to `http::header`, but properly serializes and deserializes
30/// according to NATS requirements.
31///
32/// # Examples
33///
34/// ```
35/// # #[tokio::main]
36/// # async fn main() -> Result<(), async_nats::Error> {
37/// let client = async_nats::connect("demo.nats.io").await?;
38/// let mut headers = async_nats::HeaderMap::new();
39/// headers.insert("Key", "Value");
40/// client
41///     .publish_with_headers("subject", headers, "payload".into())
42///     .await?;
43/// # Ok(())
44/// # }
45/// ```
46
47#[derive(Clone, PartialEq, Eq, Debug, Default)]
48pub struct HeaderMap {
49    inner: HashMap<HeaderName, Vec<HeaderValue>>,
50}
51
52/// Helper enum for backward-compatible deserialization using serde's untagged feature
53/// This is required because of the bug #1470 where the client incorrectly serialized
54/// headers with an "inner" wrapper.
55#[derive(Deserialize)]
56#[serde(untagged)]
57enum HeaderMapHelper {
58    // Legacy format with "inner" wrapper
59    Legacy {
60        inner: HashMap<HeaderName, Vec<HeaderValue>>,
61    },
62    // Proper format - direct HashMap
63    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        // Use the untagged enum to automatically try both formats
72        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        // Serialize as the new format (direct HashMap without "inner" wrapper)
87        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    /// Create an empty `HeaderMap`.
121    ///
122    /// # Examples
123    ///
124    /// ```
125    /// # use async_nats::HeaderMap;
126    /// let map = HeaderMap::new();
127    ///
128    /// assert!(map.is_empty());
129    /// ```
130    pub fn new() -> Self {
131        HeaderMap::default()
132    }
133
134    /// Returns true if the map contains no elements.
135    ///
136    /// # Examples
137    ///
138    /// ```
139    /// # use async_nats::HeaderMap;
140    /// # use async_nats::header::NATS_SUBJECT;
141    /// let mut map = HeaderMap::new();
142    ///
143    /// assert!(map.is_empty());
144    ///
145    /// map.insert(NATS_SUBJECT, "FOO.BAR");
146    ///
147    /// assert!(!map.is_empty());
148    /// ```
149    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    /// Inserts a new value to a [HeaderMap].
160    ///
161    /// # Examples
162    ///
163    /// ```
164    /// use async_nats::HeaderMap;
165    ///
166    /// let mut headers = HeaderMap::new();
167    /// headers.insert("Key", "Value");
168    /// ```
169    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    /// Appends a new value to the list of values to a given key.
175    /// If the key did not exist, it will be inserted with provided value.
176    ///
177    /// # Examples
178    ///
179    /// ```
180    /// use async_nats::HeaderMap;
181    ///
182    /// let mut headers = HeaderMap::new();
183    /// headers.append("Key", "Value");
184    /// headers.append("Key", "Another");
185    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    /// Gets a value for a given key. If key is not found, [Option::None] is returned.
199    ///
200    /// # Examples
201    ///
202    /// ```
203    /// # use async_nats::HeaderMap;
204    ///
205    /// let mut headers = HeaderMap::new();
206    /// headers.append("Key", "Value");
207    /// let values = headers.get("Key").unwrap();
208    /// ```
209    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    /// Gets a last value for a given key. If key is not found, [Option::None] is returned.
216    ///
217    /// # Examples
218    ///
219    /// ```
220    /// # use async_nats::HeaderMap;
221    ///
222    /// let mut headers = HeaderMap::new();
223    /// headers.append("Key", "Value");
224    /// let values = headers.get_last("Key").unwrap();
225    /// ```
226    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    /// Gets an iterator to the values for a given key.
233    ///
234    /// # Examples
235    ///
236    /// ```
237    /// # use async_nats::HeaderMap;
238    ///
239    /// let mut headers = HeaderMap::new();
240    /// headers.append("Key", "Value1");
241    /// headers.append("Key", "Value2");
242    /// let mut values = headers.get_all("Key");
243    /// let value1 = values.next();
244    /// let value2 = values.next();
245    /// ```
246    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/// Represents NATS header field value.
273///
274/// # Examples
275///
276/// ```
277/// # use async_nats::HeaderMap;
278///
279/// let mut headers = HeaderMap::new();
280/// headers.insert("Key", "Value");
281/// headers.insert("Another", "AnotherValue");
282/// ```
283#[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        Self {
388            inner: v.to_string(),
389        }
390    }
391}
392
393impl From<String> for HeaderValue {
394    fn from(inner: String) -> Self {
395        Self { inner }
396    }
397}
398
399impl HeaderValue {
400    pub fn new() -> Self {
401        HeaderValue::default()
402    }
403
404    pub fn as_str(&self) -> &str {
405        self.inner.as_str()
406    }
407}
408
409#[derive(Debug, Clone)]
410pub struct ParseHeaderValueError;
411
412impl fmt::Display for ParseHeaderValueError {
413    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
414        write!(
415            f,
416            r#"invalid character found in header value (value cannot contain '\r' or '\n')"#
417        )
418    }
419}
420
421impl std::error::Error for ParseHeaderValueError {}
422
423pub trait IntoHeaderName {
424    fn into_header_name(self) -> HeaderName;
425}
426
427impl IntoHeaderName for &str {
428    fn into_header_name(self) -> HeaderName {
429        HeaderName {
430            inner: HeaderRepr::Custom(self.into()),
431        }
432    }
433}
434
435impl IntoHeaderName for String {
436    fn into_header_name(self) -> HeaderName {
437        HeaderName {
438            inner: HeaderRepr::Custom(self.into()),
439        }
440    }
441}
442
443impl IntoHeaderName for HeaderName {
444    fn into_header_name(self) -> HeaderName {
445        self
446    }
447}
448
449pub trait IntoHeaderValue {
450    fn into_header_value(self) -> HeaderValue;
451}
452
453impl IntoHeaderValue for &str {
454    fn into_header_value(self) -> HeaderValue {
455        HeaderValue {
456            inner: self.to_string(),
457        }
458    }
459}
460
461impl IntoHeaderValue for String {
462    fn into_header_value(self) -> HeaderValue {
463        HeaderValue { inner: self }
464    }
465}
466
467impl IntoHeaderValue for HeaderValue {
468    fn into_header_value(self) -> HeaderValue {
469        self
470    }
471}
472
473macro_rules! standard_headers {
474    (
475        $(
476            $(#[$docs:meta])*
477            ($variant:ident, $constant:ident, $bytes:literal);
478        )+
479    ) => {
480        #[allow(clippy::enum_variant_names)]
481        #[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
482        enum StandardHeader {
483            $(
484                $variant,
485            )+
486        }
487
488        $(
489            $(#[$docs])*
490            pub const $constant: HeaderName = HeaderName {
491                inner: HeaderRepr::Standard(StandardHeader::$variant),
492            };
493        )+
494
495        impl StandardHeader {
496            #[inline]
497            fn as_str(&self) -> &'static str {
498                match *self {
499                    $(
500                    StandardHeader::$variant => unsafe { std::str::from_utf8_unchecked( $bytes ) },
501                    )+
502                }
503            }
504
505            const fn from_bytes(bytes: &[u8]) -> Option<StandardHeader> {
506                match bytes {
507                    $(
508                        $bytes => Some(StandardHeader::$variant),
509                    )+
510                    _ => None,
511                }
512            }
513        }
514
515        #[cfg(test)]
516        mod standard_header_tests {
517            use super::HeaderName;
518            use std::str::{self, FromStr};
519
520            const TEST_HEADERS: &'static [(&'static HeaderName, &'static [u8])] = &[
521                $(
522                (&super::$constant, $bytes),
523                )+
524            ];
525
526            #[test]
527            fn from_str() {
528                for &(header, bytes) in TEST_HEADERS {
529                    let utf8 = str::from_utf8(bytes).expect("string constants isn't utf8");
530                    assert_eq!(HeaderName::from_str(utf8).unwrap(), *header);
531                }
532            }
533        }
534    }
535}
536
537// Generate constants for all standard NATS headers.
538standard_headers! {
539    /// The name of the stream the message belongs to.
540    (NatsStream, NATS_STREAM, b"Nats-Stream");
541    /// The sequence number of the message within the stream.
542    (NatsSequence, NATS_SEQUENCE, b"Nats-Sequence");
543    /// The timestamp of when the message was sent.
544    (NatsTimeStamp, NATS_TIME_STAMP, b"Nats-Time-Stamp");
545    /// The subject of the message, used for routing and filtering messages.
546    (NatsSubject, NATS_SUBJECT, b"Nats-Subject");
547    /// A unique identifier for the message.
548    (NatsMessageId, NATS_MESSAGE_ID, b"Nats-Msg-Id");
549    /// The last known stream the message was part of.
550    (NatsLastStream, NATS_LAST_STREAM, b"Nats-Last-Stream");
551    /// The last known consumer that processed the message.
552    (NatsLastConsumer, NATS_LAST_CONSUMER, b"Nats-Last-Consumer");
553    /// The last known sequence number of the message.
554    (NatsLastSequence, NATS_LAST_SEQUENCE, b"Nats-Last-Sequence");
555    /// The expected last sequence number of the subject.
556    (NatsExpectedLastSubjectSequence, NATS_EXPECTED_LAST_SUBJECT_SEQUENCE, b"Nats-Expected-Last-Subject-Sequence");
557    /// The expected last message ID within the stream.
558    (NatsExpectedLastMessageId, NATS_EXPECTED_LAST_MESSAGE_ID, b"Nats-Expected-Last-Msg-Id");
559    /// The expected last sequence number within the stream.
560    (NatsExpectedLastSequence, NATS_EXPECTED_LAST_SEQUENCE, b"Nats-Expected-Last-Sequence");
561    /// The expected stream the message should be part of.
562    (NatsExpectedStream, NATS_EXPECTED_STREAM, b"Nats-Expected-Stream");
563    /// Sets the TTL for a single message.
564    (NatsMessageTtl, NATS_MESSAGE_TTL, b"Nats-TTL");
565    /// Reason why the delete marked on a stream with enabled markers was put.
566    (NatsMarkerReason, NATS_MARKER_REASON, b"Nats-Marker-Reason");
567}
568
569#[derive(Debug, Hash, PartialEq, Eq, Clone)]
570struct CustomHeader {
571    bytes: Bytes,
572}
573
574impl CustomHeader {
575    #[inline]
576    pub(crate) const fn from_static(value: &'static str) -> CustomHeader {
577        CustomHeader {
578            bytes: Bytes::from_static(value.as_bytes()),
579        }
580    }
581
582    #[inline]
583    pub(crate) fn as_str(&self) -> &str {
584        unsafe { std::str::from_utf8_unchecked(self.bytes.as_ref()) }
585    }
586}
587
588impl From<String> for CustomHeader {
589    #[inline]
590    fn from(value: String) -> CustomHeader {
591        CustomHeader {
592            bytes: Bytes::from(value),
593        }
594    }
595}
596
597impl<'a> From<&'a str> for CustomHeader {
598    #[inline]
599    fn from(value: &'a str) -> CustomHeader {
600        CustomHeader {
601            bytes: Bytes::copy_from_slice(value.as_bytes()),
602        }
603    }
604}
605
606#[derive(Debug, Hash, PartialEq, Eq, Clone)]
607enum HeaderRepr {
608    Standard(StandardHeader),
609    Custom(CustomHeader),
610}
611
612/// Defines a NATS header field name
613///
614/// Header field names identify the header. Header sets may include multiple
615/// headers with the same name.
616///
617/// # Representation
618///
619/// `HeaderName` represents standard header names using an `enum`, as such they
620/// will not require an allocation for storage.
621#[derive(Clone, PartialEq, Eq, Hash, Debug)]
622pub struct HeaderName {
623    inner: HeaderRepr,
624}
625
626impl HeaderName {
627    /// Converts a static string to a NATS header name.
628    #[inline]
629    pub const fn from_static(value: &'static str) -> HeaderName {
630        if let Some(standard) = StandardHeader::from_bytes(value.as_bytes()) {
631            return HeaderName {
632                inner: HeaderRepr::Standard(standard),
633            };
634        }
635
636        HeaderName {
637            inner: HeaderRepr::Custom(CustomHeader::from_static(value)),
638        }
639    }
640
641    /// Returns a `str` representation of the header.
642    #[inline]
643    fn as_str(&self) -> &str {
644        match self.inner {
645            HeaderRepr::Standard(v) => v.as_str(),
646            HeaderRepr::Custom(ref v) => v.as_str(),
647        }
648    }
649}
650
651impl FromStr for HeaderName {
652    type Err = ParseHeaderNameError;
653
654    fn from_str(s: &str) -> Result<Self, Self::Err> {
655        if s.contains(|c: char| c == ':' || (c as u8) < 33 || (c as u8) > 126) {
656            return Err(ParseHeaderNameError);
657        }
658
659        match StandardHeader::from_bytes(s.as_ref()) {
660            Some(v) => Ok(HeaderName {
661                inner: HeaderRepr::Standard(v),
662            }),
663            None => Ok(HeaderName {
664                inner: HeaderRepr::Custom(CustomHeader::from(s)),
665            }),
666        }
667    }
668}
669
670impl fmt::Display for HeaderName {
671    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
672        fmt::Display::fmt(&self.as_str(), f)
673    }
674}
675
676impl AsRef<[u8]> for HeaderName {
677    fn as_ref(&self) -> &[u8] {
678        self.as_str().as_bytes()
679    }
680}
681
682impl AsRef<str> for HeaderName {
683    fn as_ref(&self) -> &str {
684        self.as_str()
685    }
686}
687
688impl Serialize for HeaderName {
689    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
690    where
691        S: serde::Serializer,
692    {
693        serializer.serialize_str(self.as_str())
694    }
695}
696
697impl<'de> Deserialize<'de> for HeaderName {
698    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
699    where
700        D: serde::Deserializer<'de>,
701    {
702        String::deserialize(deserializer)?
703            .parse()
704            .map_err(serde::de::Error::custom)
705    }
706}
707
708#[derive(Debug, Clone)]
709pub struct ParseHeaderNameError;
710
711impl std::fmt::Display for ParseHeaderNameError {
712    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
713        write!(f, "invalid header name (name cannot contain non-ascii alphanumeric characters other than '-')")
714    }
715}
716
717impl std::error::Error for ParseHeaderNameError {}
718
719#[cfg(test)]
720mod tests {
721    use super::{HeaderMap, HeaderName, HeaderValue, IntoHeaderName, IntoHeaderValue};
722    use std::str::{from_utf8, FromStr};
723
724    #[test]
725    fn try_from() {
726        let mut headers = HeaderMap::new();
727        headers.insert("name", "something".parse::<HeaderValue>().unwrap());
728        headers.insert("name", "something2");
729    }
730
731    #[test]
732    fn append() {
733        let mut headers = HeaderMap::new();
734        headers.append("Key", "value");
735        headers.append("Key", "second_value");
736
737        let mut result = headers.get_all("Key");
738
739        assert_eq!(
740            result.next().unwrap(),
741            &HeaderValue::from_str("value").unwrap()
742        );
743
744        assert_eq!(
745            result.next().unwrap(),
746            &HeaderValue::from_str("second_value").unwrap()
747        );
748
749        assert_eq!(result.next(), None);
750    }
751
752    #[test]
753    fn get_string() {
754        let mut headers = HeaderMap::new();
755        headers.append("Key", "value");
756        headers.append("Key", "other");
757
758        assert_eq!(headers.get("Key").unwrap().to_string(), "value");
759
760        let key: String = headers.get("Key").unwrap().as_str().into();
761        assert_eq!(key, "value".to_string());
762
763        let key: String = headers.get("Key").unwrap().as_str().to_owned();
764        assert_eq!(key, "value".to_string());
765
766        assert_eq!(headers.get("Key").unwrap().as_str(), "value");
767
768        let key: String = headers.get_last("Key").unwrap().as_str().into();
769        assert_eq!(key, "other".to_string());
770    }
771
772    #[test]
773    fn insert() {
774        let mut headers = HeaderMap::new();
775        headers.insert("Key", "Value");
776
777        let mut result = headers.get_all("Key");
778
779        assert_eq!(
780            result.next().unwrap(),
781            &HeaderValue::from_str("Value").unwrap()
782        );
783        assert_eq!(result.next(), None);
784    }
785
786    #[test]
787    fn serialize() {
788        let mut headers = HeaderMap::new();
789        headers.append("Key", "value");
790        headers.append("Key", "second_value");
791        headers.insert("Second", "SecondValue");
792
793        let bytes = headers.to_bytes();
794
795        println!("bytes: {:?}", from_utf8(&bytes));
796    }
797
798    #[test]
799    fn is_empty() {
800        let mut headers = HeaderMap::new();
801        assert!(headers.is_empty());
802
803        headers.append("Key", "value");
804        headers.append("Key", "second_value");
805        headers.insert("Second", "SecondValue");
806        assert!(!headers.is_empty());
807    }
808
809    #[test]
810    fn parse_value() {
811        assert!("Foo\r".parse::<HeaderValue>().is_err());
812        assert!("Foo\n".parse::<HeaderValue>().is_err());
813        assert!("Foo\r\n".parse::<HeaderValue>().is_err());
814    }
815
816    #[test]
817    fn valid_header_name() {
818        let valid_header_name = "X-Custom-Header";
819        let parsed_header = HeaderName::from_str(valid_header_name);
820
821        assert!(
822            parsed_header.is_ok(),
823            "Expected Ok(HeaderName), but got an error: {:?}",
824            parsed_header.err()
825        );
826    }
827
828    #[test]
829    fn dollar_header_name() {
830        let valid_header_name = "$X_Custom_Header";
831        let parsed_header = HeaderName::from_str(valid_header_name);
832
833        assert!(
834            parsed_header.is_ok(),
835            "Expected Ok(HeaderName), but got an error: {:?}",
836            parsed_header.err()
837        );
838    }
839
840    #[test]
841    fn invalid_header_name_with_space() {
842        let invalid_header_name = "X Custom Header";
843        let parsed_header = HeaderName::from_str(invalid_header_name);
844
845        assert!(
846            parsed_header.is_err(),
847            "Expected Err(InvalidHeaderNameError), but got Ok: {:?}",
848            parsed_header.ok()
849        );
850    }
851
852    #[test]
853    fn invalid_header_name_with_special_chars() {
854        let invalid_header_name = "X-Header:";
855        let parsed_header = HeaderName::from_str(invalid_header_name);
856
857        assert!(
858            parsed_header.is_err(),
859            "Expected Err(InvalidHeaderNameError), but got Ok: {:?}",
860            parsed_header.ok()
861        );
862    }
863
864    #[test]
865    fn from_static_eq() {
866        let a = HeaderName::from_static("NATS-Stream");
867        let b = HeaderName::from_static("NATS-Stream");
868
869        assert_eq!(a, b);
870    }
871
872    #[test]
873    fn header_name_serde() {
874        let raw = "Nats-Stream";
875        let raw_json = "\"Nats-Stream\"";
876        let header = HeaderName::from_static(raw);
877
878        // ser/de of HeaderName should be the same as raw string
879        assert_eq!(serde_json::to_string(&header).unwrap(), raw_json);
880        assert_eq!(
881            serde_json::from_str::<HeaderName>(raw_json).unwrap(),
882            header
883        );
884    }
885
886    #[test]
887    fn header_name_from_string() {
888        let string = "NATS-Stream".to_string();
889        let name = string.into_header_name();
890
891        assert_eq!("NATS-Stream", name.as_str());
892    }
893
894    #[test]
895    fn header_value_from_string_with_trait() {
896        let string = "some value".to_string();
897
898        let value = string.into_header_value();
899
900        assert_eq!("some value", value.as_str());
901    }
902
903    #[test]
904    fn header_value_from_string() {
905        let string = "some value".to_string();
906
907        let value: HeaderValue = string.into();
908
909        assert_eq!("some value", value.as_str());
910    }
911
912    #[test]
913    fn header_map_backward_compatible_deserialization() {
914        // Test new format (direct HashMap) - this is how it should serialize now
915        let new_format_json =
916            r#"{"Content-Type": ["application/json"], "Authorization": ["Bearer token"]}"#;
917        let header_map: HeaderMap = serde_json::from_str(new_format_json).unwrap();
918
919        assert_eq!(
920            header_map.get("Content-Type").unwrap().as_str(),
921            "application/json"
922        );
923        assert_eq!(
924            header_map.get("Authorization").unwrap().as_str(),
925            "Bearer token"
926        );
927
928        // Test legacy format (with "inner" wrapper) - this is the old format that should still work
929        let legacy_format_json = r#"{"inner": {"Content-Type": ["application/json"], "Authorization": ["Bearer token"]}}"#;
930        let header_map_legacy: HeaderMap = serde_json::from_str(legacy_format_json).unwrap();
931
932        assert_eq!(
933            header_map_legacy.get("Content-Type").unwrap().as_str(),
934            "application/json"
935        );
936        assert_eq!(
937            header_map_legacy.get("Authorization").unwrap().as_str(),
938            "Bearer token"
939        );
940
941        // Both should be equal after deserialization
942        assert_eq!(header_map, header_map_legacy);
943    }
944
945    #[test]
946    fn header_map_serialization_new_format() {
947        // Test that serialization uses the new format (no "inner" wrapper)
948        let mut headers = HeaderMap::new();
949        headers.insert("Content-Type", "application/json");
950        headers.insert("Authorization", "Bearer token");
951
952        let serialized = serde_json::to_string(&headers).unwrap();
953
954        // Should not contain "inner" key
955        assert!(!serialized.contains("inner"));
956
957        // Should be able to deserialize back
958        let deserialized: HeaderMap = serde_json::from_str(&serialized).unwrap();
959        assert_eq!(headers, deserialized);
960    }
961
962    #[test]
963    fn header_map_roundtrip_compatibility() {
964        // Test that we can roundtrip both formats
965        let mut original = HeaderMap::new();
966        original.insert("X-Custom-Header", "custom-value");
967        original.append("Multi-Value", "value1");
968        original.append("Multi-Value", "value2");
969
970        // Serialize using new format
971        let new_serialized = serde_json::to_string(&original).unwrap();
972        let new_deserialized: HeaderMap = serde_json::from_str(&new_serialized).unwrap();
973        assert_eq!(original, new_deserialized);
974
975        // Manually create legacy format JSON
976        let legacy_json = format!(r#"{{"inner": {}}}"#, new_serialized);
977        let legacy_deserialized: HeaderMap = serde_json::from_str(&legacy_json).unwrap();
978        assert_eq!(original, legacy_deserialized);
979    }
980
981    #[test]
982    fn header_map_invalid_format_error() {
983        // Test that invalid JSON returns proper error
984        let invalid_json = r#"{"not_inner_or_direct": {"Content-Type": ["application/json"]}}"#;
985        let result = serde_json::from_str::<HeaderMap>(invalid_json);
986        assert!(result.is_err());
987
988        let error_message = result.unwrap_err().to_string();
989        // With untagged enum, serde will report that data doesn't match any variant
990        assert!(error_message.contains("did not match any variant"));
991    }
992
993    #[test]
994    fn header_map_empty_cases() {
995        // Test empty HeaderMap serialization/deserialization
996        let empty = HeaderMap::new();
997        let serialized = serde_json::to_string(&empty).unwrap();
998        assert_eq!(serialized, "{}");
999
1000        let deserialized: HeaderMap = serde_json::from_str("{}").unwrap();
1001        assert!(deserialized.is_empty());
1002
1003        // Test legacy empty format
1004        let legacy_empty = r#"{"inner": {}}"#;
1005        let legacy_deserialized: HeaderMap = serde_json::from_str(legacy_empty).unwrap();
1006        assert!(legacy_deserialized.is_empty());
1007    }
1008
1009    #[test]
1010    fn header_map_mixed_legacy_detection() {
1011        // Test that an "inner" header name doesn't confuse the deserializer
1012        // This would be a new format where "inner" is a legitimate header name
1013        let json_with_inner_header =
1014            r#"{"inner": ["some-value"], "Other-Header": ["other-value"]}"#;
1015        let header_map: HeaderMap = serde_json::from_str(json_with_inner_header).unwrap();
1016
1017        // Should have two headers
1018        assert_eq!(header_map.len(), 2);
1019        assert_eq!(header_map.get("inner").unwrap().as_str(), "some-value");
1020        assert_eq!(
1021            header_map.get("Other-Header").unwrap().as_str(),
1022            "other-value"
1023        );
1024    }
1025
1026    #[test]
1027    fn header_map_large_headers() {
1028        // Test with many headers
1029        let mut headers = HeaderMap::new();
1030        for i in 0..100 {
1031            headers.insert(format!("Header-{}", i), format!("Value-{}", i));
1032        }
1033
1034        let serialized = serde_json::to_string(&headers).unwrap();
1035        let deserialized: HeaderMap = serde_json::from_str(&serialized).unwrap();
1036
1037        assert_eq!(headers.len(), deserialized.len());
1038        for i in 0..100 {
1039            assert_eq!(
1040                deserialized
1041                    .get(format!("Header-{}", i).as_str())
1042                    .unwrap()
1043                    .as_str(),
1044                format!("Value-{}", i)
1045            );
1046        }
1047    }
1048}