comparison src/core/ngx_parse_time.c @ 6180:8b6fa4842133

Moved ngx_http_parse_time() to core, renamed accordingly. The function is now called ngx_parse_http_time(), and can be used by any code to parse HTTP-style date and time. In particular, it will be used for OCSP stapling. For compatibility, a macro to map ngx_http_parse_time() to the new name provided for a while.
author Maxim Dounin <mdounin@mdounin.ru>
date Thu, 11 Jun 2015 20:42:31 +0300
parents src/http/ngx_http_parse_time.c@4c36e15651f7
children 2cd019520210
comparison
equal deleted inserted replaced
6179:c61210e2e081 6180:8b6fa4842133
1
2 /*
3 * Copyright (C) Igor Sysoev
4 * Copyright (C) Nginx, Inc.
5 */
6
7
8 #include <ngx_config.h>
9 #include <ngx_core.h>
10
11
12 static ngx_uint_t mday[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
13
14 time_t
15 ngx_parse_http_time(u_char *value, size_t len)
16 {
17 u_char *p, *end;
18 ngx_int_t month;
19 ngx_uint_t day, year, hour, min, sec;
20 uint64_t time;
21 enum {
22 no = 0,
23 rfc822, /* Tue, 10 Nov 2002 23:50:13 */
24 rfc850, /* Tuesday, 10-Dec-02 23:50:13 */
25 isoc /* Tue Dec 10 23:50:13 2002 */
26 } fmt;
27
28 fmt = 0;
29 end = value + len;
30
31 #if (NGX_SUPPRESS_WARN)
32 day = 32;
33 year = 2038;
34 #endif
35
36 for (p = value; p < end; p++) {
37 if (*p == ',') {
38 break;
39 }
40
41 if (*p == ' ') {
42 fmt = isoc;
43 break;
44 }
45 }
46
47 for (p++; p < end; p++)
48 if (*p != ' ') {
49 break;
50 }
51
52 if (end - p < 18) {
53 return NGX_ERROR;
54 }
55
56 if (fmt != isoc) {
57 if (*p < '0' || *p > '9' || *(p + 1) < '0' || *(p + 1) > '9') {
58 return NGX_ERROR;
59 }
60
61 day = (*p - '0') * 10 + *(p + 1) - '0';
62 p += 2;
63
64 if (*p == ' ') {
65 if (end - p < 18) {
66 return NGX_ERROR;
67 }
68 fmt = rfc822;
69
70 } else if (*p == '-') {
71 fmt = rfc850;
72
73 } else {
74 return NGX_ERROR;
75 }
76
77 p++;
78 }
79
80 switch (*p) {
81
82 case 'J':
83 month = *(p + 1) == 'a' ? 0 : *(p + 2) == 'n' ? 5 : 6;
84 break;
85
86 case 'F':
87 month = 1;
88 break;
89
90 case 'M':
91 month = *(p + 2) == 'r' ? 2 : 4;
92 break;
93
94 case 'A':
95 month = *(p + 1) == 'p' ? 3 : 7;
96 break;
97
98 case 'S':
99 month = 8;
100 break;
101
102 case 'O':
103 month = 9;
104 break;
105
106 case 'N':
107 month = 10;
108 break;
109
110 case 'D':
111 month = 11;
112 break;
113
114 default:
115 return NGX_ERROR;
116 }
117
118 p += 3;
119
120 if ((fmt == rfc822 && *p != ' ') || (fmt == rfc850 && *p != '-')) {
121 return NGX_ERROR;
122 }
123
124 p++;
125
126 if (fmt == rfc822) {
127 if (*p < '0' || *p > '9' || *(p + 1) < '0' || *(p + 1) > '9'
128 || *(p + 2) < '0' || *(p + 2) > '9'
129 || *(p + 3) < '0' || *(p + 3) > '9')
130 {
131 return NGX_ERROR;
132 }
133
134 year = (*p - '0') * 1000 + (*(p + 1) - '0') * 100
135 + (*(p + 2) - '0') * 10 + *(p + 3) - '0';
136 p += 4;
137
138 } else if (fmt == rfc850) {
139 if (*p < '0' || *p > '9' || *(p + 1) < '0' || *(p + 1) > '9') {
140 return NGX_ERROR;
141 }
142
143 year = (*p - '0') * 10 + *(p + 1) - '0';
144 year += (year < 70) ? 2000 : 1900;
145 p += 2;
146 }
147
148 if (fmt == isoc) {
149 if (*p == ' ') {
150 p++;
151 }
152
153 if (*p < '0' || *p > '9') {
154 return NGX_ERROR;
155 }
156
157 day = *p++ - '0';
158
159 if (*p != ' ') {
160 if (*p < '0' || *p > '9') {
161 return NGX_ERROR;
162 }
163
164 day = day * 10 + *p++ - '0';
165 }
166
167 if (end - p < 14) {
168 return NGX_ERROR;
169 }
170 }
171
172 if (*p++ != ' ') {
173 return NGX_ERROR;
174 }
175
176 if (*p < '0' || *p > '9' || *(p + 1) < '0' || *(p + 1) > '9') {
177 return NGX_ERROR;
178 }
179
180 hour = (*p - '0') * 10 + *(p + 1) - '0';
181 p += 2;
182
183 if (*p++ != ':') {
184 return NGX_ERROR;
185 }
186
187 if (*p < '0' || *p > '9' || *(p + 1) < '0' || *(p + 1) > '9') {
188 return NGX_ERROR;
189 }
190
191 min = (*p - '0') * 10 + *(p + 1) - '0';
192 p += 2;
193
194 if (*p++ != ':') {
195 return NGX_ERROR;
196 }
197
198 if (*p < '0' || *p > '9' || *(p + 1) < '0' || *(p + 1) > '9') {
199 return NGX_ERROR;
200 }
201
202 sec = (*p - '0') * 10 + *(p + 1) - '0';
203
204 if (fmt == isoc) {
205 p += 2;
206
207 if (*p++ != ' ') {
208 return NGX_ERROR;
209 }
210
211 if (*p < '0' || *p > '9' || *(p + 1) < '0' || *(p + 1) > '9'
212 || *(p + 2) < '0' || *(p + 2) > '9'
213 || *(p + 3) < '0' || *(p + 3) > '9')
214 {
215 return NGX_ERROR;
216 }
217
218 year = (*p - '0') * 1000 + (*(p + 1) - '0') * 100
219 + (*(p + 2) - '0') * 10 + *(p + 3) - '0';
220 }
221
222 if (hour > 23 || min > 59 || sec > 59) {
223 return NGX_ERROR;
224 }
225
226 if (day == 29 && month == 1) {
227 if ((year & 3) || ((year % 100 == 0) && (year % 400) != 0)) {
228 return NGX_ERROR;
229 }
230
231 } else if (day > mday[month]) {
232 return NGX_ERROR;
233 }
234
235 /*
236 * shift new year to March 1 and start months from 1 (not 0),
237 * it is needed for Gauss' formula
238 */
239
240 if (--month <= 0) {
241 month += 12;
242 year -= 1;
243 }
244
245 /* Gauss' formula for Gregorian days since March 1, 1 BC */
246
247 time = (uint64_t) (
248 /* days in years including leap years since March 1, 1 BC */
249
250 365 * year + year / 4 - year / 100 + year / 400
251
252 /* days before the month */
253
254 + 367 * month / 12 - 30
255
256 /* days before the day */
257
258 + day - 1
259
260 /*
261 * 719527 days were between March 1, 1 BC and March 1, 1970,
262 * 31 and 28 days were in January and February 1970
263 */
264
265 - 719527 + 31 + 28) * 86400 + hour * 3600 + min * 60 + sec;
266
267 #if (NGX_TIME_T_SIZE <= 4)
268
269 if (time > 0x7fffffff) {
270 return NGX_ERROR;
271 }
272
273 #endif
274
275 return (time_t) time;
276 }