diff options
-rw-r--r-- | apt-pkg/contrib/strutl.cc | 113 | ||||
-rw-r--r-- | test/libapt/strutil_test.cc | 35 |
2 files changed, 112 insertions, 36 deletions
diff --git a/apt-pkg/contrib/strutl.cc b/apt-pkg/contrib/strutl.cc index 92fdee32a..23c2f78e5 100644 --- a/apt-pkg/contrib/strutl.cc +++ b/apt-pkg/contrib/strutl.cc @@ -867,7 +867,7 @@ bool ReadMessages(int Fd, vector<string> &List) // --------------------------------------------------------------------- /* This was lifted from the boa webserver which lifted it from 'wn-v1.07' Made it a bit more robust with a few tolower_ascii though. */ -static int MonthConv(char *Month) +static int MonthConv(char const * const Month) { switch (tolower_ascii(*Month)) { @@ -930,46 +930,87 @@ static time_t timegm(struct tm *t) method used to ignore the timezone and assume always UTC. */ bool RFC1123StrToTime(const char* const str,time_t &time) { - struct tm t; - auto const &posix = std::locale("C.UTF-8"); - auto const parse_time = [&](char const * const s, bool const has_timezone) { - std::istringstream ss(str); - ss.imbue(posix); - ss >> std::get_time(&t, s); - if (has_timezone && ss.fail() == false) - { - std::string timezone; - ss >> timezone; - if (timezone.empty()) + unsigned short day = 0; + signed int year = 0; // yes, Y23K problem – we gonna worry then… + std::string weekday, month, datespec, timespec, zone; + std::istringstream ss(str); + ss >> weekday; + // we only superficially check weekday, mostly to avoid accepting localized + // weekdays here and take only its length to decide which datetime format we + // encounter here. The date isn't stored. + std::transform(weekday.begin(), weekday.end(), weekday.begin(), ::tolower); + std::array<char const * const, 7> c_weekdays = {{ "sun", "mon", "tue", "wed", "thu", "fri", "sat" }}; + if (std::find(c_weekdays.begin(), c_weekdays.end(), weekday.substr(0,3)) == c_weekdays.end()) + return false; + + switch (weekday.length()) + { + case 4: + // Sun, 06 Nov 1994 08:49:37 GMT ; RFC 822, updated by RFC 1123 + if (weekday[3] != ',') + return false; + ss >> day >> month >> year >> timespec >> zone; + break; + case 3: + // Sun Nov 6 08:49:37 1994 ; ANSI C's asctime() format + ss >> month >> day >> timespec >> year; + zone = "UTC"; + break; + case 0: + case 1: + case 2: + return false; + default: + // Sunday, 06-Nov-94 08:49:37 GMT ; RFC 850, obsoleted by RFC 1036 + if (weekday[weekday.length() - 1] != ',') + return false; + ss >> datespec >> timespec >> zone; + auto const expldate = VectorizeString(datespec, '-'); + if (expldate.size() != 3) + return false; + try { + size_t pos; + day = std::stoi(expldate[0], &pos); + if (pos != expldate[0].length()) return false; - if (timezone != "GMT" && timezone != "UTC" && timezone != "Z") // RFC 822 - { - // numeric timezones as a should of RFC 1123 and generally preferred - try { - size_t pos; - auto const zone = std::stoi(timezone, &pos); - if (zone != 0 || pos != timezone.length()) - return false; - } catch (...) { - return false; - } - } + year = 1900 + std::stoi(expldate[2], &pos); + if (pos != expldate[2].length()) + return false; + strprintf(datespec, "%.4d-%.2d-%.2d", year, MonthConv(expldate[1].c_str()) + 1, day); + } catch (...) { + return false; } - t.tm_isdst = 0; - return ss.fail() == false; - }; + break; + } - bool const good = - // Sun, 06 Nov 1994 08:49:37 GMT ; RFC 822, updated by RFC 1123 - parse_time("%a, %d %b %Y %H:%M:%S", true) || - // Sunday, 06-Nov-94 08:49:37 GMT ; RFC 850, obsoleted by RFC 1036 - parse_time("%A, %d-%b-%y %H:%M:%S", true) || - // Sun Nov 6 08:49:37 1994 ; ANSI C's asctime() format - parse_time("%c", false); // "%a %b %d %H:%M:%S %Y" - if (good == false) + if (ss.fail() || ss.bad() || !ss.eof()) return false; - time = timegm(&t); + if (zone != "GMT" && zone != "UTC" && zone != "Z") // RFC 822 + { + // numeric timezones as a should of RFC 1123 and generally preferred + try { + size_t pos; + auto const z = std::stoi(zone, &pos); + if (z != 0 || pos != zone.length()) + return false; + } catch (...) { + return false; + } + } + + if (datespec.empty()) + { + if (month.empty()) + return false; + strprintf(datespec, "%.4d-%.2d-%.2d", year, MonthConv(month.c_str()) + 1, day); + } + + std::string const datetime = datespec + ' ' + timespec; + struct tm Tm; + if (strptime(datetime.c_str(), "%Y-%m-%d %H:%M:%S", &Tm) == nullptr) + return false; + time = timegm(&Tm); return true; } /*}}}*/ diff --git a/test/libapt/strutil_test.cc b/test/libapt/strutil_test.cc index b7ba816ee..90a5817ad 100644 --- a/test/libapt/strutil_test.cc +++ b/test/libapt/strutil_test.cc @@ -255,6 +255,18 @@ TEST(StrUtilTest,RFC1123StrToTime) EXPECT_EQ(784111777, t); } { time_t t; + EXPECT_TRUE(RFC1123StrToTime("Sun, 6 Nov 1994 08:49:37 UTC", t)); + EXPECT_EQ(784111777, t); + } { + time_t t; + EXPECT_TRUE(RFC1123StrToTime("Sun, 6 Nov 1994 08:49:37 UTC", t)); + EXPECT_EQ(784111777, t); + } { + time_t t; + EXPECT_TRUE(RFC1123StrToTime("Sun, 06 Nov 1994 8:49:37 UTC", t)); + EXPECT_EQ(784111777, t); + } { + time_t t; EXPECT_TRUE(RFC1123StrToTime("Sun, 06 Nov 1994 08:49:37 UTC", t)); EXPECT_EQ(784111777, t); } { @@ -271,14 +283,37 @@ TEST(StrUtilTest,RFC1123StrToTime) EXPECT_EQ(784111777, t); } { time_t t; + EXPECT_TRUE(RFC1123StrToTime("Sunday, 6-Nov-94 08:49:37 GMT", t)); + EXPECT_EQ(784111777, t); + } { + time_t t; + EXPECT_TRUE(RFC1123StrToTime("Sunday, 06-Nov-94 8:49:37 GMT", t)); + EXPECT_EQ(784111777, t); + } { + time_t t; EXPECT_TRUE(RFC1123StrToTime("Sun Nov 6 08:49:37 1994", t)); EXPECT_EQ(784111777, t); + } { + time_t t; + EXPECT_TRUE(RFC1123StrToTime("Sun Nov 06 08:49:37 1994", t)); + EXPECT_EQ(784111777, t); + } { + time_t t; + EXPECT_TRUE(RFC1123StrToTime("Sun Nov 6 8:49:37 1994", t)); + EXPECT_EQ(784111777, t); } time_t t; + EXPECT_FALSE(RFC1123StrToTime("So, 06 Nov 1994 08:49:37 UTC", t)); + EXPECT_FALSE(RFC1123StrToTime(", 06 Nov 1994 08:49:37 UTC", t)); + EXPECT_FALSE(RFC1123StrToTime("Son, 06 Nov 1994 08:49:37 UTC", t)); + EXPECT_FALSE(RFC1123StrToTime("Sun: 06 Nov 1994 08:49:37 UTC", t)); EXPECT_FALSE(RFC1123StrToTime("Sun, 06 Nov 1994 08:49:37", t)); + EXPECT_FALSE(RFC1123StrToTime("Sun, 06 Nov 1994 08:49:37 GMT+1", t)); EXPECT_FALSE(RFC1123StrToTime("Sun, 06 Nov 1994 GMT", t)); + EXPECT_FALSE(RFC1123StrToTime("Sunday, 06 Nov 1994 GMT", t)); EXPECT_FALSE(RFC1123StrToTime("Sonntag, 06 Nov 1994 08:49:37 GMT", t)); EXPECT_FALSE(RFC1123StrToTime("domingo Nov 6 08:49:37 1994", t)); + EXPECT_FALSE(RFC1123StrToTime("Sunday: 06-Nov-94 08:49:37 GMT", t)); EXPECT_FALSE(RFC1123StrToTime("Sunday, 06-Nov-94 08:49:37 GMT+1", t)); EXPECT_FALSE(RFC1123StrToTime("Sunday, 06-Nov-94 08:49:37 EDT", t)); EXPECT_FALSE(RFC1123StrToTime("Sunday, 06-Nov-94 08:49:37 -0100", t)); |