From b33c7a4f2957d4468afc1e7c4463189e180c8daa Mon Sep 17 00:00:00 2001 From: ipknHama Date: Thu, 10 Apr 2014 08:17:08 +0900 Subject: removing black magic; merging router with app --- .gitignore | 2 + Makefile | 7 +-- example.cpp | 18 ++++--- example.py | 12 ++++- flask.h | 27 +++++------ http_connection.h | 3 +- http_response.h | 6 +-- routing.h | 143 +++++++++++++++++++++--------------------------------- unittest.cpp | 34 ------------- 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 -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/"); + //([]{ + //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//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 #include #include +#include -#include "http_response.h" #include "http_server.h" +#include "routing.h" // TEST #include @@ -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 - void route(const std::string& url, F f) + auto route(std::string&& rule) + -> typename std::result_of::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 server(this, port_); server.run(); } private: uint16_t port_ = 80; - // Someday I will become real handler! - std::unordered_map> 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 #include #include +#include #include "parser.h" #include "http_response.h" @@ -118,7 +119,7 @@ namespace flask tcp::socket socket_; Handler* handler_; - std::array buffer_; + boost::array buffer_; HTTPParser 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 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 #include -#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 + void operator()(Func&& f) { - return is_equ_n(s, i, "", 0, 5); + handler_ = [f = std::move(f)]{ + return response(f()); + }; } - constexpr bool is_float(const_str s, int i) + template + void operator()(std::string&& name, Func&& f) { - return is_equ_n(s, i, "", 0, 7) || - is_equ_n(s, i, "", 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, "", 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, "", 0, 6); + name_ = name; + return *this; } - - template - struct Caller + void validate() { - template - void operator()(F f, Args... args) + if (!handler_) { - f(args...); + throw std::runtime_error("no handler for url " + rule_); } - }; - - - template struct S; - template struct S { - static_assert(N <= 4+1, "too many routing arguments (maximum 5)"); - template - using push = typename std::conditional<(N>4), S, S>::type; - using pop = S; - }; - template <> struct S<0> - { - template - using push = S<1, T>; - }; - - template - struct CallHelper; - template - struct CallHelper> - { - template ()(std::declval()...)) - > - static char __test(int); - - template - static int __test(...); - - static constexpr bool value = sizeof(__test(0)) == sizeof(char); - }; - - static_assert(CallHelper>::value, ""); - static_assert(CallHelper>::value, ""); - static_assert(!CallHelper>::value, ""); - static_assert(!CallHelper>::value, ""); + } - template > - constexpr bool validate_helper(const_str rule, unsigned i=0) + response handle(const request&) { - return - i == rule.size() - ? CallHelper::value : - is_int(rule, i) - ? validate_helper>(rule, find_closing_tag(rule, i+1)+1) : - is_float(rule, i) - ? validate_helper>(rule, find_closing_tag(rule, i+1)+1) : - is_str(rule, i) - ? validate_helper>(rule, find_closing_tag(rule, i+1)+1) : - is_path(rule, i) - ? validate_helper>(rule, find_closing_tag(rule, i+1)+1) : - validate_helper(rule, i+1) - ; + return handler_(); } - static_assert(validate_helper("/"),""); - static_assert(validate_helper("/"),""); - static_assert(!validate_helper("/"),""); - } + private: + std::string rule_; + std::string name_; + std::function 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 - constexpr bool validate() const + response handle(const request& req) { - return black_magic::validate_helper(rule); + for(auto& rule : rules_) + { + if (rule.match(req)) + { + return rule.handle(req); + } + } + return response(404); } private: - black_magic::const_str rule; + std::vector 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 -#include "utility.h" - -using namespace flask; -using namespace flask::black_magic; - -template struct ThrowTest{}; int main() { - try - { - throw ThrowTest22",0)>(); - } - catch(ThrowTest<0>) - { - } - - try - { - throw ThrowTest22",1)>(); - } - catch(ThrowTest<1>) - { - } - - { - constexpr Router r = Router("/"); - static_assert(r.validate(), "Good handler"); - static_assert(!r.validate(), "Bad handler - no int argument"); - } - { - constexpr Router r = Router("/blog/"); - static_assert(!r.validate(), "Bad handler - need argument"); - static_assert(r.validate(), "Good handler"); - static_assert(!r.validate(), "Bad handler - int is not convertible to std::string"); - static_assert(r.validate(), "Acceptable handler - int will be converted to double"); - } } -- cgit v1.2.3-54-g00ecf