Kea 2.7.5
date_time.cc
Go to the documentation of this file.
1// Copyright (C) 2016-2019 Internet Systems Consortium, Inc. ("ISC")
2//
3// This Source Code Form is subject to the terms of the Mozilla Public
4// License, v. 2.0. If a copy of the MPL was not distributed with this
5// file, You can obtain one at http://mozilla.org/MPL/2.0/.
6
7#include <config.h>
8
9#include <http/date_time.h>
10#include <boost/date_time/time_facet.hpp>
11#include <boost/date_time/local_time/local_time.hpp>
12#include <locale>
13#include <sstream>
14
15using namespace boost::local_time;
16using namespace boost::posix_time;
17
18namespace isc {
19namespace http {
20
22 : time_(boost::posix_time::second_clock::universal_time()) {
23}
24
25HttpDateTime::HttpDateTime(const boost::posix_time::ptime& t)
26 : time_(t) {
27}
28
29std::string
31 return (toString("%a, %d %b %Y %H:%M:%S GMT", "RFC 1123"));
32}
33
34std::string
36 return (toString("%A, %d-%b-%y %H:%M:%S GMT", "RFC 850"));
37}
38
39std::string
41 return (toString("%a %b %e %H:%M:%S %Y", "asctime"));
42}
43
45HttpDateTime::fromRfc1123(const std::string& time_string) {
46 return (HttpDateTime(fromString(time_string,
47 "%a, %d %b %Y %H:%M:%S %ZP",
48 "RFC 1123")));
49}
50
52HttpDateTime::fromRfc850(const std::string& time_string) {
53 return (HttpDateTime(fromString(time_string,
54 "%A, %d-%b-%y %H:%M:%S %ZP",
55 "RFC 850")));
56}
57
59HttpDateTime::fromAsctime(const std::string& time_string) {
60 // The asctime() puts space instead of leading 0 in days of
61 // month. The %e # formatter of time_input_facet doesn't deal
62 // with this. To deal with this, we make a copy of the string
63 // holding formatted time and replace a space preceding day
64 // number with 0. Thanks to this workaround we can use the
65 // %d formatter which seems to work fine. This has a side
66 // effect of accepting timestamps such as Sun Nov 06 08:49:37 1994,
67 // but it should be ok to be liberal in this case.
68 std::string time_string_copy(time_string);
69 boost::replace_all(time_string_copy, " ", " 0");
70 return (HttpDateTime(fromString(time_string_copy,
71 "%a %b %d %H:%M:%S %Y",
72 "asctime",
73 false)));
74}
75
77HttpDateTime::fromAny(const std::string& time_string) {
78 HttpDateTime date_time;
79 // Try to parse as a timestamp specified in RFC 1123 format.
80 try {
81 date_time = fromRfc1123(time_string);
82 return (date_time);
83 } catch (...) {
84 // Ignore errors, simply try different format.
85 }
86
87 // Try to parse as a timestamp specified in RFC 850 format.
88 try {
89 date_time = fromRfc850(time_string);
90 return (date_time);
91 } catch (...) {
92 // Ignore errors, simply try different format.
93 }
94
95 // Try to parse as a timestamp output by asctime() function.
96 try {
97 date_time = fromAsctime(time_string);
98 } catch (...) {
100 "unsupported time format of the '" << time_string
101 << "'");
102 }
103
104 return (date_time);
105
106}
107
108std::string
109HttpDateTime::toString(const std::string& format,
110 const std::string& method_name) const {
111 std::ostringstream s;
112 // Create raw pointer. The output stream will take responsibility for
113 // deleting the object.
114 time_facet* df(new time_facet(format.c_str()));
115 s.imbue(std::locale(std::locale::classic(), df));
116
117 // Convert time value to a string.
118 s << time_;
119 if (s.fail()) {
120 isc_throw(HttpTimeConversionError, "unable to convert "
121 << "time value of '" << time_ << "'"
122 << " to " << method_name << " format");
123 }
124 return (s.str());
125}
126
127
128ptime
129HttpDateTime::fromString(const std::string& time_string,
130 const std::string& format,
131 const std::string& method_name,
132 const bool zone_check) {
133 std::istringstream s(time_string);
134 // Create raw pointer. The input stream will take responsibility for
135 // deleting the object.
136 time_input_facet* tif(new time_input_facet(format));
137 s.imbue(std::locale(std::locale::classic(), tif));
138
139 time_zone_ptr zone(new posix_time_zone("GMT"));
140 local_date_time ldt = local_microsec_clock::local_time(zone);
141
142 // Parse the time value. The stream will not automatically detect whether
143 // the zone is GMT. We need to check it on our own.
144 s >> ldt;
145 if (s.fail() ||
146 (zone_check && (!ldt.zone() ||
147 ldt.zone()->std_zone_abbrev() != "GMT"))) {
148 isc_throw(HttpTimeConversionError, "unable to parse "
149 << method_name << " time value of '"
150 << time_string << "'");
151 }
152
153 return (ldt.local_time());
154}
155
156
157} // namespace http
158} // namespace isc
This class parses and generates time values used in HTTP.
Definition date_time.h:41
std::string rfc1123Format() const
Returns time value formatted as specified in RFC 1123.
Definition date_time.cc:30
HttpDateTime()
Default constructor.
Definition date_time.cc:21
std::string asctimeFormat() const
Returns time value formatted as output of ANSI C's asctime().
Definition date_time.cc:40
static HttpDateTime fromRfc850(const std::string &time_string)
Creates an instance from a string containing time value formatted as specified in RFC 850.
Definition date_time.cc:52
static HttpDateTime fromRfc1123(const std::string &time_string)
Creates an instance from a string containing time value formatted as specified in RFC 1123.
Definition date_time.cc:45
std::string rfc850Format() const
Returns time value formatted as specified in RFC 850.
Definition date_time.cc:35
static HttpDateTime fromAsctime(const std::string &time_string)
Creates an instance from a string containing time value formatted as output from asctime() function.
Definition date_time.cc:59
static HttpDateTime fromAny(const std::string &time_string)
Creates an instance from a string containing time value formatted in one of the supported formats.
Definition date_time.cc:77
Exception thrown when there is an error during time conversion.
Definition date_time.h:21
#define isc_throw(type, stream)
A shortcut macro to insert known values into exception arguments.
Defines the logger used by the top-level component of kea-lfc.