| /* | |
| * Copyright (C) Igor Sysoev | |
| */ | |
| #include <ngx_config.h> | |
| #include <ngx_core.h> | |
| static int mday[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; | |
| time_t | |
| ngx_http_parse_time(u_char *value, size_t len) | |
| { | |
| u_char *p, *end; | |
| int day, month, year, hour, min, sec; | |
| enum { | |
| 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; | |
| fmt = 0; | |
| end = value + len; | |
| #if (NGX_SUPPRESS_WARN) | |
| day = 32; | |
| year = 2038; | |
| #endif | |
| for (p = value; p < end; p++) { | |
| if (*p == ',') { | |
| break; | |
| } | |
| if (*p == ' ') { | |
| fmt = isoc; | |
| break; | |
| } | |
| } | |
| for (p++; p < end; p++) | |
| if (*p != ' ') { | |
| break; | |
| } | |
| if (end - p < 18) { | |
| return NGX_ERROR; | |
| } | |
| if (fmt != isoc) { | |
| if (*p < '0' || *p > '9' || *(p + 1) < '0' || *(p + 1) > '9') { | |
| return NGX_ERROR; | |
| } | |
| day = (*p - '0') * 10 + *(p + 1) - '0'; | |
| p += 2; | |
| if (*p == ' ') { | |
| if (end - p < 18) { | |
| return NGX_ERROR; | |
| } | |
| fmt = rfc822; | |
| } else if (*p == '-') { | |
| fmt = rfc850; | |
| } else { | |
| return NGX_ERROR; | |
| } | |
| p++; | |
| } | |
| switch (*p) { | |
| case 'J': | |
| month = *(p + 1) == 'a' ? 0 : *(p + 2) == 'n' ? 5 : 6; | |
| break; | |
| case 'F': | |
| month = 1; | |
| break; | |
| case 'M': | |
| month = *(p + 2) == 'r' ? 2 : 4; | |
| break; | |
| case 'A': | |
| month = *(p + 1) == 'p' ? 3 : 7; | |
| break; | |
| 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; | |
| if ((fmt == rfc822 && *p != ' ') || (fmt == rfc850 && *p != '-')) { | |
| return NGX_ERROR; | |
| } | |
| 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') | |
| { | |
| return NGX_ERROR; | |
| } | |
| year = (*p - '0') * 1000 + (*(p + 1) - '0') * 100 | |
| + (*(p + 2) - '0') * 10 + *(p + 3) - '0'; | |
| p += 4; | |
| } else if (fmt == rfc850) { | |
| if (*p < '0' || *p > '9' || *(p + 1) < '0' || *(p + 1) > '9') { | |
| return NGX_ERROR; | |
| } | |
| year = (*p - '0') * 10 + *(p + 1) - '0'; | |
| year += (year < 70) ? 2000 : 1900; | |
| p += 2; | |
| } | |
| if (fmt == isoc) { | |
| if (*p == ' ') { | |
| p++; | |
| } | |
| if (*p < '0' || *p > '9') { | |
| return NGX_ERROR; | |
| } | |
| day = *p++ - '0'; | |
| if (*p != ' ') { | |
| if (*p < '0' || *p > '9') { | |
| return NGX_ERROR; | |
| } | |
| day = day * 10 + *p++ - '0'; | |
| } | |
| if (end - p < 14) { | |
| return NGX_ERROR; | |
| } | |
| } | |
| if (*p++ != ' ') { | |
| return NGX_ERROR; | |
| } | |
| if (*p < '0' || *p > '9' || *(p + 1) < '0' || *(p + 1) > '9') { | |
| return NGX_ERROR; | |
| } | |
| hour = (*p - '0') * 10 + *(p + 1) - '0'; | |
| p += 2; | |
| if (*p++ != ':') { | |
| return NGX_ERROR; | |
| } | |
| if (*p < '0' || *p > '9' || *(p + 1) < '0' || *(p + 1) > '9') { | |
| return NGX_ERROR; | |
| } | |
| min = (*p - '0') * 10 + *(p + 1) - '0'; | |
| p += 2; | |
| if (*p++ != ':') { | |
| return NGX_ERROR; | |
| } | |
| if (*p < '0' || *p > '9' || *(p + 1) < '0' || *(p + 1) > '9') { | |
| return NGX_ERROR; | |
| } | |
| sec = (*p - '0') * 10 + *(p + 1) - '0'; | |
| if (fmt == isoc) { | |
| p += 2; | |
| if (*p++ != ' ') { | |
| return NGX_ERROR; | |
| } | |
| if (*p < '0' || *p > '9' || *(p + 1) < '0' || *(p + 1) > '9' | |
| || *(p + 2) < '0' || *(p + 2) > '9' | |
| || *(p + 3) < '0' || *(p + 3) > '9') | |
| { | |
| return NGX_ERROR; | |
| } | |
| year = (*p - '0') * 1000 + (*(p + 1) - '0') * 100 | |
| + (*(p + 2) - '0') * 10 + *(p + 3) - '0'; | |
| } | |
| if (hour > 23 || min > 59 || sec > 59) { | |
| return NGX_ERROR; | |
| } | |
| if (day == 29 && month == 1) { | |
| if ((year & 3) || ((year % 100 == 0) && (year % 400) != 0)) { | |
| return NGX_ERROR; | |
| } | |
| } else if (day > mday[month]) { | |
| return NGX_ERROR; | |
| } | |
| #if (NGX_TIME_T_SIZE <= 4) | |
| if (year >= 2038) { | |
| return NGX_ERROR; | |
| } | |
| #endif | |
| /* | |
| * shift new year to March 1 and start months from 1 (not 0), | |
| * it is needed for Gauss' formula | |
| */ | |
| if (--month <= 0) { | |
| month += 12; | |
| year -= 1; | |
| } | |
| /* Gauss' formula for Grigorian days since March 1, 1 BC */ | |
| return ( | |
| /* days in years including leap years since March 1, 1 BC */ | |
| 365 * year + year / 4 - year / 100 + year / 400 | |
| /* days before the month */ | |
| + 367 * month / 12 - 30 | |
| /* days before the day */ | |
| + day - 1 | |
| /* | |
| * 719527 days were between March 1, 1 BC and March 1, 1970, | |
| * 31 and 28 days were in January and February 1970 | |
| */ | |
| - 719527 + 31 + 28) * 86400 + hour * 3600 + min * 60 + sec; | |
| } |