Skip to main content

sipx_sip/
message.rs

1//! The message model: requests, responses and their header collection.
2//!
3//! A parsed message borrows the bytes it arrived in. Header entries hold spans into that
4//! buffer, so an unmodified message is written back byte for byte — including original
5//! capitalization, compact forms, the whitespace around each `:`, and line folding.
6//!
7//! That is not fastidiousness. A proxy forwards far more headers than it inspects, and a
8//! stack that normalizes whitespace on the way through breaks signature-bearing headers and
9//! makes every packet capture an exercise in doubt.
10
11use std::borrow::Cow;
12use std::ops::Range;
13
14use bytes::Bytes;
15
16use crate::error::{AddressEditError, HeaderError, WarningEditError};
17use crate::headers::address::{AddressValueSpan, value_spans};
18use crate::headers::grammar::is_token_char;
19use crate::headers::warning::{WarningValueSpan, value_spans as warning_value_spans};
20use crate::name::HeaderName;
21use crate::uri::Uri;
22
23/// A request method.
24///
25/// Comparison is **case-sensitive** (RFC 3261 §7.1): `Invite` is not `INVITE`. Method tokens
26/// may contain any token character, including the ones that look like punctuation — RFC 4475
27/// §3.1.1.2 sends a method built from exclamation marks, percent signs, backticks and
28/// apostrophes, and it is a perfectly legal method.
29#[derive(Debug, Clone, PartialEq, Eq, Hash)]
30pub enum Method {
31    /// `INVITE`
32    Invite,
33    /// `ACK`
34    Ack,
35    /// `BYE`
36    Bye,
37    /// `CANCEL`
38    Cancel,
39    /// `REGISTER`
40    Register,
41    /// `OPTIONS`
42    Options,
43    /// `INFO`
44    Info,
45    /// `PRACK`
46    Prack,
47    /// `UPDATE`
48    Update,
49    /// `SUBSCRIBE`
50    Subscribe,
51    /// `NOTIFY`
52    Notify,
53    /// `REFER`
54    Refer,
55    /// `MESSAGE`
56    Message,
57    /// `PUBLISH`
58    Publish,
59    /// Any other method token, retained verbatim.
60    Other(Bytes),
61}
62
63impl Method {
64    /// Resolve a method token. Never fails: an unknown method is a method.
65    #[must_use]
66    pub fn parse(raw: &Bytes) -> Self {
67        match raw.as_ref() {
68            b"INVITE" => Self::Invite,
69            b"ACK" => Self::Ack,
70            b"BYE" => Self::Bye,
71            b"CANCEL" => Self::Cancel,
72            b"REGISTER" => Self::Register,
73            b"OPTIONS" => Self::Options,
74            b"INFO" => Self::Info,
75            b"PRACK" => Self::Prack,
76            b"UPDATE" => Self::Update,
77            b"SUBSCRIBE" => Self::Subscribe,
78            b"NOTIFY" => Self::Notify,
79            b"REFER" => Self::Refer,
80            b"MESSAGE" => Self::Message,
81            b"PUBLISH" => Self::Publish,
82            _ => Self::Other(raw.clone()),
83        }
84    }
85
86    /// The method token.
87    #[must_use]
88    pub fn as_bytes(&self) -> &[u8] {
89        match self {
90            Self::Invite => b"INVITE",
91            Self::Ack => b"ACK",
92            Self::Bye => b"BYE",
93            Self::Cancel => b"CANCEL",
94            Self::Register => b"REGISTER",
95            Self::Options => b"OPTIONS",
96            Self::Info => b"INFO",
97            Self::Prack => b"PRACK",
98            Self::Update => b"UPDATE",
99            Self::Subscribe => b"SUBSCRIBE",
100            Self::Notify => b"NOTIFY",
101            Self::Refer => b"REFER",
102            Self::Message => b"MESSAGE",
103            Self::Publish => b"PUBLISH",
104            Self::Other(raw) => raw,
105        }
106    }
107}
108
109impl std::fmt::Display for Method {
110    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
111        write!(f, "{}", String::from_utf8_lossy(self.as_bytes()))
112    }
113}
114
115/// The protocol version on a start line.
116#[derive(Debug, Clone, PartialEq, Eq)]
117pub enum Version {
118    /// `SIP/2.0`, the only version sipx speaks.
119    Sip20,
120    /// Any other version. Parsed rather than rejected so the caller can answer 505 rather
121    /// than dropping the message (RFC 4475 §3.1.2.16).
122    Other(Bytes),
123}
124
125impl Version {
126    #[must_use]
127    pub(crate) fn parse(raw: &Bytes) -> Self {
128        // RFC 3261 §7.1: "The SIP-Version string is case-insensitive, but implementations
129        // MUST send upper-case." Serialization stays upper-case; only recognition folds.
130        if raw.eq_ignore_ascii_case(b"SIP/2.0") {
131            Self::Sip20
132        } else {
133            Self::Other(raw.clone())
134        }
135    }
136
137    /// The version token.
138    #[must_use]
139    pub fn as_bytes(&self) -> &[u8] {
140        match self {
141            Self::Sip20 => b"SIP/2.0",
142            Self::Other(raw) => raw,
143        }
144    }
145
146    /// Whether this is a version sipx can act on.
147    #[must_use]
148    pub fn is_supported(&self) -> bool {
149        matches!(self, Self::Sip20)
150    }
151}
152
153/// A response status code, always in `100..=699`.
154#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
155pub struct StatusCode(u16);
156
157impl StatusCode {
158    /// Build a status code, rejecting anything outside `100..=699`.
159    #[must_use]
160    pub fn new(code: u16) -> Option<Self> {
161        (100..=699).contains(&code).then_some(Self(code))
162    }
163
164    /// The numeric code.
165    #[must_use]
166    pub fn code(self) -> u16 {
167        self.0
168    }
169
170    /// The response class: 1 for provisional, 2 for success, and so on.
171    #[must_use]
172    pub fn class(self) -> u16 {
173        self.0 / 100
174    }
175
176    /// Whether this is a provisional (1xx) response.
177    #[must_use]
178    pub fn is_provisional(self) -> bool {
179        self.class() == 1
180    }
181
182    /// Whether this is a final (2xx and above) response.
183    #[must_use]
184    pub fn is_final(self) -> bool {
185        !self.is_provisional()
186    }
187
188    /// Whether this is a success (2xx) response.
189    #[must_use]
190    pub fn is_success(self) -> bool {
191        self.class() == 2
192    }
193}
194
195impl std::fmt::Display for StatusCode {
196    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
197        write!(f, "{}", self.0)
198    }
199}
200
201/// One header field.
202#[derive(Debug, Clone)]
203pub struct Header {
204    name: HeaderName,
205    repr: HeaderRepr,
206}
207
208#[derive(Debug, Clone)]
209enum HeaderRepr {
210    /// Parsed from the wire. `line` is the field exactly as it appeared — name, whatever
211    /// whitespace surrounded the colon, and the value including any folding — but not the
212    /// terminating CRLF. `value_offset` indexes into it.
213    Wire { line: Bytes, value_offset: usize },
214    /// Constructed by this process.
215    Built { value: Bytes },
216}
217
218#[derive(Debug)]
219struct AddressLayout {
220    spans: Vec<AddressValueSpan>,
221    source_map: Vec<Range<usize>>,
222    raw_len: usize,
223}
224
225#[derive(Debug)]
226struct WarningLayout {
227    spans: Vec<WarningValueSpan>,
228    source_map: Vec<Range<usize>>,
229    raw_len: usize,
230}
231
232impl Header {
233    /// Build a header without checking the value.
234    ///
235    /// Crate-private on purpose: the only callers are the parser, which works on bytes that
236    /// were already framed, and the builders in [`crate::build`], which check first. The
237    /// public way to make a header is `Header::build`, and it is fallible.
238    #[must_use]
239    pub(crate) fn new_unchecked(name: HeaderName, value: impl Into<Bytes>) -> Self {
240        Self {
241            name,
242            repr: HeaderRepr::Built {
243                value: value.into(),
244            },
245        }
246    }
247
248    pub(crate) fn from_wire(name: HeaderName, line: Bytes, value_offset: usize) -> Self {
249        Self {
250            name,
251            repr: HeaderRepr::Wire { line, value_offset },
252        }
253    }
254
255    /// The resolved header name.
256    #[must_use]
257    pub fn name(&self) -> &HeaderName {
258        &self.name
259    }
260
261    /// The value exactly as it appeared, folding included.
262    #[must_use]
263    pub fn raw_value(&self) -> &[u8] {
264        match &self.repr {
265            HeaderRepr::Wire { line, value_offset } => line.get(*value_offset..).unwrap_or(&[]),
266            HeaderRepr::Built { value } => value,
267        }
268    }
269
270    /// The value with line folding replaced by single spaces, and surrounding whitespace
271    /// trimmed — the form header grammars are defined against (RFC 3261 §7.3.1).
272    ///
273    /// Borrows when the value contains no folding, which is the common case.
274    #[must_use]
275    pub fn value(&self) -> Cow<'_, [u8]> {
276        let raw = self.raw_value();
277        if raw.iter().any(|&b| b == b'\r' || b == b'\n') {
278            let mut out = Vec::with_capacity(raw.len());
279            let mut i = 0;
280            while let Some(&b) = raw.get(i) {
281                if b == b'\r' && raw.get(i + 1) == Some(&b'\n') {
282                    // A fold: the CRLF and the whitespace run after it collapse to one SP.
283                    let mut j = i + 2;
284                    while matches!(raw.get(j), Some(b' ' | b'\t')) {
285                        j += 1;
286                    }
287                    out.push(b' ');
288                    i = j;
289                } else {
290                    out.push(b);
291                    i += 1;
292                }
293            }
294            Cow::Owned(trim(&out).to_vec())
295        } else {
296            Cow::Borrowed(trim(raw))
297        }
298    }
299
300    /// How many address values this row carries.
301    ///
302    /// The count uses the field's shared address grammar. It is useful for projecting a stable
303    /// wire-order index across repeated rows without decoding or searching for value bytes.
304    pub fn address_value_count(&self) -> Result<usize, AddressEditError> {
305        self.address_layout().map(|layout| layout.spans.len())
306    }
307
308    /// Replace the URI in one address value, indexed within this header row.
309    ///
310    /// Only the parser-owned URI span changes. The display name may contain identical URI bytes;
311    /// it is never considered because this operation consumes grammar ranges rather than searching
312    /// the field. Failures leave the header unchanged.
313    pub fn replace_address_uri(
314        &mut self,
315        value_index: usize,
316        uri: &Uri,
317    ) -> Result<(), AddressEditError> {
318        let encoded = validate_replacement_uri(uri)?;
319        let layout = self.address_layout()?;
320        let span = layout
321            .spans
322            .get(value_index)
323            .ok_or(AddressEditError::IndexOutOfRange { index: value_index })?;
324        let raw_span =
325            project_range(&layout, &span.uri).ok_or_else(|| malformed_address(self.name()))?;
326        let rewritten = self
327            .with_value_span_replaced(&raw_span, &encoded)
328            .ok_or_else(|| malformed_address(self.name()))?;
329        let candidate = rewritten.address_layout()?;
330        if candidate.spans.len() != layout.spans.len() {
331            return Err(malformed_address(self.name()));
332        }
333        let candidate_span = candidate
334            .spans
335            .get(value_index)
336            .ok_or_else(|| malformed_address(self.name()))?;
337        let candidate_raw_span = project_range(&candidate, &candidate_span.uri)
338            .ok_or_else(|| malformed_address(self.name()))?;
339        if rewritten.raw_value().get(candidate_raw_span) != Some(encoded.as_ref()) {
340            return Err(malformed_address(self.name()));
341        }
342        *self = rewritten;
343        Ok(())
344    }
345
346    /// Replace one address's display name, brackets and URI as one parser-owned span.
347    ///
348    /// The replacement always uses unambiguous name-address form. A present display name is
349    /// quoted and escaped here; every byte outside the retained presentation span stays exact.
350    /// Failures leave the header unchanged.
351    pub fn replace_address_presentation(
352        &mut self,
353        value_index: usize,
354        display_name: Option<&str>,
355        uri: &Uri,
356    ) -> Result<(), AddressEditError> {
357        let encoded = encode_address_presentation(display_name, uri)?;
358        let layout = self.address_layout()?;
359        let span = layout
360            .spans
361            .get(value_index)
362            .ok_or(AddressEditError::IndexOutOfRange { index: value_index })?;
363        let raw_span = project_range(&layout, &span.presentation)
364            .ok_or_else(|| malformed_address(self.name()))?;
365        let rewritten = self
366            .with_value_span_replaced(&raw_span, &encoded)
367            .ok_or_else(|| malformed_address(self.name()))?;
368        let candidate = rewritten.address_layout()?;
369        if candidate.spans.len() != layout.spans.len() {
370            return Err(malformed_address(self.name()));
371        }
372        let candidate_span = candidate
373            .spans
374            .get(value_index)
375            .ok_or_else(|| malformed_address(self.name()))?;
376        let candidate_raw_span = project_range(&candidate, &candidate_span.presentation)
377            .ok_or_else(|| malformed_address(self.name()))?;
378        if rewritten.raw_value().get(candidate_raw_span) != Some(encoded.as_ref()) {
379            return Err(malformed_address(self.name()));
380        }
381        *self = rewritten;
382        Ok(())
383    }
384
385    /// How many complete Warning values this row carries.
386    ///
387    /// The count uses the field's shared Warning grammar and therefore rejects an incomplete
388    /// code, missing agent or malformed quoted text instead of counting delimiters locally.
389    pub fn warning_value_count(&self) -> Result<usize, WarningEditError> {
390        self.warning_layout().map(|layout| layout.spans.len())
391    }
392
393    /// Replace one Warning agent with an RFC 3261 token pseudonym.
394    ///
395    /// Only the parser-retained agent range changes. The code, separator spaces, quoted text,
396    /// folding and list layout stay byte-identical. Failures leave the header unchanged.
397    pub fn replace_warning_agent_with_pseudonym(
398        &mut self,
399        value_index: usize,
400        pseudonym: &[u8],
401    ) -> Result<(), WarningEditError> {
402        validate_warning_pseudonym(pseudonym)?;
403        let layout = self.warning_layout()?;
404        let span = layout
405            .spans
406            .get(value_index)
407            .ok_or(WarningEditError::IndexOutOfRange { index: value_index })?;
408        let raw_span = project_source_range(&layout.source_map, layout.raw_len, &span.agent)
409            .ok_or_else(malformed_warning)?;
410        let rewritten = self
411            .with_value_span_replaced(&raw_span, pseudonym)
412            .ok_or_else(malformed_warning)?;
413        let candidate = rewritten.warning_layout()?;
414        if candidate.spans.len() != layout.spans.len() {
415            return Err(malformed_warning());
416        }
417        let candidate_span = candidate
418            .spans
419            .get(value_index)
420            .ok_or_else(malformed_warning)?;
421        let candidate_raw_span = project_source_range(
422            &candidate.source_map,
423            candidate.raw_len,
424            &candidate_span.agent,
425        )
426        .ok_or_else(malformed_warning)?;
427        if rewritten.raw_value().get(candidate_raw_span) != Some(pseudonym) {
428            return Err(malformed_warning());
429        }
430        *self = rewritten;
431        Ok(())
432    }
433
434    /// Return this row with one address value removed.
435    ///
436    /// `Ok(None)` means the selected address was the row's sole value, so the containing header
437    /// collection must remove the field line. Returning a new row keeps this operation atomic and
438    /// gives standalone [`Header`] users an honest representation of row absence.
439    pub fn without_address_value(
440        &self,
441        value_index: usize,
442    ) -> Result<Option<Self>, AddressEditError> {
443        let layout = self.address_layout()?;
444        let selected = layout
445            .spans
446            .get(value_index)
447            .ok_or(AddressEditError::IndexOutOfRange { index: value_index })?;
448        if layout.spans.len() == 1 {
449            return Ok(None);
450        }
451
452        let unfolded = if let Some(next) = layout.spans.get(value_index.saturating_add(1)) {
453            selected.item.start..next.item.start
454        } else {
455            let previous = value_index
456                .checked_sub(1)
457                .and_then(|index| layout.spans.get(index))
458                .ok_or_else(|| malformed_address(self.name()))?;
459            previous.part.end..selected.item.end
460        };
461        let raw_span =
462            project_range(&layout, &unfolded).ok_or_else(|| malformed_address(self.name()))?;
463        self.with_value_span_replaced(&raw_span, &[])
464            .map(Some)
465            .ok_or_else(|| malformed_address(self.name()))
466    }
467
468    fn address_layout(&self) -> Result<AddressLayout, AddressEditError> {
469        let (header, list) = address_grammar(self.name())?;
470        let raw = self.raw_value();
471        let (unfolded, source_map) = unfold_with_source_map(raw);
472        let spans = value_spans(&unfolded, header, list).map_err(AddressEditError::Malformed)?;
473        Ok(AddressLayout {
474            spans,
475            source_map,
476            raw_len: raw.len(),
477        })
478    }
479
480    fn warning_layout(&self) -> Result<WarningLayout, WarningEditError> {
481        if self.name() != &HeaderName::Warning {
482            return Err(malformed_warning());
483        }
484        let raw = self.raw_value();
485        let (unfolded, source_map) = unfold_with_source_map(raw);
486        let spans = warning_value_spans(&unfolded).map_err(WarningEditError::Malformed)?;
487        Ok(WarningLayout {
488            spans,
489            source_map,
490            raw_len: raw.len(),
491        })
492    }
493
494    fn with_value_span_replaced(&self, span: &Range<usize>, replacement: &[u8]) -> Option<Self> {
495        let repr = match &self.repr {
496            HeaderRepr::Wire { line, value_offset } => {
497                let start = value_offset.checked_add(span.start)?;
498                let end = value_offset.checked_add(span.end)?;
499                HeaderRepr::Wire {
500                    line: replace_byte_span(line, &(start..end), replacement)?,
501                    value_offset: *value_offset,
502                }
503            }
504            HeaderRepr::Built { value } => HeaderRepr::Built {
505                value: replace_byte_span(value, span, replacement)?,
506            },
507        };
508        Some(Self {
509            name: self.name.clone(),
510            repr,
511        })
512    }
513
514    /// Write this header as a field line, without the terminating CRLF.
515    pub fn write_to(&self, out: &mut Vec<u8>) {
516        match &self.repr {
517            HeaderRepr::Wire { line, .. } => out.extend_from_slice(line),
518            HeaderRepr::Built { value } => {
519                out.extend_from_slice(self.name.canonical());
520                out.extend_from_slice(b": ");
521                out.extend_from_slice(value);
522            }
523        }
524    }
525}
526
527fn trim(mut b: &[u8]) -> &[u8] {
528    while let Some((first, rest)) = b.split_first() {
529        if matches!(first, b' ' | b'\t') {
530            b = rest;
531        } else {
532            break;
533        }
534    }
535    while let Some((last, rest)) = b.split_last() {
536        if matches!(last, b' ' | b'\t') {
537            b = rest;
538        } else {
539            break;
540        }
541    }
542    b
543}
544
545/// The ordered header collection.
546///
547/// Order is preserved absolutely, including the relative order of same-named headers. `Via`
548/// order determines where a response goes, so nothing here ever sorts or deduplicates.
549#[derive(Debug, Clone, Default)]
550pub struct Headers {
551    entries: Vec<Header>,
552}
553
554impl Headers {
555    /// An empty collection.
556    #[must_use]
557    pub fn new() -> Self {
558        Self::default()
559    }
560
561    /// How many header fields are present.
562    #[must_use]
563    pub fn len(&self) -> usize {
564        self.entries.len()
565    }
566
567    /// Whether there are no headers.
568    #[must_use]
569    pub fn is_empty(&self) -> bool {
570        self.entries.is_empty()
571    }
572
573    /// Append a header, keeping any existing ones of the same name.
574    pub fn push(&mut self, header: Header) {
575        self.entries.push(header);
576    }
577
578    /// Insert a header at the front — where a new `Via` goes.
579    pub fn push_front(&mut self, header: Header) {
580        self.entries.insert(0, header);
581    }
582
583    /// Every header, in wire order.
584    pub fn iter(&self) -> impl Iterator<Item = &Header> {
585        self.entries.iter()
586    }
587
588    /// The first header with this name.
589    #[must_use]
590    pub fn get(&self, name: &HeaderName) -> Option<&Header> {
591        self.entries.iter().find(|h| h.name() == name)
592    }
593
594    /// Every header with this name, in wire order.
595    pub fn get_all<'a>(&'a self, name: &'a HeaderName) -> impl Iterator<Item = &'a Header> {
596        self.entries.iter().filter(move |h| h.name() == name)
597    }
598
599    /// How many headers carry this name.
600    #[must_use]
601    pub fn count(&self, name: &HeaderName) -> usize {
602        self.entries.iter().filter(|h| h.name() == name).count()
603    }
604
605    /// Remove every header with this name, returning how many went.
606    pub fn remove_all(&mut self, name: &HeaderName) -> usize {
607        let before = self.entries.len();
608        self.entries.retain(|h| h.name() != name);
609        before - self.entries.len()
610    }
611
612    /// Remove the **topmost** header with this name and return it.
613    ///
614    /// The one a forwarding element needs constantly: RFC 3261 §16.7 step 2 has a proxy remove the
615    /// topmost `Via` from a response before forwarding it, and §16.6 has it push its own onto a
616    /// request. Order is semantic for `Via`, `Route`, `Record-Route` and `Path` — it *is* the
617    /// routing — so this is an exact position rather than a set operation, and everything else
618    /// keeps its place.
619    pub fn remove_first(&mut self, name: &HeaderName) -> Option<Header> {
620        let index = self.entries.iter().position(|h| h.name() == name)?;
621        Some(self.entries.remove(index))
622    }
623
624    /// Insert a header at an absolute position.
625    ///
626    /// An index past the end **appends** rather than panicking. This crate parses hostile input and
627    /// a caller's index is often derived from it; a panic here would be a remote denial of service
628    /// reachable through arithmetic, which is exactly the class of bug the builders exist to make
629    /// unrepresentable.
630    pub fn insert(&mut self, index: usize, header: Header) {
631        let index = index.min(self.entries.len());
632        self.entries.insert(index, header);
633    }
634
635    /// Keep the headers a predicate accepts, in place and in order.
636    ///
637    /// The general case behind [`Headers::remove_all`], for the filters a forwarding element writes
638    /// that are not "by name" — stripping hop-by-hop headers, dropping a `Route` that names this
639    /// proxy, removing everything a policy did not whitelist.
640    pub fn retain(&mut self, f: impl FnMut(&Header) -> bool) {
641        self.entries.retain(f);
642    }
643
644    /// Replace one address URI by its flattened wire-order value index.
645    ///
646    /// Repeated rows and comma-joined values share one zero-based index space. Every matching row
647    /// is parsed before mutation, so a malformed later row cannot leave a partial edit behind.
648    pub fn replace_address_uri(
649        &mut self,
650        name: &HeaderName,
651        value_index: usize,
652        uri: &Uri,
653    ) -> Result<(), AddressEditError> {
654        address_grammar(name)?;
655        validate_replacement_uri(uri)?;
656        let rows = self.address_rows(name)?;
657        let (entry_index, row_index) = locate_address_value(&rows, value_index)?;
658        let header = self
659            .entries
660            .get_mut(entry_index)
661            .ok_or(AddressEditError::IndexOutOfRange { index: value_index })?;
662        header.replace_address_uri(row_index, uri)
663    }
664
665    /// Replace one address presentation by its flattened wire-order value index.
666    ///
667    /// Repeated rows and comma-joined values share one zero-based index space. Every matching row
668    /// is parsed before mutation, so a malformed later row cannot leave a partial edit behind.
669    pub fn replace_address_presentation(
670        &mut self,
671        name: &HeaderName,
672        value_index: usize,
673        display_name: Option<&str>,
674        uri: &Uri,
675    ) -> Result<(), AddressEditError> {
676        address_grammar(name)?;
677        encode_address_presentation(display_name, uri)?;
678        let rows = self.address_rows(name)?;
679        let (entry_index, row_index) = locate_address_value(&rows, value_index)?;
680        let header = self
681            .entries
682            .get_mut(entry_index)
683            .ok_or(AddressEditError::IndexOutOfRange { index: value_index })?;
684        header.replace_address_presentation(row_index, display_name, uri)
685    }
686
687    /// Replace one Warning agent by its flattened wire-order value index.
688    ///
689    /// Repeated rows and comma-joined values share one zero-based index space. Every Warning row
690    /// is parsed before mutation, so a malformed later row cannot leave a partial edit behind.
691    pub fn replace_warning_agent_with_pseudonym(
692        &mut self,
693        value_index: usize,
694        pseudonym: &[u8],
695    ) -> Result<(), WarningEditError> {
696        validate_warning_pseudonym(pseudonym)?;
697        let rows = self.warning_rows()?;
698        let (entry_index, row_index) = locate_flattened_value(&rows, value_index)
699            .map_err(|()| WarningEditError::IndexOutOfRange { index: value_index })?;
700        let header = self
701            .entries
702            .get_mut(entry_index)
703            .ok_or(WarningEditError::IndexOutOfRange { index: value_index })?;
704        header.replace_warning_agent_with_pseudonym(row_index, pseudonym)
705    }
706
707    /// Remove one address value by its flattened wire-order index.
708    ///
709    /// If it was a row's sole value, that exact field line is removed. Otherwise only the value
710    /// and one adjacent list delimiter are removed; all surviving wire bytes retain their order.
711    pub fn remove_address_value(
712        &mut self,
713        name: &HeaderName,
714        value_index: usize,
715    ) -> Result<(), AddressEditError> {
716        address_grammar(name)?;
717        let rows = self.address_rows(name)?;
718        let (entry_index, row_index) = locate_address_value(&rows, value_index)?;
719        let replacement = self
720            .entries
721            .get(entry_index)
722            .ok_or(AddressEditError::IndexOutOfRange { index: value_index })?
723            .without_address_value(row_index)?;
724        if let Some(header) = replacement {
725            let slot = self
726                .entries
727                .get_mut(entry_index)
728                .ok_or(AddressEditError::IndexOutOfRange { index: value_index })?;
729            *slot = header;
730        } else {
731            self.entries.remove(entry_index);
732        }
733        Ok(())
734    }
735
736    fn address_rows(&self, name: &HeaderName) -> Result<Vec<(usize, usize)>, AddressEditError> {
737        self.entries
738            .iter()
739            .enumerate()
740            .filter(|(_, header)| header.name() == name)
741            .map(|(index, header)| header.address_value_count().map(|count| (index, count)))
742            .collect()
743    }
744
745    fn warning_rows(&self) -> Result<Vec<(usize, usize)>, WarningEditError> {
746        self.entries
747            .iter()
748            .enumerate()
749            .filter(|(_, header)| header.name() == &HeaderName::Warning)
750            .map(|(index, header)| header.warning_value_count().map(|count| (index, count)))
751            .collect()
752    }
753
754    /// The first value with this name, unfolded.
755    #[must_use]
756    pub fn value(&self, name: &HeaderName) -> Option<Cow<'_, [u8]>> {
757        self.get(name).map(Header::value)
758    }
759
760    /// Write every header, each followed by CRLF.
761    pub fn write_to(&self, out: &mut Vec<u8>) {
762        for h in &self.entries {
763            h.write_to(out);
764            out.extend_from_slice(b"\r\n");
765        }
766    }
767}
768
769fn address_grammar(name: &HeaderName) -> Result<(&'static str, bool), AddressEditError> {
770    match name {
771        HeaderName::From => Ok(("From", false)),
772        HeaderName::To => Ok(("To", false)),
773        HeaderName::Contact => Ok(("Contact", true)),
774        HeaderName::Route => Ok(("Route", true)),
775        HeaderName::RecordRoute => Ok(("Record-Route", true)),
776        HeaderName::Path => Ok(("Path", true)),
777        HeaderName::ServiceRoute => Ok(("Service-Route", true)),
778        HeaderName::PAssertedIdentity => Ok(("P-Asserted-Identity", true)),
779        HeaderName::PPreferredIdentity => Ok(("P-Preferred-Identity", true)),
780        _ => Err(AddressEditError::UnsupportedHeader),
781    }
782}
783
784fn malformed_address(name: &HeaderName) -> AddressEditError {
785    let header = address_grammar(name).map_or("address", |(header, _)| header);
786    AddressEditError::Malformed(HeaderError::Syntax { header })
787}
788
789fn malformed_warning() -> WarningEditError {
790    WarningEditError::Malformed(HeaderError::Syntax { header: "Warning" })
791}
792
793fn validate_warning_pseudonym(pseudonym: &[u8]) -> Result<(), WarningEditError> {
794    if pseudonym.is_empty() || !pseudonym.iter().copied().all(is_token_char) {
795        return Err(WarningEditError::InvalidPseudonym);
796    }
797    Ok(())
798}
799
800fn validate_replacement_uri(uri: &Uri) -> Result<Bytes, AddressEditError> {
801    let encoded = uri.to_bytes();
802    Uri::parse(encoded.clone()).map_err(AddressEditError::InvalidUri)?;
803    Ok(encoded)
804}
805
806fn encode_address_presentation(
807    display_name: Option<&str>,
808    uri: &Uri,
809) -> Result<Bytes, AddressEditError> {
810    let uri = validate_replacement_uri(uri)?;
811    let mut encoded = Vec::new();
812    if let Some(display_name) = display_name {
813        if display_name
814            .as_bytes()
815            .iter()
816            .any(|byte| *byte < 0x20 || *byte == 0x7f)
817        {
818            return Err(AddressEditError::InvalidDisplayName);
819        }
820        encoded.push(b'"');
821        for byte in display_name.as_bytes() {
822            if matches!(byte, b'"' | b'\\') {
823                encoded.push(b'\\');
824            }
825            encoded.push(*byte);
826        }
827        encoded.extend_from_slice(b"\" ");
828    }
829    encoded.push(b'<');
830    encoded.extend_from_slice(&uri);
831    encoded.push(b'>');
832    Ok(Bytes::from(encoded))
833}
834
835fn locate_address_value(
836    rows: &[(usize, usize)],
837    value_index: usize,
838) -> Result<(usize, usize), AddressEditError> {
839    locate_flattened_value(rows, value_index)
840        .map_err(|()| AddressEditError::IndexOutOfRange { index: value_index })
841}
842
843fn locate_flattened_value(
844    rows: &[(usize, usize)],
845    value_index: usize,
846) -> Result<(usize, usize), ()> {
847    let mut first = 0usize;
848    for &(entry_index, count) in rows {
849        let end = first.checked_add(count).ok_or(())?;
850        if value_index < end {
851            return Ok((entry_index, value_index - first));
852        }
853        first = end;
854    }
855    Err(())
856}
857
858fn unfold_with_source_map(raw: &[u8]) -> (Vec<u8>, Vec<Range<usize>>) {
859    let mut unfolded = Vec::with_capacity(raw.len());
860    let mut source_map = Vec::with_capacity(raw.len());
861    let mut i = 0usize;
862    while let Some(&byte) = raw.get(i) {
863        if byte == b'\r'
864            && raw.get(i + 1) == Some(&b'\n')
865            && matches!(raw.get(i + 2), Some(b' ' | b'\t'))
866        {
867            let mut end = i + 2;
868            while matches!(raw.get(end), Some(b' ' | b'\t')) {
869                end += 1;
870            }
871            unfolded.push(b' ');
872            source_map.push(i..end);
873            i = end;
874        } else {
875            unfolded.push(byte);
876            source_map.push(i..i + 1);
877            i += 1;
878        }
879    }
880    (unfolded, source_map)
881}
882
883fn project_range(layout: &AddressLayout, span: &Range<usize>) -> Option<Range<usize>> {
884    project_source_range(&layout.source_map, layout.raw_len, span)
885}
886
887fn project_source_range(
888    source_map: &[Range<usize>],
889    raw_len: usize,
890    span: &Range<usize>,
891) -> Option<Range<usize>> {
892    if span.start > span.end || span.end > source_map.len() {
893        return None;
894    }
895    let start = source_boundary(source_map, raw_len, span.start)?;
896    let end = source_boundary(source_map, raw_len, span.end)?;
897    (start <= end).then_some(start..end)
898}
899
900fn source_boundary(source_map: &[Range<usize>], raw_len: usize, position: usize) -> Option<usize> {
901    if position == source_map.len() {
902        Some(raw_len)
903    } else {
904        source_map.get(position).map(|source| source.start)
905    }
906}
907
908/// A parsed request.
909#[derive(Debug, Clone)]
910pub struct Request {
911    /// The method.
912    pub method: Method,
913    /// The Request-URI.
914    ///
915    /// Use [`Request::set_uri`] to mutate this value. Assigning the field directly cannot update
916    /// the parser-retained start-line span and would replay stale wire bytes.
917    pub uri: Uri,
918    /// The protocol version.
919    pub version: Version,
920    /// The headers, in wire order.
921    pub headers: Headers,
922    body: Bytes,
923    raw_start_line: Option<Bytes>,
924    raw_uri_span: Option<Range<usize>>,
925}
926
927/// A parsed response.
928#[derive(Debug, Clone)]
929pub struct Response {
930    /// The protocol version.
931    pub version: Version,
932    /// The status code.
933    pub status: StatusCode,
934    /// The reason phrase, which may be empty (RFC 4475 §3.1.1.13) and may contain spaces.
935    pub reason: Bytes,
936    /// The headers, in wire order.
937    pub headers: Headers,
938    body: Bytes,
939    raw_start_line: Option<Bytes>,
940}
941
942/// A request or a response.
943#[derive(Debug, Clone)]
944pub enum Message {
945    /// A request.
946    Request(Request),
947    /// A response.
948    Response(Response),
949}
950
951impl Request {
952    pub(crate) fn from_wire(
953        method: Method,
954        uri: Uri,
955        version: Version,
956        raw_start_line: Bytes,
957        raw_uri_span: Range<usize>,
958        headers: Headers,
959        body: Bytes,
960    ) -> Self {
961        Self {
962            method,
963            uri,
964            version,
965            headers,
966            body,
967            raw_start_line: Some(raw_start_line),
968            raw_uri_span: Some(raw_uri_span),
969        }
970    }
971
972    /// Replace the Request-URI without rebuilding a parsed start line.
973    ///
974    /// Retargeting logic must use this rather than assigning the public field directly. For a
975    /// parsed request, only the parser-owned URI span changes; method spelling, separators and
976    /// SIP-version bytes stay exact. Constructed requests retain deterministic serialization.
977    /// The replacement is validated from its serialized bytes before either representation is
978    /// changed, so a failure is atomic.
979    pub fn set_uri(&mut self, uri: Uri) -> Result<(), crate::error::UriError> {
980        let encoded = uri.to_bytes();
981        Uri::parse(encoded.clone())?;
982
983        let rewritten = match (&self.raw_start_line, &self.raw_uri_span) {
984            (Some(raw), Some(span)) => Some(
985                replace_byte_span(raw, span, &encoded)
986                    .ok_or(crate::error::UriError::RetainedSpan)?,
987            ),
988            (None, None) => None,
989            _ => return Err(crate::error::UriError::RetainedSpan),
990        };
991
992        if let Some(raw) = rewritten {
993            let start = self
994                .raw_uri_span
995                .as_ref()
996                .map(|span| span.start)
997                .ok_or(crate::error::UriError::RetainedSpan)?;
998            let end = start
999                .checked_add(encoded.len())
1000                .ok_or(crate::error::UriError::RetainedSpan)?;
1001            self.raw_start_line = Some(raw);
1002            self.raw_uri_span = Some(start..end);
1003        } else {
1004            self.raw_start_line = None;
1005            self.raw_uri_span = None;
1006        }
1007        self.uri = uri;
1008        Ok(())
1009    }
1010
1011    /// Build a request.
1012    #[must_use]
1013    pub fn new(method: Method, uri: Uri) -> Self {
1014        Self {
1015            method,
1016            uri,
1017            version: Version::Sip20,
1018            headers: Headers::new(),
1019            body: Bytes::new(),
1020            raw_start_line: None,
1021            raw_uri_span: None,
1022        }
1023    }
1024
1025    /// The message body.
1026    #[must_use]
1027    pub fn body(&self) -> &Bytes {
1028        &self.body
1029    }
1030
1031    /// Replace the body. The caller is responsible for `Content-Length`.
1032    pub fn set_body(&mut self, body: Bytes) {
1033        self.body = body;
1034    }
1035
1036    /// Serialize.
1037    pub fn write_to(&self, out: &mut Vec<u8>) {
1038        if let Some(raw) = &self.raw_start_line {
1039            out.extend_from_slice(raw);
1040        } else {
1041            out.extend_from_slice(self.method.as_bytes());
1042            out.push(b' ');
1043            self.uri.write_to(out);
1044            out.push(b' ');
1045            out.extend_from_slice(self.version.as_bytes());
1046        }
1047        out.extend_from_slice(b"\r\n");
1048        self.headers.write_to(out);
1049        out.extend_from_slice(b"\r\n");
1050        out.extend_from_slice(&self.body);
1051    }
1052}
1053
1054fn replace_byte_span(source: &Bytes, span: &Range<usize>, replacement: &[u8]) -> Option<Bytes> {
1055    let prefix = source.get(..span.start)?;
1056    let suffix = source.get(span.end..)?;
1057    let capacity = prefix
1058        .len()
1059        .checked_add(replacement.len())?
1060        .checked_add(suffix.len())?;
1061    let mut out = Vec::with_capacity(capacity);
1062    out.extend_from_slice(prefix);
1063    out.extend_from_slice(replacement);
1064    out.extend_from_slice(suffix);
1065    Some(Bytes::from(out))
1066}
1067
1068impl Response {
1069    pub(crate) fn from_wire(
1070        version: Version,
1071        status: StatusCode,
1072        reason: Bytes,
1073        raw_start_line: Bytes,
1074        headers: Headers,
1075        body: Bytes,
1076    ) -> Self {
1077        Self {
1078            version,
1079            status,
1080            reason,
1081            headers,
1082            body,
1083            raw_start_line: Some(raw_start_line),
1084        }
1085    }
1086
1087    /// Build a response.
1088    #[must_use]
1089    pub fn new(status: StatusCode, reason: impl Into<Bytes>) -> Self {
1090        Self {
1091            version: Version::Sip20,
1092            status,
1093            reason: reason.into(),
1094            headers: Headers::new(),
1095            body: Bytes::new(),
1096            raw_start_line: None,
1097        }
1098    }
1099
1100    /// The message body.
1101    #[must_use]
1102    pub fn body(&self) -> &Bytes {
1103        &self.body
1104    }
1105
1106    /// Replace the body. The caller is responsible for `Content-Length`.
1107    pub fn set_body(&mut self, body: Bytes) {
1108        self.body = body;
1109    }
1110
1111    /// Serialize.
1112    pub fn write_to(&self, out: &mut Vec<u8>) {
1113        if let Some(raw) = &self.raw_start_line {
1114            out.extend_from_slice(raw);
1115        } else {
1116            out.extend_from_slice(self.version.as_bytes());
1117            out.push(b' ');
1118            out.extend_from_slice(self.status.to_string().as_bytes());
1119            out.push(b' ');
1120            out.extend_from_slice(&self.reason);
1121        }
1122        out.extend_from_slice(b"\r\n");
1123        self.headers.write_to(out);
1124        out.extend_from_slice(b"\r\n");
1125        out.extend_from_slice(&self.body);
1126    }
1127}
1128
1129impl Message {
1130    /// The headers, whichever kind of message this is.
1131    #[must_use]
1132    pub fn headers(&self) -> &Headers {
1133        match self {
1134            Self::Request(r) => &r.headers,
1135            Self::Response(r) => &r.headers,
1136        }
1137    }
1138
1139    /// The headers, mutably.
1140    pub fn headers_mut(&mut self) -> &mut Headers {
1141        match self {
1142            Self::Request(r) => &mut r.headers,
1143            Self::Response(r) => &mut r.headers,
1144        }
1145    }
1146
1147    /// The body.
1148    #[must_use]
1149    pub fn body(&self) -> &Bytes {
1150        match self {
1151            Self::Request(r) => r.body(),
1152            Self::Response(r) => r.body(),
1153        }
1154    }
1155
1156    /// The request, if this is one.
1157    #[must_use]
1158    pub fn as_request(&self) -> Option<&Request> {
1159        match self {
1160            Self::Request(r) => Some(r),
1161            Self::Response(_) => None,
1162        }
1163    }
1164
1165    /// The response, if this is one.
1166    #[must_use]
1167    pub fn as_response(&self) -> Option<&Response> {
1168        match self {
1169            Self::Response(r) => Some(r),
1170            Self::Request(_) => None,
1171        }
1172    }
1173
1174    /// Serialize.
1175    pub fn write_to(&self, out: &mut Vec<u8>) {
1176        match self {
1177            Self::Request(r) => r.write_to(out),
1178            Self::Response(r) => r.write_to(out),
1179        }
1180    }
1181
1182    /// Serialize to bytes.
1183    ///
1184    /// A parsed, unmodified message reproduces its input exactly.
1185    #[must_use]
1186    pub fn to_bytes(&self) -> Bytes {
1187        let mut out = Vec::new();
1188        self.write_to(&mut out);
1189        Bytes::from(out)
1190    }
1191}
1192
1193/// A header value that parses into a typed form.
1194pub trait TypedHeader: Sized {
1195    /// The header this type reads.
1196    const NAME: HeaderName;
1197
1198    /// Whether [`Headers::typed_all`] must collect and validate the complete field before yielding.
1199    ///
1200    /// The default keeps ordinary headers streaming and allocation-free across rows. A field with
1201    /// message-wide constraints opts in and implements [`Self::validate_list`].
1202    const VALIDATE_LIST: bool = false;
1203
1204    /// Parse one header value. The value arrives unfolded and trimmed.
1205    fn decode(value: &[u8]) -> Result<Self, HeaderError>;
1206
1207    /// Parse every value in one header row.
1208    ///
1209    /// RFC 3261 §7.3 makes a comma-joined row exactly equivalent to the same values on
1210    /// separate rows for headers whose grammar is a comma-separated list; those headers
1211    /// override this. Everything else carries exactly one value per row.
1212    fn decode_list(value: &[u8]) -> Result<Vec<Self>, HeaderError> {
1213        Self::decode(value).map(|one| vec![one])
1214    }
1215
1216    /// Validate all decoded values of this field across the complete message.
1217    ///
1218    /// Most SIP list fields have no message-wide constraint, so the default accepts every
1219    /// sequence. A field whose grammar constrains the number or relationship of values can
1220    /// override this; [`Headers::typed_all`] calls it after expanding every comma-separated row
1221    /// and repeated field line into wire order.
1222    fn validate_list(_values: &[&Self]) -> Result<(), HeaderError> {
1223        Ok(())
1224    }
1225}
1226
1227struct TypedAll<'a, H: TypedHeader> {
1228    entries: std::slice::Iter<'a, Header>,
1229    row: std::vec::IntoIter<H>,
1230    validated: Option<std::vec::IntoIter<Result<H, HeaderError>>>,
1231}
1232
1233impl<'a, H: TypedHeader> TypedAll<'a, H> {
1234    fn new(headers: &'a Headers) -> Self {
1235        let validated = H::VALIDATE_LIST.then(|| {
1236            let mut decoded: Vec<Result<H, HeaderError>> = headers
1237                .entries
1238                .iter()
1239                .filter(|header| header.name() == &H::NAME)
1240                .flat_map(|header| match H::decode_list(&header.value()) {
1241                    Ok(values) => values.into_iter().map(Ok).collect::<Vec<_>>(),
1242                    Err(error) => vec![Err(error)],
1243                })
1244                .collect();
1245
1246            // A constrained field is useful only as one complete validated value. Collapse any
1247            // row-level failure before yielding so a caller cannot observe neighboring elements
1248            // that never passed the field-wide relationship. An empty iterator still means
1249            // absence rather than an empty field value.
1250            let decode_error = decoded.iter().find_map(|result| match result {
1251                Ok(_) => None,
1252                Err(error) => Some(error.clone()),
1253            });
1254            if let Some(error) = decode_error {
1255                decoded = vec![Err(error)];
1256            } else if !decoded.is_empty() {
1257                let values: Vec<&H> = decoded
1258                    .iter()
1259                    .filter_map(|result| result.as_ref().ok())
1260                    .collect();
1261                if let Err(error) = H::validate_list(&values) {
1262                    decoded = vec![Err(error)];
1263                }
1264            }
1265            decoded.into_iter()
1266        });
1267
1268        Self {
1269            entries: headers.entries.iter(),
1270            row: Vec::new().into_iter(),
1271            validated,
1272        }
1273    }
1274}
1275
1276impl<H: TypedHeader> Iterator for TypedAll<'_, H> {
1277    type Item = Result<H, HeaderError>;
1278
1279    fn next(&mut self) -> Option<Self::Item> {
1280        if let Some(validated) = &mut self.validated {
1281            return validated.next();
1282        }
1283
1284        loop {
1285            if let Some(value) = self.row.next() {
1286                return Some(Ok(value));
1287            }
1288            let header = self.entries.find(|header| header.name() == &H::NAME)?;
1289            match H::decode_list(&header.value()) {
1290                Ok(values) => self.row = values.into_iter(),
1291                Err(error) => return Some(Err(error)),
1292            }
1293        }
1294    }
1295}
1296
1297impl Headers {
1298    /// Parse the first header of this type.
1299    ///
1300    /// Returns `None` when the header is absent and `Some(Err(..))` when it is present and
1301    /// malformed. Collapsing those two is how implementations end up treating a corrupt
1302    /// `CSeq` as a missing one.
1303    #[must_use]
1304    pub fn typed<H: TypedHeader>(&self) -> Option<Result<H, HeaderError>> {
1305        self.get(&H::NAME).map(|h| H::decode(&h.value()))
1306    }
1307
1308    /// Parse every header of this type, in wire order, yielding each element of a
1309    /// comma-separated row separately — one row of `n` values and `n` rows of one value are
1310    /// the same message (RFC 3261 §7.3).
1311    pub fn typed_all<'a, H: TypedHeader + 'a>(
1312        &'a self,
1313    ) -> impl Iterator<Item = Result<H, HeaderError>> + 'a {
1314        TypedAll::new(self)
1315    }
1316}
1317
1318#[cfg(test)]
1319#[allow(
1320    clippy::unwrap_used,
1321    clippy::expect_used,
1322    clippy::panic,
1323    clippy::indexing_slicing
1324)]
1325mod tests {
1326    use super::*;
1327
1328    #[test]
1329    fn unfolding_collapses_continuations_to_a_single_space() {
1330        let line = Bytes::from_static(b"Subject: one\r\n  two\r\n\tthree");
1331        let h = Header::from_wire(HeaderName::Subject, line, 9);
1332        assert_eq!(h.value().as_ref(), b"one two three");
1333        // The raw form keeps the folding, so forwarding is byte-exact.
1334        assert_eq!(h.raw_value(), b"one\r\n  two\r\n\tthree");
1335    }
1336
1337    #[test]
1338    fn unfolded_value_borrows_when_there_is_no_folding() {
1339        let line = Bytes::from_static(b"Subject: plain");
1340        let h = Header::from_wire(HeaderName::Subject, line, 9);
1341        assert!(matches!(h.value(), Cow::Borrowed(_)));
1342    }
1343
1344    #[test]
1345    fn status_code_range_is_enforced() {
1346        assert!(StatusCode::new(99).is_none());
1347        assert!(StatusCode::new(700).is_none());
1348        assert_eq!(StatusCode::new(200).map(StatusCode::code), Some(200));
1349        assert!(StatusCode::new(180).unwrap().is_provisional());
1350        assert!(StatusCode::new(200).unwrap().is_success());
1351        assert!(StatusCode::new(486).unwrap().is_final());
1352    }
1353
1354    #[test]
1355    fn methods_compare_case_sensitively() {
1356        // RFC 3261 7.1: method names are case-sensitive, so this is a different method and
1357        // not a sloppy spelling of INVITE.
1358        assert_ne!(
1359            Method::parse(&Bytes::from_static(b"Invite")),
1360            Method::Invite
1361        );
1362        assert_eq!(
1363            Method::parse(&Bytes::from_static(b"INVITE")),
1364            Method::Invite
1365        );
1366    }
1367
1368    /// The story's failing-first test.
1369    ///
1370    /// RFC 3261 §16.7 step 2 has a proxy remove the topmost `Via` from a response and forward what
1371    /// is left. "Topmost" is exact: removing the wrong one, or removing all of them, sends the
1372    /// response to the wrong element or to nowhere.
1373    #[test]
1374    fn remove_first_takes_only_the_topmost_via() {
1375        let mut headers = Headers::new();
1376        for value in [&b"first"[..], b"second", b"third"] {
1377            headers.push(Header::new_unchecked(
1378                HeaderName::Via,
1379                Bytes::copy_from_slice(value),
1380            ));
1381        }
1382        // A header of another name between them, to catch an implementation that counts positions
1383        // among matching headers rather than among all of them.
1384        headers.insert(
1385            1,
1386            Header::new_unchecked(HeaderName::Route, Bytes::from_static(b"r")),
1387        );
1388
1389        let taken = headers.remove_first(&HeaderName::Via).expect("a Via");
1390        assert_eq!(taken.value().as_ref(), b"first");
1391        assert_eq!(
1392            headers
1393                .get_all(&HeaderName::Via)
1394                .map(|h| h.value().to_vec())
1395                .collect::<Vec<_>>(),
1396            vec![b"second".to_vec(), b"third".to_vec()],
1397            "the remaining Vias keep their order"
1398        );
1399        assert_eq!(
1400            headers.iter().map(|h| h.name().clone()).collect::<Vec<_>>(),
1401            vec![HeaderName::Route, HeaderName::Via, HeaderName::Via],
1402            "and every other header stays where it was"
1403        );
1404    }
1405
1406    #[test]
1407    fn remove_first_on_a_name_that_is_absent_yields_nothing_and_changes_nothing() {
1408        let mut headers = Headers::new();
1409        headers.push(Header::new_unchecked(
1410            HeaderName::Via,
1411            Bytes::from_static(b"v"),
1412        ));
1413        assert!(headers.remove_first(&HeaderName::Route).is_none());
1414        assert_eq!(headers.len(), 1);
1415    }
1416
1417    /// An index past the end appends. This crate parses hostile input, and a caller's index is
1418    /// often derived from it — a panic here would be a remote denial of service reachable through
1419    /// arithmetic.
1420    #[test]
1421    fn inserting_past_the_end_appends_rather_than_panicking() {
1422        let mut headers = Headers::new();
1423        headers.push(Header::new_unchecked(
1424            HeaderName::Via,
1425            Bytes::from_static(b"v"),
1426        ));
1427        headers.insert(
1428            9999,
1429            Header::new_unchecked(HeaderName::Route, Bytes::from_static(b"r")),
1430        );
1431        assert_eq!(headers.len(), 2);
1432        assert_eq!(
1433            headers.iter().last().map(|h| h.name().clone()),
1434            Some(HeaderName::Route)
1435        );
1436    }
1437
1438    #[test]
1439    fn insert_places_a_header_at_an_absolute_position() {
1440        let mut headers = Headers::new();
1441        for name in [HeaderName::Via, HeaderName::To, HeaderName::From] {
1442            headers.push(Header::new_unchecked(name, Bytes::from_static(b"x")));
1443        }
1444        headers.insert(
1445            1,
1446            Header::new_unchecked(HeaderName::RecordRoute, Bytes::from_static(b"rr")),
1447        );
1448        assert_eq!(
1449            headers.iter().map(|h| h.name().clone()).collect::<Vec<_>>(),
1450            vec![
1451                HeaderName::Via,
1452                HeaderName::RecordRoute,
1453                HeaderName::To,
1454                HeaderName::From
1455            ]
1456        );
1457        // Zero is the front, which is `push_front`.
1458        headers.insert(
1459            0,
1460            Header::new_unchecked(HeaderName::Via, Bytes::from_static(b"newest")),
1461        );
1462        assert_eq!(headers.value(&HeaderName::Via).unwrap().as_ref(), b"newest");
1463    }
1464
1465    /// The general case behind `remove_all`: a filter that is not "by name".
1466    #[test]
1467    fn retain_filters_in_place_and_keeps_order() {
1468        let mut headers = Headers::new();
1469        for (name, value) in [
1470            (HeaderName::Via, &b"keep"[..]),
1471            (HeaderName::Route, b"drop"),
1472            (HeaderName::Via, b"drop"),
1473            (HeaderName::To, b"keep"),
1474        ] {
1475            headers.push(Header::new_unchecked(name, Bytes::copy_from_slice(value)));
1476        }
1477        headers.retain(|header| header.value().as_ref() == b"keep");
1478        assert_eq!(
1479            headers.iter().map(|h| h.name().clone()).collect::<Vec<_>>(),
1480            vec![HeaderName::Via, HeaderName::To]
1481        );
1482    }
1483
1484    #[test]
1485    fn header_order_is_preserved_including_duplicates() {
1486        let mut headers = Headers::new();
1487        headers.push(Header::new_unchecked(
1488            HeaderName::Via,
1489            Bytes::from_static(b"first"),
1490        ));
1491        headers.push(Header::new_unchecked(
1492            HeaderName::Route,
1493            Bytes::from_static(b"r"),
1494        ));
1495        headers.push(Header::new_unchecked(
1496            HeaderName::Via,
1497            Bytes::from_static(b"second"),
1498        ));
1499
1500        let vias: Vec<_> = headers
1501            .get_all(&HeaderName::Via)
1502            .map(|h| h.value().to_vec())
1503            .collect();
1504        assert_eq!(vias, vec![b"first".to_vec(), b"second".to_vec()]);
1505        assert_eq!(headers.count(&HeaderName::Via), 2);
1506
1507        // A new Via goes on the front, ahead of everything.
1508        headers.push_front(Header::new_unchecked(
1509            HeaderName::Via,
1510            Bytes::from_static(b"newest"),
1511        ));
1512        assert_eq!(headers.value(&HeaderName::Via).unwrap().as_ref(), b"newest");
1513    }
1514
1515    /// RFC 3261 §7.3: `Contact: <a>, <b>` and two `Contact` rows are the same message, so
1516    /// iterating the typed values must yield the same elements either way.
1517    #[test]
1518    fn typed_all_yields_each_element_of_a_comma_separated_row() {
1519        use crate::headers::Contact;
1520
1521        let mut headers = Headers::new();
1522        headers.push(Header::new_unchecked(
1523            HeaderName::Contact,
1524            Bytes::from_static(b"<sip:a@b.com>, <sip:c@d.com>"),
1525        ));
1526        headers.push(Header::new_unchecked(
1527            HeaderName::Contact,
1528            Bytes::from_static(b"<sip:e@f.org>"),
1529        ));
1530
1531        let contacts: Vec<Contact> = headers
1532            .typed_all::<Contact>()
1533            .collect::<Result<_, _>>()
1534            .unwrap();
1535        let uris: Vec<_> = contacts.iter().map(|c| c.uri.to_bytes()).collect();
1536        assert_eq!(
1537            uris,
1538            vec![
1539                Bytes::from_static(b"sip:a@b.com"),
1540                Bytes::from_static(b"sip:c@d.com"),
1541                Bytes::from_static(b"sip:e@f.org"),
1542            ]
1543        );
1544    }
1545
1546    #[test]
1547    fn typed_all_keeps_unconstrained_headers_lazy() {
1548        use std::sync::atomic::{AtomicUsize, Ordering};
1549
1550        static DECODES: AtomicUsize = AtomicUsize::new(0);
1551
1552        struct CountingSubject;
1553
1554        impl TypedHeader for CountingSubject {
1555            const NAME: HeaderName = HeaderName::Subject;
1556
1557            fn decode(_value: &[u8]) -> Result<Self, HeaderError> {
1558                DECODES.fetch_add(1, Ordering::SeqCst);
1559                Ok(Self)
1560            }
1561        }
1562
1563        DECODES.store(0, Ordering::SeqCst);
1564        let mut headers = Headers::new();
1565        headers.push(Header::new_unchecked(
1566            HeaderName::Subject,
1567            Bytes::from_static(b"first"),
1568        ));
1569        headers.push(Header::new_unchecked(
1570            HeaderName::Subject,
1571            Bytes::from_static(b"second"),
1572        ));
1573
1574        let mut values = headers.typed_all::<CountingSubject>();
1575        assert_eq!(DECODES.load(Ordering::SeqCst), 0);
1576        assert!(values.next().is_some_and(|value| value.is_ok()));
1577        assert_eq!(DECODES.load(Ordering::SeqCst), 1);
1578        drop(values);
1579        assert_eq!(DECODES.load(Ordering::SeqCst), 1);
1580    }
1581
1582    #[test]
1583    fn built_headers_serialize_canonically() {
1584        let mut headers = Headers::new();
1585        headers.push(Header::new_unchecked(
1586            HeaderName::MaxForwards,
1587            Bytes::from_static(b"70"),
1588        ));
1589        let mut out = Vec::new();
1590        headers.write_to(&mut out);
1591        assert_eq!(out, b"Max-Forwards: 70\r\n");
1592    }
1593
1594    #[test]
1595    fn wire_headers_serialize_verbatim() {
1596        // Original spelling, compact form and odd spacing all survive.
1597        let line = Bytes::from_static(b"MaX-fOrWaRdS  :   0068");
1598        let h = Header::from_wire(HeaderName::MaxForwards, line.clone(), 17);
1599        let mut out = Vec::new();
1600        h.write_to(&mut out);
1601        assert_eq!(out, line);
1602        assert_eq!(h.value().as_ref(), b"0068");
1603    }
1604}