]>
Commit | Line | Data |
---|---|---|
cf49df4b | 1 | /* |
0545caaa | 2 | * Copyright (C) 1996-2014 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 | 29 | static int make_month(const char *s); |
30 | static int make_num(const char *s); | |
cf49df4b | 31 | |
26ac0430 | 32 | static const char *month_names[12] = { |
cf49df4b | 33 | "Jan", "Feb", "Mar", "Apr", "May", "Jun", |
34 | "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" | |
35 | }; | |
36 | ||
cf49df4b | 37 | static int |
0ee4272b | 38 | make_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 | ||
46 | static int | |
0ee4272b | 47 | make_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 | 62 | static int |
63 | tmSaneValues(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 | 78 | static struct tm * |
e1381638 | 79 | parse_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 | 110 | static struct tm * |
e1381638 | 111 | parse_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 | 158 | time_t |
159 | parse_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 | 201 | const char * |
cf49df4b | 202 | mkrfc1123(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 |
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 | |
f53969cc | 229 |