From ae4a73645bc12fbd511ab37b49f7045ebd3675be Mon Sep 17 00:00:00 2001 From: Arseny Smirnov Date: Wed, 10 Jul 2019 20:11:16 +0200 Subject: [PATCH] Some parse_http_date implementation GitOrigin-RevId: 153367519b120453d5bc80454f568e829a3f2e49 --- test/mtproto.cpp | 102 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 102 insertions(+) diff --git a/test/mtproto.cpp b/test/mtproto.cpp index fee85f048..5ace41626 100644 --- a/test/mtproto.cpp +++ b/test/mtproto.cpp @@ -36,6 +36,7 @@ #include "td/utils/logging.h" #include "td/utils/port/IPAddress.h" #include "td/utils/port/SocketFd.h" +#include "td/utils/Parser.h" #include "td/utils/Random.h" #include "td/utils/Status.h" #include "td/utils/Time.h" @@ -120,6 +121,107 @@ TEST(Mtproto, GetHostByNameActor) { sched.finish(); } +class Date { + public: + static bool is_leap(int year) { + return year % 4 == 0 && (year % 100 != 0 || year % 400 == 0); + } + static int32 days_in_month(int year, int month) { + int cnt[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; + return cnt[month - 1] + (month == 2 && is_leap(year)); + } + static int64 seconds_in_day() { + return 24 * 60 * 60; + } + static Result to_unix_time(int32 year, int32 month, int32 day, int32 hour, int32 minute, int32 second) { + int64 res = 0; + if (year < 1970 || year > 2037) { + return td::Status::Error("invalid year"); + } + if (month < 1 || month > 12) { + return td::Status::Error("invalid month"); + } + if (day < 1 || day > days_in_month(year, month)) { + return td::Status::Error("invalid day"); + } + if (hour < 0 || hour > 24) { // is hour == 24 possible? + return td::Status::Error("invalid hour"); + } + if (minute < 0 || minute > 60) { + return td::Status::Error("invalid minute"); + } + if (second < 0 || second > 60) { + return td::Status::Error("invalid second"); + } + for (int y = 1970; y < year; y++) { + res += (is_leap(y) + 365) * seconds_in_day(); + } + for (int m = 1; m < month; m++) { + res += days_in_month(year, m) * seconds_in_day(); + } + res += (day - 1) * seconds_in_day(); + res += hour * 60 * 60; + res += minute * 60; + res += second; + return res; + } +}; + +TEST(Time, to_unix_time) { + ASSERT_EQ(0, Date::to_unix_time(1970, 1, 1, 0, 0, 0).move_as_ok()); + ASSERT_EQ(60 * 60 + 60 + 1, Date::to_unix_time(1970, 1, 1, 1, 1, 1).move_as_ok()); + ASSERT_EQ(24 * 60 * 60, Date::to_unix_time(1970, 1, 2, 0, 0, 0).move_as_ok()); + ASSERT_EQ(31 * 24 * 60 * 60, Date::to_unix_time(1970, 2, 1, 0, 0, 0).move_as_ok()); + ASSERT_EQ(365 * 24 * 60 * 60, Date::to_unix_time(1971, 1, 1, 0, 0, 0).move_as_ok()); + ASSERT_EQ(1562780559, Date::to_unix_time(2019, 7, 10, 17, 42, 39).move_as_ok()); +} + +Result parse_http_date(std::string slice) { + td::Parser p(slice); + p.read_till(','); // ignore week day + p.skip(','); + p.skip_whitespaces(); + TRY_RESULT(day, to_integer_safe(p.read_word())); + auto month_name = p.read_word(); + to_lower_inplace(month_name); + TRY_RESULT(year, to_integer_safe(p.read_word())); + p.skip_whitespaces(); + p.skip_nofail('0'); + TRY_RESULT(hour, to_integer_safe(p.read_till(':'))); + p.skip(':'); + p.skip_nofail('0'); + TRY_RESULT(minute, to_integer_safe(p.read_till(':'))); + p.skip(':'); + p.skip_nofail('0'); + TRY_RESULT(second, to_integer_safe(p.read_word())); + auto gmt = p.read_word(); + TRY_STATUS(std::move(p.status())); + if (gmt != "GMT") { + return Status::Error("timezone must be GMT"); + } + + Slice month_names[12] = {"jan", "feb", "mar", "apr", "may", "jun", "jul", "aug", "sep", "oct", "nov", "dec"}; + + int month = 0; + + for (int m = 1; m <= 12; m++) { + if (month_names[m - 1] == month_name) { + month = m; + break; + } + } + + if (month == 0) { + return Status::Error("Unknown month name"); + } + + return Date::to_unix_time(year, month, day, hour, minute, second); +} + +TEST(Time, parse_http_date) { + ASSERT_EQ(784887151, parse_http_date("Tue, 15 Nov 1994 08:12:31 GMT").move_as_ok()); +} + TEST(Mtproto, config) { ConcurrentScheduler sched; int threads_n = 0;