aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authoripknHama <ipknhama@gmail.com>2014-04-10 08:17:08 +0900
committeripknHama <ipknhama@gmail.com>2014-04-10 08:17:08 +0900
commitb33c7a4f2957d4468afc1e7c4463189e180c8daa (patch)
treeb3914100d8d6c888829645b0a98794d6e08dce7d
parentd533a619c99c5ead31e86afd14dd9b017c63a9ab (diff)
downloadcrow-b33c7a4f2957d4468afc1e7c4463189e180c8daa.tar.gz
crow-b33c7a4f2957d4468afc1e7c4463189e180c8daa.zip
removing black magic; merging router with app
-rw-r--r--.gitignore2
-rw-r--r--Makefile7
-rw-r--r--example.cpp18
-rw-r--r--example.py12
-rw-r--r--flask.h27
-rw-r--r--http_connection.h3
-rw-r--r--http_response.h6
-rw-r--r--routing.h143
-rw-r--r--unittest.cpp34
9 files changed, 101 insertions, 151 deletions
diff --git a/.gitignore b/.gitignore
index 8245f7c..3f3389f 100644
--- a/.gitignore
+++ b/.gitignore
@@ -22,3 +22,5 @@
example
unittest
+
+*.swp
diff --git a/Makefile b/Makefile
index c5ef90c..d69a960 100644
--- a/Makefile
+++ b/Makefile
@@ -1,6 +1,7 @@
-all: example unittest
-example: example.cpp flask.h http_server.h http_connection.h parser.h http_response.h
- g++ -g -std=c++11 -o example example.cpp http-parser/http_parser.c -pthread -lboost_system -lboost_thread -I http-parser/
+all: example
+# unittest
+example: example.cpp flask.h http_server.h http_connection.h parser.h http_response.h routing.h
+ g++ -g -std=c++1y -o example example.cpp http-parser/http_parser.c -pthread -lboost_system -lboost_thread -I http-parser/
test: example
pkill example || exit 0
./example &
diff --git a/example.cpp b/example.cpp
index 9357967..c518dc4 100644
--- a/example.cpp
+++ b/example.cpp
@@ -2,20 +2,26 @@
#include <iostream>
-flask::Flask app;
-
int main()
{
- app.route("/",
- []{
+ flask::Flask app;
+
+ app.route("/")
+ .name("hello")
+ ([]{
return "Hello World!";
});
- app.route("/about",
- []{
+ app.route("/about")
+ ([]{
return "About Flask example.";
});
+ //app.route("/hello/<int>");
+ //([]{
+ //return "About Flask example.";
+ //});
+
app.port(8080)
.run();
}
diff --git a/example.py b/example.py
index 541f031..1fd8fcd 100644
--- a/example.py
+++ b/example.py
@@ -5,5 +5,15 @@ app = Flask(__name__)
def hello():
return "Hello World!"
+@app.route("/about/<path:path>/hello")
+def hello1(path):
+ return "about1"
+
+@app.route("/about")
+def hello2():
+ return "about2"
+
+print app.url_map
+
if __name__ == "__main__":
- app.run(host="0.0.0.0")
+ app.run(host="0.0.0.0", port=8888)
diff --git a/flask.h b/flask.h
index fd33c61..6d222e0 100644
--- a/flask.h
+++ b/flask.h
@@ -4,9 +4,10 @@
#include <memory>
#include <future>
#include <stdint.h>
+#include <type_traits>
-#include "http_response.h"
#include "http_server.h"
+#include "routing.h"
// TEST
#include <iostream>
@@ -22,20 +23,13 @@ namespace flask
response handle(const request& req)
{
- if (yameHandlers_.count(req.url) == 0)
- {
- return response(404);
- }
- return yameHandlers_[req.url]();
+ return router_.handle(req);
}
- template <typename F>
- void route(const std::string& url, F f)
+ auto route(std::string&& rule)
+ -> typename std::result_of<decltype(&Router::new_rule)(Router, std::string&&)>::type
{
- auto yameHandler = [f = std::move(f)]{
- return response(f());
- };
- yameHandlers_.emplace(url, yameHandler);
+ return router_.new_rule(std::move(rule));
}
Flask& port(std::uint16_t port)
@@ -44,16 +38,21 @@ namespace flask
return *this;
}
+ void validate()
+ {
+ router_.validate();
+ }
+
void run()
{
+ validate();
Server<Flask> server(this, port_);
server.run();
}
private:
uint16_t port_ = 80;
- // Someday I will become real handler!
- std::unordered_map<std::string, std::function<response()>> yameHandlers_;
+ Router router_;
};
};
diff --git a/http_connection.h b/http_connection.h
index 7fd9a43..d5ee1c9 100644
--- a/http_connection.h
+++ b/http_connection.h
@@ -4,6 +4,7 @@
#include <atomic>
#include <boost/asio.hpp>
#include <boost/algorithm/string/predicate.hpp>
+#include <boost/array.hpp>
#include "parser.h"
#include "http_response.h"
@@ -118,7 +119,7 @@ namespace flask
tcp::socket socket_;
Handler* handler_;
- std::array<char, 8192> buffer_;
+ boost::array<char, 8192> buffer_;
HTTPParser<Connection> parser_;
response res;
diff --git a/http_response.h b/http_response.h
index 7927d6d..4f19848 100644
--- a/http_response.h
+++ b/http_response.h
@@ -33,9 +33,7 @@ namespace flask
std::unordered_map<std::string, std::string> headers;
response() {}
response(int status) : status(status) {}
- response(const std::string& body) : body(body) {}
- response(std::string&& body) : body(std::move(body)) {}
- response(const std::string& body, int status) : body(body), status(status) {}
- response(std::string&& body, int status) : body(std::move(body)), status(status) {}
+ response(std::string body) : body(std::move(body)) {}
+ response(std::string body, int status) : body(std::move(body)), status(status) {}
};
}
diff --git a/routing.h b/routing.h
index a150a4e..fe16288 100644
--- a/routing.h
+++ b/routing.h
@@ -5,127 +5,94 @@
#include <string>
#include <tuple>
-#include "utility.h"
+#include "http_response.h"
namespace flask
{
- namespace black_magic
+ class Rule
{
- constexpr bool is_equ_n(const_str a, int ai, const_str b, int bi, int n)
+ public:
+ explicit Rule(std::string&& rule)
+ : rule_(std::move(rule))
{
- return
- ai + n > a.size() || bi + n > b.size()
- ? false :
- n == 0
- ? true :
- a[ai] != b[bi]
- ? false :
- is_equ_n(a,ai+1,b,bi+1,n-1);
}
-
- constexpr bool is_int(const_str s, int i)
+
+ template <typename Func>
+ void operator()(Func&& f)
{
- return is_equ_n(s, i, "<int>", 0, 5);
+ handler_ = [f = std::move(f)]{
+ return response(f());
+ };
}
- constexpr bool is_float(const_str s, int i)
+ template <typename Func>
+ void operator()(std::string&& name, Func&& f)
{
- return is_equ_n(s, i, "<float>", 0, 7) ||
- is_equ_n(s, i, "<double>", 0, 8);
+ name_ = std::move(name);
+ handler_ = [f = std::move(f)]{
+ return response(f());
+ };
}
- constexpr bool is_str(const_str s, int i)
+ bool match(const request& req)
{
- return is_equ_n(s, i, "<str>", 0, 5);
+ // FIXME need url parsing
+ return req.url == rule_;
}
- constexpr bool is_path(const_str s, int i)
+ Rule& name(const std::string& name)
{
- return is_equ_n(s, i, "<path>", 0, 6);
+ name_ = name;
+ return *this;
}
-
- template <typename ...Args>
- struct Caller
+ void validate()
{
- template <typename F>
- void operator()(F f, Args... args)
+ if (!handler_)
{
- f(args...);
+ throw std::runtime_error("no handler for url " + rule_);
}
- };
-
-
- template <int N, typename ... Args> struct S;
- template <int N, typename Arg, typename ... Args> struct S<N, Arg, Args...> {
- static_assert(N <= 4+1, "too many routing arguments (maximum 5)");
- template <typename T>
- using push = typename std::conditional<(N>4), S<N, Arg, Args...>, S<N+1, Arg, Args..., T>>::type;
- using pop = S<N-1, Args...>;
- };
- template <> struct S<0>
- {
- template <typename T>
- using push = S<1, T>;
- };
-
- template <typename F, typename Set>
- struct CallHelper;
- template <typename F, int N, typename ...Args>
- struct CallHelper<F, S<N, Args...>>
- {
- template <typename F1, typename ...Args1, typename =
- decltype(std::declval<F1>()(std::declval<Args1>()...))
- >
- static char __test(int);
-
- template <typename ...>
- static int __test(...);
-
- static constexpr bool value = sizeof(__test<F, Args...>(0)) == sizeof(char);
- };
-
- static_assert(CallHelper<void(), S<0>>::value, "");
- static_assert(CallHelper<void(int), S<1, int>>::value, "");
- static_assert(!CallHelper<void(int), S<0>>::value, "");
- static_assert(!CallHelper<void(int), S<2, int, int>>::value, "");
+ }
- template <typename F,
- typename Set = S<0>>
- constexpr bool validate_helper(const_str rule, unsigned i=0)
+ response handle(const request&)
{
- return
- i == rule.size()
- ? CallHelper<F, Set>::value :
- is_int(rule, i)
- ? validate_helper<F, typename Set::template push<int>>(rule, find_closing_tag(rule, i+1)+1) :
- is_float(rule, i)
- ? validate_helper<F, typename Set::template push<double>>(rule, find_closing_tag(rule, i+1)+1) :
- is_str(rule, i)
- ? validate_helper<F, typename Set::template push<std::string>>(rule, find_closing_tag(rule, i+1)+1) :
- is_path(rule, i)
- ? validate_helper<F, typename Set::template push<std::string>>(rule, find_closing_tag(rule, i+1)+1) :
- validate_helper<F, Set>(rule, i+1)
- ;
+ return handler_();
}
- static_assert(validate_helper<void()>("/"),"");
- static_assert(validate_helper<void(int)>("/<int>"),"");
- static_assert(!validate_helper<void()>("/<int>"),"");
- }
+ private:
+ std::string rule_;
+ std::string name_;
+ std::function<response()> handler_;
+ };
class Router
{
public:
- constexpr Router(black_magic::const_str rule) : rule(rule)
+ Rule& new_rule(std::string&& rule)
+ {
+ rules_.emplace_back(std::move(rule));
+ return rules_.back();
+ }
+
+ void validate()
{
+ for(auto& rule:rules_)
+ {
+ rule.validate();
+ }
}
- template <typename F>
- constexpr bool validate() const
+ response handle(const request& req)
{
- return black_magic::validate_helper<F>(rule);
+ for(auto& rule : rules_)
+ {
+ if (rule.match(req))
+ {
+ return rule.handle(req);
+ }
+ }
+ return response(404);
}
private:
- black_magic::const_str rule;
+ std::vector<Rule> rules_;
};
}
diff --git a/unittest.cpp b/unittest.cpp
index 66c58a0..09718c2 100644
--- a/unittest.cpp
+++ b/unittest.cpp
@@ -1,40 +1,6 @@
#include "routing.h"
#include <functional>
-#include "utility.h"
-
-using namespace flask;
-using namespace flask::black_magic;
-
-template <int N> struct ThrowTest{};
int main()
{
- try
- {
- throw ThrowTest<is_int("1<int>22",0)>();
- }
- catch(ThrowTest<0>)
- {
- }
-
- try
- {
- throw ThrowTest<is_int("1<int>22",1)>();
- }
- catch(ThrowTest<1>)
- {
- }
-
- {
- constexpr Router r = Router("/");
- static_assert(r.validate<void()>(), "Good handler");
- static_assert(!r.validate<void(int)>(), "Bad handler - no int argument");
- }
- {
- constexpr Router r = Router("/blog/<int>");
- static_assert(!r.validate<void()>(), "Bad handler - need argument");
- static_assert(r.validate<void(int)>(), "Good handler");
- static_assert(!r.validate<void(std::string)>(), "Bad handler - int is not convertible to std::string");
- static_assert(r.validate<void(double)>(), "Acceptable handler - int will be converted to double");
- }
}