diff --git a/docs/guides/middleware.md b/docs/guides/middleware.md
index 883b54500..abfea9f7b 100644
--- a/docs/guides/middleware.md
+++ b/docs/guides/middleware.md
@@ -1,29 +1,94 @@
-Any middleware requires following 3 members:
-## struct context
-Storing data for the middleware; can be read from another middleware or handlers
+Middleware is used for altering and inspecting requests before and after the handler call.
+Any middleware requires the following 3 members:
+
+* A context struct for storing the middleware data.
+* A `before_handle` method, which is called before the handler. If `res.end()` is called, the operation is halted.
+* A `after_handle` method, which is called after the handler.
## before_handle
-Called before handling the request.
-If `res.end()` is called, the operation is halted. (`after_handle` will still be called)
-2 signatures:
-`#!cpp void before_handle(request& req, response& res, context& ctx)`
- if you only need to access this middleware's context.
+There are two possible signatures for before_handle
+
+1. if you only need to access this middleware's context.
+
+```cpp
+void before_handle(request& req, response& res, context& ctx)
+```
+
+2. To get access to other middlewares context
``` cpp
template
-void before_handle(request& req, response& res, context& ctx, AllContext& all_ctx)
+void before_handle(request& req, response& res, context& ctx, AllContext& all_ctx)
+{
+ auto other_ctx = all_ctx.template get();
+}
```
-You can access other middlewares' context by calling `#!cpp all_ctx.template get()`
-`#!cpp ctx == all_ctx.template get()`
## after_handle
-Called after handling the request.
+There are two possible signatures for after_handle
+
+1. if you only need to access this middleware's context.
-`#!cpp void after_handle(request& req, response& res, context& ctx)`
+```cpp
+void after_handle(request& req, response& res, context& ctx)
+```
+
+2. To get access to other middlewares context
``` cpp
template
-void after_handle(request& req, response& res, context& ctx, AllContext& all_ctx)
+void after_handle(request& req, response& res, context& ctx, AllContext& all_ctx)
+{
+ auto other_ctx = all_ctx.template get();
+}
+```
+
+## Using middleware
+
+All middleware has to be registered in the Crow application and is enabled globally by default.
+
+```cpp
+crow::App app;
```
-
-This was pulled from `cookie_parser.h`. Further Editing required, possibly use parts of [@ipkn's wiki page](https://github.com/ipkn/crow/wiki/Middleware).
+
+if you want to enable some middleware only for specific handlers, you have to extend it from `crow::ILocalMiddleware`.
+
+```cpp
+struct LocalMiddleware : crow::ILocalMiddleware
+{
+...
+```
+
+After this, you can enable it for specific handlers.
+
+```cpp
+CROW_ROUTE(app, "/with_middleware")
+.CROW_MIDDLEWARES(app, LocalMiddleware)
+([]() {
+ return "Hello world!";
+});
+```
+
+## Examples
+
+A local middleware that can be used to guard admin handlers
+
+```cpp
+struct AdminAreaGuard : crow::ILocalMiddleware
+{
+ struct context
+ {};
+
+ void before_handle(crow::request& req, crow::response& res, context& ctx)
+ {
+ if (req.remote_ip_address != ADMIN_IP)
+ {
+ res.code = 403;
+ res.end();
+ }
+ }
+
+ void after_handle(crow::request& req, crow::response& res, context& ctx)
+ {}
+};
+```
\ No newline at end of file
diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt
index ed3d6031c..27f3d9bde 100644
--- a/examples/CMakeLists.txt
+++ b/examples/CMakeLists.txt
@@ -79,6 +79,10 @@ add_executable(example_blueprint example_blueprint.cpp)
add_warnings_optimizations(example_blueprint)
target_link_libraries(example_blueprint PUBLIC Crow::Crow)
+add_executable(example_middleware example_middleware.cpp)
+add_warnings_optimizations(example_middleware)
+target_link_libraries(example_middleware PUBLIC Crow::Crow)
+
if(MSVC)
add_executable(example_vs example_vs.cpp)
add_warnings_optimizations(example_vs)
diff --git a/examples/example_middleware.cpp b/examples/example_middleware.cpp
new file mode 100644
index 000000000..e53381724
--- /dev/null
+++ b/examples/example_middleware.cpp
@@ -0,0 +1,54 @@
+#include "crow.h"
+
+struct RequestLogger
+{
+ struct context
+ {};
+
+ void before_handle(crow::request& req, crow::response& /*res*/, context& /*ctx*/)
+ {
+ CROW_LOG_INFO << "Request to:" + req.url;
+ }
+
+ void after_handle(crow::request& /*req*/, crow::response& /*res*/, context& /*ctx*/)
+ {}
+};
+
+// Per handler middleware has to extend ILocalMiddleware
+// It is called only if enabled
+struct SecretContentGuard : crow::ILocalMiddleware
+{
+ struct context
+ {};
+
+ void before_handle(crow::request& /*req*/, crow::response& res, context& /*ctx*/)
+ {
+ res.write("SECRET!");
+ res.code = 403;
+ res.end();
+ }
+
+ void after_handle(crow::request& /*req*/, crow::response& /*res*/, context& /*ctx*/)
+ {}
+};
+
+int main()
+{
+ // ALL middleware (including per handler) is listed
+ crow::App app;
+
+ CROW_ROUTE(app, "/")
+ ([]() {
+ return "Hello, world!";
+ });
+
+ CROW_ROUTE(app, "/secret")
+ // Enable SecretContentGuard for this handler
+ .CROW_MIDDLEWARES(app, SecretContentGuard)([]() {
+ return "";
+ });
+
+ app.port(18080).run();
+
+ return 0;
+}
diff --git a/include/crow.h b/include/crow.h
index 1687f9647..25c136ad6 100644
--- a/include/crow.h
+++ b/include/crow.h
@@ -17,6 +17,7 @@
#include "crow/http_response.h"
#include "crow/multipart.h"
#include "crow/routing.h"
+#include "crow/middleware.h"
#include "crow/middleware_context.h"
#include "crow/compression.h"
#include "crow/http_connection.h"
diff --git a/include/crow/app.h b/include/crow/app.h
index ec1b27e93..26d850d58 100644
--- a/include/crow/app.h
+++ b/include/crow/app.h
@@ -29,6 +29,7 @@
#else
#define CROW_ROUTE(app, url) app.route(url)
#define CROW_BP_ROUTE(blueprint, url) blueprint.new_rule_tagged(url)
+#define CROW_MIDDLEWARES(app, ...) middlewares()
#endif
#define CROW_CATCHALL_ROUTE(app) app.catchall_route()
#define CROW_BP_CATCHALL_ROUTE(blueprint) blueprint.catchall_rule()
@@ -68,7 +69,7 @@ namespace crow
}
/// Process the request and generate a response for it
- void handle(const request& req, response& res)
+ void handle(request& req, response& res)
{
router_.handle(req, res);
}
@@ -394,6 +395,7 @@ namespace crow
// middleware
using context_t = detail::context;
+ using mw_container_t = std::tuple;
template
typename T::context& get_context(const request& req)
{
diff --git a/include/crow/http_connection.h b/include/crow/http_connection.h
index d370d3fa0..168b83fa5 100644
--- a/include/crow/http_connection.h
+++ b/include/crow/http_connection.h
@@ -15,6 +15,7 @@
#include "crow/settings.h"
#include "crow/task_timer.h"
#include "crow/middleware_context.h"
+#include "crow/middleware.h"
#include "crow/socket_adaptors.h"
#include "crow/compression.h"
@@ -23,150 +24,6 @@ namespace crow
using namespace boost;
using tcp = asio::ip::tcp;
- namespace detail
- {
- template
- struct check_before_handle_arity_3_const
- {
- template
- struct get
- {};
- };
-
- template
- struct check_before_handle_arity_3
- {
- template
- struct get
- {};
- };
-
- template
- struct check_after_handle_arity_3_const
- {
- template
- struct get
- {};
- };
-
- template
- struct check_after_handle_arity_3
- {
- template
- struct get
- {};
- };
-
- template
- struct is_before_handle_arity_3_impl
- {
- template
- static std::true_type f(typename check_before_handle_arity_3_const::template get*);
-
- template
- static std::true_type f(typename check_before_handle_arity_3::template get*);
-
- template
- static std::false_type f(...);
-
- public:
- static const bool value = decltype(f(nullptr))::value;
- };
-
- template
- struct is_after_handle_arity_3_impl
- {
- template
- static std::true_type f(typename check_after_handle_arity_3_const::template get*);
-
- template
- static std::true_type f(typename check_after_handle_arity_3::template get*);
-
- template
- static std::false_type f(...);
-
- public:
- static const bool value = decltype(f(nullptr))::value;
- };
-
- template
- typename std::enable_if::value>::type
- before_handler_call(MW& mw, request& req, response& res, Context& ctx, ParentContext& /*parent_ctx*/)
- {
- mw.before_handle(req, res, ctx.template get(), ctx);
- }
-
- template
- typename std::enable_if::value>::type
- before_handler_call(MW& mw, request& req, response& res, Context& ctx, ParentContext& /*parent_ctx*/)
- {
- mw.before_handle(req, res, ctx.template get());
- }
-
- template
- typename std::enable_if::value>::type
- after_handler_call(MW& mw, request& req, response& res, Context& ctx, ParentContext& /*parent_ctx*/)
- {
- mw.after_handle(req, res, ctx.template get(), ctx);
- }
-
- template
- typename std::enable_if::value>::type
- after_handler_call(MW& mw, request& req, response& res, Context& ctx, ParentContext& /*parent_ctx*/)
- {
- mw.after_handle(req, res, ctx.template get());
- }
-
- template
- bool middleware_call_helper(Container& middlewares, request& req, response& res, Context& ctx)
- {
- using parent_context_t = typename Context::template partial;
- before_handler_call(std::get(middlewares), req, res, ctx, static_cast(ctx));
-
- if (res.is_completed())
- {
- after_handler_call(std::get(middlewares), req, res, ctx, static_cast(ctx));
- return true;
- }
-
- if (middleware_call_helper(middlewares, req, res, ctx))
- {
- after_handler_call(std::get(middlewares), req, res, ctx, static_cast(ctx));
- return true;
- }
-
- return false;
- }
-
- template
- bool middleware_call_helper(Container& /*middlewares*/, request& /*req*/, response& /*res*/, Context& /*ctx*/)
- {
- return false;
- }
-
- template
- typename std::enable_if<(N < 0)>::type
- after_handlers_call_helper(Container& /*middlewares*/, Context& /*context*/, request& /*req*/, response& /*res*/)
- {
- }
-
- template
- typename std::enable_if<(N == 0)>::type after_handlers_call_helper(Container& middlewares, Context& ctx, request& req, response& res)
- {
- using parent_context_t = typename Context::template partial;
- using CurrentMW = typename std::tuple_element::type>::type;
- after_handler_call(std::get(middlewares), req, res, ctx, static_cast(ctx));
- }
-
- template
- typename std::enable_if<(N > 0)>::type after_handlers_call_helper(Container& middlewares, Context& ctx, request& req, response& res)
- {
- using parent_context_t = typename Context::template partial;
- using CurrentMW = typename std::tuple_element::type>::type;
- after_handler_call(std::get(middlewares), req, res, ctx, static_cast(ctx));
- after_handlers_call_helper(middlewares, ctx, req, res);
- }
- } // namespace detail
#ifdef CROW_ENABLE_DEBUG
static std::atomic connectionCount;
@@ -316,8 +173,11 @@ namespace crow
ctx_ = detail::context();
req.middleware_context = static_cast(&ctx_);
+ req.middleware_container = static_cast(middlewares_);
req.io_service = &adaptor_.get_io_service();
- detail::middleware_call_helper<0, decltype(ctx_), decltype(*middlewares_), Middlewares...>(*middlewares_, req, res, ctx_);
+
+ detail::middleware_call_helper(*middlewares_, req, res, ctx_);
if (!res.completed_)
{
@@ -351,6 +211,7 @@ namespace crow
// call all after_handler of middlewares
detail::after_handlers_call_helper<
+ detail::middleware_call_criteria_only_global,
(static_cast(sizeof...(Middlewares)) - 1),
decltype(ctx_),
decltype(*middlewares_)>(*middlewares_, ctx_, req_, res);
diff --git a/include/crow/http_request.h b/include/crow/http_request.h
index 809f5edfe..c27778005 100644
--- a/include/crow/http_request.h
+++ b/include/crow/http_request.h
@@ -34,6 +34,7 @@ namespace crow
std::string remote_ip_address; ///< The IP address from which the request was sent.
void* middleware_context{};
+ void* middleware_container{};
boost::asio::io_service* io_service{};
/// Construct an empty request. (sets the method to `GET`)
diff --git a/include/crow/http_response.h b/include/crow/http_response.h
index bfae40517..473acb611 100644
--- a/include/crow/http_response.h
+++ b/include/crow/http_response.h
@@ -19,12 +19,21 @@ namespace crow
template
class Connection;
+ namespace detail
+ {
+ template
+ struct handler_middleware_wrapper;
+ } // namespace detail
+
/// HTTP response
struct response
{
template
friend class crow::Connection;
+ template
+ friend struct crow::detail::handler_middleware_wrapper;
+
int code{200}; ///< The Status code for the response.
std::string body; ///< The actual payload containing the response data.
ci_map headers; ///< HTTP headers.
diff --git a/include/crow/middleware.h b/include/crow/middleware.h
new file mode 100644
index 000000000..c8b10fe4e
--- /dev/null
+++ b/include/crow/middleware.h
@@ -0,0 +1,322 @@
+#pragma once
+
+#include "crow/http_request.h"
+#include "crow/http_response.h"
+#include "crow/utility.h"
+
+#include
+#include
+#include
+#include
+
+namespace crow
+{
+
+ /// Local middleware should extend ILocalMiddleware
+ struct ILocalMiddleware
+ {
+ using call_global = std::false_type;
+ };
+
+ namespace detail
+ {
+ template
+ struct check_before_handle_arity_3_const
+ {
+ template
+ struct get
+ {};
+ };
+
+ template
+ struct check_before_handle_arity_3
+ {
+ template
+ struct get
+ {};
+ };
+
+ template
+ struct check_after_handle_arity_3_const
+ {
+ template
+ struct get
+ {};
+ };
+
+ template
+ struct check_after_handle_arity_3
+ {
+ template
+ struct get
+ {};
+ };
+
+ template
+ struct check_global_call_false
+ {
+ template::type = true>
+ struct get
+ {};
+ };
+
+ template
+ struct is_before_handle_arity_3_impl
+ {
+ template
+ static std::true_type f(typename check_before_handle_arity_3_const::template get*);
+
+ template
+ static std::true_type f(typename check_before_handle_arity_3::template get*);
+
+ template
+ static std::false_type f(...);
+
+ public:
+ static const bool value = decltype(f(nullptr))::value;
+ };
+
+ template
+ struct is_after_handle_arity_3_impl
+ {
+ template
+ static std::true_type f(typename check_after_handle_arity_3_const::template get*);
+
+ template
+ static std::true_type f(typename check_after_handle_arity_3::template get*);
+
+ template
+ static std::false_type f(...);
+
+ public:
+ static constexpr bool value = decltype(f(nullptr))::value;
+ };
+
+ template
+ typename std::enable_if::value>::type
+ before_handler_call(MW& mw, request& req, response& res, Context& ctx, ParentContext& /*parent_ctx*/)
+ {
+ mw.before_handle(req, res, ctx.template get(), ctx);
+ }
+
+ template
+ typename std::enable_if::value>::type
+ before_handler_call(MW& mw, request& req, response& res, Context& ctx, ParentContext& /*parent_ctx*/)
+ {
+ mw.before_handle(req, res, ctx.template get());
+ }
+
+ template
+ typename std::enable_if::value>::type
+ after_handler_call(MW& mw, request& req, response& res, Context& ctx, ParentContext& /*parent_ctx*/)
+ {
+ mw.after_handle(req, res, ctx.template get(), ctx);
+ }
+
+ template
+ typename std::enable_if::value>::type
+ after_handler_call(MW& mw, request& req, response& res, Context& ctx, ParentContext& /*parent_ctx*/)
+ {
+ mw.after_handle(req, res, ctx.template get());
+ }
+
+
+ template class CallCriteria, // Checks if QueryMW should be called in this context
+ int N, typename Context, typename Container>
+ typename std::enable_if<(N < std::tuple_size::type>::value), bool>::type
+ middleware_call_helper(Container& middlewares, request& req, response& res, Context& ctx)
+ {
+
+ using CurrentMW = typename std::tuple_element::type>::type;
+
+ if (!CallCriteria::value)
+ {
+ return middleware_call_helper(middlewares, req, res, ctx);
+ }
+
+ using parent_context_t = typename Context::template partial;
+ before_handler_call(std::get(middlewares), req, res, ctx, static_cast(ctx));
+ if (res.is_completed())
+ {
+ after_handler_call(std::get(middlewares), req, res, ctx, static_cast(ctx));
+ return true;
+ }
+
+ if (middleware_call_helper(middlewares, req, res, ctx))
+ {
+ after_handler_call(std::get(middlewares), req, res, ctx, static_cast(ctx));
+ return true;
+ }
+
+ return false;
+ }
+
+ template class CallCriteria, int N, typename Context, typename Container>
+ typename std::enable_if<(N >= std::tuple_size::type>::value), bool>::type
+ middleware_call_helper(Container& /*middlewares*/, request& /*req*/, response& /*res*/, Context& /*ctx*/)
+ {
+ return false;
+ }
+
+ template class CallCriteria, int N, typename Context, typename Container>
+ typename std::enable_if<(N < 0)>::type
+ after_handlers_call_helper(Container& /*middlewares*/, Context& /*context*/, request& /*req*/, response& /*res*/)
+ {
+ }
+
+ template class CallCriteria, int N, typename Context, typename Container>
+ typename std::enable_if<(N == 0)>::type after_handlers_call_helper(Container& middlewares, Context& ctx, request& req, response& res)
+ {
+ using parent_context_t = typename Context::template partial;
+ using CurrentMW = typename std::tuple_element::type>::type;
+ if (CallCriteria::value)
+ {
+ after_handler_call(std::get(middlewares), req, res, ctx, static_cast(ctx));
+ }
+ }
+
+ template class CallCriteria, int N, typename Context, typename Container>
+ typename std::enable_if<(N > 0)>::type after_handlers_call_helper(Container& middlewares, Context& ctx, request& req, response& res)
+ {
+ using parent_context_t = typename Context::template partial;
+ using CurrentMW = typename std::tuple_element::type>::type;
+ if (CallCriteria::value)
+ {
+ after_handler_call(std::get(middlewares), req, res, ctx, static_cast(ctx));
+ }
+ after_handlers_call_helper(middlewares, ctx, req, res);
+ }
+
+ // A CallCriteria that accepts only global middleware
+ template
+ struct middleware_call_criteria_only_global
+ {
+ template
+ static std::false_type f(typename check_global_call_false::template get*);
+
+ template
+ static std::true_type f(...);
+
+ static const bool value = decltype(f(nullptr))::value;
+ };
+
+ // wrapped_handler_call transparently wraps a handler call behind (req, res, args...)
+ template
+ typename std::enable_if::value>::type
+ wrapped_handler_call(crow::request& req, crow::response& res, const F& f, Args&&... args)
+ {
+ static_assert(std::is_same(), std::declval(), std::declval()...))>::value,
+ "Handler function with response argument should have void return type");
+
+ f(req, res, std::forward(args)...);
+ }
+
+ template
+ typename std::enable_if::value && !black_magic::is_callable::value>::type
+ wrapped_handler_call(crow::request& req, crow::response& res, const F& f, Args&&... args)
+ {
+ static_assert(std::is_same(), std::declval(), std::declval()...))>::value,
+ "Handler function with response argument should have void return type");
+
+ f(req, res, std::forward(args)...);
+ }
+
+ template
+ typename std::enable_if::value>::type
+ wrapped_handler_call(crow::request& /*req*/, crow::response& res, const F& f, Args&&... args)
+ {
+ static_assert(std::is_same(), std::declval()...))>::value,
+ "Handler function with response argument should have void return type");
+
+ f(res, std::forward(args)...);
+ }
+
+ template
+ typename std::enable_if::value>::type
+ wrapped_handler_call(crow::request& req, crow::response& res, const F& f, Args&&... args)
+ {
+ static_assert(!std::is_same(), std::declval()...))>::value,
+ "Handler function cannot have void return type; valid return types: string, int, crow::response, crow::returnable");
+
+ res = crow::response(f(req, std::forward(args)...));
+ res.end();
+ }
+
+ template
+ typename std::enable_if::value>::type
+ wrapped_handler_call(crow::request& /*req*/, crow::response& res, const F& f, Args&&... args)
+ {
+ static_assert(!std::is_same()...))>::value,
+ "Handler function cannot have void return type; valid return types: string, int, crow::response, crow::returnable");
+
+ res = crow::response(f(std::forward(args)...));
+ res.end();
+ }
+
+ template
+ struct handler_middleware_wrapper
+ {
+ // CallCriteria bound to the current Middlewares pack
+ template
+ struct middleware_call_criteria
+ {
+ static constexpr bool value = black_magic::has_type>::value;
+ };
+
+ template
+ void operator()(crow::request& req, crow::response& res, Args&&... args) const
+ {
+ auto& ctx = *reinterpret_cast(req.middleware_context);
+ auto& container = *reinterpret_cast(req.middleware_container);
+
+ auto glob_completion_handler = std::move(res.complete_request_handler_);
+ res.complete_request_handler_ = [] {};
+
+ middleware_call_helper(container, req, res, ctx);
+
+ if (res.completed_)
+ {
+ glob_completion_handler();
+ return;
+ }
+
+ res.complete_request_handler_ = [&ctx, &container, &req, &res, &glob_completion_handler] {
+ after_handlers_call_helper<
+ middleware_call_criteria,
+ std::tuple_size::value - 1,
+ typename App::context_t,
+ typename App::mw_container_t>(container, ctx, req, res);
+ glob_completion_handler();
+ };
+
+ wrapped_handler_call(req, res, f, std::forward(args)...);
+ }
+
+ F f;
+ };
+
+ template
+ struct handler_call_bridge
+ {
+ template
+ using check_app_contains = typename black_magic::has_type;
+
+ static_assert(black_magic::all_true<(std::is_base_of::value)...>::value,
+ "Local middleware has to inherit crow::ILocalMiddleware");
+
+ static_assert(black_magic::all_true<(check_app_contains::value)...>::value,
+ "Local middleware has to be listed in app middleware");
+
+ template
+ void operator()(F&& f) const
+ {
+ auto wrapped = handler_middleware_wrapper{std::forward(f)};
+ tptr->operator()(std::move(wrapped));
+ }
+
+ Route* tptr;
+ };
+
+ } // namespace detail
+} // namespace crow
diff --git a/include/crow/middleware_context.h b/include/crow/middleware_context.h
index 3ac5b488b..6d9c3b122 100644
--- a/include/crow/middleware_context.h
+++ b/include/crow/middleware_context.h
@@ -34,23 +34,18 @@ namespace crow
};
-
- template
- bool middleware_call_helper(Container& middlewares, request& req, response& res, Context& ctx);
-
-
-
template
struct context : private partial_context
//struct context : private Middlewares::context... // simple but less type-safe
{
- template
+ template class CallCriteria, int N, typename Context, typename Container>
friend typename std::enable_if<(N == 0)>::type after_handlers_call_helper(Container& middlewares, Context& ctx, request& req, response& res);
- template
+ template class CallCriteria, int N, typename Context, typename Container>
friend typename std::enable_if<(N > 0)>::type after_handlers_call_helper(Container& middlewares, Context& ctx, request& req, response& res);
- template
- friend bool middleware_call_helper(Container& middlewares, request& req, response& res, Context& ctx);
+ template class CallCriteria, int N, typename Context, typename Container>
+ friend typename std::enable_if<(N < std::tuple_size::type>::value), bool>::type
+ middleware_call_helper(Container& middlewares, request& req, response& res, Context& ctx);
template
typename T::context& get()
diff --git a/include/crow/routing.h b/include/crow/routing.h
index d95efc33b..155cc4525 100644
--- a/include/crow/routing.h
+++ b/include/crow/routing.h
@@ -15,6 +15,7 @@
#include "crow/logging.h"
#include "crow/websocket.h"
#include "crow/mustache.h"
+#include "crow/middleware.h"
namespace crow
{
@@ -44,7 +45,7 @@ namespace crow
return {};
}
- virtual void handle(const request&, response&, const routing_params&) = 0;
+ virtual void handle(request&, response&, const routing_params&) = 0;
virtual void handle_upgrade(const request&, response& res, SocketAdaptor&&)
{
res = response(404);
@@ -109,7 +110,7 @@ namespace crow
{
H1& handler;
const routing_params& params;
- const request& req;
+ request& req;
response& res;
};
@@ -251,7 +252,7 @@ namespace crow
typename handler_type_helper::type handler_;
- void operator()(const request& req, response& res, const routing_params& params)
+ void operator()(request& req, response& res, const routing_params& params)
{
detail::routing_handler_call_helper::call<
detail::routing_handler_call_helper::call_params<
@@ -378,7 +379,7 @@ namespace crow
void validate() override
{}
- void handle(const request&, response& res, const routing_params&) override
+ void handle(request&, response& res, const routing_params&) override
{
res = response(404);
res.end();
@@ -490,7 +491,7 @@ namespace crow
}
}
- void handle(const request& req, response& res, const routing_params& params) override
+ void handle(request& req, response& res, const routing_params& params) override
{
if (!custom_templates_base.empty())
mustache::set_base(custom_templates_base);
@@ -518,7 +519,7 @@ namespace crow
#else
template
#endif
- std::function
+ std::function
wrap(Func f, black_magic::seq)
{
#ifdef CROW_MSVC_WORKAROUND
@@ -547,7 +548,7 @@ namespace crow
}
private:
- std::function erased_handler_;
+ std::function erased_handler_;
};
/// Default rule created when CROW_ROUTE is called.
@@ -570,94 +571,19 @@ namespace crow
}
template
- typename std::enable_if>::value, void>::type
- operator()(Func&& f)
+ void operator()(Func&& f)
{
- static_assert(black_magic::CallHelper>::value ||
- black_magic::CallHelper>::value,
- "Handler type is mismatched with URL parameters");
- static_assert(!std::is_same()...))>::value,
- "Handler function cannot have void return type; valid return types: string, int, crow::response, crow::returnable");
-
handler_ = (
#ifdef CROW_CAN_USE_CPP14
[f = std::move(f)]
#else
[f]
#endif
- (const request&, response& res, Args... args) {
- res = response(f(args...));
- res.end();
+ (crow::request& req, crow::response& res, Args... args) {
+ detail::wrapped_handler_call(req, res, f, std::forward(args)...);
});
}
- template
- typename std::enable_if<
- !black_magic::CallHelper>::value &&
- black_magic::CallHelper>::value,
- void>::type
- operator()(Func&& f)
- {
- static_assert(black_magic::CallHelper>::value ||
- black_magic::CallHelper>::value,
- "Handler type is mismatched with URL parameters");
- static_assert(!std::is_same(), std::declval()...))>::value,
- "Handler function cannot have void return type; valid return types: string, int, crow::response, crow::returnable");
-
- handler_ = (
-#ifdef CROW_CAN_USE_CPP14
- [f = std::move(f)]
-#else
- [f]
-#endif
- (const crow::request& req, crow::response& res, Args... args) {
- res = response(f(req, args...));
- res.end();
- });
- }
-
- template
- typename std::enable_if<
- !black_magic::CallHelper>::value &&
- !black_magic::CallHelper>::value &&
- black_magic::CallHelper>::value,
- void>::type
- operator()(Func&& f)
- {
- static_assert(black_magic::CallHelper>::value ||
- black_magic::CallHelper>::value,
- "Handler type is mismatched with URL parameters");
- static_assert(std::is_same(), std::declval()...))>::value,
- "Handler function with response argument should have void return type");
- handler_ = (
-#ifdef CROW_CAN_USE_CPP14
- [f = std::move(f)]
-#else
- [f]
-#endif
- (const crow::request&, crow::response& res, Args... args) {
- f(res, args...);
- });
- }
-
- template
- typename std::enable_if<
- !black_magic::CallHelper>::value &&
- !black_magic::CallHelper