/rust/registry/src/index.crates.io-1949cf8c6b5b557f/headers-0.4.1/src/common/range.rs
Line | Count | Source |
1 | | use std::ops::{Bound, RangeBounds}; |
2 | | |
3 | | use http::{HeaderName, HeaderValue}; |
4 | | |
5 | | use crate::{Error, Header}; |
6 | | |
7 | | /// `Range` header, defined in [RFC7233](https://tools.ietf.org/html/rfc7233#section-3.1) |
8 | | /// |
9 | | /// The "Range" header field on a GET request modifies the method |
10 | | /// semantics to request transfer of only one or more subranges of the |
11 | | /// selected representation data, rather than the entire selected |
12 | | /// representation data. |
13 | | /// |
14 | | /// # ABNF |
15 | | /// |
16 | | /// ```text |
17 | | /// Range = byte-ranges-specifier / other-ranges-specifier |
18 | | /// other-ranges-specifier = other-range-unit "=" other-range-set |
19 | | /// other-range-set = 1*VCHAR |
20 | | /// |
21 | | /// bytes-unit = "bytes" |
22 | | /// |
23 | | /// byte-ranges-specifier = bytes-unit "=" byte-range-set |
24 | | /// byte-range-set = 1#(byte-range-spec / suffix-byte-range-spec) |
25 | | /// byte-range-spec = first-byte-pos "-" [last-byte-pos] |
26 | | /// first-byte-pos = 1*DIGIT |
27 | | /// last-byte-pos = 1*DIGIT |
28 | | /// ``` |
29 | | /// |
30 | | /// # Example values |
31 | | /// |
32 | | /// * `bytes=1000-` |
33 | | /// * `bytes=-2000` |
34 | | /// * `bytes=0-1,30-40` |
35 | | /// * `bytes=0-10,20-90,-100` |
36 | | /// |
37 | | /// # Examples |
38 | | /// |
39 | | /// ``` |
40 | | /// use headers::Range; |
41 | | /// |
42 | | /// |
43 | | /// let range = Range::bytes(0..1234).unwrap(); |
44 | | /// ``` |
45 | | #[derive(Clone, Debug, PartialEq)] |
46 | | pub struct Range(HeaderValue); |
47 | | |
48 | | error_type!(InvalidRange); |
49 | | |
50 | | impl Range { |
51 | | /// Creates a `Range` header from bounds. |
52 | 0 | pub fn bytes(bounds: impl RangeBounds<u64>) -> Result<Self, InvalidRange> { |
53 | 0 | let v = match (bounds.start_bound(), bounds.end_bound()) { |
54 | 0 | (Bound::Included(start), Bound::Included(end)) => format!("bytes={}-{}", start, end), |
55 | 0 | (Bound::Included(start), Bound::Excluded(&end)) => { |
56 | 0 | format!("bytes={}-{}", start, end - 1) |
57 | | } |
58 | 0 | (Bound::Included(start), Bound::Unbounded) => format!("bytes={}-", start), |
59 | | // These do not directly translate. |
60 | | //(Bound::Unbounded, Bound::Included(end)) => format!("bytes=-{}", end), |
61 | | //(Bound::Unbounded, Bound::Excluded(&end)) => format!("bytes=-{}", end - 1), |
62 | 0 | _ => return Err(InvalidRange { _inner: () }), |
63 | | }; |
64 | | |
65 | 0 | Ok(Range(HeaderValue::from_str(&v).unwrap())) |
66 | 0 | } |
67 | | |
68 | | /// Iterate the range sets as a tuple of bounds, if valid with length. |
69 | | /// |
70 | | /// The length of the content is passed as an argument, and all ranges |
71 | | /// that can be satisfied will be iterated. |
72 | 0 | pub fn satisfiable_ranges( |
73 | 0 | &self, |
74 | 0 | len: u64, |
75 | 0 | ) -> impl Iterator<Item = (Bound<u64>, Bound<u64>)> + '_ { |
76 | 0 | let s = self |
77 | 0 | .0 |
78 | 0 | .to_str() |
79 | 0 | .expect("valid string checked in Header::decode()"); |
80 | | |
81 | 0 | s["bytes=".len()..].split(',').filter_map(move |spec| { |
82 | 0 | let mut iter = spec.trim().splitn(2, '-'); |
83 | 0 | let start = parse_bound(iter.next()?)?; |
84 | 0 | let end = parse_bound(iter.next()?)?; |
85 | | |
86 | | // Unbounded ranges in HTTP are actually a suffix |
87 | | // For example, `-100` means the last 100 bytes. |
88 | 0 | if let Bound::Unbounded = start { |
89 | 0 | if let Bound::Included(end) = end { |
90 | 0 | if len < end { |
91 | | // Last N bytes is larger than available! |
92 | 0 | return None; |
93 | 0 | } |
94 | 0 | return Some((Bound::Included(len - end), Bound::Unbounded)); |
95 | 0 | } |
96 | | // else fall through |
97 | 0 | } |
98 | | |
99 | 0 | Some((start, end)) |
100 | 0 | }) |
101 | 0 | } |
102 | | } |
103 | | |
104 | 0 | fn parse_bound(s: &str) -> Option<Bound<u64>> { |
105 | 0 | if s.is_empty() { |
106 | 0 | return Some(Bound::Unbounded); |
107 | 0 | } |
108 | | |
109 | 0 | s.parse().ok().map(Bound::Included) |
110 | 0 | } |
111 | | |
112 | | impl Header for Range { |
113 | 0 | fn name() -> &'static HeaderName { |
114 | 0 | &::http::header::RANGE |
115 | 0 | } |
116 | | |
117 | 0 | fn decode<'i, I: Iterator<Item = &'i HeaderValue>>(values: &mut I) -> Result<Self, Error> { |
118 | 0 | values |
119 | 0 | .next() |
120 | 0 | .and_then(|val| { |
121 | 0 | if val.to_str().ok()?.starts_with("bytes=") { |
122 | 0 | Some(Range(val.clone())) |
123 | | } else { |
124 | 0 | None |
125 | | } |
126 | 0 | }) |
127 | 0 | .ok_or_else(Error::invalid) |
128 | 0 | } |
129 | | |
130 | 0 | fn encode<E: Extend<HeaderValue>>(&self, values: &mut E) { |
131 | 0 | values.extend(::std::iter::once(self.0.clone())); |
132 | 0 | } |
133 | | } |
134 | | |
135 | | /* |
136 | | |
137 | | impl ByteRangeSpec { |
138 | | /// Given the full length of the entity, attempt to normalize the byte range |
139 | | /// into an satisfiable end-inclusive (from, to) range. |
140 | | /// |
141 | | /// The resulting range is guaranteed to be a satisfiable range within the bounds |
142 | | /// of `0 <= from <= to < full_length`. |
143 | | /// |
144 | | /// If the byte range is deemed unsatisfiable, `None` is returned. |
145 | | /// An unsatisfiable range is generally cause for a server to either reject |
146 | | /// the client request with a `416 Range Not Satisfiable` status code, or to |
147 | | /// simply ignore the range header and serve the full entity using a `200 OK` |
148 | | /// status code. |
149 | | /// |
150 | | /// This function closely follows [RFC 7233][1] section 2.1. |
151 | | /// As such, it considers ranges to be satisfiable if they meet the following |
152 | | /// conditions: |
153 | | /// |
154 | | /// > If a valid byte-range-set includes at least one byte-range-spec with |
155 | | /// a first-byte-pos that is less than the current length of the |
156 | | /// representation, or at least one suffix-byte-range-spec with a |
157 | | /// non-zero suffix-length, then the byte-range-set is satisfiable. |
158 | | /// Otherwise, the byte-range-set is unsatisfiable. |
159 | | /// |
160 | | /// The function also computes remainder ranges based on the RFC: |
161 | | /// |
162 | | /// > If the last-byte-pos value is |
163 | | /// absent, or if the value is greater than or equal to the current |
164 | | /// length of the representation data, the byte range is interpreted as |
165 | | /// the remainder of the representation (i.e., the server replaces the |
166 | | /// value of last-byte-pos with a value that is one less than the current |
167 | | /// length of the selected representation). |
168 | | /// |
169 | | /// [1]: https://tools.ietf.org/html/rfc7233 |
170 | | pub fn to_satisfiable_range(&self, full_length: u64) -> Option<(u64, u64)> { |
171 | | // If the full length is zero, there is no satisfiable end-inclusive range. |
172 | | if full_length == 0 { |
173 | | return None; |
174 | | } |
175 | | match self { |
176 | | &ByteRangeSpec::FromTo(from, to) => { |
177 | | if from < full_length && from <= to { |
178 | | Some((from, ::std::cmp::min(to, full_length - 1))) |
179 | | } else { |
180 | | None |
181 | | } |
182 | | }, |
183 | | &ByteRangeSpec::AllFrom(from) => { |
184 | | if from < full_length { |
185 | | Some((from, full_length - 1)) |
186 | | } else { |
187 | | None |
188 | | } |
189 | | }, |
190 | | &ByteRangeSpec::Last(last) => { |
191 | | if last > 0 { |
192 | | // From the RFC: If the selected representation is shorter |
193 | | // than the specified suffix-length, |
194 | | // the entire representation is used. |
195 | | if last > full_length { |
196 | | Some((0, full_length - 1)) |
197 | | } else { |
198 | | Some((full_length - last, full_length - 1)) |
199 | | } |
200 | | } else { |
201 | | None |
202 | | } |
203 | | } |
204 | | } |
205 | | } |
206 | | } |
207 | | |
208 | | impl Range { |
209 | | /// Get the most common byte range header ("bytes=from-to") |
210 | | pub fn bytes(from: u64, to: u64) -> Range { |
211 | | Range::Bytes(vec![ByteRangeSpec::FromTo(from, to)]) |
212 | | } |
213 | | |
214 | | /// Get byte range header with multiple subranges |
215 | | /// ("bytes=from1-to1,from2-to2,fromX-toX") |
216 | | pub fn bytes_multi(ranges: Vec<(u64, u64)>) -> Range { |
217 | | Range::Bytes(ranges.iter().map(|r| ByteRangeSpec::FromTo(r.0, r.1)).collect()) |
218 | | } |
219 | | } |
220 | | |
221 | | |
222 | | impl fmt::Display for ByteRangeSpec { |
223 | | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
224 | | match *self { |
225 | | ByteRangeSpec::FromTo(from, to) => write!(f, "{}-{}", from, to), |
226 | | ByteRangeSpec::Last(pos) => write!(f, "-{}", pos), |
227 | | ByteRangeSpec::AllFrom(pos) => write!(f, "{}-", pos), |
228 | | } |
229 | | } |
230 | | } |
231 | | |
232 | | |
233 | | impl fmt::Display for Range { |
234 | | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
235 | | match *self { |
236 | | Range::Bytes(ref ranges) => { |
237 | | try!(write!(f, "bytes=")); |
238 | | |
239 | | for (i, range) in ranges.iter().enumerate() { |
240 | | if i != 0 { |
241 | | try!(f.write_str(",")); |
242 | | } |
243 | | try!(Display::fmt(range, f)); |
244 | | } |
245 | | Ok(()) |
246 | | }, |
247 | | Range::Unregistered(ref unit, ref range_str) => { |
248 | | write!(f, "{}={}", unit, range_str) |
249 | | }, |
250 | | } |
251 | | } |
252 | | } |
253 | | |
254 | | impl FromStr for Range { |
255 | | type Err = ::Error; |
256 | | |
257 | | fn from_str(s: &str) -> ::Result<Range> { |
258 | | let mut iter = s.splitn(2, '='); |
259 | | |
260 | | match (iter.next(), iter.next()) { |
261 | | (Some("bytes"), Some(ranges)) => { |
262 | | let ranges = from_comma_delimited(ranges); |
263 | | if ranges.is_empty() { |
264 | | return Err(::Error::Header); |
265 | | } |
266 | | Ok(Range::Bytes(ranges)) |
267 | | } |
268 | | (Some(unit), Some(range_str)) if unit != "" && range_str != "" => { |
269 | | Ok(Range::Unregistered(unit.to_owned(), range_str.to_owned())) |
270 | | |
271 | | }, |
272 | | _ => Err(::Error::Header) |
273 | | } |
274 | | } |
275 | | } |
276 | | |
277 | | impl FromStr for ByteRangeSpec { |
278 | | type Err = ::Error; |
279 | | |
280 | | fn from_str(s: &str) -> ::Result<ByteRangeSpec> { |
281 | | let mut parts = s.splitn(2, '-'); |
282 | | |
283 | | match (parts.next(), parts.next()) { |
284 | | (Some(""), Some(end)) => { |
285 | | end.parse().or(Err(::Error::Header)).map(ByteRangeSpec::Last) |
286 | | }, |
287 | | (Some(start), Some("")) => { |
288 | | start.parse().or(Err(::Error::Header)).map(ByteRangeSpec::AllFrom) |
289 | | }, |
290 | | (Some(start), Some(end)) => { |
291 | | match (start.parse(), end.parse()) { |
292 | | (Ok(start), Ok(end)) if start <= end => Ok(ByteRangeSpec::FromTo(start, end)), |
293 | | _ => Err(::Error::Header) |
294 | | } |
295 | | }, |
296 | | _ => Err(::Error::Header) |
297 | | } |
298 | | } |
299 | | } |
300 | | |
301 | | fn from_comma_delimited<T: FromStr>(s: &str) -> Vec<T> { |
302 | | s.split(',') |
303 | | .filter_map(|x| match x.trim() { |
304 | | "" => None, |
305 | | y => Some(y) |
306 | | }) |
307 | | .filter_map(|x| x.parse().ok()) |
308 | | .collect() |
309 | | } |
310 | | |
311 | | impl Header for Range { |
312 | | |
313 | | fn header_name() -> &'static str { |
314 | | static NAME: &'static str = "Range"; |
315 | | NAME |
316 | | } |
317 | | |
318 | | fn parse_header(raw: &Raw) -> ::Result<Range> { |
319 | | from_one_raw_str(raw) |
320 | | } |
321 | | |
322 | | fn fmt_header(&self, f: &mut ::Formatter) -> fmt::Result { |
323 | | f.fmt_line(self) |
324 | | } |
325 | | |
326 | | } |
327 | | |
328 | | #[test] |
329 | | fn test_parse_bytes_range_valid() { |
330 | | let r: Range = Header::parse_header(&"bytes=1-100".into()).unwrap(); |
331 | | let r2: Range = Header::parse_header(&"bytes=1-100,-".into()).unwrap(); |
332 | | let r3 = Range::bytes(1, 100); |
333 | | assert_eq!(r, r2); |
334 | | assert_eq!(r2, r3); |
335 | | |
336 | | let r: Range = Header::parse_header(&"bytes=1-100,200-".into()).unwrap(); |
337 | | let r2: Range = Header::parse_header(&"bytes= 1-100 , 101-xxx, 200- ".into()).unwrap(); |
338 | | let r3 = Range::Bytes( |
339 | | vec![ByteRangeSpec::FromTo(1, 100), ByteRangeSpec::AllFrom(200)] |
340 | | ); |
341 | | assert_eq!(r, r2); |
342 | | assert_eq!(r2, r3); |
343 | | |
344 | | let r: Range = Header::parse_header(&"bytes=1-100,-100".into()).unwrap(); |
345 | | let r2: Range = Header::parse_header(&"bytes=1-100, ,,-100".into()).unwrap(); |
346 | | let r3 = Range::Bytes( |
347 | | vec![ByteRangeSpec::FromTo(1, 100), ByteRangeSpec::Last(100)] |
348 | | ); |
349 | | assert_eq!(r, r2); |
350 | | assert_eq!(r2, r3); |
351 | | |
352 | | let r: Range = Header::parse_header(&"custom=1-100,-100".into()).unwrap(); |
353 | | let r2 = Range::Unregistered("custom".to_owned(), "1-100,-100".to_owned()); |
354 | | assert_eq!(r, r2); |
355 | | |
356 | | } |
357 | | |
358 | | #[test] |
359 | | fn test_parse_unregistered_range_valid() { |
360 | | let r: Range = Header::parse_header(&"custom=1-100,-100".into()).unwrap(); |
361 | | let r2 = Range::Unregistered("custom".to_owned(), "1-100,-100".to_owned()); |
362 | | assert_eq!(r, r2); |
363 | | |
364 | | let r: Range = Header::parse_header(&"custom=abcd".into()).unwrap(); |
365 | | let r2 = Range::Unregistered("custom".to_owned(), "abcd".to_owned()); |
366 | | assert_eq!(r, r2); |
367 | | |
368 | | let r: Range = Header::parse_header(&"custom=xxx-yyy".into()).unwrap(); |
369 | | let r2 = Range::Unregistered("custom".to_owned(), "xxx-yyy".to_owned()); |
370 | | assert_eq!(r, r2); |
371 | | } |
372 | | |
373 | | #[test] |
374 | | fn test_parse_invalid() { |
375 | | let r: ::Result<Range> = Header::parse_header(&"bytes=1-a,-".into()); |
376 | | assert_eq!(r.ok(), None); |
377 | | |
378 | | let r: ::Result<Range> = Header::parse_header(&"bytes=1-2-3".into()); |
379 | | assert_eq!(r.ok(), None); |
380 | | |
381 | | let r: ::Result<Range> = Header::parse_header(&"abc".into()); |
382 | | assert_eq!(r.ok(), None); |
383 | | |
384 | | let r: ::Result<Range> = Header::parse_header(&"bytes=1-100=".into()); |
385 | | assert_eq!(r.ok(), None); |
386 | | |
387 | | let r: ::Result<Range> = Header::parse_header(&"bytes=".into()); |
388 | | assert_eq!(r.ok(), None); |
389 | | |
390 | | let r: ::Result<Range> = Header::parse_header(&"custom=".into()); |
391 | | assert_eq!(r.ok(), None); |
392 | | |
393 | | let r: ::Result<Range> = Header::parse_header(&"=1-100".into()); |
394 | | assert_eq!(r.ok(), None); |
395 | | } |
396 | | |
397 | | #[test] |
398 | | fn test_fmt() { |
399 | | use Headers; |
400 | | |
401 | | let mut headers = Headers::new(); |
402 | | |
403 | | headers.set( |
404 | | Range::Bytes( |
405 | | vec![ByteRangeSpec::FromTo(0, 1000), ByteRangeSpec::AllFrom(2000)] |
406 | | )); |
407 | | assert_eq!(&headers.to_string(), "Range: bytes=0-1000,2000-\r\n"); |
408 | | |
409 | | headers.clear(); |
410 | | headers.set(Range::Bytes(vec![])); |
411 | | |
412 | | assert_eq!(&headers.to_string(), "Range: bytes=\r\n"); |
413 | | |
414 | | headers.clear(); |
415 | | headers.set(Range::Unregistered("custom".to_owned(), "1-xxx".to_owned())); |
416 | | |
417 | | assert_eq!(&headers.to_string(), "Range: custom=1-xxx\r\n"); |
418 | | } |
419 | | |
420 | | #[test] |
421 | | fn test_byte_range_spec_to_satisfiable_range() { |
422 | | assert_eq!(Some((0, 0)), ByteRangeSpec::FromTo(0, 0).to_satisfiable_range(3)); |
423 | | assert_eq!(Some((1, 2)), ByteRangeSpec::FromTo(1, 2).to_satisfiable_range(3)); |
424 | | assert_eq!(Some((1, 2)), ByteRangeSpec::FromTo(1, 5).to_satisfiable_range(3)); |
425 | | assert_eq!(None, ByteRangeSpec::FromTo(3, 3).to_satisfiable_range(3)); |
426 | | assert_eq!(None, ByteRangeSpec::FromTo(2, 1).to_satisfiable_range(3)); |
427 | | assert_eq!(None, ByteRangeSpec::FromTo(0, 0).to_satisfiable_range(0)); |
428 | | |
429 | | assert_eq!(Some((0, 2)), ByteRangeSpec::AllFrom(0).to_satisfiable_range(3)); |
430 | | assert_eq!(Some((2, 2)), ByteRangeSpec::AllFrom(2).to_satisfiable_range(3)); |
431 | | assert_eq!(None, ByteRangeSpec::AllFrom(3).to_satisfiable_range(3)); |
432 | | assert_eq!(None, ByteRangeSpec::AllFrom(5).to_satisfiable_range(3)); |
433 | | assert_eq!(None, ByteRangeSpec::AllFrom(0).to_satisfiable_range(0)); |
434 | | |
435 | | assert_eq!(Some((1, 2)), ByteRangeSpec::Last(2).to_satisfiable_range(3)); |
436 | | assert_eq!(Some((2, 2)), ByteRangeSpec::Last(1).to_satisfiable_range(3)); |
437 | | assert_eq!(Some((0, 2)), ByteRangeSpec::Last(5).to_satisfiable_range(3)); |
438 | | assert_eq!(None, ByteRangeSpec::Last(0).to_satisfiable_range(3)); |
439 | | assert_eq!(None, ByteRangeSpec::Last(2).to_satisfiable_range(0)); |
440 | | } |
441 | | |
442 | | bench_header!(bytes_multi, Range, { vec![b"bytes=1-1001,2001-3001,10001-".to_vec()]}); |
443 | | bench_header!(custom_unit, Range, { vec![b"other=0-100000".to_vec()]}); |
444 | | */ |
445 | | |
446 | | #[test] |
447 | | fn test_to_satisfiable_range_suffix() { |
448 | | let range = super::test_decode::<Range>(&["bytes=-100"]).unwrap(); |
449 | | let bounds = range.satisfiable_ranges(350).next().unwrap(); |
450 | | assert_eq!(bounds, (Bound::Included(250), Bound::Unbounded)); |
451 | | } |
452 | | |
453 | | #[test] |
454 | | fn test_to_unsatisfiable_range_suffix() { |
455 | | let range = super::test_decode::<Range>(&["bytes=-350"]).unwrap(); |
456 | | let bounds = range.satisfiable_ranges(100).next(); |
457 | | assert_eq!(bounds, None); |
458 | | } |