- /*-
- * Copyright 2019 Vsevolod Stakhov
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
- #include "libserver/http/http_util.h"
- #include "libutil/printf.h"
- #include "libutil/util.h"
-
- static const char *http_week[] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};
- static const char *http_month[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun",
- "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
-
- /*
- * Obtained from nginx
- * Copyright (C) Igor Sysoev
- */
- static unsigned int mday[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
-
- time_t
- rspamd_http_parse_date(const char *header, gsize len)
- {
- const char *p, *end;
- int month;
- unsigned int day, year, hour, min, sec;
- uint64_t time;
- 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;
- if (len > 0) {
- end = header + len;
- }
- else {
- end = header + strlen(header);
- }
-
- day = 32;
- year = 2038;
-
- for (p = header; p < end; p++) {
- if (*p == ',') {
- break;
- }
-
- if (*p == ' ') {
- fmt = isoc;
- break;
- }
- }
-
- for (p++; p < end; p++)
- if (*p != ' ') {
- break;
- }
-
- if (end - p < 18) {
- return (time_t) -1;
- }
-
- if (fmt != isoc) {
- if (*p < '0' || *p > '9' || *(p + 1) < '0' || *(p + 1) > '9') {
- return (time_t) -1;
- }
-
- day = (*p - '0') * 10 + *(p + 1) - '0';
- p += 2;
-
- if (*p == ' ') {
- if (end - p < 18) {
- return (time_t) -1;
- }
- fmt = rfc822;
- }
- else if (*p == '-') {
- fmt = rfc850;
- }
- else {
- return (time_t) -1;
- }
-
- 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 (time_t) -1;
- }
-
- p += 3;
-
- if ((fmt == rfc822 && *p != ' ') || (fmt == rfc850 && *p != '-')) {
- return (time_t) -1;
- }
-
- 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 (time_t) -1;
- }
-
- 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 (time_t) -1;
- }
-
- 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 (time_t) -1;
- }
-
- day = *p++ - '0';
-
- if (*p != ' ') {
- if (*p < '0' || *p > '9') {
- return (time_t) -1;
- }
-
- day = day * 10 + *p++ - '0';
- }
-
- if (end - p < 14) {
- return (time_t) -1;
- }
- }
-
- if (*p++ != ' ') {
- return (time_t) -1;
- }
-
- if (*p < '0' || *p > '9' || *(p + 1) < '0' || *(p + 1) > '9') {
- return (time_t) -1;
- }
-
- hour = (*p - '0') * 10 + *(p + 1) - '0';
- p += 2;
-
- if (*p++ != ':') {
- return (time_t) -1;
- }
-
- if (*p < '0' || *p > '9' || *(p + 1) < '0' || *(p + 1) > '9') {
- return (time_t) -1;
- }
-
- min = (*p - '0') * 10 + *(p + 1) - '0';
- p += 2;
-
- if (*p++ != ':') {
- return (time_t) -1;
- }
-
- if (*p < '0' || *p > '9' || *(p + 1) < '0' || *(p + 1) > '9') {
- return (time_t) -1;
- }
-
- sec = (*p - '0') * 10 + *(p + 1) - '0';
-
- if (fmt == isoc) {
- p += 2;
-
- if (*p++ != ' ') {
- return (time_t) -1;
- }
-
- if (*p < '0' || *p > '9' || *(p + 1) < '0' || *(p + 1) > '9' || *(p + 2) < '0' || *(p + 2) > '9' || *(p + 3) < '0' || *(p + 3) > '9') {
- return (time_t) -1;
- }
-
- year = (*p - '0') * 1000 + (*(p + 1) - '0') * 100 + (*(p + 2) - '0') * 10 + *(p + 3) - '0';
- }
-
- if (hour > 23 || min > 59 || sec > 59) {
- return (time_t) -1;
- }
-
- if (day == 29 && month == 1) {
- if ((year & 3) || ((year % 100 == 0) && (year % 400) != 0)) {
- return (time_t) -1;
- }
- }
- else if (day > mday[month]) {
- return (time_t) -1;
- }
-
- /*
- * 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 Gregorian days since March 1, 1 BC */
-
- time = (uint64_t) (
- /* 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;
-
- return (time_t) time;
- }
-
- glong rspamd_http_date_format(char *buf, gsize len, time_t time)
- {
- struct tm tms;
-
- rspamd_gmtime(time, &tms);
-
- return rspamd_snprintf(buf, len, "%s, %02d %s %4d %02d:%02d:%02d GMT",
- http_week[tms.tm_wday], tms.tm_mday,
- http_month[tms.tm_mon], tms.tm_year + 1900,
- tms.tm_hour, tms.tm_min, tms.tm_sec);
- }
|