1#ifndef SOURCEMETA_CORE_HTTP_MESSAGE_H_
2#define SOURCEMETA_CORE_HTTP_MESSAGE_H_
4#include <sourcemeta/core/http_syntax.h>
5#include <sourcemeta/core/text.h>
14namespace sourcemeta::core {
32 return line.starts_with(
"HTTP/");
53template <
typename Buffer>
54 requires requires(Buffer buffer, std::string_view line) {
59 const std::string_view line) ->
void {
87template <
typename Callback>
88 requires std::invocable<Callback, std::string_view, std::string_view>
91 std::size_t cursor{input.find(
"\r\n")};
92 while (cursor != std::string_view::npos) {
94 const auto end{input.find(
"\r\n", cursor)};
95 if (end == std::string_view::npos || end == cursor) {
99 auto line{input.substr(cursor, end - cursor)};
107 if (line.front() ==
' ' || line.front() ==
'\t') {
108 while (!line.empty() && (line.front() ==
' ' || line.front() ==
'\t')) {
109 line.remove_prefix(1);
112 while (!line.empty() && (line.back() ==
' ' || line.back() ==
'\t')) {
113 line.remove_suffix(1);
123 callback(std::string_view{}, line);
128 if (!parts.has_value() || parts->first.empty()) {
132 const auto name{parts->first};
136 if (name.back() ==
' ' || name.back() ==
'\t') {
140 auto value{parts->second};
144 while (!value.empty() && (value.front() ==
' ' || value.front() ==
'\t')) {
145 value.remove_prefix(1);
148 while (!value.empty() && (value.back() ==
' ' || value.back() ==
'\t')) {
149 value.remove_suffix(1);
161 callback(name, value);
191template <
typename Callback>
192 requires std::invocable<Callback, std::string_view, std::string_view>
195 std::string_view rest{input};
196 while (!rest.empty()) {
197 std::string_view pair;
198 const auto separator{rest.find(
';')};
199 if (separator == std::string_view::npos) {
203 pair = rest.substr(0, separator);
204 rest = rest.substr(separator + 1);
208 if (!parts.has_value()) {
212 const auto name{
trim(parts->first)};
217 callback(name,
trim(parts->second));
240template <
typename Container>
241 requires requires(Container container, std::string_view entry) {
242 container.emplace_back(entry, entry);
247 [&cookies](
const std::string_view name,
248 const std::string_view value) ->
void {
249 cookies.emplace_back(name, value);
280template <
typename Container>
281 requires requires(Container container, std::string_view entry) {
282 container.emplace_back(entry);
285 const std::string_view name, Container &values)
288 [&name, &values](
const std::string_view cookie,
289 const std::string_view value) ->
void {
290 if (cookie == name) {
291 values.emplace_back(value);
317template <
typename Container>
318 requires requires(Container container, std::string name, std::string value,
319 const char character) {
320 container.emplace_back(std::move(name), std::move(value));
321 { container.empty() } -> std::convertible_to<bool>;
322 container.back().second += character;
327 [&headers](
const std::string_view name,
328 const std::string_view value) ->
auto {
333 if (!headers.empty()) {
334 auto &previous_value{headers.back().second};
335 previous_value +=
' ';
336 previous_value += value;
342 std::string header_name{name};
344 headers.emplace_back(std::move(header_name),
365template <
typename Headers>
367 std::size_t total_size{0};
368 for (
const auto &[name, value] : headers) {
375 if constexpr (
requires { value.bytes(); }) {
379 total_size += name.size() + value.bytes().size() + 4;
384 total_size += name.size() + value.size() + 4;
389 result.reserve(total_size);
390 for (
const auto &[name, value] : headers) {
402 if constexpr (
requires { value.bytes(); }) {
409 result += value.bytes();
443template <
typename Headers>
445 const std::string_view name)
446 -> std::optional<std::string_view> {
450 if constexpr (
requires { headers.find(name) != headers.end(); }) {
451 const auto match{headers.find(name)};
452 if (match != headers.end()) {
453 return std::string_view{match->second};
458 for (
const auto &[header_name, header_value] : headers) {
459 if (header_name == name) {
460 return std::string_view{header_value};
auto http_parse_headers(const std::string_view input, Callback callback) -> void
Definition http_message.h:89
auto http_accumulate_header_line(Buffer &buffer, const std::string_view line) -> void
Definition http_message.h:58
auto http_field_line_has_forbidden_byte(const std::string_view value) noexcept -> bool
Definition http_syntax.h:196
auto http_parse_cookies(const std::string_view input, Callback callback) -> void
Definition http_message.h:193
constexpr auto http_is_status_line(const std::string_view line) noexcept -> bool
Definition http_message.h:27
auto http_cookie_values(const std::string_view input, const std::string_view name, Container &values) -> void
Definition http_message.h:284
auto http_serialize_headers(const Headers &headers) -> std::string
Definition http_message.h:366
auto http_header_find(const Headers &headers, const std::string_view name) -> std::optional< std::string_view >
Definition http_message.h:444
SOURCEMETA_CORE_TEXT_EXPORT auto trim(const std::string_view input) noexcept -> std::string_view
constexpr auto to_lowercase(const Character character) noexcept -> Character
Definition text.h:70
SOURCEMETA_CORE_TEXT_EXPORT auto split_once(const std::string_view input, const char delimiter) noexcept -> std::optional< std::pair< std::string_view, std::string_view > >