cyfs_lib/base/
range.rs

1use cyfs_base::*;
2
3use serde::{Deserialize, Serialize};
4use std::ops::{Deref, DerefMut, Range};
5
6/*
7Remember that the range is zero-indexed, so Range: bytes=0-999 is actually requesting 1000 bytes, not 999, so respond with something like:
8
9Content-Length: 1000
10Content-Range: bytes 0-999/123456
11*/
12
13#[derive(Clone, Debug)]
14pub struct NDNDataRange {
15    pub start: Option<u64>,
16    pub length: Option<u64>,
17}
18
19impl NDNDataRange {
20    // https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Headers/Range
21    pub fn to_string(&self) -> String {
22        let start = self.start.unwrap_or(0);
23        match self.length {
24            Some(len) => {
25                format!("{}-{}", start, start + len - 1)
26            }
27            None => {
28                format!("{}-", start)
29            }
30        }
31    }
32}
33
34impl From<Range<u64>> for NDNDataRange {
35    fn from(v: Range<u64>) -> Self {
36        let length = if v.end >= v.start {
37            v.end - v.start
38        } else {
39            0
40        };
41
42        Self {
43            start: Some(v.start),
44            length: Some(length),
45        }
46    }
47}
48
49#[derive(Clone, Debug)]
50pub struct NDNDataRanges(Vec<NDNDataRange>);
51
52impl Deref for NDNDataRanges {
53    type Target = Vec<NDNDataRange>;
54
55    fn deref(&self) -> &Self::Target {
56        &self.0
57    }
58}
59
60impl DerefMut for NDNDataRanges {
61    fn deref_mut(&mut self) -> &mut Self::Target {
62        &mut self.0
63    }
64}
65
66
67impl NDNDataRanges {
68    pub fn ranges(&self) -> &Vec<NDNDataRange> {
69        &self.0
70    }
71
72    // Range: <unit>=<range-start>-<range-end>, <range-start>-<range-end>
73    pub fn to_string(&self) -> String {
74        if self.0.len() == 0 {
75            "bytes=0-".to_owned()
76        } else {
77            let ranges: Vec<String> = self.0.iter().map(|range| range.to_string()).collect();
78
79            format!("bytes={}", ranges.join(", "))
80        }
81    }
82}
83
84#[derive(Clone, Debug)]
85pub enum NDNDataRequestRange {
86    Unparsed(String),
87    Range(NDNDataRanges),
88}
89
90impl std::fmt::Display for NDNDataRequestRange {
91    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
92        write!(f, "{}", self.to_display_string())
93    }
94}
95
96#[derive(Clone, Debug, Serialize, Deserialize)]
97pub enum NDNDataResponseRange {
98    NoOverlap(u64),
99    InvalidRange,
100    Range((Vec<Range<u64>>, u64)),
101}
102
103impl ObjectFormatAutoWithSerde for NDNDataResponseRange {}
104impl JsonCodecAutoWithSerde for NDNDataResponseRange {}
105
106impl NDNDataRequestRange {
107    pub fn new_data_range(ranges: Vec<NDNDataRange>) -> Self {
108        Self::Range(NDNDataRanges(ranges))
109    }
110
111    pub fn new_range(ranges: Vec<Range<u64>>) -> Self {
112        let ranges = ranges.into_iter().map(|v| {
113            v.into()
114        }).collect();
115
116        Self::new_data_range(ranges)
117    }
118
119    pub fn new_unparsed(s: impl ToString) -> Self {
120        Self::Unparsed(s.to_string())
121    }
122
123    pub fn encode_string(&self) -> String {
124        match self {
125            Self::Unparsed(s) => s.clone(),
126            Self::Range(range) => range.to_string(),
127        }
128    }
129
130    pub fn to_display_string(&self) -> String {
131        match self {
132            Self::Unparsed(s) => {
133                format!("unparsed: {}", s)
134            }
135            Self::Range(range) => range.to_string(),
136        }
137    }
138
139    pub fn convert_to_response(&self, size: u64) -> Option<NDNDataResponseRange> {
140        let ret = match self {
141            Self::Unparsed(s) => Self::parse_str(s.as_str(), size),
142            Self::Range(list) => Self::parse_ranges(list, size),
143        };
144
145        info!("data range convert: {} -> {:?}", self, ret);
146
147        ret
148    }
149
150    fn parse_ranges(list: &NDNDataRanges, size: u64) -> Option<NDNDataResponseRange> {
151        let mut no_overlap = false;
152        let mut ranges = vec![];
153        for range in list.ranges() {
154            match Self::parse_range(range, size) {
155                Some(v) => match v {
156                    NDNDataResponseRange::Range((range, _)) => {
157                        assert!(range.len() > 0);
158                        ranges.extend_from_slice(&range);
159                    }
160                    NDNDataResponseRange::InvalidRange => {
161                        return Some(NDNDataResponseRange::InvalidRange);
162                    }
163                    NDNDataResponseRange::NoOverlap(_) => {
164                        unreachable!();
165                    }
166                },
167                None => {
168                    no_overlap = true;
169                    continue;
170                }
171            }
172        }
173
174        if ranges.is_empty() {
175            if no_overlap {
176                return Some(NDNDataResponseRange::NoOverlap(size));
177            } else {
178                return None;
179            }
180        }
181
182        Some(NDNDataResponseRange::Range((ranges, size)))
183    }
184
185    fn parse_range(range: &NDNDataRange, size: u64) -> Option<NDNDataResponseRange> {
186        match range.start {
187            Some(start) => {
188                if start >= size {
189                    return None;
190                }
191
192                match range.length {
193                    Some(mut len) => {
194                        if len == 0 {
195                            None
196                        } else {
197                            if start + len > size {
198                                len = size - start;
199                            }
200                            let range = Range {
201                                start,
202                                end: start + len,
203                            };
204                            Some(NDNDataResponseRange::Range((vec![range], size)))
205                        }
206                    }
207                    None => {
208                        let len = size - start;
209                        let range = Range {
210                            start,
211                            end: start + len,
212                        };
213                        Some(NDNDataResponseRange::Range((vec![range], size)))
214                    }
215                }
216            }
217            // treat start as 0
218            None => match range.length {
219                Some(mut len) => {
220                    if len > size {
221                        len = size;
222                    }
223
224                    let range = Range { start: 0, end: len };
225                    Some(NDNDataResponseRange::Range((vec![range], size)))
226                }
227                None => Some(NDNDataResponseRange::InvalidRange),
228            },
229        }
230    }
231
232    fn parse_str(range_str: &str, size: u64) -> Option<NDNDataResponseRange> {
233        let ranges = match http_range::HttpRange::parse(range_str, size) {
234            Ok(r) => r,
235            Err(err) => {
236                let res = match err {
237                    http_range::HttpRangeParseError::NoOverlap => {
238                        NDNDataResponseRange::NoOverlap(size)
239                    }
240                    http_range::HttpRangeParseError::InvalidRange => {
241                        warn!("invalid range: {}, size={}", range_str, size);
242                        NDNDataResponseRange::InvalidRange
243                    }
244                };
245
246                return Some(res);
247            }
248        };
249
250        if ranges.is_empty() {
251            return None;
252        }
253
254        let ranges: Vec<Range<u64>> = ranges
255            .into_iter()
256            .map(|item| Range {
257                start: item.start,
258                end: item.start + item.length,
259            })
260            .collect();
261
262        Some(NDNDataResponseRange::Range((ranges, size)))
263    }
264}
265
266pub struct RangeHelper<Idx> {
267    _marker: std::marker::PhantomData<Idx>,
268}
269
270impl<Idx> RangeHelper<Idx> {
271    pub fn intersect(left: &Range<Idx>, right: &Range<Idx>) -> Option<Range<Idx>>
272    where
273        Idx: PartialOrd<Idx> + Ord + Copy,
274    {
275        if left.end <= right.start {
276            None
277        } else if left.start >= right.end {
278            None
279        } else {
280            let start = std::cmp::max(left.start, right.start);
281            let end = std::cmp::min(left.end, right.end);
282
283            let r = Range { start, end };
284            if r.is_empty() {
285                None
286            } else {
287                Some(r)
288            }
289        }
290    }
291
292    pub fn intersect_list(target: &Range<Idx>, ranges: &Vec<Range<Idx>>) -> Vec<Range<Idx>>
293    where
294        Idx: PartialOrd<Idx> + Ord + Copy,
295    {
296        ranges
297            .iter()
298            .filter_map(|range| Self::intersect(target, range))
299            .collect()
300    }
301
302    pub fn sum(ranges: &Vec<Range<Idx>>) -> Idx
303    where
304        Idx: std::ops::Add<Output = Idx> + std::ops::Sub<Output = Idx> + Default + Copy,
305    {
306        ranges
307            .iter()
308            .fold(Idx::default(), |acc, v| acc + (v.end - v.start))
309    }
310}
311
312use super::requestor_helper::RequestorHelper;
313
314pub struct RequestorRangeHelper {}
315
316impl RequestorRangeHelper {
317    // https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Range
318    fn encode_content_range(range: &Vec<Range<u64>>, size: u64) -> String {
319        assert!(range.len() > 0);
320        if range.len() > 1 {
321            warn!(
322                "only single range support for http range protocol! ranges={:?}, size={}",
323                range, size
324            );
325        }
326
327        let range = &range[0];
328
329        if size > 0 {
330            format!("bytes {}-{}/{}", range.start, range.end - 1, size)
331        } else {
332            format!("bytes {}-{}/*", range.start, range.end - 1)
333        }
334    }
335
336    fn encode_empty_range(size: u64) -> String {
337        format!("bytes */{}", size)
338    }
339
340    pub fn new_range_response(range_resp: &NDNDataResponseRange) -> http_types::Response {
341        let mut resp = match range_resp {
342            NDNDataResponseRange::Range((ranges, len)) => {
343                let mut resp =
344                    RequestorHelper::new_response(http_types::StatusCode::PartialContent);
345
346                let value = Self::encode_content_range(ranges, *len);
347                resp.insert_header(http_types::headers::CONTENT_RANGE, value);
348
349                resp
350            }
351            NDNDataResponseRange::NoOverlap(len) => {
352                let msg = format!("Invalid range, no overlap! size={}", len);
353                let e = BuckyError::new(BuckyErrorCode::RangeNotSatisfiable, msg);
354
355                let mut resp: http_types::Response = RequestorHelper::trans_error(e);
356
357                let value = Self::encode_empty_range(*len);
358                resp.insert_header(http_types::headers::CONTENT_RANGE, value);
359
360                resp
361            }
362            NDNDataResponseRange::InvalidRange => {
363                let e = BuckyError::new(BuckyErrorCode::RangeNotSatisfiable, "Invalid range");
364
365                RequestorHelper::trans_error(e)
366            }
367        };
368
369        resp.insert_header(http_types::headers::ACCEPT_RANGES, "bytes");
370
371        resp
372    }
373}