diff --git a/include/crow/http_connection.h b/include/crow/http_connection.h index c059ce8d9..7c37cb40a 100644 --- a/include/crow/http_connection.h +++ b/include/crow/http_connection.h @@ -162,7 +162,7 @@ namespace crow need_to_call_after_handlers_ = false; if (!is_invalid_request) { - res.complete_request_handler_ = nullptr; + res.complete_request_handler_.clear(); auto self = this->shared_from_this(); res.is_alive_helper_ = [self]() -> bool { return self->adaptor_.is_open(); @@ -202,7 +202,7 @@ namespace crow void complete_request() { CROW_LOG_INFO << "Response: " << this << ' ' << req_.raw_url << ' ' << res.code << ' ' << close_connection_; - res.is_alive_helper_ = nullptr; + res.is_alive_helper_.clear(); if (need_to_call_after_handlers_) { @@ -271,8 +271,8 @@ namespace crow private: void prepare_buffers() { - res.complete_request_handler_ = nullptr; - res.is_alive_helper_ = nullptr; + res.complete_request_handler_.clear(); + res.is_alive_helper_.clear(); if (!adaptor_.is_open()) { diff --git a/include/crow/http_response.h b/include/crow/http_response.h index 47d1dc171..898fdbb7b 100644 --- a/include/crow/http_response.h +++ b/include/crow/http_response.h @@ -318,8 +318,8 @@ namespace crow private: bool completed_{}; - std::function complete_request_handler_; - std::function is_alive_helper_; + crow::utility::lambda_wrapper complete_request_handler_; + crow::utility::lambda_wrapper is_alive_helper_; static_file_info file_info; }; } // namespace crow diff --git a/include/crow/utility.h b/include/crow/utility.h index be5b08cdb..fe9ae7a6f 100644 --- a/include/crow/utility.h +++ b/include/crow/utility.h @@ -220,7 +220,7 @@ namespace crow { return p == s.size() ? 0 : s[p] == '<' ? ( - is_int(s, p) ? get_parameter_tag(s, find_closing_tag(s, p)) * 6 + 1 : + is_int(s, p) ? get_parameter_tag(s, find_closing_tag(s, p)) * 6 + 1 : is_uint(s, p) ? get_parameter_tag(s, find_closing_tag(s, p)) * 6 + 2 : is_float(s, p) ? get_parameter_tag(s, find_closing_tag(s, p)) * 6 + 3 : is_str(s, p) ? get_parameter_tag(s, find_closing_tag(s, p)) * 6 + 4 : @@ -489,7 +489,6 @@ namespace crow namespace detail { - template struct get_index_of_element_from_tuple_by_type_impl { @@ -715,8 +714,8 @@ namespace crow // a special device. Thus we search for the string (case-insensitive), and then check if the string ends or if // is has a dangerous follow up character (.:\/) auto sanitizeSpecialFile = [](std::string& source, unsigned ofs, const char* pattern, bool includeNumber, char replacement) { - unsigned i = ofs; - size_t len = source.length(); + unsigned i = ofs; + size_t len = source.length(); const char* p = pattern; while (*p) { @@ -897,5 +896,48 @@ namespace crow return v.substr(begin, end - begin); } + + class call_error : public std::runtime_error + { + public: + call_error() : std::runtime_error{"call error"} + { + } + }; + + template + class lambda_wrapper + { + public: + lambda_wrapper() = default; + + lambda_wrapper(std::function func) : valid_(true), func_(func) + { + } + + void clear() { valid_ = false; } + + operator bool() const { return valid_; } + + lambda_wrapper& operator=(std::function func) + { + valid_ = true; + func_ = func; + return *this; + } + + ReturnType operator()(Args... args) const + { + if (valid_) + { + return func_(args...); + } + throw call_error(); + } + + private: + mutable bool valid_{}; + std::function func_; + }; } // namespace utility } // namespace crow diff --git a/tests/unittest.cpp b/tests/unittest.cpp index b280f07d6..e8153250f 100644 --- a/tests/unittest.cpp +++ b/tests/unittest.cpp @@ -3445,3 +3445,25 @@ TEST_CASE("lexical_cast") CHECK(utility::lexical_cast(4) == "4"); CHECK(utility::lexical_cast("10", 2) == 10.0f); } + +TEST_CASE("lambda_wrapper") +{ + utility::lambda_wrapper empty; + CHECK(empty != true); + CHECK_THROWS_AS(empty("hello"), crow::utility::call_error); + + utility::lambda_wrapper const_val([]()->int { return 42; }); + CHECK(const_val == true); + CHECK(const_val() == 42); + + utility::lambda_wrapper plus([](int a, int b)->int { return a + b; }); + CHECK(plus == true); + CHECK(plus(2, 3) == 5); + + const std::string name{"Motoko"}; + utility::lambda_wrapper func([name](std::string& str) { str = name; }); + CHECK(func == true); + std::string strval; + func(strval); + CHECK(strval == name); +}