]> git.ipfire.org Git - thirdparty/squid.git/blob - lib/rfc1123.c
Merge from trunk
[thirdparty/squid.git] / lib / rfc1123.c
1
2 /*
3 * $Id$
4 *
5 * DEBUG:
6 * AUTHOR: Harvest Derived
7 *
8 * SQUID Web Proxy Cache http://www.squid-cache.org/
9 * ----------------------------------------------------------
10 *
11 * Squid is the result of efforts by numerous individuals from
12 * the Internet community; see the CONTRIBUTORS file for full
13 * details. Many organizations have provided support for Squid's
14 * development; see the SPONSORS file for full details. Squid is
15 * Copyrighted (C) 2001 by the Regents of the University of
16 * California; see the COPYRIGHT file for full details. Squid
17 * incorporates software developed and/or copyrighted by other
18 * sources; see the CREDITS file for full details.
19 *
20 * This program is free software; you can redistribute it and/or modify
21 * it under the terms of the GNU General Public License as published by
22 * the Free Software Foundation; either version 2 of the License, or
23 * (at your option) any later version.
24 *
25 * This program is distributed in the hope that it will be useful,
26 * but WITHOUT ANY WARRANTY; without even the implied warranty of
27 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
28 * GNU General Public License for more details.
29 *
30 * You should have received a copy of the GNU General Public License
31 * along with this program; if not, write to the Free Software
32 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
33 *
34 */
35
36 #include "config.h"
37
38
39 /*
40 * Adapted from HTSUtils.c in CERN httpd 3.0 (http://info.cern.ch/httpd/)
41 * by Darren Hardy <hardy@cs.colorado.edu>, November 1994.
42 */
43 #if HAVE_STDIO_H
44 #include <stdio.h>
45 #endif
46 #if HAVE_STDLIB_H
47 #include <stdlib.h>
48 #endif
49 #if HAVE_STRING_H
50 #include <string.h>
51 #endif
52 #if HAVE_CTYPE_H
53 #include <ctype.h>
54 #endif
55 #if HAVE_SYS_TYPES_H
56 #include <sys/types.h>
57 #endif
58 #if HAVE_TIME_H
59 #include <time.h>
60 #endif
61 #if HAVE_SYS_TIME_H
62 #include <sys/time.h>
63 #endif
64 #include "assert.h"
65
66 #include "util.h"
67
68 #define RFC850_STRFTIME "%A, %d-%b-%y %H:%M:%S GMT"
69 #define RFC1123_STRFTIME "%a, %d %b %Y %H:%M:%S GMT"
70
71 static int make_month(const char *s);
72 static int make_num(const char *s);
73
74 static const char *month_names[12] = {
75 "Jan", "Feb", "Mar", "Apr", "May", "Jun",
76 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
77 };
78
79
80 static int
81 make_num(const char *s)
82 {
83 if (*s >= '0' && *s <= '9')
84 return 10 * (*s - '0') + *(s + 1) - '0';
85 else
86 return *(s + 1) - '0';
87 }
88
89 static int
90 make_month(const char *s)
91 {
92 int i;
93 char month[3];
94
95 month[0] = xtoupper(*s);
96 month[1] = xtolower(*(s + 1));
97 month[2] = xtolower(*(s + 2));
98
99 for (i = 0; i < 12; i++)
100 if (!strncmp(month_names[i], month, 3))
101 return i;
102 return -1;
103 }
104
105 static int
106 tmSaneValues(struct tm *tm)
107 {
108 if (tm->tm_sec < 0 || tm->tm_sec > 59)
109 return 0;
110 if (tm->tm_min < 0 || tm->tm_min > 59)
111 return 0;
112 if (tm->tm_hour < 0 || tm->tm_hour > 23)
113 return 0;
114 if (tm->tm_mday < 1 || tm->tm_mday > 31)
115 return 0;
116 if (tm->tm_mon < 0 || tm->tm_mon > 11)
117 return 0;
118 return 1;
119 }
120
121 static struct tm *
122 parse_date_elements(const char *day, const char *month, const char *year,
123 const char *time, const char *zone) {
124 static struct tm tm;
125 char *t;
126 memset(&tm, 0, sizeof(tm));
127
128 if (!day || !month || !year || !time)
129 return NULL;
130 tm.tm_mday = atoi(day);
131 tm.tm_mon = make_month(month);
132 if (tm.tm_mon < 0)
133 return NULL;
134 tm.tm_year = atoi(year);
135 if (strlen(year) == 4)
136 tm.tm_year -= 1900;
137 else if (tm.tm_year < 70)
138 tm.tm_year += 100;
139 else if (tm.tm_year > 19000)
140 tm.tm_year -= 19000;
141 tm.tm_hour = make_num(time);
142 t = strchr(time, ':');
143 if (!t)
144 return NULL;
145 t++;
146 tm.tm_min = atoi(t);
147 t = strchr(t, ':');
148 if (t)
149 tm.tm_sec = atoi(t + 1);
150 return tmSaneValues(&tm) ? &tm : NULL;
151 }
152
153 static struct tm *
154 parse_date(const char *str) {
155 struct tm *tm;
156 static char tmp[64];
157 char *t;
158 char *wday = NULL;
159 char *day = NULL;
160 char *month = NULL;
161 char *year = NULL;
162 char *time = NULL;
163 char *zone = NULL;
164
165 xstrncpy(tmp, str, 64);
166
167 for (t = strtok(tmp, ", "); t; t = strtok(NULL, ", ")) {
168 if (xisdigit(*t)) {
169 if (!day) {
170 day = t;
171 t = strchr(t, '-');
172 if (t) {
173 *t++ = '\0';
174 month = t;
175 t = strchr(t, '-');
176 if (!t)
177 return NULL;
178 *t++ = '\0';
179 year = t;
180 }
181 } else if (strchr(t, ':'))
182 time = t;
183 else if (!year)
184 year = t;
185 } else if (!wday)
186 wday = t;
187 else if (!month)
188 month = t;
189 else if (!zone)
190 zone = t;
191 }
192 tm = parse_date_elements(day, month, year, time, zone);
193
194 return tm;
195 }
196
197 time_t
198 parse_rfc1123(const char *str)
199 {
200 struct tm *tm;
201 time_t t;
202 if (NULL == str)
203 return -1;
204 tm = parse_date(str);
205 if (!tm)
206 return -1;
207 tm->tm_isdst = -1;
208 #ifdef HAVE_TIMEGM
209 t = timegm(tm);
210 #elif HAVE_TM_TM_GMTOFF
211 t = mktime(tm);
212 if (t != -1) {
213 struct tm *local = localtime(&t);
214 t += local->tm_gmtoff;
215 }
216 #else
217 /* some systems do not have tm_gmtoff so we fake it */
218 t = mktime(tm);
219 if (t != -1) {
220 time_t dst = 0;
221 #if defined (_TIMEZONE)
222 #elif defined (_timezone)
223 #elif defined(_SQUID_AIX_)
224 #elif defined(_SQUID_CYGWIN_)
225 #elif defined(_SQUID_MSWIN_)
226 #elif defined(_SQUID_SGI_)
227 #else
228 extern long timezone;
229 #endif
230 /*
231 * The following assumes a fixed DST offset of 1 hour,
232 * which is probably wrong.
233 */
234 if (tm->tm_isdst > 0)
235 dst = -3600;
236 #if defined ( _timezone) || defined(_SQUID_WIN32_)
237 t -= (_timezone + dst);
238 #else
239 t -= (timezone + dst);
240 #endif
241 }
242 #endif
243 return t;
244 }
245
246 const char *
247 mkrfc1123(time_t t)
248 {
249 static char buf[128];
250
251 struct tm *gmt = gmtime(&t);
252
253 buf[0] = '\0';
254 strftime(buf, 127, RFC1123_STRFTIME, gmt);
255 return buf;
256 }
257
258 const char *
259 mkhttpdlogtime(const time_t * t)
260 {
261 static char buf[128];
262
263 struct tm *gmt = gmtime(t);
264
265 #ifndef USE_GMT
266 int gmt_min, gmt_hour, gmt_yday, day_offset;
267 size_t len;
268 struct tm *lt;
269 int min_offset;
270
271 /* localtime & gmtime may use the same static data */
272 gmt_min = gmt->tm_min;
273 gmt_hour = gmt->tm_hour;
274 gmt_yday = gmt->tm_yday;
275
276 lt = localtime(t);
277
278 day_offset = lt->tm_yday - gmt_yday;
279 /* wrap round on end of year */
280 if (day_offset > 1)
281 day_offset = -1;
282 else if (day_offset < -1)
283 day_offset = 1;
284
285 min_offset = day_offset * 1440 + (lt->tm_hour - gmt_hour) * 60
286 + (lt->tm_min - gmt_min);
287
288 len = strftime(buf, 127 - 5, "%d/%b/%Y:%H:%M:%S ", lt);
289 snprintf(buf + len, 128 - len, "%+03d%02d",
290 (min_offset / 60) % 24,
291 min_offset % 60);
292 #else /* USE_GMT */
293 buf[0] = '\0';
294 strftime(buf, 127, "%d/%b/%Y:%H:%M:%S -000", gmt);
295 #endif /* USE_GMT */
296
297 return buf;
298 }
299
300 #if 0
301 int
302 main()
303 {
304 char *x;
305 time_t t, pt;
306
307 t = time(NULL);
308 x = mkrfc1123(t);
309 printf("HTTP Time: %s\n", x);
310
311 pt = parse_rfc1123(x);
312 printf("Parsed: %d vs. %d\n", pt, t);
313 }
314
315 #endif