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