blob: 985af31725b74646ceae26d5ba4386b6adeb1507 [file] [log] [blame]
Igor Sysoevb0869052002-12-10 18:05:12 +00001
Igor Sysoevd90282d2004-09-28 08:34:51 +00002/*
Igor Sysoevff8da912004-09-29 16:00:49 +00003 * Copyright (C) Igor Sysoev
Maxim Konovalovf8d59e32012-01-18 15:07:43 +00004 * Copyright (C) Nginx, Inc.
Igor Sysoevd90282d2004-09-28 08:34:51 +00005 */
6
7
Igor Sysoev42feecb2002-12-15 06:25:09 +00008#include <ngx_config.h>
9#include <ngx_core.h>
Ruslan Ermilov1efcca32012-07-24 15:09:54 +000010#include <ngx_http.h>
Igor Sysoev3add4642002-12-11 16:57:54 +000011
Igor Sysoev3add4642002-12-11 16:57:54 +000012
Igor Sysoev5143e392009-10-15 13:09:58 +000013static ngx_uint_t mday[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
Igor Sysoev3add4642002-12-11 16:57:54 +000014
Igor Sysoev8152d0a2007-11-09 13:12:25 +000015time_t
16ngx_http_parse_time(u_char *value, size_t len)
Igor Sysoevb0869052002-12-10 18:05:12 +000017{
Igor Sysoev5143e392009-10-15 13:09:58 +000018 u_char *p, *end;
19 ngx_int_t month;
20 ngx_uint_t day, year, hour, min, sec;
Igor Sysoev55045412009-10-15 13:19:34 +000021 uint64_t time;
Igor Sysoevb0869052002-12-10 18:05:12 +000022 enum {
Igor Sysoev3add4642002-12-11 16:57:54 +000023 no = 0,
Igor Sysoevacdb80a2006-08-31 10:40:45 +000024 rfc822, /* Tue, 10 Nov 2002 23:50:13 */
Igor Sysoev3add4642002-12-11 16:57:54 +000025 rfc850, /* Tuesday, 10-Dec-02 23:50:13 */
26 isoc /* Tue Dec 10 23:50:13 2002 */
27 } fmt;
Igor Sysoevb0869052002-12-10 18:05:12 +000028
Igor Sysoev42feecb2002-12-15 06:25:09 +000029 fmt = 0;
Igor Sysoev3add4642002-12-11 16:57:54 +000030 end = value + len;
Igor Sysoevb0869052002-12-10 18:05:12 +000031
Igor Sysoev86de4cb2003-01-30 07:28:09 +000032#if (NGX_SUPPRESS_WARN)
33 day = 32;
34 year = 2038;
35#endif
36
Igor Sysoev3add4642002-12-11 16:57:54 +000037 for (p = value; p < end; p++) {
Igor Sysoev4e9393a2003-01-09 05:36:00 +000038 if (*p == ',') {
Igor Sysoevb0869052002-12-10 18:05:12 +000039 break;
Igor Sysoev4e9393a2003-01-09 05:36:00 +000040 }
Igor Sysoevb0869052002-12-10 18:05:12 +000041
Igor Sysoev3add4642002-12-11 16:57:54 +000042 if (*p == ' ') {
43 fmt = isoc;
44 break;
Igor Sysoevb0869052002-12-10 18:05:12 +000045 }
46 }
Igor Sysoev3add4642002-12-11 16:57:54 +000047
48 for (p++; p < end; p++)
Igor Sysoev4e9393a2003-01-09 05:36:00 +000049 if (*p != ' ') {
Igor Sysoev3add4642002-12-11 16:57:54 +000050 break;
Igor Sysoev4e9393a2003-01-09 05:36:00 +000051 }
Igor Sysoev3add4642002-12-11 16:57:54 +000052
Igor Sysoev4e9393a2003-01-09 05:36:00 +000053 if (end - p < 18) {
Igor Sysoev3add4642002-12-11 16:57:54 +000054 return NGX_ERROR;
Igor Sysoev4e9393a2003-01-09 05:36:00 +000055 }
Igor Sysoev3add4642002-12-11 16:57:54 +000056
57 if (fmt != isoc) {
Igor Sysoev4e9393a2003-01-09 05:36:00 +000058 if (*p < '0' || *p > '9' || *(p + 1) < '0' || *(p + 1) > '9') {
Igor Sysoev3add4642002-12-11 16:57:54 +000059 return NGX_ERROR;
Igor Sysoev4e9393a2003-01-09 05:36:00 +000060 }
Igor Sysoev3add4642002-12-11 16:57:54 +000061
62 day = (*p - '0') * 10 + *(p + 1) - '0';
63 p += 2;
64
65 if (*p == ' ') {
Igor Sysoev4e9393a2003-01-09 05:36:00 +000066 if (end - p < 18) {
Igor Sysoev3add4642002-12-11 16:57:54 +000067 return NGX_ERROR;
Igor Sysoev4e9393a2003-01-09 05:36:00 +000068 }
Igor Sysoev3add4642002-12-11 16:57:54 +000069 fmt = rfc822;
70
71 } else if (*p == '-') {
72 fmt = rfc850;
73
74 } else {
75 return NGX_ERROR;
76 }
77
78 p++;
79 }
80
81 switch (*p) {
82
83 case 'J':
84 month = *(p + 1) == 'a' ? 0 : *(p + 2) == 'n' ? 5 : 6;
85 break;
86
87 case 'F':
88 month = 1;
89 break;
90
91 case 'M':
92 month = *(p + 2) == 'r' ? 2 : 4;
93 break;
94
95 case 'A':
96 month = *(p + 1) == 'p' ? 3 : 7;
97 break;
98
99 case 'S':
100 month = 8;
101 break;
102
103 case 'O':
104 month = 9;
105 break;
106
107 case 'N':
108 month = 10;
109 break;
110
111 case 'D':
112 month = 11;
113 break;
114
115 default:
116 return NGX_ERROR;
117 }
118
119 p += 3;
120
Igor Sysoev4e9393a2003-01-09 05:36:00 +0000121 if ((fmt == rfc822 && *p != ' ') || (fmt == rfc850 && *p != '-')) {
Igor Sysoev3add4642002-12-11 16:57:54 +0000122 return NGX_ERROR;
Igor Sysoev4e9393a2003-01-09 05:36:00 +0000123 }
Igor Sysoev3add4642002-12-11 16:57:54 +0000124
125 p++;
126
127 if (fmt == rfc822) {
128 if (*p < '0' || *p > '9' || *(p + 1) < '0' || *(p + 1) > '9'
129 || *(p + 2) < '0' || *(p + 2) > '9'
130 || *(p + 3) < '0' || *(p + 3) > '9')
Igor Sysoev4e9393a2003-01-09 05:36:00 +0000131 {
Igor Sysoev3add4642002-12-11 16:57:54 +0000132 return NGX_ERROR;
Igor Sysoev4e9393a2003-01-09 05:36:00 +0000133 }
Igor Sysoev3add4642002-12-11 16:57:54 +0000134
135 year = (*p - '0') * 1000 + (*(p + 1) - '0') * 100
136 + (*(p + 2) - '0') * 10 + *(p + 3) - '0';
137 p += 4;
138
139 } else if (fmt == rfc850) {
Igor Sysoev4e9393a2003-01-09 05:36:00 +0000140 if (*p < '0' || *p > '9' || *(p + 1) < '0' || *(p + 1) > '9') {
Igor Sysoev3add4642002-12-11 16:57:54 +0000141 return NGX_ERROR;
Igor Sysoev4e9393a2003-01-09 05:36:00 +0000142 }
Igor Sysoev3add4642002-12-11 16:57:54 +0000143
144 year = (*p - '0') * 10 + *(p + 1) - '0';
145 year += (year < 70) ? 2000 : 1900;
146 p += 2;
147 }
148
149 if (fmt == isoc) {
Igor Sysoev4e9393a2003-01-09 05:36:00 +0000150 if (*p == ' ') {
Igor Sysoev3add4642002-12-11 16:57:54 +0000151 p++;
Igor Sysoev4e9393a2003-01-09 05:36:00 +0000152 }
Igor Sysoev3add4642002-12-11 16:57:54 +0000153
Igor Sysoev4e9393a2003-01-09 05:36:00 +0000154 if (*p < '0' || *p > '9') {
Igor Sysoev3add4642002-12-11 16:57:54 +0000155 return NGX_ERROR;
Igor Sysoev4e9393a2003-01-09 05:36:00 +0000156 }
Igor Sysoev3add4642002-12-11 16:57:54 +0000157
158 day = *p++ - '0';
159
160 if (*p != ' ') {
Igor Sysoev4e9393a2003-01-09 05:36:00 +0000161 if (*p < '0' || *p > '9') {
Igor Sysoev3add4642002-12-11 16:57:54 +0000162 return NGX_ERROR;
Igor Sysoev4e9393a2003-01-09 05:36:00 +0000163 }
Igor Sysoev3add4642002-12-11 16:57:54 +0000164
165 day = day * 10 + *p++ - '0';
166 }
167
Igor Sysoev4e9393a2003-01-09 05:36:00 +0000168 if (end - p < 14) {
Igor Sysoev3add4642002-12-11 16:57:54 +0000169 return NGX_ERROR;
Igor Sysoev4e9393a2003-01-09 05:36:00 +0000170 }
Igor Sysoev3add4642002-12-11 16:57:54 +0000171 }
172
Igor Sysoev4e9393a2003-01-09 05:36:00 +0000173 if (*p++ != ' ') {
Igor Sysoev3add4642002-12-11 16:57:54 +0000174 return NGX_ERROR;
Igor Sysoev4e9393a2003-01-09 05:36:00 +0000175 }
Igor Sysoev3add4642002-12-11 16:57:54 +0000176
Igor Sysoev4e9393a2003-01-09 05:36:00 +0000177 if (*p < '0' || *p > '9' || *(p + 1) < '0' || *(p + 1) > '9') {
Igor Sysoev3add4642002-12-11 16:57:54 +0000178 return NGX_ERROR;
Igor Sysoev4e9393a2003-01-09 05:36:00 +0000179 }
Igor Sysoev3add4642002-12-11 16:57:54 +0000180
181 hour = (*p - '0') * 10 + *(p + 1) - '0';
182 p += 2;
183
Igor Sysoev4e9393a2003-01-09 05:36:00 +0000184 if (*p++ != ':') {
Igor Sysoev3add4642002-12-11 16:57:54 +0000185 return NGX_ERROR;
Igor Sysoev4e9393a2003-01-09 05:36:00 +0000186 }
Igor Sysoev3add4642002-12-11 16:57:54 +0000187
Igor Sysoev4e9393a2003-01-09 05:36:00 +0000188 if (*p < '0' || *p > '9' || *(p + 1) < '0' || *(p + 1) > '9') {
Igor Sysoev3add4642002-12-11 16:57:54 +0000189 return NGX_ERROR;
Igor Sysoev4e9393a2003-01-09 05:36:00 +0000190 }
Igor Sysoev3add4642002-12-11 16:57:54 +0000191
192 min = (*p - '0') * 10 + *(p + 1) - '0';
193 p += 2;
194
Igor Sysoev4e9393a2003-01-09 05:36:00 +0000195 if (*p++ != ':') {
Igor Sysoev3add4642002-12-11 16:57:54 +0000196 return NGX_ERROR;
Igor Sysoev4e9393a2003-01-09 05:36:00 +0000197 }
Igor Sysoev3add4642002-12-11 16:57:54 +0000198
Igor Sysoev4e9393a2003-01-09 05:36:00 +0000199 if (*p < '0' || *p > '9' || *(p + 1) < '0' || *(p + 1) > '9') {
Igor Sysoev3add4642002-12-11 16:57:54 +0000200 return NGX_ERROR;
Igor Sysoev4e9393a2003-01-09 05:36:00 +0000201 }
Igor Sysoev3add4642002-12-11 16:57:54 +0000202
203 sec = (*p - '0') * 10 + *(p + 1) - '0';
204
205 if (fmt == isoc) {
206 p += 2;
207
Igor Sysoev4e9393a2003-01-09 05:36:00 +0000208 if (*p++ != ' ') {
Igor Sysoev3add4642002-12-11 16:57:54 +0000209 return NGX_ERROR;
Igor Sysoev4e9393a2003-01-09 05:36:00 +0000210 }
Igor Sysoev3add4642002-12-11 16:57:54 +0000211
212 if (*p < '0' || *p > '9' || *(p + 1) < '0' || *(p + 1) > '9'
213 || *(p + 2) < '0' || *(p + 2) > '9'
214 || *(p + 3) < '0' || *(p + 3) > '9')
Igor Sysoev4e9393a2003-01-09 05:36:00 +0000215 {
Igor Sysoev3add4642002-12-11 16:57:54 +0000216 return NGX_ERROR;
Igor Sysoev4e9393a2003-01-09 05:36:00 +0000217 }
Igor Sysoev3add4642002-12-11 16:57:54 +0000218
219 year = (*p - '0') * 1000 + (*(p + 1) - '0') * 100
220 + (*(p + 2) - '0') * 10 + *(p + 3) - '0';
221 }
222
Igor Sysoev4e9393a2003-01-09 05:36:00 +0000223 if (hour > 23 || min > 59 || sec > 59) {
Igor Sysoev3add4642002-12-11 16:57:54 +0000224 return NGX_ERROR;
Igor Sysoev4e9393a2003-01-09 05:36:00 +0000225 }
Igor Sysoev3add4642002-12-11 16:57:54 +0000226
227 if (day == 29 && month == 1) {
Igor Sysoev4e9393a2003-01-09 05:36:00 +0000228 if ((year & 3) || ((year % 100 == 0) && (year % 400) != 0)) {
Igor Sysoev3add4642002-12-11 16:57:54 +0000229 return NGX_ERROR;
Igor Sysoev4e9393a2003-01-09 05:36:00 +0000230 }
Igor Sysoev3add4642002-12-11 16:57:54 +0000231
Igor Sysoev42feecb2002-12-15 06:25:09 +0000232 } else if (day > mday[month]) {
Igor Sysoev3add4642002-12-11 16:57:54 +0000233 return NGX_ERROR;
234 }
235
Igor Sysoev43beb6c2003-11-12 17:25:12 +0000236 /*
237 * shift new year to March 1 and start months from 1 (not 0),
Igor Sysoevb8a71b62008-04-10 09:37:12 +0000238 * it is needed for Gauss' formula
Igor Sysoev43beb6c2003-11-12 17:25:12 +0000239 */
Igor Sysoev27c30f92003-11-11 18:13:43 +0000240
Igor Sysoev3add4642002-12-11 16:57:54 +0000241 if (--month <= 0) {
Igor Sysoev66f76d22007-01-19 11:35:26 +0000242 month += 12;
243 year -= 1;
Igor Sysoev3add4642002-12-11 16:57:54 +0000244 }
Igor Sysoev27c30f92003-11-11 18:13:43 +0000245
Ruslan Ermilovb74f8ff2012-02-28 11:31:05 +0000246 /* Gauss' formula for Gregorian days since March 1, 1 BC */
Igor Sysoev27c30f92003-11-11 18:13:43 +0000247
Igor Sysoev55045412009-10-15 13:19:34 +0000248 time = (uint64_t) (
Igor Sysoevb8a71b62008-04-10 09:37:12 +0000249 /* days in years including leap years since March 1, 1 BC */
250
251 365 * year + year / 4 - year / 100 + year / 400
252
253 /* days before the month */
254
255 + 367 * month / 12 - 30
256
257 /* days before the day */
258
259 + day - 1
Igor Sysoev43beb6c2003-11-12 17:25:12 +0000260
Igor Sysoev02025fd2005-01-18 13:03:58 +0000261 /*
262 * 719527 days were between March 1, 1 BC and March 1, 1970,
Igor Sysoev66f76d22007-01-19 11:35:26 +0000263 * 31 and 28 days were in January and February 1970
Igor Sysoev02025fd2005-01-18 13:03:58 +0000264 */
Igor Sysoev27c30f92003-11-11 18:13:43 +0000265
Igor Sysoev42feecb2002-12-15 06:25:09 +0000266 - 719527 + 31 + 28) * 86400 + hour * 3600 + min * 60 + sec;
Igor Sysoev55045412009-10-15 13:19:34 +0000267
268#if (NGX_TIME_T_SIZE <= 4)
269
270 if (time > 0x7fffffff) {
271 return NGX_ERROR;
272 }
273
274#endif
275
276 return (time_t) time;
Igor Sysoev3add4642002-12-11 16:57:54 +0000277}