From 5b45f0d8c42c663b3cc3987ea5c8acb00ed84ccf Mon Sep 17 00:00:00 2001 From: Raul Metsma Date: Fri, 9 Aug 2024 14:28:19 +0300 Subject: [PATCH] HTTP headers should be compared case-insensitive IB-8163 Signed-off-by: Raul Metsma --- src/crypto/Connect.cpp | 31 ++++++++++++++----------------- src/crypto/Connect.h | 7 +++++-- src/crypto/TSL.cpp | 17 ++++++++--------- src/util/File.cpp | 5 +++-- 4 files changed, 30 insertions(+), 30 deletions(-) diff --git a/src/crypto/Connect.cpp b/src/crypto/Connect.cpp index d5b66718e..9601d48c7 100644 --- a/src/crypto/Connect.cpp +++ b/src/crypto/Connect.cpp @@ -173,7 +173,7 @@ Connect::Connect(const string &_url, string _method, int _timeout, const vector< } } -#if OPENSSL_VERSION_NUMBER > 0x30000000L +#if OPENSSL_VERSION_NUMBER < 0x30000000L if(_timeout > 0) { int fd = BIO_get_fd(d, nullptr); @@ -251,12 +251,6 @@ string Connect::decompress(const string &encoding, const string &data) return out; } -Connect::Result Connect::exec(initializer_list> headers, - const vector &data) -{ - return exec(headers, data.data(), data.size()); -} - Connect::Result Connect::exec(initializer_list> headers, const unsigned char *data, size_t size) { @@ -295,6 +289,10 @@ Connect::Result Connect::exec(initializer_list> he stringstream stream(r.content); string line; + auto to_lower = [](string str) { + std::transform(str.begin(), str.end(), str.begin(), ::tolower); + return str; + }; while(getline(stream, line)) { line.resize(max(line.size() - 1, 0)); @@ -307,18 +305,17 @@ Connect::Result Connect::exec(initializer_list> he } size_t split = line.find(": "); if(split != string::npos) - r.headers[line.substr(0, split)] = line.substr(split + 2); + r.headers[to_lower(line.substr(0, split))] = line.substr(split + 2); else - r.headers[line] = string(); + r.headers[to_lower(line)] = string(); } pos = r.content.find("\r\n\r\n"); if(pos != string::npos) r.content.erase(0, pos + 4); - - const auto transfer_encoding = r.headers.find("Transfer-Encoding"); - if(transfer_encoding != r.headers.cend() && - transfer_encoding->second.find("chunked") != string::npos) { + if(const auto it = r.headers.find("transfer-encoding"); + it != r.headers.cend() && + it->second.find("chunked") != string::npos) { pos = 0; for(size_t chunkpos = r.content.find("\r\n", pos); chunkpos != string::npos; @@ -331,14 +328,14 @@ Connect::Result Connect::exec(initializer_list> he } } - const auto it = r.headers.find("Content-Encoding"); - if(it != r.headers.cend()) + if(const auto it = r.headers.find("content-encoding"); + it != r.headers.cend()) r.content = decompress(it->second, r.content); if(!r.isRedirect() || recursive > 3) return r; - string location = r.headers.find("Location") == r.headers.cend() ? r.headers["location"] : r.headers["Location"]; - string url = location.find("://") != string::npos ? location : baseurl + location; + string &location = r.headers["location"]; + string url = location.find("://") != string::npos ? std::move(location) : baseurl + location; Connect c(url, method, timeout); c.recursive = recursive + 1; return c.exec(headers); diff --git a/src/crypto/Connect.h b/src/crypto/Connect.h index 059ee6722..c74f73010 100644 --- a/src/crypto/Connect.h +++ b/src/crypto/Connect.h @@ -63,8 +63,11 @@ class Connect Connect(const std::string &url, std::string method = "POST", int timeout = 0, const std::vector &certs = {}); ~Connect(); - Result exec(std::initializer_list> headers, - const std::vector &data); + inline Result exec(std::initializer_list> headers, + const std::vector &data) + { + return exec(headers, data.data(), data.size()); + } Result exec(std::initializer_list> headers = {}, const unsigned char *data = nullptr, size_t size = 0); diff --git a/src/crypto/TSL.cpp b/src/crypto/TSL.cpp index 266b28c87..f20f05444 100644 --- a/src/crypto/TSL.cpp +++ b/src/crypto/TSL.cpp @@ -174,7 +174,7 @@ string TSL::fetch(const string &url, const string &path) if(!r || r.content.empty()) THROW("HTTP status code is not 200 or content is empty"); ofstream(File::encodeName(path), fstream::binary|fstream::trunc) << r.content; - return r.headers["ETag"]; + return r.headers["etag"]; } catch(const Exception &) { @@ -254,13 +254,13 @@ TSL TSL::parseTSL(const string &url, const vector &certs, TSL tsl(path); tsl.validate(certs); valid = std::move(tsl); - DEBUG("TSL %s (%llu) signature is valid", territory.c_str(), tsl.sequenceNumber()); + DEBUG("TSL %s (%llu) signature is valid", territory.c_str(), valid.sequenceNumber()); if(valid.isExpired()) { if(!CONF(TSLAutoUpdate) && CONF(TSLAllowExpired)) return valid; - THROW("TSL %s (%llu) is expired", territory.c_str(), tsl.sequenceNumber()); + THROW("TSL %s (%llu) is expired", territory.c_str(), valid.sequenceNumber()); } if(CONF(TSLOnlineDigest) && (File::modifiedTime(path) < (time(nullptr) - (60 * 60 * 24)))) @@ -289,7 +289,7 @@ TSL TSL::parseTSL(const string &url, const vector &certs, filesystem::remove(filesystem::u8path(tmp), ec); ofstream(File::encodeName(path + ".etag"), ofstream::trunc) << etag; - DEBUG("TSL %s (%llu) signature is valid", territory.c_str(), tsl.sequenceNumber()); + DEBUG("TSL %s (%llu) signature is valid", territory.c_str(), valid.sequenceNumber()); } catch(const Exception &) { ERR("TSL %s signature is invalid", territory.c_str()); if(!valid) @@ -384,7 +384,7 @@ bool TSL::parseInfo(XMLNode info, Service &s) string TSL::path() const { - return get() && get()->name ? string(get()->name) : string(); + return File::fromUriPath(to_string_view(get(), &xmlDoc::URL)); } vector TSL::pivotURLs() const @@ -545,7 +545,7 @@ void TSL::validate(const vector &certs, int recursion) const { string etag = fetch(urls[0], path); ofstream(File::encodeName(path + ".etag"), ofstream::trunc) << etag; - pivot = TSL(std::move(path)); + pivot = TSL(path); } pivot.validate(certs, recursion + 1); validate(pivot.signingCerts(), recursion); @@ -570,7 +570,7 @@ bool TSL::validateETag(const string &url) return false; } - auto it = r.headers.find("ETag"); + auto it = r.headers.find("etag"); if(it == r.headers.cend()) return validateRemoteDigest(url); @@ -578,8 +578,7 @@ bool TSL::validateETag(const string &url) ifstream is(File::encodeName(path() + ".etag")); if(!is.is_open()) THROW("Cached ETag does not exist"); - string etag(it->second.size(), 0); - is.read(etag.data(), streamsize(etag.size())); + string etag(istreambuf_iterator(is), {}); DEBUG("Cached ETag: %s", etag.c_str()); if(etag != it->second) THROW("Remote ETag does not match"); diff --git a/src/util/File.cpp b/src/util/File.cpp index e46bd8a93..776c202c5 100644 --- a/src/util/File.cpp +++ b/src/util/File.cpp @@ -345,6 +345,7 @@ string File::toUriPath(const string &path) string File::fromUriPath(string_view path) { string ret; + ret.reserve(path.size()); char data[] = "00"; for(auto i = path.begin(); i != path.end(); ++i) { @@ -354,9 +355,8 @@ string File::fromUriPath(string_view path) data[1] = *(++i); ret += static_cast(strtoul(data, nullptr, 16)); } - else { + else ret += *i; - } } return ret; } @@ -364,6 +364,7 @@ string File::fromUriPath(string_view path) vector File::hexToBin(const string &in) { vector out; + out.reserve(in.size() / 2); char data[] = "00"; for(string::const_iterator i = in.cbegin(); distance(i, in.cend()) >= 2;) {