fix panic when requesting zero segment duration

The recording::Segment was constructing a segment with no frames in it, which
was causing a panic when appending a zero-length stts to the Slices. Fix this
in a couple ways:

* Slices::append should return Err rather than panic. No reason to crash the
  whole program when we have trouble serving a single .mp4 request.
* recording::Segment shouldn't produce zero-frame segments
This commit is contained in:
Scott Lamb 2017-10-17 08:55:21 -07:00
parent 1d08698d0c
commit 9041eeb907
3 changed files with 31 additions and 12 deletions

View File

@ -1405,8 +1405,7 @@ impl BodyState {
fn append_slice(&mut self, len: u64, t: SliceType, p: usize) -> Result<(), Error> { fn append_slice(&mut self, len: u64, t: SliceType, p: usize) -> Result<(), Error> {
let l = self.slices.len(); let l = self.slices.len();
self.slices.append(Slice::new(l + len, t, p)?); self.slices.append(Slice::new(l + len, t, p)?)
Ok(())
} }
/// Appends a static bytestring, flushing the buffer if necessary. /// Appends a static bytestring, flushing the buffer if necessary.

View File

@ -406,10 +406,13 @@ impl Segment {
if self_.desired_range_90k.start == 0 && if self_.desired_range_90k.start == 0 &&
self_.desired_range_90k.end == recording.duration_90k { self_.desired_range_90k.end == recording.duration_90k {
// Fast path. Existing entry is fine. // Fast path. Existing entry is fine.
trace!("recording::Segment::new fast path, recording={:#?}", recording);
return Ok(self_) return Ok(self_)
} }
// Slow path. Need to iterate through the index. // Slow path. Need to iterate through the index.
trace!("recording::Segment::new slow path, desired_range_90k={:?}, recording={:#?}",
self_.desired_range_90k, recording);
db.with_recording_playback(self_.camera_id, self_.recording_id, |playback| { db.with_recording_playback(self_.camera_id, self_.recording_id, |playback| {
let mut begin = Box::new(SampleIndexIterator::new()); let mut begin = Box::new(SampleIndexIterator::new());
let data = &(&playback).video_index; let data = &(&playback).video_index;
@ -441,7 +444,7 @@ impl Segment {
self_.frames = 0; self_.frames = 0;
self_.key_frames = 0; self_.key_frames = 0;
} }
if it.start_90k >= end_90k { if it.start_90k >= end_90k && self_.frames > 0 {
break; break;
} }
self_.frames += 1; self_.frames += 1;
@ -709,6 +712,18 @@ mod tests {
assert_eq!(&get_frames(&db.db, &segment, |it| it.bytes), &[2, 3]); assert_eq!(&get_frames(&db.db, &segment, |it| it.bytes), &[2, 3]);
} }
/// Even if the desired duration is 0, there should still be a frame.
#[test]
fn test_segment_zero_desired_duration() {
testutil::init();
let mut encoder = SampleIndexEncoder::new();
encoder.add_sample(1, 1, true);
let db = TestDb::new();
let row = db.create_recording_from_encoder(encoder);
let segment = Segment::new(&db.db.lock(), &row, 0 .. 0).unwrap();
assert_eq!(&get_frames(&db.db, &segment, |it| it.bytes), &[1]);
}
/// Test a `Segment` which uses the whole recording. /// Test a `Segment` which uses the whole recording.
/// This takes a fast path which skips scanning the index in `new()`. /// This takes a fast path which skips scanning the index in `new()`.
#[test] #[test]

View File

@ -30,6 +30,7 @@
//! Tools for implementing a `http_entity::Entity` body composed from many "slices". //! Tools for implementing a `http_entity::Entity` body composed from many "slices".
use error::Error;
use reffers::ARefs; use reffers::ARefs;
use futures::stream; use futures::stream;
use futures::Stream; use futures::Stream;
@ -92,12 +93,16 @@ impl<S> Slices<S> where S: Slice {
self.slices.reserve(additional) self.slices.reserve(additional)
} }
/// Appends the given slice. /// Appends the given slice, which must have end > the Slice's current len.
pub fn append(&mut self, slice: S) { pub fn append(&mut self, slice: S) -> Result<(), Error> {
assert!(slice.end() > self.len, "end {} <= len {} while adding slice {:?} to slices:\n{:?}", if slice.end() <= self.len {
slice.end(), self.len, slice, self); return Err(Error::new(
format!("end {} <= len {} while adding slice {:?} to slices:\n{:?}",
slice.end(), self.len, slice, self)));
}
self.len = slice.end(); self.len = slice.end();
self.slices.push(slice); self.slices.push(slice);
Ok(())
} }
/// Returns the total byte length of all slices. /// Returns the total byte length of all slices.
@ -182,11 +187,11 @@ mod tests {
lazy_static! { lazy_static! {
static ref SLICES: Slices<FakeSlice> = { static ref SLICES: Slices<FakeSlice> = {
let mut s = Slices::new(); let mut s = Slices::new();
s.append(FakeSlice{end: 5, name: "a"}); s.append(FakeSlice{end: 5, name: "a"}).unwrap();
s.append(FakeSlice{end: 5+13, name: "b"}); s.append(FakeSlice{end: 5+13, name: "b"}).unwrap();
s.append(FakeSlice{end: 5+13+7, name: "c"}); s.append(FakeSlice{end: 5+13+7, name: "c"}).unwrap();
s.append(FakeSlice{end: 5+13+7+17, name: "d"}); s.append(FakeSlice{end: 5+13+7+17, name: "d"}).unwrap();
s.append(FakeSlice{end: 5+13+7+17+19, name: "e"}); s.append(FakeSlice{end: 5+13+7+17+19, name: "e"}).unwrap();
s s
}; };
} }