]> git.ipfire.org Git - thirdparty/squid.git/blame - lib/rfc1123.c
SourceFormat Enforcement
[thirdparty/squid.git] / lib / rfc1123.c
CommitLineData
cf49df4b 1/*
4ac4a490 2 * Copyright (C) 1996-2017 The Squid Software Foundation and contributors
e25c139f 3 *
0545caaa
AJ
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.
cf49df4b 7 */
8
f7f3304a 9#include "squid.h"
25f98340 10#include "rfc1123.h"
cf49df4b 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 */
cf49df4b 16#if HAVE_STRING_H
17#include <string.h>
18#endif
19#if HAVE_CTYPE_H
20#include <ctype.h>
21#endif
cf49df4b 22#if HAVE_TIME_H
23#include <time.h>
24#endif
cf49df4b 25
2a8a7464 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
f5b8bbc4 29static int make_month(const char *s);
30static int make_num(const char *s);
cf49df4b 31
26ac0430 32static const char *month_names[12] = {
cf49df4b 33 "Jan", "Feb", "Mar", "Apr", "May", "Jun",
34 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
35};
36
cf49df4b 37static int
0ee4272b 38make_num(const char *s)
cf49df4b 39{
40 if (*s >= '0' && *s <= '9')
26ac0430 41 return 10 * (*s - '0') + *(s + 1) - '0';
cf49df4b 42 else
26ac0430 43 return *(s + 1) - '0';
cf49df4b 44}
45
46static int
0ee4272b 47make_month(const char *s)
cf49df4b 48{
49 int i;
0ee4272b 50 char month[3];
cf49df4b 51
b6a2f15e 52 month[0] = xtoupper(*s);
53 month[1] = xtolower(*(s + 1));
54 month[2] = xtolower(*(s + 2));
cf49df4b 55
56 for (i = 0; i < 12; i++)
26ac0430
AJ
57 if (!strncmp(month_names[i], month, 3))
58 return i;
506f9cfe 59 return -1;
cf49df4b 60}
61
2b79de37 62static int
63tmSaneValues(struct tm *tm)
64{
65 if (tm->tm_sec < 0 || tm->tm_sec > 59)
26ac0430 66 return 0;
2b79de37 67 if (tm->tm_min < 0 || tm->tm_min > 59)
26ac0430 68 return 0;
2b79de37 69 if (tm->tm_hour < 0 || tm->tm_hour > 23)
26ac0430 70 return 0;
2b79de37 71 if (tm->tm_mday < 1 || tm->tm_mday > 31)
26ac0430 72 return 0;
2b79de37 73 if (tm->tm_mon < 0 || tm->tm_mon > 11)
26ac0430 74 return 0;
737e901b 75 return 1;
2b79de37 76}
cf49df4b 77
2b79de37 78static struct tm *
e1381638 79parse_date_elements(const char *day, const char *month, const char *year,
18ec8500 80 const char *aTime, const char *zone) {
2b79de37 81 static struct tm tm;
506f9cfe 82 char *t;
83 memset(&tm, 0, sizeof(tm));
2b79de37 84
1bcd740b 85 if (!day || !month || !year || !aTime || (zone && strcmp(zone, "GMT")))
26ac0430 86 return NULL;
506f9cfe 87 tm.tm_mday = atoi(day);
88 tm.tm_mon = make_month(month);
89 if (tm.tm_mon < 0)
26ac0430 90 return NULL;
506f9cfe 91 tm.tm_year = atoi(year);
92 if (strlen(year) == 4)
26ac0430 93 tm.tm_year -= 1900;
506f9cfe 94 else if (tm.tm_year < 70)
26ac0430 95 tm.tm_year += 100;
506f9cfe 96 else if (tm.tm_year > 19000)
26ac0430 97 tm.tm_year -= 19000;
18ec8500
FC
98 tm.tm_hour = make_num(aTime);
99 t = strchr(aTime, ':');
506f9cfe 100 if (!t)
26ac0430 101 return NULL;
506f9cfe 102 t++;
103 tm.tm_min = atoi(t);
104 t = strchr(t, ':');
105 if (t)
26ac0430 106 tm.tm_sec = atoi(t + 1);
2b79de37 107 return tmSaneValues(&tm) ? &tm : NULL;
108}
cf49df4b 109
2b79de37 110static struct tm *
e1381638 111parse_date(const char *str) {
506f9cfe 112 struct tm *tm;
a69938ae 113 static char tmp[64];
506f9cfe 114 char *t;
115 char *wday = NULL;
116 char *day = NULL;
117 char *month = NULL;
118 char *year = NULL;
18ec8500 119 char *timestr = NULL;
506f9cfe 120 char *zone = NULL;
121
a69938ae 122 xstrncpy(tmp, str, 64);
123
506f9cfe 124 for (t = strtok(tmp, ", "); t; t = strtok(NULL, ", ")) {
26ac0430
AJ
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, ':'))
18ec8500 139 timestr = t;
26ac0430
AJ
140 else if (!year)
141 year = t;
1bcd740b
AR
142 else
143 return NULL;
26ac0430
AJ
144 } else if (!wday)
145 wday = t;
146 else if (!month)
147 month = t;
148 else if (!zone)
149 zone = t;
1bcd740b
AR
150 else
151 return NULL;
506f9cfe 152 }
18ec8500 153 tm = parse_date_elements(day, month, year, timestr, zone);
506f9cfe 154
506f9cfe 155 return tm;
2b79de37 156}
cf49df4b 157
2b79de37 158time_t
159parse_rfc1123(const char *str)
160{
161 struct tm *tm;
162 time_t t;
163 if (NULL == str)
26ac0430 164 return -1;
506f9cfe 165 tm = parse_date(str);
166 if (!tm)
26ac0430 167 return -1;
2b79de37 168 tm->tm_isdst = -1;
32d002cb 169#if HAVE_TIMEGM
2b79de37 170 t = timegm(tm);
6a9f6389 171#elif HAVE_TM_TM_GMTOFF
2b79de37 172 t = mktime(tm);
737e901b 173 if (t != -1) {
26ac0430
AJ
174 struct tm *local = localtime(&t);
175 t += local->tm_gmtoff;
cf49df4b 176 }
177#else
178 /* some systems do not have tm_gmtoff so we fake it */
2b79de37 179 t = mktime(tm);
737e901b 180 if (t != -1) {
26ac0430 181 time_t dst = 0;
be266cb2 182#if !(defined(_TIMEZONE) || defined(_timezone) || _SQUID_AIX_ || _SQUID_WINDOWS_ || _SQUID_SGI_)
cf3a562b 183 extern long timezone;
9b6dbb2a 184#endif
26ac0430
AJ
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;
be266cb2 191#if defined(_timezone) || _SQUID_WINDOWS_
26ac0430 192 t -= (_timezone + dst);
9b6dbb2a 193#else
f53969cc 194 t -= (timezone + dst);
9b6dbb2a 195#endif
cf49df4b 196 }
197#endif
198 return t;
199}
200
0ee4272b 201const char *
cf49df4b 202mkrfc1123(time_t t)
203{
204 static char buf[128];
205
206 struct tm *gmt = gmtime(&t);
207
208 buf[0] = '\0';
2a8a7464 209 strftime(buf, 127, RFC1123_STRFTIME, gmt);
cf49df4b 210 return buf;
211}
212
cf49df4b 213#if 0
214int
215main()
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
f53969cc 229