Commit 00db7852 authored by Dominik Charousset's avatar Dominik Charousset

Fix build on MSVC

parent cd8ce5fc
......@@ -77,10 +77,13 @@ bool icase_equal(std::string_view x, std::string_view y) {
std::pair<std::string_view, std::string_view> split_by(std::string_view str,
std::string_view sep) {
auto i = std::search(str.begin(), str.end(), sep.begin(), sep.end());
if (i != str.end()) {
return {make_string_view(str.begin(), i),
make_string_view(i + sep.size(), str.end())};
// We need actual char* pointers for make_string_view. On some compilers,
// begin() and end() may return iterator types, so we use data() instead.
auto str_end = str.data() + str.size();
auto i = std::search(str.data(), str_end, sep.begin(), sep.end());
if (i != str_end) {
return {make_string_view(str.data(), i),
make_string_view(i + sep.size(), str_end)};
} else {
return {str, {}};
}
......
......@@ -2,6 +2,7 @@
#include "caf/expected.hpp"
#include "caf/logger.hpp"
#include "caf/string_algorithms.hpp"
namespace caf::net::http {
......@@ -11,9 +12,10 @@ constexpr std::string_view eol = "\r\n";
template <class F>
bool for_each_line(std::string_view input, F&& f) {
for (auto pos = input.begin();;) {
auto line_end = std::search(pos, input.end(), eol.begin(), eol.end());
if (line_end == input.end() || std::distance(pos, input.end()) == 2) {
auto input_end = input.data() + input.size();
for (auto pos = input.data();;) {
auto line_end = std::search(pos, input_end, eol.begin(), eol.end());
if (line_end == input_end || std::distance(pos, input_end) == 2) {
// Reaching the end or hitting the last empty line tells us we're done.
return true;
}
......@@ -26,43 +28,6 @@ bool for_each_line(std::string_view input, F&& f) {
return true;
}
std::string_view trim(std::string_view str) {
str.remove_prefix(std::min(str.find_first_not_of(' '), str.size()));
auto trim_pos = str.find_last_not_of(' ');
if (trim_pos != str.npos)
str.remove_suffix(str.size() - (trim_pos + 1));
return str;
}
/// Splits `str` at the first occurrence of `sep` into the head and the
/// remainder (excluding the separator).
static std::pair<std::string_view, std::string_view>
split(std::string_view str, std::string_view sep) {
auto i = std::search(str.begin(), str.end(), sep.begin(), sep.end());
if (i != str.end()) {
auto n = static_cast<size_t>(std::distance(str.begin(), i));
auto j = i + sep.size();
auto m = static_cast<size_t>(std::distance(j, str.end()));
return {{str.begin(), n}, {j, m}};
} else {
return {{str}, {}};
}
}
/// Convenience function for splitting twice.
static std::tuple<std::string_view, std::string_view, std::string_view>
split2(std::string_view str, std::string_view sep) {
auto [first, r1] = split(str, sep);
auto [second, third] = split(r1, sep);
return {first, second, third};
}
/// @pre `y` is all lowercase
bool case_insensitive_eq(std::string_view x, std::string_view y) {
return std::equal(x.begin(), x.end(), y.begin(), y.end(),
[](char a, char b) { return tolower(a) == b; });
}
} // namespace
header::header(const header& other) {
......@@ -112,8 +77,9 @@ std::pair<status, std::string_view> header::parse(std::string_view raw) {
raw_.assign(raw.begin(), raw.end());
// Parse the first line, i.e., "METHOD REQUEST-URI VERSION".
auto [first_line, remainder]
= split(std::string_view{raw_.data(), raw_.size()}, eol);
auto [method_str, request_uri_str, version] = split2(first_line, " ");
= split_by(std::string_view{raw_.data(), raw_.size()}, eol);
auto [method_str, first_line_remainder] = split_by(first_line, " ");
auto [request_uri_str, version] = split_by(first_line_remainder, " ");
// The path must be absolute.
if (request_uri_str.empty() || request_uri_str.front() != '/') {
CAF_LOG_DEBUG("Malformed Request-URI: expected an absolute path.");
......@@ -132,21 +98,21 @@ std::pair<status, std::string_view> header::parse(std::string_view raw) {
return {status::bad_request, "Malformed Request-URI."};
}
// Verify and store the method.
if (case_insensitive_eq(method_str, "get")) {
if (icase_equal(method_str, "get")) {
method_ = method::get;
} else if (case_insensitive_eq(method_str, "head")) {
} else if (icase_equal(method_str, "head")) {
method_ = method::head;
} else if (case_insensitive_eq(method_str, "post")) {
} else if (icase_equal(method_str, "post")) {
method_ = method::post;
} else if (case_insensitive_eq(method_str, "put")) {
} else if (icase_equal(method_str, "put")) {
method_ = method::put;
} else if (case_insensitive_eq(method_str, "delete")) {
} else if (icase_equal(method_str, "delete")) {
method_ = method::del;
} else if (case_insensitive_eq(method_str, "connect")) {
} else if (icase_equal(method_str, "connect")) {
method_ = method::connect;
} else if (case_insensitive_eq(method_str, "options")) {
} else if (icase_equal(method_str, "options")) {
method_ = method::options;
} else if (case_insensitive_eq(method_str, "trace")) {
} else if (icase_equal(method_str, "trace")) {
method_ = method::trace;
} else {
CAF_LOG_DEBUG("Invalid HTTP method.");
......@@ -160,9 +126,9 @@ std::pair<status, std::string_view> header::parse(std::string_view raw) {
if (auto sep = std::find(line.begin(), line.end(), ':');
sep != line.end()) {
auto n = static_cast<size_t>(std::distance(line.begin(), sep));
auto key = trim(std::string_view{line.begin(), n});
auto key = trim(std::string_view{line.data(), n});
auto m = static_cast<size_t>(std::distance(sep + 1, line.end()));
auto val = trim(std::string_view{sep + 1, m});
auto val = trim(std::string_view{std::addressof(*(sep + 1)), m});
if (!key.empty()) {
fields_.emplace(key, val);
return true;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment