From c72166d9755a49306fae56aed2a20cc6858bd3fa Mon Sep 17 00:00:00 2001 From: "Y. T. Chung" Date: Wed, 27 Jun 2018 23:09:51 +0800 Subject: [PATCH] [#64] Captured invalid timestamp, preventing chrono panicking --- src/decoder/error.rs | 11 ++++++++++- src/decoder/mod.rs | 9 +++++++-- 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/src/decoder/error.rs b/src/decoder/error.rs index 65c12651..5873b1bc 100644 --- a/src/decoder/error.rs +++ b/src/decoder/error.rs @@ -1,5 +1,5 @@ -use std::{error, fmt, io, string}; use std::fmt::Display; +use std::{error, fmt, io, string}; use serde::de::{self, Expected, Unexpected}; @@ -28,6 +28,11 @@ pub enum DecoderError { UnknownVariant(String), // Invalid value InvalidValue(String), + // Invalid timestamp + InvalidTimestamp(i64), + // Ambiguous timestamp + AmbiguousTimestamp(i64), + Unknown(String), } @@ -62,6 +67,8 @@ impl fmt::Display for DecoderError { DecoderError::UnknownVariant(ref var) => write!(fmt, "unknown variant `{}`", var), DecoderError::InvalidValue(ref desc) => desc.fmt(fmt), DecoderError::Unknown(ref inner) => inner.fmt(fmt), + DecoderError::InvalidTimestamp(ref i) => write!(fmt, "no such local time {}", i), + DecoderError::AmbiguousTimestamp(ref i) => write!(fmt, "ambiguous local time {}", i), } } } @@ -83,6 +90,8 @@ impl error::Error for DecoderError { DecoderError::UnknownVariant(_) => "unknown variant", DecoderError::InvalidValue(ref desc) => desc, DecoderError::Unknown(ref inner) => inner, + DecoderError::InvalidTimestamp(..) => "no such local time", + DecoderError::AmbiguousTimestamp(..) => "ambiguous local time", } } fn cause(&self) -> Option<&error::Error> { diff --git a/src/decoder/mod.rs b/src/decoder/mod.rs index d7c6b595..9fd19b98 100644 --- a/src/decoder/mod.rs +++ b/src/decoder/mod.rs @@ -30,8 +30,8 @@ pub use self::serde::Decoder; use std::io::Read; use byteorder::{LittleEndian, ReadBytesExt}; +use chrono::offset::{LocalResult, TimeZone}; use chrono::Utc; -use chrono::offset::TimeZone; use bson::{Array, Bson, Document}; use oid; @@ -199,7 +199,12 @@ fn decode_bson(reader: &mut R, tag: u8, utf8_lossy: bool) -> D Some(TimeStamp) => read_i64(reader).map(Bson::TimeStamp), Some(UtcDatetime) => { let time = read_i64(reader)?; - Ok(Bson::UtcDatetime(Utc.timestamp(time / 1000, (time % 1000) as u32 * 1000000))) + + match Utc.timestamp_opt(time / 1000, (time % 1000) as u32 * 1000000) { + LocalResult::None => Err(DecoderError::InvalidTimestamp(time)), + LocalResult::Ambiguous(..) => Err(DecoderError::AmbiguousTimestamp(time)), + LocalResult::Single(t) => Ok(Bson::UtcDatetime(t)), + } } Some(Symbol) => read_string(reader, utf8_lossy).map(Bson::Symbol), Some(Undefined) | Some(DbPointer) | Some(MaxKey) | Some(MinKey) | None => {