rfc1123.cc
Go to the documentation of this file.
1/*
2 * Copyright (C) 1996-2023 The Squid Software Foundation and contributors
3 *
4 * Squid software is distributed under GPLv2+ license and includes
5 * contributions from numerous individuals and organizations.
6 * Please see the COPYING and CONTRIBUTORS files for details.
7 */
8
9#include "squid.h"
10#include "time/gadgets.h"
11
12/*
13 * Adapted from HTSUtils.c in CERN httpd 3.0 (http://info.cern.ch/httpd/)
14 * by Darren Hardy <hardy@cs.colorado.edu>, November 1994.
15 */
16#include <cctype>
17#include <cstring>
18#include <ctime>
19
20#define RFC850_STRFTIME "%A, %d-%b-%y %H:%M:%S GMT"
21#define RFC1123_STRFTIME "%a, %d %b %Y %H:%M:%S GMT"
22
23static int make_month(const char *s);
24static int make_num(const char *s);
25
26static const char *month_names[12] = {
27 "Jan", "Feb", "Mar", "Apr", "May", "Jun",
28 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
29};
30
31static int
32make_num(const char *s)
33{
34 if (*s >= '0' && *s <= '9')
35 return 10 * (*s - '0') + *(s + 1) - '0';
36 else
37 return *(s + 1) - '0';
38}
39
40static int
41make_month(const char *s)
42{
43 int i;
44 char month[3];
45
46 month[0] = xtoupper(*s);
47 month[1] = xtolower(*(s + 1));
48 month[2] = xtolower(*(s + 2));
49
50 for (i = 0; i < 12; i++)
51 if (!strncmp(month_names[i], month, 3))
52 return i;
53 return -1;
54}
55
56static int
57tmSaneValues(struct tm *tm)
58{
59 if (tm->tm_sec < 0 || tm->tm_sec > 59)
60 return 0;
61 if (tm->tm_min < 0 || tm->tm_min > 59)
62 return 0;
63 if (tm->tm_hour < 0 || tm->tm_hour > 23)
64 return 0;
65 if (tm->tm_mday < 1 || tm->tm_mday > 31)
66 return 0;
67 if (tm->tm_mon < 0 || tm->tm_mon > 11)
68 return 0;
69 return 1;
70}
71
72static struct tm *
73parse_date_elements(const char *day, const char *month, const char *year,
74 const char *aTime, const char *zone) {
75 static struct tm tm;
76 const char *t;
77 memset(&tm, 0, sizeof(tm));
78
79 if (!day || !month || !year || !aTime || (zone && strcmp(zone, "GMT")))
80 return nullptr;
81 tm.tm_mday = atoi(day);
82 tm.tm_mon = make_month(month);
83 if (tm.tm_mon < 0)
84 return nullptr;
85 tm.tm_year = atoi(year);
86 if (strlen(year) == 4)
87 tm.tm_year -= 1900;
88 else if (tm.tm_year < 70)
89 tm.tm_year += 100;
90 else if (tm.tm_year > 19000)
91 tm.tm_year -= 19000;
92 tm.tm_hour = make_num(aTime);
93 t = strchr(aTime, ':');
94 if (!t)
95 return nullptr;
96 t++;
97 tm.tm_min = atoi(t);
98 t = strchr(t, ':');
99 if (t)
100 tm.tm_sec = atoi(t + 1);
101 return tmSaneValues(&tm) ? &tm : nullptr;
102}
103
104static struct tm *
105parse_date(const char *str) {
106 struct tm *tm;
107 static char tmp[64];
108 char *t;
109 char *wday = nullptr;
110 char *day = nullptr;
111 char *month = nullptr;
112 char *year = nullptr;
113 char *timestr = nullptr;
114 char *zone = nullptr;
115
116 xstrncpy(tmp, str, 64);
117
118 for (t = strtok(tmp, ", "); t; t = strtok(nullptr, ", ")) {
119 if (xisdigit(*t)) {
120 if (!day) {
121 day = t;
122 t = strchr(t, '-');
123 if (t) {
124 *t++ = '\0';
125 month = t;
126 t = strchr(t, '-');
127 if (!t)
128 return nullptr;
129 *t++ = '\0';
130 year = t;
131 }
132 } else if (strchr(t, ':'))
133 timestr = t;
134 else if (!year)
135 year = t;
136 else
137 return nullptr;
138 } else if (!wday)
139 wday = t;
140 else if (!month)
141 month = t;
142 else if (!zone)
143 zone = t;
144 else
145 return nullptr;
146 }
147 tm = parse_date_elements(day, month, year, timestr, zone);
148
149 return tm;
150}
151
152time_t
153Time::ParseRfc1123(const char *str)
154{
155 struct tm *tm;
156 time_t t;
157 if (nullptr == str)
158 return -1;
159 tm = parse_date(str);
160 if (!tm)
161 return -1;
162 tm->tm_isdst = -1;
163#if HAVE_TIMEGM
164 t = timegm(tm);
165#elif HAVE_TM_TM_GMTOFF
166 t = mktime(tm);
167 if (t != -1) {
168 struct tm *local = localtime(&t);
169 t += local->tm_gmtoff;
170 }
171#else
172 /* some systems do not have tm_gmtoff so we fake it */
173 t = mktime(tm);
174 if (t != -1) {
175 time_t dst = 0;
176#if !(defined(_TIMEZONE) || defined(_timezone) || _SQUID_AIX_ || _SQUID_WINDOWS_ || _SQUID_SGI_)
177 extern long timezone;
178#endif
179 /*
180 * The following assumes a fixed DST offset of 1 hour,
181 * which is probably wrong.
182 */
183 if (tm->tm_isdst > 0)
184 dst = -3600;
185#if defined(_timezone) || _SQUID_WINDOWS_
186 t -= (_timezone + dst);
187#else
188 t -= (timezone + dst);
189#endif
190 }
191#endif
192 return t;
193}
194
195const char *
197{
198 static char buf[128];
199
200 struct tm *gmt = gmtime(&t);
201
202 buf[0] = '\0';
203 strftime(buf, 127, RFC1123_STRFTIME, gmt);
204 return buf;
205}
206
time_t ParseRfc1123(const char *)
Convert from RFC 1123 style time: "www, DD MMM YYYY hh:mm:ss ZZZ".
Definition: rfc1123.cc:153
const char * FormatRfc1123(time_t)
Definition: rfc1123.cc:196
static struct tm * parse_date(const char *str)
Definition: rfc1123.cc:105
static struct tm * parse_date_elements(const char *day, const char *month, const char *year, const char *aTime, const char *zone)
Definition: rfc1123.cc:73
static int make_month(const char *s)
Definition: rfc1123.cc:41
#define RFC1123_STRFTIME
Definition: rfc1123.cc:21
static int tmSaneValues(struct tm *tm)
Definition: rfc1123.cc:57
static int make_num(const char *s)
Definition: rfc1123.cc:32
static const char * month_names[12]
Definition: rfc1123.cc:26
#define xtoupper(x)
Definition: xis.h:16
#define xisdigit(x)
Definition: xis.h:18
#define xtolower(x)
Definition: xis.h:17
char * xstrncpy(char *dst, const char *src, size_t n)
Definition: xstring.cc:37

 

Introduction

Documentation

Support

Miscellaneous

Web Site Translations

Mirrors