Kea  1.9.9-git
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 
15 using namespace boost::local_time;
16 using namespace boost::posix_time;
17 
18 namespace isc {
19 namespace http {
20 
21 HttpDateTime::HttpDateTime()
22  : time_(boost::posix_time::second_clock::universal_time()) {
23 }
24 
25 HttpDateTime::HttpDateTime(const boost::posix_time::ptime& t)
26  : time_(t) {
27 }
28 
29 std::string
31  return (toString("%a, %d %b %Y %H:%M:%S GMT", "RFC 1123"));
32 }
33 
34 std::string
36  return (toString("%A, %d-%b-%y %H:%M:%S GMT", "RFC 850"));
37 }
38 
39 std::string
41  return (toString("%a %b %e %H:%M:%S %Y", "asctime"));
42 }
43 
45 HttpDateTime::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 
52 HttpDateTime::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 
59 HttpDateTime::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 
77 HttpDateTime::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 
108 std::string
109 HttpDateTime::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 
128 ptime
129 HttpDateTime::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
std::string asctimeFormat() const
Returns time value formatted as output of ANSI C's asctime().
Definition: date_time.cc:40
std::string rfc1123Format() const
Returns time value formatted as specified in RFC 1123.
Definition: date_time.cc:30
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
#define isc_throw(type, stream)
A shortcut macro to insert known values into exception arguments.
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 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
This class parses and generates time values used in HTTP.
Definition: date_time.h:41
Defines the logger used by the top-level component of kea-dhcp-ddns.
std::string rfc850Format() const
Returns time value formatted as specified in RFC 850.
Definition: date_time.cc:35
HttpDateTime()
Default constructor.
Definition: date_time.cc:21
Exception thrown when there is an error during time conversion.
Definition: date_time.h:21
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
std::string format(const std::string &format, const std::vector< std::string > &args)
Apply Formatting.
Definition: strutil.cc:157