]> git.ipfire.org Git - thirdparty/squid.git/blob - lib/rfc1123.c
Updated copyright
[thirdparty/squid.git] / lib / rfc1123.c
1
2 /*
3 * $Id: rfc1123.c,v 1.28 2001/01/12 00:37:13 wessels Exp $
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 #include "snprintf.h"
68
69 #define RFC850_STRFTIME "%A, %d-%b-%y %H:%M:%S GMT"
70 #define RFC1123_STRFTIME "%a, %d %b %Y %H:%M:%S GMT"
71
72 static const char *const w_space = " \t\r\n";
73
74 static int make_month(const char *s);
75 static int make_num(const char *s);
76
77 static char *month_names[12] =
78 {
79 "Jan", "Feb", "Mar", "Apr", "May", "Jun",
80 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
81 };
82
83
84 static int
85 make_num(const char *s)
86 {
87 if (*s >= '0' && *s <= '9')
88 return 10 * (*s - '0') + *(s + 1) - '0';
89 else
90 return *(s + 1) - '0';
91 }
92
93 static int
94 make_month(const char *s)
95 {
96 int i;
97 char month[3];
98
99 month[0] = xtoupper(*s);
100 month[1] = xtolower(*(s + 1));
101 month[2] = xtolower(*(s + 2));
102
103 for (i = 0; i < 12; i++)
104 if (!strncmp(month_names[i], month, 3))
105 return i;
106 return 0;
107 }
108
109 static int
110 tmSaneValues(struct tm *tm)
111 {
112 if (tm->tm_sec < 0 || tm->tm_sec > 59)
113 return 0;
114 if (tm->tm_min < 0 || tm->tm_min > 59)
115 return 0;
116 if (tm->tm_hour < 0 || tm->tm_hour > 23)
117 return 0;
118 if (tm->tm_mday < 1 || tm->tm_mday > 31)
119 return 0;
120 if (tm->tm_mon < 0 || tm->tm_mon > 11)
121 return 0;
122 if (tm->tm_year < 70 || tm->tm_year > 120)
123 return 0;
124 return 1;
125 }
126
127 static struct tm *
128 parse_date1(const char *str)
129 {
130 /* Thursday, 10-Jun-93 01:29:59 GMT */
131 const char *s;
132 static struct tm tm;
133 assert(NULL != str);
134 memset(&tm, '\0', sizeof(struct tm));
135 s = strchr(str, ',');
136 if (NULL == s)
137 return NULL;
138 s++;
139 while (*s == ' ')
140 s++;
141 /* backup if month is only one digit */
142 if (xisdigit(*s) && !xisdigit(*(s + 1)))
143 s--;
144 if (!strchr(s, '-'))
145 return NULL;
146 if ((int) strlen(s) < 18)
147 return NULL;
148 memset(&tm, '\0', sizeof(tm));
149 tm.tm_mday = make_num(s);
150 tm.tm_mon = make_month(s + 3);
151 tm.tm_year = make_num(s + 7);
152 /*
153 * Y2K: Arjan de Vet <Arjan.deVet@adv.IAEhv.nl>
154 * if tm.tm_year < 70, assume it's after the year 2000.
155 */
156 if (tm.tm_year < 70)
157 tm.tm_year += 100;
158 tm.tm_hour = make_num(s + 10);
159 tm.tm_min = make_num(s + 13);
160 tm.tm_sec = make_num(s + 16);
161 return tmSaneValues(&tm) ? &tm : NULL;
162 }
163
164 static struct tm *
165 parse_date2(const char *str)
166 {
167 /* Thu, 10 Jan 1993 01:29:59 GMT */
168 const char *s;
169 static struct tm tm;
170 assert(NULL != str);
171 memset(&tm, '\0', sizeof(struct tm));
172 s = strchr(str, ',');
173 if (NULL == s)
174 return NULL;
175 s++;
176 while (*s == ' ')
177 s++;
178 /* backup if month is only one digit */
179 if (xisdigit(*s) && !xisdigit(*(s + 1)))
180 s--;
181 if (strchr(s, '-'))
182 return NULL;
183 if ((int) strlen(s) < 20)
184 return NULL;
185 memset(&tm, '\0', sizeof(tm));
186 tm.tm_mday = make_num(s);
187 tm.tm_mon = make_month(s + 3);
188 tm.tm_year = (100 * make_num(s + 7) - 1900) + make_num(s + 9);
189 tm.tm_hour = make_num(s + 12);
190 tm.tm_min = make_num(s + 15);
191 tm.tm_sec = make_num(s + 18);
192 return tmSaneValues(&tm) ? &tm : NULL;
193 }
194
195 static struct tm *
196 parse_date3(const char *str)
197 {
198 /* Wed Jun 9 01:29:59 1993 GMT */
199 static struct tm tm;
200 char *s;
201 static char buf[128];
202 while (*str && *str == ' ')
203 str++;
204 xstrncpy(buf, str, 128);
205 if (NULL == (s = strtok(buf, w_space)))
206 return NULL;
207 if (NULL == (s = strtok(NULL, w_space)))
208 return NULL;
209 tm.tm_mon = make_month(s);
210 if (NULL == (s = strtok(NULL, w_space)))
211 return NULL;
212 tm.tm_mday = atoi(s);
213 if (NULL == (s = strtok(NULL, ":")))
214 return NULL;
215 tm.tm_hour = atoi(s);
216 if (NULL == (s = strtok(NULL, ":")))
217 return NULL;
218 tm.tm_min = atoi(s);
219 if (NULL == (s = strtok(NULL, w_space)))
220 return NULL;
221 tm.tm_sec = atoi(s);
222 if (NULL == (s = strtok(NULL, w_space)))
223 return NULL;
224 /* Y2K fix, richard.kettlewell@kewill.com */
225 tm.tm_year = atoi(s) - 1900;
226 return tmSaneValues(&tm) ? &tm : NULL;
227 }
228
229 time_t
230 parse_rfc1123(const char *str)
231 {
232 struct tm *tm;
233 time_t t;
234 if (NULL == str)
235 return -1;
236 tm = parse_date1(str);
237 if (NULL == tm) {
238 tm = parse_date2(str);
239 if (NULL == tm) {
240 tm = parse_date3(str);
241 if (NULL == tm)
242 return -1;
243 }
244 }
245 tm->tm_isdst = -1;
246 #ifdef HAVE_TIMEGM
247 t = timegm(tm);
248 #elif HAVE_TM_GMTOFF
249 t = mktime(tm);
250 {
251 struct tm *local = localtime(&t);
252 t += local->tm_gmtoff;
253 }
254 #else
255 /* some systems do not have tm_gmtoff so we fake it */
256 t = mktime(tm);
257 {
258 time_t dst = 0;
259 #if defined (_TIMEZONE)
260 #elif defined (_timezone)
261 #elif defined(_SQUID_AIX_)
262 #elif defined(_SQUID_CYGWIN_)
263 #else
264 extern time_t timezone;
265 #endif
266 /*
267 * The following assumes a fixed DST offset of 1 hour,
268 * which is probably wrong.
269 */
270 if (tm->tm_isdst > 0)
271 dst = -3600;
272 #if defined ( _timezone) || defined(_SQUID_CYGWIN_)
273 t -= (_timezone + dst);
274 #else
275 t -= (timezone + dst);
276 #endif
277 }
278 #endif
279 return t;
280 }
281
282 const char *
283 mkrfc1123(time_t t)
284 {
285 static char buf[128];
286
287 struct tm *gmt = gmtime(&t);
288
289 buf[0] = '\0';
290 strftime(buf, 127, RFC1123_STRFTIME, gmt);
291 return buf;
292 }
293
294 const char *
295 mkhttpdlogtime(const time_t * t)
296 {
297 static char buf[128];
298
299 struct tm *gmt = gmtime(t);
300
301 #ifndef USE_GMT
302 int gmt_min, gmt_hour, gmt_yday, day_offset;
303 size_t len;
304 struct tm *lt;
305 int min_offset;
306
307 /* localtime & gmtime may use the same static data */
308 gmt_min = gmt->tm_min;
309 gmt_hour = gmt->tm_hour;
310 gmt_yday = gmt->tm_yday;
311
312 lt = localtime(t);
313
314 day_offset = lt->tm_yday - gmt_yday;
315 /* wrap round on end of year */
316 if (day_offset > 1)
317 day_offset = -1;
318 else if (day_offset < -1)
319 day_offset = 1;
320
321 min_offset = day_offset * 1440 + (lt->tm_hour - gmt_hour) * 60
322 + (lt->tm_min - gmt_min);
323
324 len = strftime(buf, 127 - 5, "%d/%b/%Y:%H:%M:%S ", lt);
325 snprintf(buf + len, 128 - len, "%+03d%02d",
326 (min_offset / 60) % 24,
327 min_offset % 60);
328 #else /* USE_GMT */
329 buf[0] = '\0';
330 strftime(buf, 127, "%d/%b/%Y:%H:%M:%S -000", gmt);
331 #endif /* USE_GMT */
332
333 return buf;
334 }
335
336 #if 0
337 int
338 main()
339 {
340 char *x;
341 time_t t, pt;
342
343 t = time(NULL);
344 x = mkrfc1123(t);
345 printf("HTTP Time: %s\n", x);
346
347 pt = parse_rfc1123(x);
348 printf("Parsed: %d vs. %d\n", pt, t);
349 }
350
351 #endif