mirror of https://github.com/fafhrd91/actix-web
Implement logic to convert a RFC 850 two-digit year into a full length year, and organize time parsing related functions
This commit is contained in:
parent
dca8e23b4d
commit
34bbf75ecc
|
@ -10,6 +10,8 @@ use time::{Duration, PrimitiveDateTime, UtcOffset};
|
||||||
|
|
||||||
use super::{Cookie, CookieStr, SameSite};
|
use super::{Cookie, CookieStr, SameSite};
|
||||||
|
|
||||||
|
use crate::time_parser;
|
||||||
|
|
||||||
/// Enum corresponding to a parsing error.
|
/// Enum corresponding to a parsing error.
|
||||||
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
|
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
|
||||||
pub enum ParseError {
|
pub enum ParseError {
|
||||||
|
@ -182,12 +184,10 @@ fn parse_inner<'c>(s: &str, decode: bool) -> Result<Cookie<'c>, ParseError> {
|
||||||
// Try parsing with three date formats according to
|
// Try parsing with three date formats according to
|
||||||
// http://tools.ietf.org/html/rfc2616#section-3.3.1. Try
|
// http://tools.ietf.org/html/rfc2616#section-3.3.1. Try
|
||||||
// additional ones as encountered in the real world.
|
// additional ones as encountered in the real world.
|
||||||
let tm = PrimitiveDateTime::parse(v, "%a, %d %b %Y %H:%M:%S")
|
let tm = time_parser::parse_http_date(v)
|
||||||
.or_else(|_| PrimitiveDateTime::parse(v, "%A, %d-%b-%y %H:%M:%S"))
|
.or_else(|| PrimitiveDateTime::parse(v, "%a, %d-%b-%Y %H:%M:%S").ok());
|
||||||
.or_else(|_| PrimitiveDateTime::parse(v, "%a, %d-%b-%Y %H:%M:%S"))
|
|
||||||
.or_else(|_| PrimitiveDateTime::parse(v, "%a %b %d %H:%M:%S %Y"));
|
|
||||||
|
|
||||||
if let Ok(time) = tm {
|
if let Some(time) = tm {
|
||||||
cookie.expires = Some(time.using_offset(UtcOffset::UTC))
|
cookie.expires = Some(time.using_offset(UtcOffset::UTC))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,6 +9,7 @@ use time::{PrimitiveDateTime, OffsetDateTime, UtcOffset};
|
||||||
|
|
||||||
use crate::error::ParseError;
|
use crate::error::ParseError;
|
||||||
use crate::header::IntoHeaderValue;
|
use crate::header::IntoHeaderValue;
|
||||||
|
use crate::time_parser;
|
||||||
|
|
||||||
/// A timestamp with HTTP formatting and parsing
|
/// A timestamp with HTTP formatting and parsing
|
||||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
|
||||||
|
@ -18,14 +19,9 @@ impl FromStr for HttpDate {
|
||||||
type Err = ParseError;
|
type Err = ParseError;
|
||||||
|
|
||||||
fn from_str(s: &str) -> Result<HttpDate, ParseError> {
|
fn from_str(s: &str) -> Result<HttpDate, ParseError> {
|
||||||
match PrimitiveDateTime::parse(s, "%a, %d %b %Y %H:%M:%S")
|
match time_parser::parse_http_date(s) {
|
||||||
.or_else(|_| PrimitiveDateTime::parse(s, "%A, %d-%b-%y %H:%M:%S"))
|
Some(t) => Ok(HttpDate(t.using_offset(UtcOffset::UTC))),
|
||||||
.or_else(|_| PrimitiveDateTime::parse(s, "%c"))
|
None => Err(ParseError::Header)
|
||||||
{
|
|
||||||
Ok(t) => Ok(HttpDate(t.using_offset(UtcOffset::UTC))),
|
|
||||||
Err(_) => {
|
|
||||||
Err(ParseError::Header)
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -37,7 +33,7 @@ impl Display for HttpDate {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<OffsetDateTime> for HttpDate {
|
impl From<OffsetDateTime> for HttpDate {
|
||||||
fn from(dt: time::OffsetDateTime) -> HttpDate {
|
fn from(dt: OffsetDateTime) -> HttpDate {
|
||||||
HttpDate(dt)
|
HttpDate(dt)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,6 +27,7 @@ mod payload;
|
||||||
mod request;
|
mod request;
|
||||||
mod response;
|
mod response;
|
||||||
mod service;
|
mod service;
|
||||||
|
mod time_parser;
|
||||||
|
|
||||||
pub mod cookie;
|
pub mod cookie;
|
||||||
pub mod error;
|
pub mod error;
|
||||||
|
|
|
@ -0,0 +1,42 @@
|
||||||
|
use time::{PrimitiveDateTime, Date};
|
||||||
|
|
||||||
|
/// Attempt to parse a `time` string as one of either RFC 1123, RFC 850, or asctime.
|
||||||
|
pub fn parse_http_date(time: &str) -> Option<PrimitiveDateTime> {
|
||||||
|
try_parse_rfc_1123(time)
|
||||||
|
.or_else(|| try_parse_rfc_850(time))
|
||||||
|
.or_else(|| try_parse_asctime(time))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Attempt to parse a `time` string as a RFC 1123 formatted date time string.
|
||||||
|
fn try_parse_rfc_1123(time: &str) -> Option<PrimitiveDateTime> {
|
||||||
|
PrimitiveDateTime::parse(time, "%a, %d %b %Y %H:%M:%S").ok()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Attempt to parse a `time` string as a RFC 850 formatted date time string.
|
||||||
|
fn try_parse_rfc_850(time: &str) -> Option<PrimitiveDateTime> {
|
||||||
|
match PrimitiveDateTime::parse(time, "%A, %d-%b-%y %H:%M:%S") {
|
||||||
|
Ok(dt) => {
|
||||||
|
// If the `time` string contains a two-digit year, then as per RFC 2616 § 19.3,
|
||||||
|
// we consider the year as part of this century if it's within the next 50 years,
|
||||||
|
// otherwise we consider as part of the previous century.
|
||||||
|
let now = PrimitiveDateTime::now();
|
||||||
|
let century_start_year = (now.year() / 100) * 100;
|
||||||
|
let mut expanded_year = century_start_year + dt.year();
|
||||||
|
|
||||||
|
if expanded_year > now.year() + 50 {
|
||||||
|
expanded_year -= 100;
|
||||||
|
}
|
||||||
|
|
||||||
|
match Date::try_from_ymd(expanded_year, dt.month(), dt.day()) {
|
||||||
|
Ok(date) => Some(PrimitiveDateTime::new(date, dt.time())),
|
||||||
|
Err(_) => None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(_) => None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Attempt to parse a `time` string using ANSI C's `asctime` format.
|
||||||
|
fn try_parse_asctime(time: &str) -> Option<PrimitiveDateTime> {
|
||||||
|
PrimitiveDateTime::parse(time, "%c").ok()
|
||||||
|
}
|
Loading…
Reference in New Issue