diff --git a/loader/include/Geode/utils/web.hpp b/loader/include/Geode/utils/web.hpp index ad06e247..d762c724 100644 --- a/loader/include/Geode/utils/web.hpp +++ b/loader/include/Geode/utils/web.hpp @@ -83,6 +83,15 @@ namespace geode::utils::web { std::vector headers() const; std::optional header(std::string_view name) const; + + /** + * Retrieves a list of all headers from the response with a given name - there can be + * multiple headers with the same name, such as Set-Cookie, with each cookie in a separate + * header + * @param name name of the header + * @return std::optional> + */ + std::optional> getAllHeadersNamed(std::string_view name) const; }; class GEODE_DLL WebProgress final { @@ -286,9 +295,9 @@ namespace geode::utils::web { /** * Gets the request headers * - * @return std::unordered_map + * @return std::unordered_map> */ - std::unordered_map getHeaders() const; + std::unordered_map> getHeaders() const; /** * Gets the parameters inside the URL diff --git a/loader/src/utils/web.cpp b/loader/src/utils/web.cpp index d83f5388..e14ab106 100644 --- a/loader/src/utils/web.cpp +++ b/loader/src/utils/web.cpp @@ -96,7 +96,7 @@ class WebResponse::Impl { public: int m_code; ByteVector m_data; - std::unordered_map m_headers; + std::unordered_map> m_headers; Result<> into(std::filesystem::path const& path) const; }; @@ -146,8 +146,14 @@ std::vector WebResponse::headers() const { } std::optional WebResponse::header(std::string_view name) const { - auto str = std::string(name); - if (m_impl->m_headers.contains(str)) { + if (auto str = std::string(name); m_impl->m_headers.contains(str)) { + return m_impl->m_headers.at(str).at(0); + } + return std::nullopt; +} + +std::optional> WebResponse::getAllHeadersNamed(std::string_view name) const { + if (auto str = std::string(name); m_impl->m_headers.contains(str)) { return m_impl->m_headers.at(str); } return std::nullopt; @@ -189,7 +195,7 @@ public: std::string m_method; std::string m_url; - std::unordered_map m_headers; + std::unordered_map> m_headers; std::unordered_map m_urlParameters; std::optional m_userAgent; std::optional m_acceptEncodingType; @@ -270,15 +276,17 @@ WebTask WebRequest::send(std::string_view method, std::string_view url) { // Set headers curl_slist* headers = nullptr; - for (auto& [name, value] : impl->m_headers) { + for (auto& [name, values] : impl->m_headers) { // Sanitize header name auto header = name; header.erase(std::remove_if(header.begin(), header.end(), [](char c) { return c == '\r' || c == '\n'; }), header.end()); // Append value - header += ": " + value; - headers = curl_slist_append(headers, header.c_str()); + for (const auto& value: values) { + header += ": " + value; + headers = curl_slist_append(headers, header.c_str()); + } } curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers); @@ -406,7 +414,12 @@ WebTask WebRequest::send(std::string_view method, std::string_view url) { if (value.ends_with('\r')) { value = value.substr(0, value.size() - 1); } - headers.insert_or_assign(key, value); + // Create a new vector and add to it or add to an already existing one + if (headers.contains(key)) { + headers.at(key).push_back(value); + } else { + headers.insert_or_assign(key, std::vector{value}); + } } return size * nitems; })); @@ -508,7 +521,14 @@ WebRequest& WebRequest::header(std::string_view name, std::string_view value) { } } - m_impl->m_headers.insert_or_assign(std::string(name), std::string(value)); + // Create a new vector and add to it or add to an already existing one + std::string strName = std::string(name); + std::string strValue = std::string(value); + if (m_impl->m_headers.contains(strName)) { + m_impl->m_headers.at(strName).push_back(strValue); + } else { + m_impl->m_headers.insert_or_assign(strName, std::vector{strValue}); + } return *this; } @@ -609,7 +629,7 @@ std::string WebRequest::getUrl() const { return m_impl->m_url; } -std::unordered_map WebRequest::getHeaders() const { +std::unordered_map> WebRequest::getHeaders() const { return m_impl->m_headers; }