@@ -3,14 +3,18 @@ use std::fmt::{self, Display, Formatter};
3
3
use std:: str:: { from_utf8, FromStr } ;
4
4
use std:: time:: { Duration , SystemTime , UNIX_EPOCH } ;
5
5
6
- /// HTTP timestamp type.
7
- ///
8
- /// Parse using `FromStr` impl.
6
+ const IMF_FIXDATE_LENGTH : usize = 29 ;
7
+ const RFC850_MAX_LENGTH : usize = 23 ;
8
+ const ASCTIME_LENGTH : usize = 24 ;
9
+
10
+ const YEAR_9999_SECONDS : u64 = 253402300800 ;
11
+ const SECONDS_IN_DAY : u64 = 86400 ;
12
+ const SECONDS_IN_HOUR : u64 = 3600 ;
13
+
9
14
/// Format using the `Display` trait.
10
15
/// Convert timestamp into/from `SytemTime` to use.
11
16
/// Supports comparsion and sorting.
12
- //#[derive(Copy, Clone, Debug, Eq, Ord)]
13
- #[ derive( Copy , Clone , Debug ) ]
17
+ #[ derive( Copy , Clone , Debug , Eq , Ord ) ]
14
18
pub struct HttpDate {
15
19
/// 0...59
16
20
second : u8 ,
@@ -62,7 +66,12 @@ impl HttpDate {
62
66
63
67
fn parse_imf_fixdate ( s : & [ u8 ] ) -> Result < HttpDate , Exception > {
64
68
// Example: `Sun, 06 Nov 1994 08:49:37 GMT`
65
- if s. len ( ) != 29 || & s[ 25 ..] != b" GMT" || s[ 16 ] != b' ' || s[ 19 ] != b':' || s[ 22 ] != b':' {
69
+ if s. len ( ) != IMF_FIXDATE_LENGTH
70
+ || & s[ 25 ..] != b" GMT"
71
+ || s[ 16 ] != b' '
72
+ || s[ 19 ] != b':'
73
+ || s[ 22 ] != b':'
74
+ {
66
75
return Err ( "Date time not in imf fixdate format" . into ( ) ) ;
67
76
}
68
77
Ok ( HttpDate {
@@ -101,7 +110,7 @@ fn parse_imf_fixdate(s: &[u8]) -> Result<HttpDate, Exception> {
101
110
102
111
fn parse_rfc850_date ( s : & [ u8 ] ) -> Result < HttpDate , Exception > {
103
112
// Example: `Sunday, 06-Nov-94 08:49:37 GMT`
104
- if s. len ( ) < 23 {
113
+ if s. len ( ) < RFC850_MAX_LENGTH {
105
114
return Err ( "Date time not in rfc850 format" . into ( ) ) ;
106
115
}
107
116
@@ -155,7 +164,8 @@ fn parse_rfc850_date(s: &[u8]) -> Result<HttpDate, Exception> {
155
164
156
165
fn parse_asctime ( s : & [ u8 ] ) -> Result < HttpDate , Exception > {
157
166
// Example: `Sun Nov 6 08:49:37 1994`
158
- if s. len ( ) != 24 || s[ 10 ] != b' ' || s[ 13 ] != b':' || s[ 16 ] != b':' || s[ 19 ] != b' ' {
167
+ if s. len ( ) != ASCTIME_LENGTH || s[ 10 ] != b' ' || s[ 13 ] != b':' || s[ 16 ] != b':' || s[ 19 ] != b' '
168
+ {
159
169
return Err ( "Date time not in asctime format" . into ( ) ) ;
160
170
}
161
171
Ok ( HttpDate {
@@ -202,7 +212,7 @@ impl From<SystemTime> for HttpDate {
202
212
. expect ( "all times should be after the epoch" ) ;
203
213
let secs_since_epoch = dur. as_secs ( ) ;
204
214
205
- if secs_since_epoch >= 253402300800 {
215
+ if secs_since_epoch >= YEAR_9999_SECONDS {
206
216
// year 9999
207
217
panic ! ( "date must be before year 9999" ) ;
208
218
}
@@ -213,8 +223,8 @@ impl From<SystemTime> for HttpDate {
213
223
const DAYS_PER_100Y : i64 = 365 * 100 + 24 ;
214
224
const DAYS_PER_4Y : i64 = 365 * 4 + 1 ;
215
225
216
- let days = ( secs_since_epoch / 86400 ) as i64 - LEAPOCH ;
217
- let secs_of_day = secs_since_epoch % 86400 ;
226
+ let days = ( secs_since_epoch / SECONDS_IN_DAY ) as i64 - LEAPOCH ;
227
+ let secs_of_day = secs_since_epoch % SECONDS_IN_DAY ;
218
228
219
229
let mut qc_cycles = days / DAYS_PER_400Y ;
220
230
let mut remdays = days % DAYS_PER_400Y ;
@@ -268,8 +278,8 @@ impl From<SystemTime> for HttpDate {
268
278
269
279
HttpDate {
270
280
second : ( secs_of_day % 60 ) as u8 ,
271
- minute : ( ( secs_of_day % 3600 ) / 60 ) as u8 ,
272
- hour : ( secs_of_day / 3600 ) as u8 ,
281
+ minute : ( ( secs_of_day % SECONDS_IN_HOUR ) / 60 ) as u8 ,
282
+ hour : ( secs_of_day / SECONDS_IN_HOUR ) as u8 ,
273
283
day : mday as u8 ,
274
284
month : month as u8 ,
275
285
year : year as u16 ,
@@ -306,8 +316,8 @@ impl From<HttpDate> for SystemTime {
306
316
+ Duration :: from_secs (
307
317
http_date. second as u64
308
318
+ http_date. minute as u64 * 60
309
- + http_date. hour as u64 * 3600
310
- + days * 86400 ,
319
+ + http_date. hour as u64 * SECONDS_IN_HOUR
320
+ + days * SECONDS_IN_DAY ,
311
321
)
312
322
}
313
323
}
@@ -403,10 +413,9 @@ fn is_leap_year(year: u16) -> bool {
403
413
404
414
#[ cfg( test) ]
405
415
mod tests {
406
- use std:: str;
407
416
use std:: time:: { Duration , UNIX_EPOCH } ;
408
417
409
- use super :: { fmt_http_date, parse_http_date, HttpDate } ;
418
+ use super :: { fmt_http_date, parse_http_date, HttpDate , SECONDS_IN_DAY , SECONDS_IN_HOUR } ;
410
419
411
420
#[ test]
412
421
fn test_rfc_example ( ) {
@@ -438,9 +447,9 @@ mod tests {
438
447
fn test3 ( ) {
439
448
let mut d = UNIX_EPOCH ;
440
449
assert_eq ! ( d, parse_http_date( "Thu, 01 Jan 1970 00:00:00 GMT" ) . unwrap( ) ) ;
441
- d += Duration :: from_secs ( 3600 ) ;
450
+ d += Duration :: from_secs ( SECONDS_IN_HOUR ) ;
442
451
assert_eq ! ( d, parse_http_date( "Thu, 01 Jan 1970 01:00:00 GMT" ) . unwrap( ) ) ;
443
- d += Duration :: from_secs ( 86400 ) ;
452
+ d += Duration :: from_secs ( SECONDS_IN_DAY ) ;
444
453
assert_eq ! ( d, parse_http_date( "Fri, 02 Jan 1970 01:00:00 GMT" ) . unwrap( ) ) ;
445
454
d += Duration :: from_secs ( 2592000 ) ;
446
455
assert_eq ! ( d, parse_http_date( "Sun, 01 Feb 1970 01:00:00 GMT" ) . unwrap( ) ) ;
@@ -464,17 +473,6 @@ mod tests {
464
473
assert_eq ! ( fmt_http_date( d) , "Sun, 02 Oct 2016 14:44:11 GMT" ) ;
465
474
}
466
475
467
- #[ allow( dead_code) ]
468
- fn testcase ( data : & [ u8 ] ) {
469
- if let Ok ( s) = str:: from_utf8 ( data) {
470
- println ! ( "{:?}" , s) ;
471
- if let Ok ( d) = parse_http_date ( s) {
472
- let o = fmt_http_date ( d) ;
473
- assert ! ( !o. is_empty( ) ) ;
474
- }
475
- }
476
- }
477
-
478
476
#[ test]
479
477
fn size_of ( ) {
480
478
assert_eq ! ( :: std:: mem:: size_of:: <HttpDate >( ) , 8 ) ;
0 commit comments