Skip to content

Commit c522d03

Browse files
Make Date header parsing locale-independent
Parse RFC1123 Date headers with std::get_time using the classic locale and a literal GMT token, and trim header whitespace before parsing. Treat invalid/partial parses as missing timestamps and remove the extra GMT offset correction now that UTC parsing is explicit. Relates-To: HERESUP-57013 Signed-off-by: Mykhailo Diachenko <ext-mykhailo.z.diachenko@here.com>
1 parent df55ff5 commit c522d03

File tree

1 file changed

+29
-9
lines changed

1 file changed

+29
-9
lines changed

olp-cpp-sdk-authentication/src/AuthenticationClientUtils.cpp

Lines changed: 29 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121

2222
#include <chrono>
2323
#include <iomanip>
24+
#include <locale>
2425
#include <sstream>
2526
#include <utility>
2627

@@ -108,18 +109,34 @@ std::time_t ParseTime(const std::string& value) {
108109

109110
#else
110111

112+
std::string TrimDateHeaderValue(const std::string& value) {
113+
const auto begin = value.find_first_not_of(" \t\r\n");
114+
if (begin == std::string::npos) {
115+
return {};
116+
}
117+
const auto end = value.find_last_not_of(" \t\r\n");
118+
return value.substr(begin, end - begin + 1);
119+
}
120+
111121
std::time_t ParseTime(const std::string& value) {
112122
std::tm tm = {};
113-
const auto format = "%a, %d %b %Y %H:%M:%S %Z";
114-
const auto parsed_until = ::strptime(value.c_str(), format, &tm);
115-
if (parsed_until != value.c_str() + value.size()) {
123+
const auto trimmed_value = TrimDateHeaderValue(value);
124+
std::istringstream stream(trimmed_value);
125+
stream.imbue(std::locale::classic());
126+
// Parse RFC1123 with a fixed C locale and a literal "GMT".
127+
// This keeps parsing locale-independent and avoids `%Z` timezone-name
128+
// parsing.
129+
stream >> std::get_time(&tm, "%a, %d %b %Y %H:%M:%S GMT");
130+
131+
if (stream.fail() || !stream.eof()) {
116132
OLP_SDK_LOG_WARNING(kLogTag, "Timestamp is not fully parsed" << value);
133+
return static_cast<std::time_t>(-1);
117134
}
118-
// MacOS updates `tm_isdst`, `tm_zone` and `tm_gmtoff` fields in `timegm`
119-
// call.
120-
const auto gmtoff = tm.tm_gmtoff;
121-
const auto local_time = timegm(&tm);
122-
return local_time - gmtoff;
135+
136+
// With literal GMT, tm is already in UTC and `tm_gmtoff` stays 0.
137+
// `timegm` may still normalize timezone-related fields on macOS, but no
138+
// additional offset correction is needed here.
139+
return timegm(&tm);
123140
}
124141

125142
#endif
@@ -133,7 +150,10 @@ porting::optional<std::time_t> GetTimestampFromHeaders(
133150
obg.first, kDate);
134151
});
135152
if (it != end(headers)) {
136-
return ParseTime(it->second);
153+
const auto timestamp = ParseTime(it->second);
154+
if (timestamp != static_cast<std::time_t>(-1)) {
155+
return timestamp;
156+
}
137157
}
138158
return porting::none;
139159
}

0 commit comments

Comments
 (0)