1 /******************************************************************************
2 
3     Parses a HTTP compliant date/time string and converts it to the
4     UNIX time value
5 
6     Copyright:
7         Copyright (c) 2009-2016 dunnhumby Germany GmbH.
8         All rights reserved.
9 
10     License:
11         Boost Software License Version 1.0. See LICENSE_BOOST.txt for details.
12         Alternatively, this file may be distributed under the terms of the Tango
13         3-Clause BSD License (see LICENSE_BSD.txt for details).
14 
15  ******************************************************************************/
16 
17 module ocean.net.http.time.HttpTimeParser;
18 
19 
20 import ocean.meta.types.Qualifiers;
21 
22 import TimeStamp = ocean.text.convert.TimeStamp: rfc1123, rfc850, asctime;
23 
24 import ocean.time.Time: Date, TimeOfDay;
25 
26 import core.stdc.time: time_t, tm;
27 import core.sys.posix.time: timegm;
28 
29 version (unittest) import ocean.core.Test;
30 
31 /******************************************************************************
32 
33     Parses timestamp, which is expected to be a HTTP compliant date/time string,
34     and converts it to the UNIX time value.
35 
36         @see http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.3
37 
38     Params:
39         timestamp = HTTP compliant date/time string
40         t         = resulting UNIX time value; changed only if the return value
41                     is true
42 
43     Returns:
44         true if the conversion succeeded or false on parse error or invalid
45         date/time value
46 
47  ******************************************************************************/
48 
49 bool parse ( cstring timestamp, ref time_t t )
50 {
51     Date      date;
52     TimeOfDay tod;
53 
54     bool ok = TimeStamp.rfc1123(timestamp, tod, date) != 0;
55 
56     if (!ok)
57     {
58         ok = TimeStamp.rfc850(timestamp, tod, date) != 0;
59     }
60 
61     if (!ok)
62     {
63         ok = TimeStamp.asctime(timestamp, tod, date) != 0;
64     }
65 
66     if (ok)
67     {
68         tm timeval;
69 
70         with (timeval)
71         {
72             tm_sec  = tod.seconds;
73             tm_min  = tod.minutes;
74             tm_hour = tod.hours;
75             tm_mday = date.day;
76             tm_mon  = date.month - 1;
77             tm_year = date.year - 1900;
78         }
79 
80         time_t t_ = timegm(&timeval);
81 
82         ok = t_ >= 0;
83 
84         if (ok)
85         {
86             t = t_;
87         }
88     }
89 
90     return ok;
91 }
92 
93 /******************************************************************************
94 
95     Using http://www.epochconverter.com/ as reference.
96 
97  ******************************************************************************/
98 
99 unittest
100 {
101     static immutable time_t T = 352716457;
102 
103     time_t t;
104 
105     bool ok = parse("Fri, 06 Mar 1981 08:47:37 GMT", t);
106     test (ok);
107     test (t == T);
108 
109     ok = parse("Friday, 06-Mar-81 08:47:37 GMT", t);
110     test (ok);
111     test (t == T);
112 
113     ok = parse("Fri Mar  6 08:47:37 1981", t);
114     test (ok);
115     test (t == T);
116 }