Skip to content

Commit c72166d

Browse files
committed
[#64] Captured invalid timestamp, preventing chrono panicking
1 parent 60745f1 commit c72166d

File tree

2 files changed

+17
-3
lines changed

2 files changed

+17
-3
lines changed

src/decoder/error.rs

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
use std::{error, fmt, io, string};
21
use std::fmt::Display;
2+
use std::{error, fmt, io, string};
33

44
use serde::de::{self, Expected, Unexpected};
55

@@ -28,6 +28,11 @@ pub enum DecoderError {
2828
UnknownVariant(String),
2929
// Invalid value
3030
InvalidValue(String),
31+
// Invalid timestamp
32+
InvalidTimestamp(i64),
33+
// Ambiguous timestamp
34+
AmbiguousTimestamp(i64),
35+
3136
Unknown(String),
3237
}
3338

@@ -62,6 +67,8 @@ impl fmt::Display for DecoderError {
6267
DecoderError::UnknownVariant(ref var) => write!(fmt, "unknown variant `{}`", var),
6368
DecoderError::InvalidValue(ref desc) => desc.fmt(fmt),
6469
DecoderError::Unknown(ref inner) => inner.fmt(fmt),
70+
DecoderError::InvalidTimestamp(ref i) => write!(fmt, "no such local time {}", i),
71+
DecoderError::AmbiguousTimestamp(ref i) => write!(fmt, "ambiguous local time {}", i),
6572
}
6673
}
6774
}
@@ -83,6 +90,8 @@ impl error::Error for DecoderError {
8390
DecoderError::UnknownVariant(_) => "unknown variant",
8491
DecoderError::InvalidValue(ref desc) => desc,
8592
DecoderError::Unknown(ref inner) => inner,
93+
DecoderError::InvalidTimestamp(..) => "no such local time",
94+
DecoderError::AmbiguousTimestamp(..) => "ambiguous local time",
8695
}
8796
}
8897
fn cause(&self) -> Option<&error::Error> {

src/decoder/mod.rs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,8 @@ pub use self::serde::Decoder;
3030
use std::io::Read;
3131

3232
use byteorder::{LittleEndian, ReadBytesExt};
33+
use chrono::offset::{LocalResult, TimeZone};
3334
use chrono::Utc;
34-
use chrono::offset::TimeZone;
3535

3636
use bson::{Array, Bson, Document};
3737
use oid;
@@ -199,7 +199,12 @@ fn decode_bson<R: Read + ?Sized>(reader: &mut R, tag: u8, utf8_lossy: bool) -> D
199199
Some(TimeStamp) => read_i64(reader).map(Bson::TimeStamp),
200200
Some(UtcDatetime) => {
201201
let time = read_i64(reader)?;
202-
Ok(Bson::UtcDatetime(Utc.timestamp(time / 1000, (time % 1000) as u32 * 1000000)))
202+
203+
match Utc.timestamp_opt(time / 1000, (time % 1000) as u32 * 1000000) {
204+
LocalResult::None => Err(DecoderError::InvalidTimestamp(time)),
205+
LocalResult::Ambiguous(..) => Err(DecoderError::AmbiguousTimestamp(time)),
206+
LocalResult::Single(t) => Ok(Bson::UtcDatetime(t)),
207+
}
203208
}
204209
Some(Symbol) => read_string(reader, utf8_lossy).map(Bson::Symbol),
205210
Some(Undefined) | Some(DbPointer) | Some(MaxKey) | Some(MinKey) | None => {

0 commit comments

Comments
 (0)