]> git.ipfire.org Git - thirdparty/squid.git/blob - lib/rfc1123.c
Source Format Enforcement (#532)
[thirdparty/squid.git] / lib / rfc1123.c
1 /*
2 * Copyright (C) 1996-2020 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 "rfc1123.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 #if HAVE_STRING_H
17 #include <string.h>
18 #endif
19 #if HAVE_CTYPE_H
20 #include <ctype.h>
21 #endif
22 #if HAVE_TIME_H
23 #include <time.h>
24 #endif
25
26 #define RFC850_STRFTIME "%A, %d-%b-%y %H:%M:%S GMT"
27 #define RFC1123_STRFTIME "%a, %d %b %Y %H:%M:%S GMT"
28
29 static int make_month(const char *s);
30 static int make_num(const char *s);
31
32 static const char *month_names[12] = {
33 "Jan", "Feb", "Mar", "Apr", "May", "Jun",
34 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
35 };
36
37 static int
38 make_num(const char *s)
39 {
40 if (*s >= '0' && *s <= '9')
41 return 10 * (*s - '0') + *(s + 1) - '0';
42 else
43 return *(s + 1) - '0';
44 }
45
46 static int
47 make_month(const char *s)
48 {
49 int i;
50 char month[3];
51
52 month[0] = xtoupper(*s);
53 month[1] = xtolower(*(s + 1));
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 char *t;
83 memset(&tm, 0, sizeof(tm));
84
85 if (!day || !month || !year || !aTime || (zone && strcmp(zone, "GMT")))
86 return NULL;
87 tm.tm_mday = atoi(day);
88 tm.tm_mon = make_month(month);
89 if (tm.tm_mon < 0)
90 return NULL;
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 NULL;
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 : NULL;
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 = NULL;
116 char *day = NULL;
117 char *month = NULL;
118 char *year = NULL;
119 char *timestr = NULL;
120 char *zone = NULL;
121
122 xstrncpy(tmp, str, 64);
123
124 for (t = strtok(tmp, ", "); t; t = strtok(NULL, ", ")) {
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 NULL;
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 NULL;
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 NULL;
152 }
153 tm = parse_date_elements(day, month, year, timestr, zone);
154
155 return tm;
156 }
157
158 time_t
159 parse_rfc1123(const char *str)
160 {
161 struct tm *tm;
162 time_t t;
163 if (NULL == 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 *
202 mkrfc1123(time_t t)
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
213 #if 0
214 int
215 main()
216 {
217 char *x;
218 time_t t, pt;
219
220 t = time(NULL);
221 x = mkrfc1123(t);
222 printf("HTTP Time: %s\n", x);
223
224 pt = parse_rfc1123(x);
225 printf("Parsed: %d vs. %d\n", pt, t);
226 }
227
228 #endif
229