sark_http/h1/field/
transfer.rs1use crate::h1::{
2 field::{
3 value,
4 value::{Match, Parser},
5 },
6 framing,
7};
8
9#[derive(Clone, Copy, PartialEq, Eq)]
12pub struct Transfer {
13 codings: u16,
14 last: framing::Transfer,
15}
16
17impl Default for Transfer {
18 fn default() -> Self {
19 Self {
20 codings: 0,
21 last: framing::Transfer::None,
22 }
23 }
24}
25
26impl Transfer {
27 pub fn parse(mut self, value: &[u8]) -> Result<Self, value::Error> {
28 let mut parser = Parser::new(value);
29 parser.skip_ows();
30 if parser.is_done() {
31 return Err(value::Error::Empty);
32 }
33 loop {
34 if matches!(self.last, framing::Transfer::Chunked) {
35 return Err(value::Error::InvalidOrdering);
36 }
37 let coding = if parser.token()?.eq_ignore_ascii_case(b"chunked") {
38 framing::Transfer::Chunked
39 } else {
40 framing::Transfer::Other
41 };
42 parser.skip_ows();
43 let mut param = false;
44 while parser.take(b';') == Match::Taken {
45 param = true;
46 parser.skip_ows();
47 parser.token()?;
48 parser.skip_ows();
49 if parser.take(b'=') == Match::Other {
50 return Err(value::Error::InvalidByte);
51 }
52 parser.skip_ows();
53 parser.item()?;
54 parser.skip_ows();
55 }
56 if matches!(coding, framing::Transfer::Chunked) && param {
57 return Err(value::Error::InvalidByte);
58 }
59 self.codings = self.codings.checked_add(1).ok_or(value::Error::Overflow)?;
60 self.last = coding;
61 if parser.is_done() {
62 return Ok(self);
63 }
64 if parser.take(b',') == Match::Other {
65 return Err(value::Error::InvalidByte);
66 }
67 parser.skip_ows();
68 if parser.is_done() {
69 return Err(value::Error::Empty);
70 }
71 }
72 }
73
74 pub const fn has_encoding(self) -> bool {
75 self.codings != 0
76 }
77
78 pub const fn is_chunked(self) -> bool {
79 matches!(self.last, framing::Transfer::Chunked)
80 }
81
82 pub(in crate::h1) const fn has_other(self) -> bool {
83 self.codings > 1 || matches!(self.last, framing::Transfer::Other)
84 }
85
86 pub const fn framing(self) -> framing::Transfer {
87 self.last
88 }
89
90 pub(crate) fn try_join(self, value: Self) -> Result<Self, value::Error> {
91 if value.codings == 0 {
92 return Err(value::Error::Empty);
93 }
94 if matches!(self.last, framing::Transfer::Chunked) {
95 return Err(value::Error::InvalidOrdering);
96 }
97 let codings = self
98 .codings
99 .checked_add(value.codings)
100 .ok_or(value::Error::Overflow)?;
101 Ok(Self {
102 codings,
103 last: value.last,
104 })
105 }
106}
107
108const _: () = assert!(core::mem::size_of::<Transfer>() <= 4);