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 
23 static int make_month(const char *s);
24 static int make_num(const char *s);
25 
26 static const char *month_names[12] = {
27  "Jan", "Feb", "Mar", "Apr", "May", "Jun",
28  "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
29 };
30 
31 static int
32 make_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 
40 static int
41 make_month(const char *s)
42 {
43  int i;
44  char month[3];
45 
46  month[0] = xtoupper(*s);
47  if (!month[0])
48  return -1; // protects *(s + 1) below
49 
50  month[1] = xtolower(*(s + 1));
51  if (!month[1])
52  return -1; // protects *(s + 2) below
53 
54  month[2] = xtolower(*(s + 2));
55 
56  for (i = 0; i < 12; i++)
57  if (!strncmp(month_names[i], month, 3))
58  return i;
59  return -1;
60 }
61 
62 static int
63 tmSaneValues(struct tm *tm)
64 {
65  if (tm->tm_sec < 0 || tm->tm_sec > 59)
66  return 0;
67  if (tm->tm_min < 0 || tm->tm_min > 59)
68  return 0;
69  if (tm->tm_hour < 0 || tm->tm_hour > 23)
70  return 0;
71  if (tm->tm_mday < 1 || tm->tm_mday > 31)
72  return 0;
73  if (tm->tm_mon < 0 || tm->tm_mon > 11)
74  return 0;
75  return 1;
76 }
77 
78 static struct tm *
79 parse_date_elements(const char *day, const char *month, const char *year,
80  const char *aTime, const char *zone) {
81  static struct tm tm;
82  const char *t;
83  memset(&tm, 0, sizeof(tm));
84 
85  if (!day || !month || !year || !aTime || (zone && strcmp(zone, "GMT")))
86  return nullptr;
87  tm.tm_mday = atoi(day);
88  tm.tm_mon = make_month(month);
89  if (tm.tm_mon < 0)
90  return nullptr;
91  tm.tm_year = atoi(year);
92  if (strlen(year) == 4)
93  tm.tm_year -= 1900;
94  else if (tm.tm_year < 70)
95  tm.tm_year += 100;
96  else if (tm.tm_year > 19000)
97  tm.tm_year -= 19000;
98  tm.tm_hour = make_num(aTime);
99  t = strchr(aTime, ':');
100  if (!t)
101  return nullptr;
102  t++;
103  tm.tm_min = atoi(t);
104  t = strchr(t, ':');
105  if (t)
106  tm.tm_sec = atoi(t + 1);
107  return tmSaneValues(&tm) ? &tm : nullptr;
108 }
109 
110 static struct tm *
111 parse_date(const char *str) {
112  struct tm *tm;
113  static char tmp[64];
114  char *t;
115  char *wday = nullptr;
116  char *day = nullptr;
117  char *month = nullptr;
118  char *year = nullptr;
119  char *timestr = nullptr;
120  char *zone = nullptr;
121 
122  xstrncpy(tmp, str, 64);
123 
124  for (t = strtok(tmp, ", "); t; t = strtok(nullptr, ", ")) {
125  if (xisdigit(*t)) {
126  if (!day) {
127  day = t;
128  t = strchr(t, '-');
129  if (t) {
130  *t++ = '\0';
131  month = t;
132  t = strchr(t, '-');
133  if (!t)
134  return nullptr;
135  *t++ = '\0';
136  year = t;
137  }
138  } else if (strchr(t, ':'))
139  timestr = t;
140  else if (!year)
141  year = t;
142  else
143  return nullptr;
144  } else if (!wday)
145  wday = t;
146  else if (!month)
147  month = t;
148  else if (!zone)
149  zone = t;
150  else
151  return nullptr;
152  }
153  tm = parse_date_elements(day, month, year, timestr, zone);
154 
155  return tm;
156 }
157 
158 time_t
159 Time::ParseRfc1123(const char *str)
160 {
161  struct tm *tm;
162  time_t t;
163  if (nullptr == str)
164  return -1;
165  tm = parse_date(str);
166  if (!tm)
167  return -1;
168  tm->tm_isdst = -1;
169 #if HAVE_TIMEGM
170  t = timegm(tm);
171 #elif HAVE_TM_TM_GMTOFF
172  t = mktime(tm);
173  if (t != -1) {
174  struct tm *local = localtime(&t);
175  t += local->tm_gmtoff;
176  }
177 #else
178  /* some systems do not have tm_gmtoff so we fake it */
179  t = mktime(tm);
180  if (t != -1) {
181  time_t dst = 0;
182 #if !(defined(_TIMEZONE) || defined(_timezone) || _SQUID_AIX_ || _SQUID_WINDOWS_ || _SQUID_SGI_)
183  extern long timezone;
184 #endif
185  /*
186  * The following assumes a fixed DST offset of 1 hour,
187  * which is probably wrong.
188  */
189  if (tm->tm_isdst > 0)
190  dst = -3600;
191 #if defined(_timezone) || _SQUID_WINDOWS_
192  t -= (_timezone + dst);
193 #else
194  t -= (timezone + dst);
195 #endif
196  }
197 #endif
198  return t;
199 }
200 
201 const char *
203 {
204  static char buf[128];
205 
206  struct tm *gmt = gmtime(&t);
207 
208  buf[0] = '\0';
209  strftime(buf, 127, RFC1123_STRFTIME, gmt);
210  return buf;
211 }
212 
static int make_num(const char *s)
Definition: rfc1123.cc:32
#define RFC1123_STRFTIME
Definition: rfc1123.cc:21
#define xtoupper(x)
Definition: xis.h:16
time_t ParseRfc1123(const char *)
Convert from RFC 1123 style time: "www, DD MMM YYYY hh:mm:ss ZZZ".
Definition: rfc1123.cc:159
char * xstrncpy(char *dst, const char *src, size_t n)
Definition: xstring.cc:37
#define xtolower(x)
Definition: xis.h:17
static int make_month(const char *s)
Definition: rfc1123.cc:41
const char * FormatRfc1123(time_t)
Definition: rfc1123.cc:202
static struct tm * parse_date(const char *str)
Definition: rfc1123.cc:111
static int tmSaneValues(struct tm *tm)
Definition: rfc1123.cc:63
static struct tm * parse_date_elements(const char *day, const char *month, const char *year, const char *aTime, const char *zone)
Definition: rfc1123.cc:79
#define xisdigit(x)
Definition: xis.h:18
static const char * month_names[12]
Definition: rfc1123.cc:26

 

Introduction

Documentation

Support

Miscellaneous