aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Makefile2
-rw-r--r--example.cpp12
-rw-r--r--flask.h17
-rw-r--r--http_connection.h60
-rw-r--r--http_server.h14
5 files changed, 83 insertions, 22 deletions
diff --git a/Makefile b/Makefile
index ff23cb6..ad6dcf2 100644
--- a/Makefile
+++ b/Makefile
@@ -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();
}
diff --git a/flask.h b/flask.h
index ddc91e8..cf1d9d6 100644
--- a/flask.h
+++ b/flask.h
@@ -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";
};
}