aboutsummaryrefslogtreecommitdiff
path: root/src/zenhttp/httpclient.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/zenhttp/httpclient.cpp')
-rw-r--r--src/zenhttp/httpclient.cpp56
1 files changed, 56 insertions, 0 deletions
diff --git a/src/zenhttp/httpclient.cpp b/src/zenhttp/httpclient.cpp
index 9d5846f71..b6a07250e 100644
--- a/src/zenhttp/httpclient.cpp
+++ b/src/zenhttp/httpclient.cpp
@@ -320,6 +320,62 @@ HttpClient::Response::IsSuccess() const noexcept
return !Error && IsHttpSuccessCode(StatusCode);
}
+std::string_view
+HttpClient::Response::FindHeader(std::string_view Name) const
+{
+ // Scan the raw arena first - the async client populates this and leaves
+ // Header empty by default. Lines are "Key: Value\r\n" (the trailing \r\n
+ // is what curl hands the HEADER callback; we keep it verbatim).
+ if (!HeaderArena.empty())
+ {
+ std::string_view View(HeaderArena);
+ while (!View.empty())
+ {
+ const size_t LineEnd = View.find('\n');
+ std::string_view Line = LineEnd == std::string_view::npos ? View : View.substr(0, LineEnd);
+ View = LineEnd == std::string_view::npos ? std::string_view{} : View.substr(LineEnd + 1);
+
+ while (!Line.empty() && (Line.back() == '\r' || Line.back() == '\n'))
+ {
+ Line.remove_suffix(1);
+ }
+ if (Line.empty())
+ {
+ continue;
+ }
+ const size_t Colon = Line.find(':');
+ if (Colon == std::string_view::npos)
+ {
+ continue; // HTTP status line or malformed
+ }
+ std::string_view K = Line.substr(0, Colon);
+ std::string_view V = Line.substr(Colon + 1);
+ while (!K.empty() && K.back() == ' ')
+ {
+ K.remove_suffix(1);
+ }
+ while (!V.empty() && V.front() == ' ')
+ {
+ V.remove_prefix(1);
+ }
+ if (StrCaseEquals(K, Name))
+ {
+ return V;
+ }
+ }
+ }
+
+ // Fall back to the parsed map (sync client populates this).
+ for (const auto& [K, V] : *Header)
+ {
+ if (StrCaseEquals(K, Name))
+ {
+ return V;
+ }
+ }
+ return {};
+}
+
std::string
HttpClient::Response::ErrorMessage(std::string_view Prefix) const
{