diff --git a/src/common/util.c b/src/common/util.c index ed5b6a06f4..252f566dee 100644 --- a/src/common/util.c +++ b/src/common/util.c @@ -914,6 +914,57 @@ time_t tor_timegm (struct tm *tm) { return ret; } +/* strftime is locale-specific, so we need to replace those parts */ +static const char *WEEKDAY_NAMES[] = + { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" }; +static const char *MONTH_NAMES[] = + { "Jan", "Feb", "Mar", "Apr", "May", "Jun", + "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; + +void tor_format_rfc1123_time(char *buf, time_t t) { + struct tm *tm = gmtime(&t); + + strftime(buf, RFC1123_TIME_LEN+1, "XXX, %d XXX %Y %H:%M:%S GMT", tm); + tor_assert(tm->tm_wday >= 0 && tm->tm_wday <= 6); + memcpy(buf, WEEKDAY_NAMES[tm->tm_wday], 3); + tor_assert(tm->tm_wday >= 0 && tm->tm_mon <= 11); + memcpy(buf+8, MONTH_NAMES[tm->tm_mon], 3); +} + +int tor_parse_rfc1123_time(const char *buf, time_t *t) { + struct tm tm; + char month[4]; + char weekday[4]; + int i, m; + + if (strlen(buf) != RFC1123_TIME_LEN) + return -1; + memset(&tm, 0, sizeof(tm)); + if (sscanf(buf, "%3s, %d %3s %d %d:%d:%d GMT", weekday, + &tm.tm_mday, month, &tm.tm_year, &tm.tm_hour, + &tm.tm_min, &tm.tm_sec) < 7) { + log_fn(LOG_WARN, "Got invalid RFC1123 time \"%s\"", buf); + return -1; + } + + m = -1; + for (i = 0; i < 12; ++i) { + if (!strcmp(month, MONTH_NAMES[i])) { + m = i; + break; + } + } + if (m<0) { + log_fn(LOG_WARN, "Got invalid RFC1123 time \"%s\"", buf); + return -1; + } + + tm.tm_mon = m; + tm.tm_year -= 1900; + *t = tor_timegm(&tm); + return 0; +} + /* * Low-level I/O. */ diff --git a/src/common/util.h b/src/common/util.h index 2d4702312a..8ee05b2fc1 100644 --- a/src/common/util.h +++ b/src/common/util.h @@ -201,6 +201,9 @@ void tv_addms(struct timeval *a, long ms); void tv_add(struct timeval *a, struct timeval *b); int tv_cmp(struct timeval *a, struct timeval *b); time_t tor_timegm(struct tm *tm); +#define RFC1123_TIME_LEN 29 +void tor_format_rfc1123_time(char *buf, time_t t); +int tor_parse_rfc1123_time(const char *buf, time_t *t); int write_all(int fd, const char *buf, size_t count, int isSocket); int read_all(int fd, char *buf, size_t count, int isSocket); diff --git a/src/or/test.c b/src/or/test.c index f76e66d2d8..dd39513702 100644 --- a/src/or/test.c +++ b/src/or/test.c @@ -439,6 +439,9 @@ test_util() { struct timeval start, end; struct tm a_time; smartlist_t *sl; + char timestr[RFC1123_TIME_LEN+1]; + time_t t_res; + int i; start.tv_sec = 5; start.tv_usec = 5000; @@ -479,6 +482,15 @@ test_util() { a_time.tm_mday = 10; test_eq((time_t) 1076393695UL, tor_timegm(&a_time)); + tor_format_rfc1123_time(timestr, 0); + test_streq("Thu, 01 Jan 1970 00:00:00 GMT", timestr); + tor_format_rfc1123_time(timestr, (time_t)1091580502UL); + test_streq("Wed, 04 Aug 2004 00:48:22 GMT", timestr); + + t_res = 0; + i = tor_parse_rfc1123_time(timestr, &t_res); + test_eq(i,0); + test_eq(t_res, (time_t)1091580502UL); /* Test smartlist */ sl = smartlist_create();