]> git.ipfire.org Git - thirdparty/rspamd.git/commitdiff
Parse HTTP date in map requests.
authorVsevolod Stakhov <vsevolod@highsecure.ru>
Wed, 26 Jun 2013 16:59:50 +0000 (17:59 +0100)
committerVsevolod Stakhov <vsevolod@highsecure.ru>
Wed, 26 Jun 2013 16:59:50 +0000 (17:59 +0100)
src/map.c
src/util.c
src/util.h

index 0950d5682774a57995d008f68906cd7b8399de84..ea7f0adbb91fcd05ffa207fdfffff8da804e146f 100644 (file)
--- a/src/map.c
+++ b/src/map.c
@@ -305,7 +305,7 @@ read_http_common (struct rspamd_map *map, struct http_map_data *data, struct htt
 {
        gchar                         *remain, *pos;
        ssize_t                         r;
-       gchar                           *te;
+       gchar                           *te, *date;
        
        if ((r = read (fd, data->read_buf + data->rlen, sizeof (data->read_buf) - data->rlen)) > 0) {
                r += data->rlen;
@@ -346,6 +346,14 @@ read_http_common (struct rspamd_map *map, struct http_map_data *data, struct htt
                                        data->chunked = -1;
                                }
                        }
+                       /* Check for date */
+                       date = g_hash_table_lookup (reply->headers, "Date");
+                       if (date != NULL) {
+                               data->last_checked = parse_http_date (date, -1);
+                       }
+                       else {
+                               data->last_checked = (time_t)-1;
+                       }
 
                        if (data->chunked > 0) {
                                return read_http_chunked (data->read_buf, r, map, data, cbdata);
@@ -402,7 +410,9 @@ read_http_sync (struct rspamd_map *map, struct http_map_data *data)
 
        map->fin_callback (map->pool, &cbdata);
        *map->user_data = cbdata.cur_data;
-       data->last_checked = time (NULL);
+       if (data->last_checked == (time_t)-1) {
+               data->last_checked = time (NULL);
+       }
 
        g_hash_table_destroy (repl->headers);
        g_free (repl);
@@ -846,14 +856,18 @@ http_async_callback (gint fd, short what, void *ud)
                        if (!read_http_common (cbd->map, cbd->data, cbd->reply, &cbd->cbdata, cbd->fd)) {
                                /* Handle Not-Modified in a special way */
                                if (cbd->reply->code == 304) {
-                                       cbd->data->last_checked = time (NULL);
+                                       if (cbd->data->last_checked == (time_t)-1) {
+                                               cbd->data->last_checked = time (NULL);
+                                       }
                                        msg_info ("data is not modified for server %s", cbd->data->host);
                                }
                                else if (cbd->cbdata.cur_data != NULL) {
                                        /* Destroy old data and start reading request data */
                                        cbd->map->fin_callback (cbd->map->pool, &cbd->cbdata);
                                        *cbd->map->user_data = cbd->cbdata.cur_data;
-                                       cbd->data->last_checked = time (NULL);
+                                       if (cbd->data->last_checked == (time_t)-1) {
+                                               cbd->data->last_checked = time (NULL);
+                                       }
                                }
                                if (cbd->state == 1 && cbd->reply->code == 200) {
                                        /* Write to log that data is modified */
index 7757c7ad03da07b3e8e1e2be6871e663db6affe0..441ce007a8b961ecf1d99e09f5d2f2fa3dd86567 100644 (file)
@@ -38,8 +38,6 @@
 /* Default connect timeout for sync sockets */
 #define CONNECT_TIMEOUT 3
 
-static gchar* rspamd_sprintf_num (gchar *buf, gchar *last, guint64 ui64, gchar zero, guint hexadecimal, guint width);
-
 gint
 make_socket_nonblocking (gint fd)
 {
@@ -1859,6 +1857,274 @@ parse_ipmask_v4 (const char *line, struct in_addr *ina, int *mask)
        return TRUE;
 }
 
+/*
+ * Obtained from nginx
+ * Copyright (C) Igor Sysoev
+ */
+static guint mday[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
+
+time_t
+parse_http_date (const gchar *header, gsize len)
+{
+       const gchar *p, *end;
+       gint month;
+       guint day, year, hour, min, sec;
+       guint64 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);
+       }
+
+#if (NGX_SUPPRESS_WARN)
+       day = 32;
+       year = 2038;
+#endif
+
+       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 = (guint64) (
+                       /* 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;
+}
+
 /*
  * vi:ts=4
  */
index 228fb74451b18ccdf03b11bef65312bc87aaaaec..b1e07c53815767db4bd68c4b33e1e6e3488c458e 100644 (file)
@@ -400,4 +400,12 @@ gpointer rspamd_str_pool_copy (gconstpointer data, gpointer ud);
  */
 gboolean parse_ipmask_v4 (const char *line, struct in_addr *ina, int *mask);
 
+/**
+ * Parse HTTP date header and return it as time_t
+ * @param header HTTP date header
+ * @param len length of header
+ * @return time_t or (time_t)-1 in case of error
+ */
+time_t parse_http_date (const gchar *header, gsize len);
+
 #endif