nginx/src/http/ngx_http_parse_time.c

283 lines
5.6 KiB
C
Raw Normal View History

2002-12-11 02:05:12 +08:00
2002-12-15 14:25:09 +08:00
#include <ngx_config.h>
#include <ngx_core.h>
#include <ngx_types.h>
2002-12-12 00:57:54 +08:00
static int mday[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
time_t ngx_http_parse_time(char *value, size_t len)
2002-12-11 02:05:12 +08:00
{
2002-12-12 00:57:54 +08:00
char *p, *end;
int day, month, year, hour, min, sec;
2002-12-11 02:05:12 +08:00
enum {
2002-12-12 00:57:54 +08:00
no = 0,
rfc822, /* Tue 10 Nov 2002 23:50:13 */
rfc850, /* Tuesday, 10-Dec-02 23:50:13 */
isoc /* Tue Dec 10 23:50:13 2002 */
} fmt;
2002-12-11 02:05:12 +08:00
2002-12-15 14:25:09 +08:00
fmt = 0;
2002-12-12 00:57:54 +08:00
end = value + len;
2002-12-11 02:05:12 +08:00
2003-01-30 15:28:09 +08:00
#if (NGX_SUPPRESS_WARN)
day = 32;
year = 2038;
#endif
2002-12-12 00:57:54 +08:00
for (p = value; p < end; p++) {
2003-01-09 13:36:00 +08:00
if (*p == ',') {
2002-12-12 00:57:54 +08:00
break;
2003-01-09 13:36:00 +08:00
}
2002-12-11 02:05:12 +08:00
2002-12-12 00:57:54 +08:00
if (*p == ' ') {
fmt = isoc;
break;
}
}
2002-12-11 02:05:12 +08:00
2002-12-12 00:57:54 +08:00
for (p++; p < end; p++)
2003-01-09 13:36:00 +08:00
if (*p != ' ') {
2002-12-11 02:05:12 +08:00
break;
2003-01-09 13:36:00 +08:00
}
2002-12-11 02:05:12 +08:00
2003-01-09 13:36:00 +08:00
if (end - p < 18) {
2002-12-12 00:57:54 +08:00
return NGX_ERROR;
2003-01-09 13:36:00 +08:00
}
2002-12-11 02:05:12 +08:00
2002-12-12 00:57:54 +08:00
if (fmt != isoc) {
2003-01-09 13:36:00 +08:00
if (*p < '0' || *p > '9' || *(p + 1) < '0' || *(p + 1) > '9') {
2002-12-12 00:57:54 +08:00
return NGX_ERROR;
2003-01-09 13:36:00 +08:00
}
2002-12-11 02:05:12 +08:00
2002-12-12 00:57:54 +08:00
day = (*p - '0') * 10 + *(p + 1) - '0';
p += 2;
2002-12-11 02:05:12 +08:00
2002-12-12 00:57:54 +08:00
if (*p == ' ') {
2003-01-09 13:36:00 +08:00
if (end - p < 18) {
2002-12-12 00:57:54 +08:00
return NGX_ERROR;
2003-01-09 13:36:00 +08:00
}
2002-12-12 00:57:54 +08:00
fmt = rfc822;
} else if (*p == '-') {
fmt = rfc850;
} else {
2002-12-11 02:05:12 +08:00
return NGX_ERROR;
2002-12-12 00:57:54 +08:00
}
p++;
}
switch (*p) {
case 'J':
month = *(p + 1) == 'a' ? 0 : *(p + 2) == 'n' ? 5 : 6;
break;
case 'F':
month = 1;
break;
2002-12-11 02:05:12 +08:00
2002-12-12 00:57:54 +08:00
case 'M':
month = *(p + 2) == 'r' ? 2 : 4;
break;
2002-12-11 02:05:12 +08:00
2002-12-12 00:57:54 +08:00
case 'A':
month = *(p + 1) == 'p' ? 3 : 7;
break;
2002-12-11 02:05:12 +08:00
2002-12-12 00:57:54 +08:00
case 'S':
month = 8;
break;
case 'O':
month = 9;
break;
case 'N':
month = 10;
break;
case 'D':
month = 11;
break;
default:
return NGX_ERROR;
}
p += 3;
2003-01-09 13:36:00 +08:00
if ((fmt == rfc822 && *p != ' ') || (fmt == rfc850 && *p != '-')) {
2002-12-12 00:57:54 +08:00
return NGX_ERROR;
2003-01-09 13:36:00 +08:00
}
2002-12-12 00:57:54 +08:00
p++;
if (fmt == rfc822) {
if (*p < '0' || *p > '9' || *(p + 1) < '0' || *(p + 1) > '9'
|| *(p + 2) < '0' || *(p + 2) > '9'
|| *(p + 3) < '0' || *(p + 3) > '9')
2003-01-09 13:36:00 +08:00
{
2002-12-11 02:05:12 +08:00
return NGX_ERROR;
2003-01-09 13:36:00 +08:00
}
2002-12-11 02:05:12 +08:00
2002-12-12 00:57:54 +08:00
year = (*p - '0') * 1000 + (*(p + 1) - '0') * 100
+ (*(p + 2) - '0') * 10 + *(p + 3) - '0';
p += 4;
2002-12-11 02:05:12 +08:00
2002-12-12 00:57:54 +08:00
} else if (fmt == rfc850) {
2003-01-09 13:36:00 +08:00
if (*p < '0' || *p > '9' || *(p + 1) < '0' || *(p + 1) > '9') {
2002-12-12 00:57:54 +08:00
return NGX_ERROR;
2003-01-09 13:36:00 +08:00
}
2002-12-12 00:57:54 +08:00
year = (*p - '0') * 10 + *(p + 1) - '0';
year += (year < 70) ? 2000 : 1900;
p += 2;
}
if (fmt == isoc) {
2003-01-09 13:36:00 +08:00
if (*p == ' ') {
2002-12-12 00:57:54 +08:00
p++;
2003-01-09 13:36:00 +08:00
}
2002-12-11 02:05:12 +08:00
2003-01-09 13:36:00 +08:00
if (*p < '0' || *p > '9') {
2002-12-12 00:57:54 +08:00
return NGX_ERROR;
2003-01-09 13:36:00 +08:00
}
2002-12-12 00:57:54 +08:00
day = *p++ - '0';
2002-12-11 02:05:12 +08:00
2002-12-12 00:57:54 +08:00
if (*p != ' ') {
2003-01-09 13:36:00 +08:00
if (*p < '0' || *p > '9') {
2002-12-12 00:57:54 +08:00
return NGX_ERROR;
2003-01-09 13:36:00 +08:00
}
2002-12-11 02:05:12 +08:00
2002-12-12 00:57:54 +08:00
day = day * 10 + *p++ - '0';
2002-12-11 02:05:12 +08:00
}
2002-12-12 00:57:54 +08:00
2003-01-09 13:36:00 +08:00
if (end - p < 14) {
2002-12-12 00:57:54 +08:00
return NGX_ERROR;
2003-01-09 13:36:00 +08:00
}
2002-12-11 02:05:12 +08:00
}
2002-12-12 00:57:54 +08:00
2003-01-09 13:36:00 +08:00
if (*p++ != ' ') {
2002-12-12 00:57:54 +08:00
return NGX_ERROR;
2003-01-09 13:36:00 +08:00
}
2002-12-12 00:57:54 +08:00
2003-01-09 13:36:00 +08:00
if (*p < '0' || *p > '9' || *(p + 1) < '0' || *(p + 1) > '9') {
2002-12-12 00:57:54 +08:00
return NGX_ERROR;
2003-01-09 13:36:00 +08:00
}
2002-12-12 00:57:54 +08:00
hour = (*p - '0') * 10 + *(p + 1) - '0';
p += 2;
2003-01-09 13:36:00 +08:00
if (*p++ != ':') {
2002-12-12 00:57:54 +08:00
return NGX_ERROR;
2003-01-09 13:36:00 +08:00
}
2002-12-12 00:57:54 +08:00
2003-01-09 13:36:00 +08:00
if (*p < '0' || *p > '9' || *(p + 1) < '0' || *(p + 1) > '9') {
2002-12-12 00:57:54 +08:00
return NGX_ERROR;
2003-01-09 13:36:00 +08:00
}
2002-12-12 00:57:54 +08:00
min = (*p - '0') * 10 + *(p + 1) - '0';
p += 2;
2003-01-09 13:36:00 +08:00
if (*p++ != ':') {
2002-12-12 00:57:54 +08:00
return NGX_ERROR;
2003-01-09 13:36:00 +08:00
}
2002-12-12 00:57:54 +08:00
2003-01-09 13:36:00 +08:00
if (*p < '0' || *p > '9' || *(p + 1) < '0' || *(p + 1) > '9') {
2002-12-12 00:57:54 +08:00
return NGX_ERROR;
2003-01-09 13:36:00 +08:00
}
2002-12-12 00:57:54 +08:00
sec = (*p - '0') * 10 + *(p + 1) - '0';
if (fmt == isoc) {
p += 2;
2003-01-09 13:36:00 +08:00
if (*p++ != ' ') {
2002-12-12 00:57:54 +08:00
return NGX_ERROR;
2003-01-09 13:36:00 +08:00
}
2002-12-12 00:57:54 +08:00
if (*p < '0' || *p > '9' || *(p + 1) < '0' || *(p + 1) > '9'
|| *(p + 2) < '0' || *(p + 2) > '9'
|| *(p + 3) < '0' || *(p + 3) > '9')
2003-01-09 13:36:00 +08:00
{
2002-12-12 00:57:54 +08:00
return NGX_ERROR;
2003-01-09 13:36:00 +08:00
}
2002-12-12 00:57:54 +08:00
year = (*p - '0') * 1000 + (*(p + 1) - '0') * 100
+ (*(p + 2) - '0') * 10 + *(p + 3) - '0';
}
2002-12-15 14:25:09 +08:00
#if 0
2002-12-12 00:57:54 +08:00
printf("%d.%d.%d %d:%d:%d\n", day, month + 1, year, hour, min, sec);
2002-12-15 14:25:09 +08:00
#endif
2002-12-12 00:57:54 +08:00
2003-01-09 13:36:00 +08:00
if (hour > 23 || min > 59 || sec > 59) {
2002-12-12 00:57:54 +08:00
return NGX_ERROR;
2003-01-09 13:36:00 +08:00
}
2002-12-12 00:57:54 +08:00
if (day == 29 && month == 1) {
2003-01-09 13:36:00 +08:00
if ((year & 3) || ((year % 100 == 0) && (year % 400) != 0)) {
2002-12-12 00:57:54 +08:00
return NGX_ERROR;
2003-01-09 13:36:00 +08:00
}
2002-12-12 00:57:54 +08:00
2002-12-15 14:25:09 +08:00
} else if (day > mday[month]) {
2002-12-12 00:57:54 +08:00
return NGX_ERROR;
}
2003-01-09 13:36:00 +08:00
if (sizeof(time_t) <= 4 && year >= 2038) {
2002-12-12 00:57:54 +08:00
return NGX_ERROR;
2003-01-09 13:36:00 +08:00
}
2002-12-12 00:57:54 +08:00
2003-11-13 01:25:12 +08:00
/*
* shift new year to March 1 and start months from 1 (not 0),
* it's needed for Gauss's formula
*/
2003-11-12 02:13:43 +08:00
2002-12-12 00:57:54 +08:00
if (--month <= 0) {
month += 12;
year -= 1;
}
2003-11-12 02:13:43 +08:00
2003-11-13 01:25:12 +08:00
/* Gauss's formula for Grigorian days from 1 March 1 BC */
2003-11-12 02:13:43 +08:00
2002-12-15 14:25:09 +08:00
return (365 * year + year / 4 - year / 100 + year / 400
2003-11-13 01:25:12 +08:00
+ 367 * month / 12 - 31
+ day
2003-11-12 02:13:43 +08:00
/*
2003-11-13 01:25:12 +08:00
* 719527 days were between March 1, 1 BC and March 1, 1970,
2003-11-12 02:13:43 +08:00
* 31 and 28 days in January and February 1970
*/
2002-12-15 14:25:09 +08:00
- 719527 + 31 + 28) * 86400 + hour * 3600 + min * 60 + sec;
2002-12-12 00:57:54 +08:00
}
2002-12-15 14:25:09 +08:00
#if 0
2002-12-12 00:57:54 +08:00
char zero[] = "Sun, 01 Jan 1970 08:49:30";
char one[] = "Sunday, 11-Dec-02 08:49:30";
char two[] = "Sun Mar 1 08:49:37 2000";
char thr[] = "Sun Dec 11 08:49:37 2002";
main()
{
int rc;
rc = ngx_http_parse_time(zero, sizeof(zero) - 1);
printf("rc: %d\n", rc);
rc = ngx_http_parse_time(one, sizeof(one) - 1);
printf("rc: %d\n", rc);
rc = ngx_http_parse_time(two, sizeof(two) - 1);
printf("rc: %d\n", rc);
rc = ngx_http_parse_time(thr, sizeof(thr) - 1);
printf("rc: %d\n", rc);
2002-12-11 02:05:12 +08:00
}
2002-12-15 14:25:09 +08:00
#endif