hyperx/header/common/
content_range.rs1use std::fmt::{self, Display};
2use std::str::FromStr;
3
4header! {
5 (ContentRange, "Content-Range") => [ContentRangeSpec]
8
9 test_content_range {
10 test_header!(test_bytes,
11 vec![b"bytes 0-499/500"],
12 Some(ContentRange(ContentRangeSpec::Bytes {
13 range: Some((0, 499)),
14 instance_length: Some(500)
15 })));
16
17 test_header!(test_bytes_unknown_len,
18 vec![b"bytes 0-499/*"],
19 Some(ContentRange(ContentRangeSpec::Bytes {
20 range: Some((0, 499)),
21 instance_length: None
22 })));
23
24 test_header!(test_bytes_unknown_range,
25 vec![b"bytes */500"],
26 Some(ContentRange(ContentRangeSpec::Bytes {
27 range: None,
28 instance_length: Some(500)
29 })));
30
31 test_header!(test_unregistered,
32 vec![b"seconds 1-2"],
33 Some(ContentRange(ContentRangeSpec::Unregistered {
34 unit: "seconds".to_owned(),
35 resp: "1-2".to_owned()
36 })));
37
38 test_header!(test_no_len,
39 vec![b"bytes 0-499"],
40 None::<ContentRange>);
41
42 test_header!(test_only_unit,
43 vec![b"bytes"],
44 None::<ContentRange>);
45
46 test_header!(test_end_less_than_start,
47 vec![b"bytes 499-0/500"],
48 None::<ContentRange>);
49
50 test_header!(test_blank,
51 vec![b""],
52 None::<ContentRange>);
53
54 test_header!(test_bytes_many_spaces,
55 vec![b"bytes 1-2/500 3"],
56 None::<ContentRange>);
57
58 test_header!(test_bytes_many_slashes,
59 vec![b"bytes 1-2/500/600"],
60 None::<ContentRange>);
61
62 test_header!(test_bytes_many_dashes,
63 vec![b"bytes 1-2-3/500"],
64 None::<ContentRange>);
65
66 }
67}
68
69#[derive(PartialEq, Clone, Debug)]
90pub enum ContentRangeSpec {
91 Bytes {
93 range: Option<(u64, u64)>,
96
97 instance_length: Option<u64>
99 },
100
101 Unregistered {
103 unit: String,
105
106 resp: String
108 }
109}
110
111fn split_in_two(s: &str, separator: char) -> Option<(&str, &str)> {
112 let mut iter = s.splitn(2, separator);
113 match (iter.next(), iter.next()) {
114 (Some(a), Some(b)) => Some((a, b)),
115 _ => None
116 }
117}
118
119impl FromStr for ContentRangeSpec {
120 type Err = ::Error;
121
122 fn from_str(s: &str) -> ::Result<Self> {
123 let res = match split_in_two(s, ' ') {
124 Some(("bytes", resp)) => {
125 let (range, instance_length) = split_in_two(resp, '/').ok_or(::Error::Header)?;
126
127 let instance_length = if instance_length == "*" {
128 None
129 } else {
130 Some(instance_length.parse().map_err(|_| ::Error::Header)?)
131 };
132
133 let range = if range == "*" {
134 None
135 } else {
136 let (first_byte, last_byte) = split_in_two(range, '-').ok_or(::Error::Header)?;
137 let first_byte = first_byte.parse().map_err(|_| ::Error::Header)?;
138 let last_byte = last_byte.parse().map_err(|_| ::Error::Header)?;
139 if last_byte < first_byte {
140 return Err(::Error::Header);
141 }
142 Some((first_byte, last_byte))
143 };
144
145 ContentRangeSpec::Bytes {
146 range: range,
147 instance_length: instance_length
148 }
149 }
150 Some((unit, resp)) => {
151 ContentRangeSpec::Unregistered {
152 unit: unit.to_owned(),
153 resp: resp.to_owned()
154 }
155 }
156 _ => return Err(::Error::Header)
157 };
158 Ok(res)
159 }
160}
161
162impl Display for ContentRangeSpec {
163 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
164 match *self {
165 ContentRangeSpec::Bytes { range, instance_length } => {
166 f.write_str("bytes ")?;
167 match range {
168 Some((first_byte, last_byte)) => {
169 write!(f, "{}-{}", first_byte, last_byte)?;
170 },
171 None => {
172 f.write_str("*")?;
173 }
174 };
175 f.write_str("/")?;
176 if let Some(v) = instance_length {
177 write!(f, "{}", v)
178 } else {
179 f.write_str("*")
180 }
181 }
182 ContentRangeSpec::Unregistered { ref unit, ref resp } => {
183 f.write_str(&unit)?;
184 f.write_str(" ")?;
185 f.write_str(resp)
186 }
187 }
188 }
189}
190
191standard_header!(ContentRange, CONTENT_RANGE);