From 57079c0276e3f1f82883fbd2e70c2472d94d3dff Mon Sep 17 00:00:00 2001 From: Jason Volk Date: Mon, 31 Dec 2018 11:06:18 -0800 Subject: [PATCH] ircd::http: Add more functionality to headers class. --- include/ircd/http.h | 16 +++++- ircd/http.cc | 123 +++++++++++++++++++++++++++++++++++++++----- 2 files changed, 125 insertions(+), 14 deletions(-) diff --git a/include/ircd/http.h b/include/ircd/http.h index 6e827e8c4..2318aac55 100644 --- a/include/ircd/http.h +++ b/include/ircd/http.h @@ -30,11 +30,12 @@ namespace ircd::http void writeline(window_buffer &, const window_buffer::closure &); void write(window_buffer &, const header &); void write(window_buffer &, const vector_view &); - bool has(const vector_view &, const string_view &key); size_t serialized(const vector_view &); std::string strung(const vector_view &); void writechunk(window_buffer &, const uint32_t &size); const_buffer writechunk(const mutable_buffer &, const uint32_t &size); + bool has(const headers &, const string_view &key); + bool has(const vector_view &, const string_view &key); } /// Root exception for HTTP. @@ -158,6 +159,7 @@ struct ircd::http::header { bool operator<(const string_view &s) const { return iless(first, s); } bool operator==(const string_view &s) const { return iequals(first, s); } + bool operator!=(const string_view &s) const { return !operator==(s); } using std::pair::pair; header(const line &); @@ -174,8 +176,20 @@ struct ircd::http::headers :string_view { using closure = std::function; + using closure_bool = std::function; + bool for_each(const closure_bool &) const; + string_view operator[](const string_view &key) const; + string_view at(const string_view &key) const; + bool has(const string_view &key) const; + + using string_view::string_view; + headers(parse::capstan &, closure_bool); headers(parse::capstan &, const closure & = {}); + headers() = default; + + friend bool has(const headers &, const string_view &key); + friend bool has(const vector_view &, const string_view &key); }; /// HTTP request suite. Functionality to send and receive requests. diff --git a/ircd/http.cc b/ircd/http.cc index da8d4143d..a917dc1e9 100644 --- a/ircd/http.cc +++ b/ircd/http.cc @@ -428,22 +428,130 @@ catch(const qi::expectation_failure &e) throw_error(e, true); } +// +// headers +// + +bool +ircd::http::has(const vector_view &headers, + const string_view &key) +{ + return end(headers) != std::find_if(begin(headers), end(headers), [&key] + (const header &header) + { + return header == key; + }); +} + +bool +ircd::http::has(const headers &headers, + const string_view &key) +{ + return headers.has(key); +} + +// +// headers::headers +// + ircd::http::headers::headers(parse::capstan &pc, const closure &c) +:headers +{ + pc, closure_bool{[&c](const auto &header) + { + if(c) + c(header); + + return true; + }} +} +{ +} + +ircd::http::headers::headers(parse::capstan &pc, + closure_bool c) :string_view{[&pc, &c] () -> string_view { header h{pc}; const char *const &started{h.first.data()}, *stopped{started}; for(; !h.first.empty(); stopped = h.second.data() + h.second.size(), h = header{pc}) - if(c) - c(h); + if(c && !c(h)) + c = {}; return { started, stopped }; }()} { } +bool +ircd::http::headers::has(const string_view &key) +const +{ + // has header if break early from for_each + return !for_each([&key] + (const header &header) + { + // true to continue; false to break (for_each protocol) + return header != key; + }); +} + +ircd::string_view +ircd::http::headers::at(const string_view &key) +const +{ + const string_view ret + { + this->operator[](key) + }; + + if(unlikely(!ret)) + throw std::out_of_range{key}; + + return ret; +} + +ircd::string_view +ircd::http::headers::operator[](const string_view &key) +const +{ + string_view ret; + for_each([&key, &ret](const auto &header) + { + if(header == key) + { + ret = header.second; + return false; + } + else return true; + }); + + return ret; +} + +bool +ircd::http::headers::for_each(const closure_bool &closure) +const +{ + if(empty()) + return true; + + parse::buffer pb{const_buffer{*this}}; + parse::capstan pc{pb}; + header h{pc}; + for(; !h.first.empty(); h = header{pc}) + if(!closure(h)) + return false; + + return true; +} + +// +// header +// + ircd::http::header::header(const line &line) try { @@ -617,17 +725,6 @@ ircd::http::writechunk(window_buffer &buf, }); } -bool -ircd::http::has(const vector_view &headers, - const string_view &key) -{ - return end(headers) != std::find_if(begin(headers), end(headers), [&key] - (const header &header) - { - return iequals(header.first, key); - }); -} - std::string ircd::http::strung(const vector_view &headers) {