aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authoripknHama <ipknhama@gmail.com>2014-09-07 01:24:45 +0900
committeripknHama <ipknhama@gmail.com>2014-09-07 01:24:45 +0900
commitc89cafa820ec02f041c3b0e52877bc321f6a1ba9 (patch)
tree8b74deacdefd07048c230cb553efe6bb4e7352e1
parentdaa3c820878f8e189120cf9359caf8b2359d61ca (diff)
downloadcrow-c89cafa820ec02f041c3b0e52877bc321f6a1ba9.tar.gz
crow-c89cafa820ec02f041c3b0e52877bc321f6a1ba9.zip
add Middlewares template to Crow main class, context implementation
-rw-r--r--examples/example.cpp2
-rw-r--r--examples/example_chat.cpp2
-rw-r--r--include/crow.h19
-rw-r--r--include/http_request.h2
-rw-r--r--include/middleware.h50
-rw-r--r--include/middleware_context.h32
-rw-r--r--include/utility.h73
-rw-r--r--tests/unittest.cpp14
8 files changed, 184 insertions, 10 deletions
diff --git a/examples/example.cpp b/examples/example.cpp
index b8e58f8..b360adb 100644
--- a/examples/example.cpp
+++ b/examples/example.cpp
@@ -12,7 +12,7 @@ class ExampleLogHandler : public crow::ILogHandler {
int main()
{
- crow::Crow app;
+ crow::SimpleApp app;
CROW_ROUTE(app, "/")
.name("hello")
diff --git a/examples/example_chat.cpp b/examples/example_chat.cpp
index b12926a..31f16c5 100644
--- a/examples/example_chat.cpp
+++ b/examples/example_chat.cpp
@@ -28,7 +28,7 @@ void broadcast(const string& msg)
int main()
{
- crow::App app;
+ crow::SimpleApp app;
crow::mustache::set_base(".");
CROW_ROUTE(app, "/")
diff --git a/include/crow.h b/include/crow.h
index 55572bf..a018f31 100644
--- a/include/crow.h
+++ b/include/crow.h
@@ -13,6 +13,8 @@
#include "http_server.h"
#include "utility.h"
#include "routing.h"
+#include "middleware_impl.h"
+#include "http_request.h"
// TEST
#include <iostream>
@@ -21,6 +23,7 @@
namespace crow
{
+ template <typename ... Middlewares>
class Crow
{
public:
@@ -78,12 +81,26 @@ namespace crow
router_.debug_print();
}
+ // middleware
+ using context_t = detail::context<Middlewares...>;
+ template <typename T>
+ T& get_middleware_context(request& req)
+ {
+ static_assert(black_magic::contains<T, Middlewares...>::value, "App doesn't have the specified middleware type.");
+ auto& ctx = *reinterpret_cast<context_t*>(req.middleware_context);
+ return ctx.get<T>();
+ }
+
private:
uint16_t port_ = 80;
uint16_t concurrency_ = 1;
+ std::tuple<Middlewares...> middlewares_;
+
Router router_;
};
- using App = Crow;
+ template <typename ... Middlewares>
+ using App = Crow<Middlewares...>;
+ using SimpleApp = Crow<>;
};
diff --git a/include/http_request.h b/include/http_request.h
index 83b6059..77b3ecb 100644
--- a/include/http_request.h
+++ b/include/http_request.h
@@ -10,5 +10,7 @@ namespace crow
std::string url;
std::unordered_map<std::string, std::string> headers;
std::string body;
+
+ void* middleware_context;
};
}
diff --git a/include/middleware.h b/include/middleware.h
new file mode 100644
index 0000000..270e026
--- /dev/null
+++ b/include/middleware.h
@@ -0,0 +1,50 @@
+#pragma once
+#include "http_request.h"
+#include "http_response.h"
+
+namespace crow
+{
+ class CookieParser
+ {
+ struct context
+ {
+ std::unordered_map<std::string, std::string> jar;
+ };
+
+ template <typename AllContext>
+ void before_handle(request& req, response& res, context& ctx, AllContext& all_ctx)
+ {
+ // ctx == all_ctx.bind<CookieParser>()
+ // ctx.jar[] = ;
+ }
+
+ template <typename AllContext>
+ void after_handle(request& req, response& res, context& ctx, AllContext& all_ctx)
+ {
+ }
+ }
+
+ /*
+ App<CookieParser, AnotherJarMW> app;
+ A B C
+ A::context
+ int aa;
+
+ ctx1 : public A::context
+ ctx2 : public ctx1, public B::context
+ ctx3 : public ctx2, public C::context
+
+ C depends on A
+
+ C::handle
+ context.aaa
+
+ App::context : private CookieParser::contetx, ...
+ {
+ jar
+
+ }
+
+ SimpleApp
+ */
+}
diff --git a/include/middleware_context.h b/include/middleware_context.h
new file mode 100644
index 0000000..6dbf923
--- /dev/null
+++ b/include/middleware_context.h
@@ -0,0 +1,32 @@
+#pragma once
+
+#include "utility.h"
+
+namespace crow
+{
+ namespace detail
+ {
+ template <typename ... Middlewares>
+ struct partial_context
+ : public black_magic::pop_back<Middlewares...>::template rebind<partial_context>
+ , public black_magic::last_element_type<Middlewares...>::type::context
+ {
+ };
+
+ template <>
+ struct partial_context<>
+ {
+ };
+
+ template <typename ... Middlewares>
+ struct context : private partial_context<Middlewares...>
+ //struct context : private Middlewares::context... // simple but less type-safe
+ {
+ template <typename T>
+ typename T::context& get()
+ {
+ return static_cast<typename T::context&>(*this);
+ }
+ };
+ }
+}
diff --git a/include/utility.h b/include/utility.h
index a46d577..35ea848 100644
--- a/include/utility.h
+++ b/include/utility.h
@@ -2,6 +2,8 @@
#include <cstdint>
#include <stdexcept>
+#include <tuple>
+#include <type_traits>
namespace crow
{
@@ -211,5 +213,76 @@ template <typename F, typename Set>
using type = S<>;
};
+ template <typename ... T>
+ struct last_element_type
+ {
+ using type = typename std::tuple_element<sizeof...(T)-1, std::tuple<T...>>::type;
+ };
+
+
+ template <>
+ struct last_element_type<>
+ {
+ };
+
+
+ // from http://stackoverflow.com/questions/13072359/c11-compile-time-array-with-logarithmic-evaluation-depth
+ template<class T> using Invoke = typename T::type;
+
+ template<unsigned...> struct seq{ using type = seq; };
+
+ template<class S1, class S2> struct concat;
+
+ template<unsigned... I1, unsigned... I2>
+ struct concat<seq<I1...>, seq<I2...>>
+ : seq<I1..., (sizeof...(I1)+I2)...>{};
+
+ template<class S1, class S2>
+ using Concat = Invoke<concat<S1, S2>>;
+
+ template<unsigned N> struct gen_seq;
+ template<unsigned N> using GenSeq = Invoke<gen_seq<N>>;
+
+ template<unsigned N>
+ struct gen_seq : Concat<GenSeq<N/2>, GenSeq<N - N/2>>{};
+
+ template<> struct gen_seq<0> : seq<>{};
+ template<> struct gen_seq<1> : seq<0>{};
+
+ template <typename Seq, typename Tuple>
+ struct pop_back_helper;
+
+ template <unsigned ... N, typename Tuple>
+ struct pop_back_helper<seq<N...>, Tuple>
+ {
+ template <template <typename ... Args> class U>
+ using rebind = U<std::tuple_element<N, Tuple>...>;
+ };
+
+ template <typename ... T>
+ struct pop_back : public pop_back_helper<typename gen_seq<sizeof...(T)-1>::type, std::tuple<T...>>
+ {
+ };
+
+ template <>
+ struct pop_back<>
+ {
+ template <template <typename ... Args> class U>
+ using rebind = U<>;
+ };
+
+ // from http://stackoverflow.com/questions/2118541/check-if-c0x-parameter-pack-contains-a-type
+ template < typename Tp, typename... List >
+ struct contains : std::true_type {};
+
+ template < typename Tp, typename Head, typename... Rest >
+ struct contains<Tp, Head, Rest...>
+ : std::conditional< std::is_same<Tp, Head>::value,
+ std::true_type,
+ contains<Tp, Rest...>
+ >::type {};
+
+ template < typename Tp >
+ struct contains<Tp> : std::false_type {};
}
}
diff --git a/tests/unittest.cpp b/tests/unittest.cpp
index 918d027..17bc53c 100644
--- a/tests/unittest.cpp
+++ b/tests/unittest.cpp
@@ -112,7 +112,7 @@ TEST(ParameterTagging)
TEST(RoutingTest)
{
- Crow app;
+ SimpleApp app;
int A{};
uint32_t B{};
double C{};
@@ -238,7 +238,7 @@ TEST(simple_response_routing_params)
TEST(handler_with_response)
{
- Crow app;
+ SimpleApp app;
CROW_ROUTE(app, "/")([](const crow::request&, crow::response&)
{
});
@@ -247,9 +247,9 @@ TEST(handler_with_response)
TEST(server_handling_error_request)
{
static char buf[2048];
- Crow app;
+ SimpleApp app;
CROW_ROUTE(app, "/")([]{return "A";});
- Server<Crow> server(&app, 45451);
+ Server<SimpleApp> server(&app, 45451);
auto _ = async(launch::async, [&]{server.run();});
std::string sendmsg = "POX";
asio::io_service is;
@@ -276,12 +276,12 @@ TEST(server_handling_error_request)
TEST(multi_server)
{
static char buf[2048];
- Crow app1, app2;
+ SimpleApp app1, app2;
CROW_ROUTE(app1, "/")([]{return "A";});
CROW_ROUTE(app2, "/")([]{return "B";});
- Server<Crow> server1(&app1, 45451);
- Server<Crow> server2(&app2, 45452);
+ Server<SimpleApp> server1(&app1, 45451);
+ Server<SimpleApp> server2(&app2, 45452);
auto _ = async(launch::async, [&]{server1.run();});
auto _2 = async(launch::async, [&]{server2.run();});