mirror of
https://github.com/CrowCpp/Crow.git
synced 2024-06-07 21:10:44 +00:00
Merge pull request #327 from dranikpg/local-middleware
Local middleware
This commit is contained in:
commit
71f1a51c83
@ -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.<br>
|
||||
If `res.end()` is called, the operation is halted. (`after_handle` will still be called)<br>
|
||||
2 signatures:<br>
|
||||
`#!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 <typename AllContext>
|
||||
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<OtherMiddleware>();
|
||||
}
|
||||
```
|
||||
You can access other middlewares' context by calling `#!cpp all_ctx.template get<MW>()`<br>
|
||||
`#!cpp ctx == all_ctx.template get<CurrentMiddleware>()`
|
||||
|
||||
|
||||
## after_handle
|
||||
Called after handling the request.<br>
|
||||
There are two possible signatures for after_handle
|
||||
|
||||
`#!cpp void after_handle(request& req, response& res, context& ctx)`
|
||||
1. if you only need to access this middleware's context.
|
||||
|
||||
```cpp
|
||||
void after_handle(request& req, response& res, context& ctx)
|
||||
```
|
||||
|
||||
2. To get access to other middlewares context
|
||||
``` cpp
|
||||
template <typename AllContext>
|
||||
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<OtherMiddleware>();
|
||||
}
|
||||
```
|
||||
<br><br>
|
||||
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).
|
||||
|
||||
## Using middleware
|
||||
|
||||
All middleware has to be registered in the Crow application and is enabled globally by default.
|
||||
|
||||
```cpp
|
||||
crow::App<FirstMiddleware, SecondMiddleware> app;
|
||||
```
|
||||
|
||||
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)
|
||||
{}
|
||||
};
|
||||
```
|
@ -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)
|
||||
|
54
examples/example_middleware.cpp
Normal file
54
examples/example_middleware.cpp
Normal file
@ -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<RequestLogger, SecretContentGuard> 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;
|
||||
}
|
@ -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"
|
||||
|
@ -29,6 +29,7 @@
|
||||
#else
|
||||
#define CROW_ROUTE(app, url) app.route<crow::black_magic::get_parameter_tag(url)>(url)
|
||||
#define CROW_BP_ROUTE(blueprint, url) blueprint.new_rule_tagged<crow::black_magic::get_parameter_tag(url)>(url)
|
||||
#define CROW_MIDDLEWARES(app, ...) middlewares<decltype(app), __VA_ARGS__>()
|
||||
#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<Middlewares...>;
|
||||
using mw_container_t = std::tuple<Middlewares...>;
|
||||
template<typename T>
|
||||
typename T::context& get_context(const request& req)
|
||||
{
|
||||
|
@ -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<typename MW>
|
||||
struct check_before_handle_arity_3_const
|
||||
{
|
||||
template<typename T, void (T::*)(request&, response&, typename MW::context&) const = &T::before_handle>
|
||||
struct get
|
||||
{};
|
||||
};
|
||||
|
||||
template<typename MW>
|
||||
struct check_before_handle_arity_3
|
||||
{
|
||||
template<typename T, void (T::*)(request&, response&, typename MW::context&) = &T::before_handle>
|
||||
struct get
|
||||
{};
|
||||
};
|
||||
|
||||
template<typename MW>
|
||||
struct check_after_handle_arity_3_const
|
||||
{
|
||||
template<typename T, void (T::*)(request&, response&, typename MW::context&) const = &T::after_handle>
|
||||
struct get
|
||||
{};
|
||||
};
|
||||
|
||||
template<typename MW>
|
||||
struct check_after_handle_arity_3
|
||||
{
|
||||
template<typename T, void (T::*)(request&, response&, typename MW::context&) = &T::after_handle>
|
||||
struct get
|
||||
{};
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct is_before_handle_arity_3_impl
|
||||
{
|
||||
template<typename C>
|
||||
static std::true_type f(typename check_before_handle_arity_3_const<T>::template get<C>*);
|
||||
|
||||
template<typename C>
|
||||
static std::true_type f(typename check_before_handle_arity_3<T>::template get<C>*);
|
||||
|
||||
template<typename C>
|
||||
static std::false_type f(...);
|
||||
|
||||
public:
|
||||
static const bool value = decltype(f<T>(nullptr))::value;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct is_after_handle_arity_3_impl
|
||||
{
|
||||
template<typename C>
|
||||
static std::true_type f(typename check_after_handle_arity_3_const<T>::template get<C>*);
|
||||
|
||||
template<typename C>
|
||||
static std::true_type f(typename check_after_handle_arity_3<T>::template get<C>*);
|
||||
|
||||
template<typename C>
|
||||
static std::false_type f(...);
|
||||
|
||||
public:
|
||||
static const bool value = decltype(f<T>(nullptr))::value;
|
||||
};
|
||||
|
||||
template<typename MW, typename Context, typename ParentContext>
|
||||
typename std::enable_if<!is_before_handle_arity_3_impl<MW>::value>::type
|
||||
before_handler_call(MW& mw, request& req, response& res, Context& ctx, ParentContext& /*parent_ctx*/)
|
||||
{
|
||||
mw.before_handle(req, res, ctx.template get<MW>(), ctx);
|
||||
}
|
||||
|
||||
template<typename MW, typename Context, typename ParentContext>
|
||||
typename std::enable_if<is_before_handle_arity_3_impl<MW>::value>::type
|
||||
before_handler_call(MW& mw, request& req, response& res, Context& ctx, ParentContext& /*parent_ctx*/)
|
||||
{
|
||||
mw.before_handle(req, res, ctx.template get<MW>());
|
||||
}
|
||||
|
||||
template<typename MW, typename Context, typename ParentContext>
|
||||
typename std::enable_if<!is_after_handle_arity_3_impl<MW>::value>::type
|
||||
after_handler_call(MW& mw, request& req, response& res, Context& ctx, ParentContext& /*parent_ctx*/)
|
||||
{
|
||||
mw.after_handle(req, res, ctx.template get<MW>(), ctx);
|
||||
}
|
||||
|
||||
template<typename MW, typename Context, typename ParentContext>
|
||||
typename std::enable_if<is_after_handle_arity_3_impl<MW>::value>::type
|
||||
after_handler_call(MW& mw, request& req, response& res, Context& ctx, ParentContext& /*parent_ctx*/)
|
||||
{
|
||||
mw.after_handle(req, res, ctx.template get<MW>());
|
||||
}
|
||||
|
||||
template<int N, typename Context, typename Container, typename CurrentMW, typename... Middlewares>
|
||||
bool middleware_call_helper(Container& middlewares, request& req, response& res, Context& ctx)
|
||||
{
|
||||
using parent_context_t = typename Context::template partial<N - 1>;
|
||||
before_handler_call<CurrentMW, Context, parent_context_t>(std::get<N>(middlewares), req, res, ctx, static_cast<parent_context_t&>(ctx));
|
||||
|
||||
if (res.is_completed())
|
||||
{
|
||||
after_handler_call<CurrentMW, Context, parent_context_t>(std::get<N>(middlewares), req, res, ctx, static_cast<parent_context_t&>(ctx));
|
||||
return true;
|
||||
}
|
||||
|
||||
if (middleware_call_helper<N + 1, Context, Container, Middlewares...>(middlewares, req, res, ctx))
|
||||
{
|
||||
after_handler_call<CurrentMW, Context, parent_context_t>(std::get<N>(middlewares), req, res, ctx, static_cast<parent_context_t&>(ctx));
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
template<int N, typename Context, typename Container>
|
||||
bool middleware_call_helper(Container& /*middlewares*/, request& /*req*/, response& /*res*/, Context& /*ctx*/)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
template<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<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<N - 1>;
|
||||
using CurrentMW = typename std::tuple_element<N, typename std::remove_reference<Container>::type>::type;
|
||||
after_handler_call<CurrentMW, Context, parent_context_t>(std::get<N>(middlewares), req, res, ctx, static_cast<parent_context_t&>(ctx));
|
||||
}
|
||||
|
||||
template<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<N - 1>;
|
||||
using CurrentMW = typename std::tuple_element<N, typename std::remove_reference<Container>::type>::type;
|
||||
after_handler_call<CurrentMW, Context, parent_context_t>(std::get<N>(middlewares), req, res, ctx, static_cast<parent_context_t&>(ctx));
|
||||
after_handlers_call_helper<N - 1, Context, Container>(middlewares, ctx, req, res);
|
||||
}
|
||||
} // namespace detail
|
||||
|
||||
#ifdef CROW_ENABLE_DEBUG
|
||||
static std::atomic<int> connectionCount;
|
||||
@ -316,8 +173,11 @@ namespace crow
|
||||
|
||||
ctx_ = detail::context<Middlewares...>();
|
||||
req.middleware_context = static_cast<void*>(&ctx_);
|
||||
req.middleware_container = static_cast<void*>(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<detail::middleware_call_criteria_only_global,
|
||||
0, decltype(ctx_), decltype(*middlewares_)>(*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<int>(sizeof...(Middlewares)) - 1),
|
||||
decltype(ctx_),
|
||||
decltype(*middlewares_)>(*middlewares_, ctx_, req_, res);
|
||||
|
@ -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`)
|
||||
|
@ -19,12 +19,21 @@ namespace crow
|
||||
template<typename Adaptor, typename Handler, typename... Middlewares>
|
||||
class Connection;
|
||||
|
||||
namespace detail
|
||||
{
|
||||
template<typename F, typename App, typename... Middlewares>
|
||||
struct handler_middleware_wrapper;
|
||||
} // namespace detail
|
||||
|
||||
/// HTTP response
|
||||
struct response
|
||||
{
|
||||
template<typename Adaptor, typename Handler, typename... Middlewares>
|
||||
friend class crow::Connection;
|
||||
|
||||
template<typename F, typename App, typename... Middlewares>
|
||||
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.
|
||||
|
322
include/crow/middleware.h
Normal file
322
include/crow/middleware.h
Normal file
@ -0,0 +1,322 @@
|
||||
#pragma once
|
||||
|
||||
#include "crow/http_request.h"
|
||||
#include "crow/http_response.h"
|
||||
#include "crow/utility.h"
|
||||
|
||||
#include <tuple>
|
||||
#include <type_traits>
|
||||
#include <iostream>
|
||||
#include <utility>
|
||||
|
||||
namespace crow
|
||||
{
|
||||
|
||||
/// Local middleware should extend ILocalMiddleware
|
||||
struct ILocalMiddleware
|
||||
{
|
||||
using call_global = std::false_type;
|
||||
};
|
||||
|
||||
namespace detail
|
||||
{
|
||||
template<typename MW>
|
||||
struct check_before_handle_arity_3_const
|
||||
{
|
||||
template<typename T, void (T::*)(request&, response&, typename MW::context&) const = &T::before_handle>
|
||||
struct get
|
||||
{};
|
||||
};
|
||||
|
||||
template<typename MW>
|
||||
struct check_before_handle_arity_3
|
||||
{
|
||||
template<typename T, void (T::*)(request&, response&, typename MW::context&) = &T::before_handle>
|
||||
struct get
|
||||
{};
|
||||
};
|
||||
|
||||
template<typename MW>
|
||||
struct check_after_handle_arity_3_const
|
||||
{
|
||||
template<typename T, void (T::*)(request&, response&, typename MW::context&) const = &T::after_handle>
|
||||
struct get
|
||||
{};
|
||||
};
|
||||
|
||||
template<typename MW>
|
||||
struct check_after_handle_arity_3
|
||||
{
|
||||
template<typename T, void (T::*)(request&, response&, typename MW::context&) = &T::after_handle>
|
||||
struct get
|
||||
{};
|
||||
};
|
||||
|
||||
template<typename MW>
|
||||
struct check_global_call_false
|
||||
{
|
||||
template<typename T, typename std::enable_if<T::call_global::value == false, bool>::type = true>
|
||||
struct get
|
||||
{};
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct is_before_handle_arity_3_impl
|
||||
{
|
||||
template<typename C>
|
||||
static std::true_type f(typename check_before_handle_arity_3_const<T>::template get<C>*);
|
||||
|
||||
template<typename C>
|
||||
static std::true_type f(typename check_before_handle_arity_3<T>::template get<C>*);
|
||||
|
||||
template<typename C>
|
||||
static std::false_type f(...);
|
||||
|
||||
public:
|
||||
static const bool value = decltype(f<T>(nullptr))::value;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct is_after_handle_arity_3_impl
|
||||
{
|
||||
template<typename C>
|
||||
static std::true_type f(typename check_after_handle_arity_3_const<T>::template get<C>*);
|
||||
|
||||
template<typename C>
|
||||
static std::true_type f(typename check_after_handle_arity_3<T>::template get<C>*);
|
||||
|
||||
template<typename C>
|
||||
static std::false_type f(...);
|
||||
|
||||
public:
|
||||
static constexpr bool value = decltype(f<T>(nullptr))::value;
|
||||
};
|
||||
|
||||
template<typename MW, typename Context, typename ParentContext>
|
||||
typename std::enable_if<!is_before_handle_arity_3_impl<MW>::value>::type
|
||||
before_handler_call(MW& mw, request& req, response& res, Context& ctx, ParentContext& /*parent_ctx*/)
|
||||
{
|
||||
mw.before_handle(req, res, ctx.template get<MW>(), ctx);
|
||||
}
|
||||
|
||||
template<typename MW, typename Context, typename ParentContext>
|
||||
typename std::enable_if<is_before_handle_arity_3_impl<MW>::value>::type
|
||||
before_handler_call(MW& mw, request& req, response& res, Context& ctx, ParentContext& /*parent_ctx*/)
|
||||
{
|
||||
mw.before_handle(req, res, ctx.template get<MW>());
|
||||
}
|
||||
|
||||
template<typename MW, typename Context, typename ParentContext>
|
||||
typename std::enable_if<!is_after_handle_arity_3_impl<MW>::value>::type
|
||||
after_handler_call(MW& mw, request& req, response& res, Context& ctx, ParentContext& /*parent_ctx*/)
|
||||
{
|
||||
mw.after_handle(req, res, ctx.template get<MW>(), ctx);
|
||||
}
|
||||
|
||||
template<typename MW, typename Context, typename ParentContext>
|
||||
typename std::enable_if<is_after_handle_arity_3_impl<MW>::value>::type
|
||||
after_handler_call(MW& mw, request& req, response& res, Context& ctx, ParentContext& /*parent_ctx*/)
|
||||
{
|
||||
mw.after_handle(req, res, ctx.template get<MW>());
|
||||
}
|
||||
|
||||
|
||||
template<template<typename QueryMW> 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<typename std::remove_reference<Container>::type>::value), bool>::type
|
||||
middleware_call_helper(Container& middlewares, request& req, response& res, Context& ctx)
|
||||
{
|
||||
|
||||
using CurrentMW = typename std::tuple_element<N, typename std::remove_reference<Container>::type>::type;
|
||||
|
||||
if (!CallCriteria<CurrentMW>::value)
|
||||
{
|
||||
return middleware_call_helper<CallCriteria, N + 1, Context, Container>(middlewares, req, res, ctx);
|
||||
}
|
||||
|
||||
using parent_context_t = typename Context::template partial<N - 1>;
|
||||
before_handler_call<CurrentMW, Context, parent_context_t>(std::get<N>(middlewares), req, res, ctx, static_cast<parent_context_t&>(ctx));
|
||||
if (res.is_completed())
|
||||
{
|
||||
after_handler_call<CurrentMW, Context, parent_context_t>(std::get<N>(middlewares), req, res, ctx, static_cast<parent_context_t&>(ctx));
|
||||
return true;
|
||||
}
|
||||
|
||||
if (middleware_call_helper<CallCriteria, N + 1, Context, Container>(middlewares, req, res, ctx))
|
||||
{
|
||||
after_handler_call<CurrentMW, Context, parent_context_t>(std::get<N>(middlewares), req, res, ctx, static_cast<parent_context_t&>(ctx));
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
template<template<typename QueryMW> class CallCriteria, int N, typename Context, typename Container>
|
||||
typename std::enable_if<(N >= std::tuple_size<typename std::remove_reference<Container>::type>::value), bool>::type
|
||||
middleware_call_helper(Container& /*middlewares*/, request& /*req*/, response& /*res*/, Context& /*ctx*/)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
template<template<typename QueryMW> 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<template<typename QueryMW> 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<N - 1>;
|
||||
using CurrentMW = typename std::tuple_element<N, typename std::remove_reference<Container>::type>::type;
|
||||
if (CallCriteria<CurrentMW>::value)
|
||||
{
|
||||
after_handler_call<CurrentMW, Context, parent_context_t>(std::get<N>(middlewares), req, res, ctx, static_cast<parent_context_t&>(ctx));
|
||||
}
|
||||
}
|
||||
|
||||
template<template<typename QueryMW> 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<N - 1>;
|
||||
using CurrentMW = typename std::tuple_element<N, typename std::remove_reference<Container>::type>::type;
|
||||
if (CallCriteria<CurrentMW>::value)
|
||||
{
|
||||
after_handler_call<CurrentMW, Context, parent_context_t>(std::get<N>(middlewares), req, res, ctx, static_cast<parent_context_t&>(ctx));
|
||||
}
|
||||
after_handlers_call_helper<CallCriteria, N - 1, Context, Container>(middlewares, ctx, req, res);
|
||||
}
|
||||
|
||||
// A CallCriteria that accepts only global middleware
|
||||
template<typename MW>
|
||||
struct middleware_call_criteria_only_global
|
||||
{
|
||||
template<typename C>
|
||||
static std::false_type f(typename check_global_call_false<MW>::template get<C>*);
|
||||
|
||||
template<typename C>
|
||||
static std::true_type f(...);
|
||||
|
||||
static const bool value = decltype(f<MW>(nullptr))::value;
|
||||
};
|
||||
|
||||
// wrapped_handler_call transparently wraps a handler call behind (req, res, args...)
|
||||
template<typename F, typename... Args>
|
||||
typename std::enable_if<black_magic::is_callable<F, const crow::request, crow::response&, Args...>::value>::type
|
||||
wrapped_handler_call(crow::request& req, crow::response& res, const F& f, Args&&... args)
|
||||
{
|
||||
static_assert(std::is_same<void, decltype(f(std::declval<crow::request>(), std::declval<crow::response&>(), std::declval<Args>()...))>::value,
|
||||
"Handler function with response argument should have void return type");
|
||||
|
||||
f(req, res, std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template<typename F, typename... Args>
|
||||
typename std::enable_if<black_magic::is_callable<F, crow::request&, crow::response&, Args...>::value && !black_magic::is_callable<F, const crow::request, crow::response&, Args...>::value>::type
|
||||
wrapped_handler_call(crow::request& req, crow::response& res, const F& f, Args&&... args)
|
||||
{
|
||||
static_assert(std::is_same<void, decltype(f(std::declval<crow::request&>(), std::declval<crow::response&>(), std::declval<Args>()...))>::value,
|
||||
"Handler function with response argument should have void return type");
|
||||
|
||||
f(req, res, std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template<typename F, typename... Args>
|
||||
typename std::enable_if<black_magic::is_callable<F, crow::response&, Args...>::value>::type
|
||||
wrapped_handler_call(crow::request& /*req*/, crow::response& res, const F& f, Args&&... args)
|
||||
{
|
||||
static_assert(std::is_same<void, decltype(f(std::declval<crow::response&>(), std::declval<Args>()...))>::value,
|
||||
"Handler function with response argument should have void return type");
|
||||
|
||||
f(res, std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template<typename F, typename... Args>
|
||||
typename std::enable_if<black_magic::is_callable<F, crow::request, Args...>::value>::type
|
||||
wrapped_handler_call(crow::request& req, crow::response& res, const F& f, Args&&... args)
|
||||
{
|
||||
static_assert(!std::is_same<void, decltype(f(std::declval<crow::request>(), std::declval<Args>()...))>::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>(args)...));
|
||||
res.end();
|
||||
}
|
||||
|
||||
template<typename F, typename... Args>
|
||||
typename std::enable_if<black_magic::is_callable<F, Args...>::value>::type
|
||||
wrapped_handler_call(crow::request& /*req*/, crow::response& res, const F& f, Args&&... args)
|
||||
{
|
||||
static_assert(!std::is_same<void, decltype(f(std::declval<Args>()...))>::value,
|
||||
"Handler function cannot have void return type; valid return types: string, int, crow::response, crow::returnable");
|
||||
|
||||
res = crow::response(f(std::forward<Args>(args)...));
|
||||
res.end();
|
||||
}
|
||||
|
||||
template<typename F, typename App, typename... Middlewares>
|
||||
struct handler_middleware_wrapper
|
||||
{
|
||||
// CallCriteria bound to the current Middlewares pack
|
||||
template<typename MW>
|
||||
struct middleware_call_criteria
|
||||
{
|
||||
static constexpr bool value = black_magic::has_type<MW, std::tuple<Middlewares...>>::value;
|
||||
};
|
||||
|
||||
template<typename... Args>
|
||||
void operator()(crow::request& req, crow::response& res, Args&&... args) const
|
||||
{
|
||||
auto& ctx = *reinterpret_cast<typename App::context_t*>(req.middleware_context);
|
||||
auto& container = *reinterpret_cast<typename App::mw_container_t*>(req.middleware_container);
|
||||
|
||||
auto glob_completion_handler = std::move(res.complete_request_handler_);
|
||||
res.complete_request_handler_ = [] {};
|
||||
|
||||
middleware_call_helper<middleware_call_criteria,
|
||||
0, typename App::context_t, typename App::mw_container_t>(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<typename App::mw_container_t>::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>(args)...);
|
||||
}
|
||||
|
||||
F f;
|
||||
};
|
||||
|
||||
template<typename Route, typename App, typename... Middlewares>
|
||||
struct handler_call_bridge
|
||||
{
|
||||
template<typename MW>
|
||||
using check_app_contains = typename black_magic::has_type<MW, typename App::mw_container_t>;
|
||||
|
||||
static_assert(black_magic::all_true<(std::is_base_of<crow::ILocalMiddleware, Middlewares>::value)...>::value,
|
||||
"Local middleware has to inherit crow::ILocalMiddleware");
|
||||
|
||||
static_assert(black_magic::all_true<(check_app_contains<Middlewares>::value)...>::value,
|
||||
"Local middleware has to be listed in app middleware");
|
||||
|
||||
template<typename F>
|
||||
void operator()(F&& f) const
|
||||
{
|
||||
auto wrapped = handler_middleware_wrapper<F, App, Middlewares...>{std::forward<F>(f)};
|
||||
tptr->operator()(std::move(wrapped));
|
||||
}
|
||||
|
||||
Route* tptr;
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
} // namespace crow
|
@ -34,23 +34,18 @@ namespace crow
|
||||
};
|
||||
|
||||
|
||||
|
||||
template<int N, typename Context, typename Container, typename CurrentMW, typename... Middlewares>
|
||||
bool middleware_call_helper(Container& middlewares, request& req, response& res, Context& ctx);
|
||||
|
||||
|
||||
|
||||
template<typename... Middlewares>
|
||||
struct context : private partial_context<Middlewares...>
|
||||
//struct context : private Middlewares::context... // simple but less type-safe
|
||||
{
|
||||
template<int N, typename Context, typename Container>
|
||||
template<template<typename QueryMW> 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<int N, typename Context, typename Container>
|
||||
template<template<typename QueryMW> 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<int N, typename Context, typename Container, typename CurrentMW, typename... Middlewares2>
|
||||
friend bool middleware_call_helper(Container& middlewares, request& req, response& res, Context& ctx);
|
||||
template<template<typename QueryMW> class CallCriteria, int N, typename Context, typename Container>
|
||||
friend typename std::enable_if<(N < std::tuple_size<typename std::remove_reference<Container>::type>::value), bool>::type
|
||||
middleware_call_helper(Container& middlewares, request& req, response& res, Context& ctx);
|
||||
|
||||
template<typename T>
|
||||
typename T::context& get()
|
||||
|
@ -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<ArgsWrapped...>::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<typename Func, unsigned... Indices>
|
||||
#endif
|
||||
std::function<void(const request&, response&, const routing_params&)>
|
||||
std::function<void(request&, response&, const routing_params&)>
|
||||
wrap(Func f, black_magic::seq<Indices...>)
|
||||
{
|
||||
#ifdef CROW_MSVC_WORKAROUND
|
||||
@ -547,7 +548,7 @@ namespace crow
|
||||
}
|
||||
|
||||
private:
|
||||
std::function<void(const request&, response&, const routing_params&)> erased_handler_;
|
||||
std::function<void(request&, response&, const routing_params&)> erased_handler_;
|
||||
};
|
||||
|
||||
/// Default rule created when CROW_ROUTE is called.
|
||||
@ -570,94 +571,19 @@ namespace crow
|
||||
}
|
||||
|
||||
template<typename Func>
|
||||
typename std::enable_if<black_magic::CallHelper<Func, black_magic::S<Args...>>::value, void>::type
|
||||
operator()(Func&& f)
|
||||
void operator()(Func&& f)
|
||||
{
|
||||
static_assert(black_magic::CallHelper<Func, black_magic::S<Args...>>::value ||
|
||||
black_magic::CallHelper<Func, black_magic::S<crow::request, Args...>>::value,
|
||||
"Handler type is mismatched with URL parameters");
|
||||
static_assert(!std::is_same<void, decltype(f(std::declval<Args>()...))>::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>(args)...);
|
||||
});
|
||||
}
|
||||
|
||||
template<typename Func>
|
||||
typename std::enable_if<
|
||||
!black_magic::CallHelper<Func, black_magic::S<Args...>>::value &&
|
||||
black_magic::CallHelper<Func, black_magic::S<crow::request, Args...>>::value,
|
||||
void>::type
|
||||
operator()(Func&& f)
|
||||
{
|
||||
static_assert(black_magic::CallHelper<Func, black_magic::S<Args...>>::value ||
|
||||
black_magic::CallHelper<Func, black_magic::S<crow::request, Args...>>::value,
|
||||
"Handler type is mismatched with URL parameters");
|
||||
static_assert(!std::is_same<void, decltype(f(std::declval<crow::request>(), std::declval<Args>()...))>::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 Func>
|
||||
typename std::enable_if<
|
||||
!black_magic::CallHelper<Func, black_magic::S<Args...>>::value &&
|
||||
!black_magic::CallHelper<Func, black_magic::S<crow::request, Args...>>::value &&
|
||||
black_magic::CallHelper<Func, black_magic::S<crow::response&, Args...>>::value,
|
||||
void>::type
|
||||
operator()(Func&& f)
|
||||
{
|
||||
static_assert(black_magic::CallHelper<Func, black_magic::S<Args...>>::value ||
|
||||
black_magic::CallHelper<Func, black_magic::S<crow::response&, Args...>>::value,
|
||||
"Handler type is mismatched with URL parameters");
|
||||
static_assert(std::is_same<void, decltype(f(std::declval<crow::response&>(), std::declval<Args>()...))>::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 Func>
|
||||
typename std::enable_if<
|
||||
!black_magic::CallHelper<Func, black_magic::S<Args...>>::value &&
|
||||
!black_magic::CallHelper<Func, black_magic::S<crow::request, Args...>>::value &&
|
||||
!black_magic::CallHelper<Func, black_magic::S<crow::response&, Args...>>::value,
|
||||
void>::type
|
||||
operator()(Func&& f)
|
||||
{
|
||||
static_assert(black_magic::CallHelper<Func, black_magic::S<Args...>>::value ||
|
||||
black_magic::CallHelper<Func, black_magic::S<crow::request, Args...>>::value ||
|
||||
black_magic::CallHelper<Func, black_magic::S<crow::request, crow::response&, Args...>>::value,
|
||||
"Handler type is mismatched with URL parameters");
|
||||
static_assert(std::is_same<void, decltype(f(std::declval<crow::request>(), std::declval<crow::response&>(), std::declval<Args>()...))>::value,
|
||||
"Handler function with response argument should have void return type");
|
||||
|
||||
handler_ = std::move(f);
|
||||
}
|
||||
|
||||
template<typename Func>
|
||||
void operator()(std::string name, Func&& f)
|
||||
{
|
||||
@ -665,7 +591,7 @@ namespace crow
|
||||
(*this).template operator()<Func>(std::forward(f));
|
||||
}
|
||||
|
||||
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);
|
||||
@ -673,17 +599,25 @@ namespace crow
|
||||
mustache::set_base("templates");
|
||||
|
||||
detail::routing_handler_call_helper::call<
|
||||
detail::routing_handler_call_helper::call_params<
|
||||
decltype(handler_)>,
|
||||
detail::routing_handler_call_helper::call_params<decltype(handler_)>,
|
||||
0, 0, 0, 0,
|
||||
black_magic::S<Args...>,
|
||||
black_magic::S<>>()(
|
||||
detail::routing_handler_call_helper::call_params<
|
||||
decltype(handler_)>{handler_, params, req, res});
|
||||
detail::routing_handler_call_helper::call_params<decltype(handler_)>{handler_, params, req, res});
|
||||
}
|
||||
|
||||
/// Enable local middleware for this handler
|
||||
template<typename App, typename... Middlewares>
|
||||
crow::detail::handler_call_bridge<TaggedRule<Args...>, App, Middlewares...>
|
||||
middlewares()
|
||||
{
|
||||
// the handler_call_bridge allows the functor to be placed directly after this function
|
||||
// instead of wrapping it with more parentheses
|
||||
return {this};
|
||||
}
|
||||
|
||||
private:
|
||||
std::function<void(const crow::request&, crow::response&, Args...)> handler_;
|
||||
std::function<void(crow::request&, crow::response&, Args...)> handler_;
|
||||
};
|
||||
|
||||
const int RULE_SPECIAL_REDIRECT_SLASH = 1;
|
||||
@ -1507,7 +1441,7 @@ namespace crow
|
||||
return std::string();
|
||||
}
|
||||
|
||||
void handle(const request& req, response& res)
|
||||
void handle(request& req, response& res)
|
||||
{
|
||||
HTTPMethod method_actual = req.method;
|
||||
if (req.method >= HTTPMethod::InternalMethodCount)
|
||||
|
@ -237,6 +237,40 @@ namespace crow
|
||||
static constexpr bool value = sizeof(__test<F, Args...>(0)) == sizeof(char);
|
||||
};
|
||||
|
||||
// Check Tuple contains type T
|
||||
template<typename T, typename Tuple>
|
||||
struct has_type;
|
||||
|
||||
template<typename T>
|
||||
struct has_type<T, std::tuple<>> : std::false_type
|
||||
{};
|
||||
|
||||
template<typename T, typename U, typename... Ts>
|
||||
struct has_type<T, std::tuple<U, Ts...>> : has_type<T, std::tuple<Ts...>>
|
||||
{};
|
||||
|
||||
template<typename T, typename... Ts>
|
||||
struct has_type<T, std::tuple<T, Ts...>> : std::true_type
|
||||
{};
|
||||
|
||||
// Check F is callable with Args
|
||||
template<typename F, typename... Args>
|
||||
struct is_callable
|
||||
{
|
||||
template<typename F2, typename... Args2>
|
||||
static std::true_type __test(decltype(std::declval<F2>()(std::declval<Args2>()...))*);
|
||||
|
||||
template<typename F2, typename... Args2>
|
||||
static std::false_type __test(...);
|
||||
|
||||
static constexpr bool value = decltype(__test<F, Args...>(nullptr))::value;
|
||||
};
|
||||
|
||||
// Kind of fold expressions in C++11
|
||||
template<bool...>
|
||||
struct bool_pack;
|
||||
template<bool... bs>
|
||||
using all_true = std::is_same<bool_pack<bs..., true>, bool_pack<true, bs...>>;
|
||||
|
||||
template<int N>
|
||||
struct single_tag_to_type
|
||||
|
@ -44,10 +44,11 @@ TEST_CASE("Rule")
|
||||
r.validate();
|
||||
|
||||
response res;
|
||||
request req;
|
||||
|
||||
// executing handler
|
||||
CHECK(0 == x);
|
||||
r.handle(request(), res, routing_params());
|
||||
r.handle(req, res, routing_params());
|
||||
CHECK(1 == x);
|
||||
|
||||
// registering handler with request argument
|
||||
@ -60,7 +61,7 @@ TEST_CASE("Rule")
|
||||
|
||||
// executing handler
|
||||
CHECK(1 == x);
|
||||
r.handle(request(), res, routing_params());
|
||||
r.handle(req, res, routing_params());
|
||||
CHECK(2 == x);
|
||||
} // Rule
|
||||
|
||||
@ -1141,12 +1142,14 @@ TEST_CASE("template_basic")
|
||||
|
||||
TEST_CASE("template_function")
|
||||
{
|
||||
auto t = crow::mustache::compile("attack of {{func}}");
|
||||
crow::mustache::context ctx;
|
||||
ctx["name"] = "killer tomatoes";
|
||||
ctx["func"] = [&](std::string){return std::string("{{name}}, IN SPACE!");};
|
||||
auto result = t.render(ctx);
|
||||
CHECK("attack of killer tomatoes, IN SPACE!" == result);
|
||||
auto t = crow::mustache::compile("attack of {{func}}");
|
||||
crow::mustache::context ctx;
|
||||
ctx["name"] = "killer tomatoes";
|
||||
ctx["func"] = [&](std::string) {
|
||||
return std::string("{{name}}, IN SPACE!");
|
||||
};
|
||||
auto result = t.render(ctx);
|
||||
CHECK("attack of killer tomatoes, IN SPACE!" == result);
|
||||
}
|
||||
|
||||
TEST_CASE("template_load")
|
||||
@ -1374,6 +1377,71 @@ TEST_CASE("middleware_context")
|
||||
app.stop();
|
||||
} // middleware_context
|
||||
|
||||
struct LocalSecretMiddleware : crow::ILocalMiddleware
|
||||
{
|
||||
struct context
|
||||
{};
|
||||
|
||||
void before_handle(request& /*req*/, response& res, context& /*ctx*/)
|
||||
{
|
||||
res.code = 403;
|
||||
res.end();
|
||||
}
|
||||
|
||||
void after_handle(request& /*req*/, response& /*res*/, context& /*ctx*/)
|
||||
{}
|
||||
};
|
||||
|
||||
TEST_CASE("local_middleware")
|
||||
{
|
||||
static char buf[2048];
|
||||
|
||||
App<LocalSecretMiddleware> app;
|
||||
|
||||
CROW_ROUTE(app, "/")
|
||||
([]() {
|
||||
return "works!";
|
||||
});
|
||||
|
||||
CROW_ROUTE(app, "/secret")
|
||||
.middlewares<decltype(app), LocalSecretMiddleware>()([]() {
|
||||
return "works!";
|
||||
});
|
||||
|
||||
app.validate();
|
||||
|
||||
auto _ = async(launch::async,
|
||||
[&] {
|
||||
app.bindaddr(LOCALHOST_ADDRESS).port(45451).run();
|
||||
});
|
||||
app.wait_for_server_start();
|
||||
asio::io_service is;
|
||||
|
||||
{
|
||||
asio::ip::tcp::socket c(is);
|
||||
c.connect(asio::ip::tcp::endpoint(
|
||||
asio::ip::address::from_string(LOCALHOST_ADDRESS), 45451));
|
||||
c.send(asio::buffer("GET /\r\n\r\n"));
|
||||
c.receive(asio::buffer(buf, 2048));
|
||||
c.close();
|
||||
|
||||
CHECK(std::string(buf).find("200") != std::string::npos);
|
||||
}
|
||||
|
||||
{
|
||||
asio::ip::tcp::socket c(is);
|
||||
c.connect(asio::ip::tcp::endpoint(
|
||||
asio::ip::address::from_string(LOCALHOST_ADDRESS), 45451));
|
||||
c.send(asio::buffer("GET /secret\r\n\r\n"));
|
||||
c.receive(asio::buffer(buf, 2048));
|
||||
c.close();
|
||||
|
||||
CHECK(std::string(buf).find("403") != std::string::npos);
|
||||
}
|
||||
|
||||
app.stop();
|
||||
} // local_middleware
|
||||
|
||||
TEST_CASE("middleware_cookieparser")
|
||||
{
|
||||
static char buf[2048];
|
||||
|
Loading…
Reference in New Issue
Block a user