diff options
-rw-r--r-- | Makefile | 2 | ||||
-rw-r--r-- | example.cpp | 12 | ||||
-rw-r--r-- | flask.h | 17 | ||||
-rw-r--r-- | http_connection.h | 60 | ||||
-rw-r--r-- | http_server.h | 14 |
5 files changed, 83 insertions, 22 deletions
@@ -1,6 +1,6 @@ all: covtest example example: example.cpp flask.h http_server.h http_connection.h parser.h http_response.h routing.h common.h utility.h - g++ -Wall -g -O2 -std=c++11 -o example example.cpp http-parser/http_parser.c -pthread -lboost_system -lboost_thread -I http-parser/ + g++ -Wall -g -O3 -std=c++11 -o example example.cpp http-parser/http_parser.c -pthread -lboost_system -lboost_thread -I http-parser/ test: covtest diff --git a/example.cpp b/example.cpp index 2b2e268..54efccf 100644 --- a/example.cpp +++ b/example.cpp @@ -7,11 +7,16 @@ int main() flask::Flask app; FLASK_ROUTE(app, "/") - .name("hello") + .name("hello") ([]{ return "Hello World!"; }); + FLASK_ROUTE(app, "/json") + ([]{ + return "{\"message\":\"Hello, World!\"}"; + }); + FLASK_ROUTE(app, "/about") ([](){ return "About Flask example."; @@ -32,6 +37,7 @@ int main() //return flask::response(500); //}); - app.port(8080) - .run(); + app.port(18080) + .multithreaded() + .run(); } @@ -5,6 +5,7 @@ #include <future> #include <stdint.h> #include <type_traits> +#include <thread> #include "http_server.h" #include "utility.h" @@ -48,6 +49,19 @@ namespace flask return *this; } + Flask& multithreaded() + { + return concurrency(std::thread::hardware_concurrency()); + } + + Flask& concurrency(std::uint16_t concurrency) + { + if (concurrency < 1) + concurrency = 1; + concurrency_ = concurrency; + return *this; + } + void validate() { router_.validate(); @@ -56,7 +70,7 @@ namespace flask void run() { validate(); - Server<Flask> server(this, port_); + Server<Flask> server(this, port_, concurrency_); server.run(); } void debug_print() @@ -67,6 +81,7 @@ namespace flask private: uint16_t port_ = 80; + uint16_t concurrency_ = 1; Router router_; }; diff --git a/http_connection.h b/http_connection.h index f248907..a1a810c 100644 --- a/http_connection.h +++ b/http_connection.h @@ -5,6 +5,7 @@ #include <boost/asio.hpp> #include <boost/algorithm/string/predicate.hpp> #include <boost/array.hpp> +#include <boost/lexical_cast.hpp> #include "parser.h" #include "http_response.h" @@ -17,7 +18,7 @@ namespace flask class Connection { public: - Connection(tcp::socket&& socket, Handler* handler) : socket_(std::move(socket)), handler_(handler), parser_(this) + Connection(tcp::socket&& socket, Handler* handler, const std::string& server_name) : socket_(std::move(socket)), handler_(handler), parser_(this), server_name_(server_name) { } @@ -34,32 +35,62 @@ namespace flask static std::string seperator = ": "; static std::string crlf = "\r\n"; - std::vector<boost::asio::const_buffer> buffers; + buffers_.clear(); + buffers_.reserve(4*(res.headers.size()+4)+3); - buffers.push_back(boost::asio::buffer(statusCodes[res.code])); + if (!statusCodes.count(res.code)) + res.code = 500; + { + auto& status = statusCodes.find(res.code)->second; + buffers_.emplace_back(status.data(), status.size()); + } if (res.code > 400 && res.body.empty()) res.body = statusCodes[res.code].substr(9); bool has_content_length = false; + bool has_date = false; + bool has_server = false; + for(auto& kv : res.headers) { - buffers.push_back(boost::asio::buffer(kv.first)); - buffers.push_back(boost::asio::buffer(seperator)); - buffers.push_back(boost::asio::buffer(kv.second)); - buffers.push_back(boost::asio::buffer(crlf)); + buffers_.emplace_back(kv.first.data(), kv.first.size()); + buffers_.emplace_back(seperator.data(), seperator.size()); + buffers_.emplace_back(kv.second.data(), kv.second.size()); + buffers_.emplace_back(crlf.data(), crlf.size()); if (boost::iequals(kv.first, "content-length")) has_content_length = true; + if (boost::iequals(kv.first, "date")) + has_date = true; + if (boost::iequals(kv.first, "server")) + has_server = true; } if (!has_content_length) - close_connection_ = true; + { + auto ret = res.headers.emplace("Content-Length", boost::lexical_cast<std::string>(res.body.size())); + buffers_.emplace_back(ret.first->first.data(), ret.first->first.size()); + buffers_.emplace_back(seperator.data(), seperator.size()); + buffers_.emplace_back(ret.first->second.data(), ret.first->second.size()); + buffers_.emplace_back(crlf.data(), crlf.size()); + } + if (!has_server) + { + auto ret = res.headers.emplace("Server", server_name_); + buffers_.emplace_back(ret.first->first.data(), ret.first->first.size()); + buffers_.emplace_back(seperator.data(), seperator.size()); + buffers_.emplace_back(ret.first->second.data(), ret.first->second.size()); + buffers_.emplace_back(crlf.data(), crlf.size()); + } + if (!has_date) + { + } - buffers.push_back(boost::asio::buffer(crlf)); - buffers.push_back(boost::asio::buffer(res.body)); + buffers_.emplace_back(crlf.data(), crlf.size()); + buffers_.emplace_back(res.body.data(), res.body.size()); - do_write(buffers); + do_write(); } private: @@ -99,10 +130,10 @@ namespace flask }); } - void do_write(const std::vector<boost::asio::const_buffer>& buffers) + void do_write() { life_++; - boost::asio::async_write(socket_, buffers, + boost::asio::async_write(socket_, buffers_, [this](const boost::system::error_code& ec, std::size_t bytes_transferred) { bool should_close = false; @@ -140,5 +171,8 @@ namespace flask std::atomic<int> life_; bool close_connection_ = false; + + const std::string& server_name_; + std::vector<boost::asio::const_buffer> buffers_; }; } diff --git a/http_server.h b/http_server.h index 64dff94..10e335b 100644 --- a/http_server.h +++ b/http_server.h @@ -16,15 +16,19 @@ namespace flask class Server { public: - Server(Handler* handler, uint16_t port) - : acceptor_(io_service_, tcp::endpoint(asio::ip::address(), port)), socket_(io_service_), handler_(handler) + Server(Handler* handler, uint16_t port, uint16_t concurrency = 1) + : acceptor_(io_service_, tcp::endpoint(asio::ip::address(), port)), socket_(io_service_), handler_(handler), concurrency_(concurrency) { do_accept(); } void run() { - auto _ = std::async(std::launch::async, [this]{io_service_.run();}); + std::vector<std::future<void>> v; + for(uint16_t i = 0; i < concurrency_; i ++) + v.push_back( + std::async(std::launch::async, [this]{io_service_.run();}) + ); } void stop() @@ -39,7 +43,7 @@ namespace flask [this](boost::system::error_code ec) { if (!ec) - (new Connection<Handler>(std::move(socket_), handler_))->start(); + (new Connection<Handler>(std::move(socket_), handler_, server_name_))->start(); do_accept(); }); } @@ -49,5 +53,7 @@ namespace flask tcp::acceptor acceptor_; tcp::socket socket_; Handler* handler_; + uint16_t concurrency_ = 1; + std::string server_name_ = "Flask++/0.1"; }; } |