aboutsummaryrefslogtreecommitdiffstats
path: root/include
diff options
context:
space:
mode:
authorJaeseung Ha <ipknhama@gmail.com>2015-09-20 22:06:00 +0900
committerJaeseung Ha <ipknhama@gmail.com>2015-09-20 22:06:00 +0900
commite4708671bcfd2514edaa1a8e0bd5fa58f00c5fd1 (patch)
treeb47fc83d73c9b6031f75e576e8e633b93eee8901 /include
parent5282c9d4aae7ae1450a76fa29ddf837c8eb2f56d (diff)
downloadcrow-e4708671bcfd2514edaa1a8e0bd5fa58f00c5fd1.tar.gz
crow-e4708671bcfd2514edaa1a8e0bd5fa58f00c5fd1.zip
implement HTTPS support
- define CROW_ENABLE_SSL to use - close #88
Diffstat (limited to 'include')
-rw-r--r--include/crow.h85
-rw-r--r--include/http_connection.h58
-rw-r--r--include/http_response.h4
-rw-r--r--include/http_server.h22
-rw-r--r--include/settings.h3
-rw-r--r--include/socket_adaptors.h98
6 files changed, 237 insertions, 33 deletions
diff --git a/include/crow.h b/include/crow.h
index 3a49e40..ec4c0ee 100644
--- a/include/crow.h
+++ b/include/crow.h
@@ -25,12 +25,18 @@
namespace crow
{
+#ifdef CROW_ENABLE_SSL
+ using ssl_context_t = boost::asio::ssl::context;
+#endif
template <typename ... Middlewares>
class Crow
{
public:
using self_t = Crow;
- using server_t = Server<Crow, Middlewares...>;
+ using server_t = Server<Crow, SocketAdaptor, Middlewares...>;
+#ifdef CROW_ENABLE_SSL
+ using ssl_server_t = Server<Crow, SSLAdaptor, Middlewares...>;
+#endif
Crow()
{
}
@@ -79,8 +85,18 @@ namespace crow
void run()
{
validate();
- server_t server(this, port_, &middlewares_, concurrency_);
- server.run();
+#ifdef CROW_ENABLE_SSL
+ if (use_ssl_)
+ {
+ ssl_server_t server(this, port_, &middlewares_, concurrency_, &ssl_context_);
+ server.run();
+ }
+ else
+#endif
+ {
+ server_t server(this, port_, &middlewares_, concurrency_, nullptr);
+ server.run();
+ }
}
void debug_print()
@@ -89,6 +105,69 @@ namespace crow
router_.debug_print();
}
+#ifdef CROW_ENABLE_SSL
+ self_t& ssl_file(const std::string& crt_filename, const std::string& key_filename)
+ {
+ use_ssl_ = true;
+ ssl_context_.set_verify_mode(boost::asio::ssl::verify_peer);
+ ssl_context_.use_certificate_file(crt_filename, ssl_context_t::pem);
+ ssl_context_.use_private_key_file(key_filename, ssl_context_t::pem);
+ ssl_context_.set_options(
+ boost::asio::ssl::context::default_workarounds
+ | boost::asio::ssl::context::no_sslv2
+ | boost::asio::ssl::context::no_sslv3
+ );
+ return *this;
+ }
+
+ self_t& ssl_file(const std::string& pem_filename)
+ {
+ use_ssl_ = true;
+ ssl_context_.set_verify_mode(boost::asio::ssl::verify_peer);
+ ssl_context_.load_verify_file(pem_filename);
+ ssl_context_.set_options(
+ boost::asio::ssl::context::default_workarounds
+ | boost::asio::ssl::context::no_sslv2
+ | boost::asio::ssl::context::no_sslv3
+ );
+ return *this;
+ }
+
+ self_t& ssl(boost::asio::ssl::context&& ctx)
+ {
+ use_ssl_ = true;
+ ssl_context_ = std::move(ctx);
+ return *this;
+ }
+
+
+ bool use_ssl_{false};
+ ssl_context_t ssl_context_{boost::asio::ssl::context::sslv23};
+
+#else
+ template <typename T, typename ... Remain>
+ self_t& ssl_file(T&& t, Remain&&...)
+ {
+ // We can't call .ssl() member function unless CROW_ENABLE_SSL is defined.
+ static_assert(
+ // make static_assert dependent to T; always false
+ std::is_base_of<T, void>::value,
+ "Define CROW_ENABLE_SSL to enable ssl support.");
+ return *this;
+ }
+
+ template <typename T>
+ self_t& ssl(T&& ctx)
+ {
+ // We can't call .ssl() member function unless CROW_ENABLE_SSL is defined.
+ static_assert(
+ // make static_assert dependent to T; always false
+ std::is_base_of<T, void>::value,
+ "Define CROW_ENABLE_SSL to enable ssl support.");
+ return *this;
+ }
+#endif
+
// middleware
using context_t = detail::context<Middlewares...>;
template <typename T>
diff --git a/include/http_connection.h b/include/http_connection.h
index b1157a9..3d516a9 100644
--- a/include/http_connection.h
+++ b/include/http_connection.h
@@ -15,9 +15,13 @@
#include "settings.h"
#include "dumb_timer_queue.h"
#include "middleware_context.h"
+#include "socket_adaptors.h"
namespace crow
{
+ using namespace boost;
+ using tcp = asio::ip::tcp;
+
namespace detail
{
template <typename MW>
@@ -171,12 +175,10 @@ namespace crow
}
}
- using namespace boost;
- using tcp = asio::ip::tcp;
#ifdef CROW_ENABLE_DEBUG
static int connectionCount;
#endif
- template <typename Handler, typename ... Middlewares>
+ template <typename Adaptor, typename Handler, typename ... Middlewares>
class Connection
{
public:
@@ -186,9 +188,10 @@ namespace crow
const std::string& server_name,
std::tuple<Middlewares...>* middlewares,
std::function<std::string()>& get_cached_date_str_f,
- detail::dumb_timer_queue& timer_queue
+ detail::dumb_timer_queue& timer_queue,
+ typename Adaptor::context* adaptor_ctx_
)
- : socket_(io_service),
+ : adaptor_(io_service, adaptor_ctx_),
handler_(handler),
parser_(this),
server_name_(server_name),
@@ -212,17 +215,25 @@ namespace crow
#endif
}
- tcp::socket& socket()
+ decltype(std::declval<Adaptor>().raw_socket())& socket()
{
- return socket_;
+ return adaptor_.raw_socket();
}
void start()
{
- //auto self = this->shared_from_this();
- start_deadline();
+ adaptor_.start([this](const boost::system::error_code& ec) {
+ if (!ec)
+ {
+ start_deadline();
- do_read();
+ do_read();
+ }
+ else
+ {
+ check_destroy();
+ }
+ });
}
void handle_header()
@@ -273,7 +284,7 @@ namespace crow
}
}
- CROW_LOG_INFO << "Request: " << boost::lexical_cast<std::string>(socket_.remote_endpoint()) << " " << this << " HTTP/" << parser_.http_major << "." << parser_.http_minor << ' '
+ CROW_LOG_INFO << "Request: " << boost::lexical_cast<std::string>(adaptor_.remote_endpoint()) << " " << this << " HTTP/" << parser_.http_major << "." << parser_.http_minor << ' '
<< method_name(req.method) << " " << req.url;
@@ -281,7 +292,7 @@ namespace crow
if (!is_invalid_request)
{
res.complete_request_handler_ = []{};
- res.is_alive_helper_ = [this]()->bool{ return socket_.is_open(); };
+ res.is_alive_helper_ = [this]()->bool{ return adaptor_.is_open(); };
ctx_ = detail::context<Middlewares...>();
req.middleware_context = (void*)&ctx_;
@@ -325,7 +336,7 @@ namespace crow
//auto self = this->shared_from_this();
res.complete_request_handler_ = nullptr;
- if (!socket_.is_open())
+ if (!adaptor_.is_open())
{
//CROW_LOG_DEBUG << this << " delete (socket is closed) " << is_reading << ' ' << is_writing;
//delete this;
@@ -415,7 +426,8 @@ namespace crow
}
buffers_.emplace_back(crlf.data(), crlf.size());
- buffers_.emplace_back(res.body.data(), res.body.size());
+ res_body_copy_.swap(res.body);
+ buffers_.emplace_back(res_body_copy_.data(), res_body_copy_.size());
do_write();
res.clear();
@@ -433,14 +445,14 @@ namespace crow
{
//auto self = this->shared_from_this();
is_reading = true;
- socket_.async_read_some(boost::asio::buffer(buffer_),
+ adaptor_.socket().async_read_some(boost::asio::buffer(buffer_),
[this](const boost::system::error_code& ec, std::size_t bytes_transferred)
{
bool error_while_reading = true;
if (!ec)
{
bool ret = parser_.feed(buffer_.data(), bytes_transferred);
- if (ret && socket_.is_open() && !close_connection_)
+ if (ret && adaptor_.is_open() && !close_connection_)
{
error_while_reading = false;
}
@@ -450,7 +462,7 @@ namespace crow
{
cancel_deadline_timer();
parser_.done();
- socket_.close();
+ adaptor_.close();
is_reading = false;
CROW_LOG_DEBUG << this << " from read(1)";
check_destroy();
@@ -472,15 +484,16 @@ namespace crow
{
//auto self = this->shared_from_this();
is_writing = true;
- boost::asio::async_write(socket_, buffers_,
+ boost::asio::async_write(adaptor_.socket(), buffers_,
[&](const boost::system::error_code& ec, std::size_t bytes_transferred)
{
is_writing = false;
+ res_body_copy_.clear();
if (!ec)
{
if (close_connection_)
{
- socket_.close();
+ adaptor_.close();
CROW_LOG_DEBUG << this << " from write(1)";
check_destroy();
}
@@ -515,17 +528,17 @@ namespace crow
timer_cancel_key_ = timer_queue.add([this]
{
- if (!socket_.is_open())
+ if (!adaptor_.is_open())
{
return;
}
- socket_.close();
+ adaptor_.close();
});
CROW_LOG_DEBUG << this << " timer added: " << timer_cancel_key_.first << ' ' << timer_cancel_key_.second;
}
private:
- tcp::socket socket_;
+ Adaptor adaptor_;
Handler* handler_;
boost::array<char, 4096> buffer_;
@@ -541,6 +554,7 @@ namespace crow
std::string content_length_;
std::string date_str_;
+ std::string res_body_copy_;
//boost::asio::deadline_timer deadline_;
detail::dumb_timer_queue::key timer_cancel_key_;
diff --git a/include/http_response.h b/include/http_response.h
index c84856b..0ce2916 100644
--- a/include/http_response.h
+++ b/include/http_response.h
@@ -7,11 +7,11 @@
namespace crow
{
- template <typename Handler, typename ... Middlewares>
+ template <typename Adaptor, typename Handler, typename ... Middlewares>
class Connection;
struct response
{
- template <typename Handler, typename ... Middlewares>
+ template <typename Adaptor, typename Handler, typename ... Middlewares>
friend class crow::Connection;
std::string body;
diff --git a/include/http_server.h b/include/http_server.h
index 143b58d..80ef7a4 100644
--- a/include/http_server.h
+++ b/include/http_server.h
@@ -2,6 +2,9 @@
#include <boost/date_time/posix_time/posix_time.hpp>
#include <boost/asio.hpp>
+#ifdef CROW_ENABLE_SSL
+#include <boost/asio/ssl.hpp>
+#endif
#include <cstdint>
#include <atomic>
#include <future>
@@ -18,17 +21,18 @@ namespace crow
using namespace boost;
using tcp = asio::ip::tcp;
- template <typename Handler, typename ... Middlewares>
+ template <typename Handler, typename Adaptor = SocketAdaptor, typename ... Middlewares>
class Server
{
public:
- Server(Handler* handler, uint16_t port, std::tuple<Middlewares...>* middlewares = nullptr, uint16_t concurrency = 1)
+ Server(Handler* handler, uint16_t port, std::tuple<Middlewares...>* middlewares = nullptr, uint16_t concurrency = 1, typename Adaptor::context* adaptor_ctx = nullptr)
: acceptor_(io_service_, tcp::endpoint(asio::ip::address(), port)),
signals_(io_service_, SIGINT, SIGTERM),
handler_(handler),
concurrency_(concurrency),
port_(port),
- middlewares_(middlewares)
+ middlewares_(middlewares),
+ adaptor_ctx_(adaptor_ctx)
{
}
@@ -137,10 +141,10 @@ namespace crow
void do_accept()
{
asio::io_service& is = pick_io_service();
- auto p = new Connection<Handler, Middlewares...>(
+ auto p = new Connection<Adaptor, Handler, Middlewares...>(
is, handler_, server_name_, middlewares_,
- get_cached_date_str_pool_[roundrobin_index_], *timer_queue_pool_[roundrobin_index_]
- );
+ get_cached_date_str_pool_[roundrobin_index_], *timer_queue_pool_[roundrobin_index_],
+ adaptor_ctx_);
acceptor_.async_accept(p->socket(),
[this, p, &is](boost::system::error_code ec)
{
@@ -170,5 +174,11 @@ namespace crow
unsigned int roundrobin_index_{};
std::tuple<Middlewares...>* middlewares_;
+
+#ifdef CROW_ENABLE_SSL
+ bool use_ssl_{false};
+ boost::asio::ssl::context ssl_context_{boost::asio::ssl::context::sslv23};
+#endif
+ typename Adaptor::context* adaptor_ctx_;
};
}
diff --git a/include/settings.h b/include/settings.h
index 31a39e3..fc9392c 100644
--- a/include/settings.h
+++ b/include/settings.h
@@ -8,6 +8,9 @@
/* #ifdef - enables logging */
#define CROW_ENABLE_LOGGING
+/* #ifdef - enables SSL */
+//#define CROW_ENABLE_SSL
+
/* #define - specifies log level */
/*
DEBUG = 0
diff --git a/include/socket_adaptors.h b/include/socket_adaptors.h
new file mode 100644
index 0000000..201360c
--- /dev/null
+++ b/include/socket_adaptors.h
@@ -0,0 +1,98 @@
+#pragma once
+#include <boost/asio.hpp>
+#include "settings.h"
+namespace crow
+{
+ using namespace boost;
+ using tcp = asio::ip::tcp;
+
+ struct SocketAdaptor
+ {
+ using context = void;
+ SocketAdaptor(boost::asio::io_service& io_service, context*)
+ : socket_(io_service)
+ {
+ }
+
+ tcp::socket& raw_socket()
+ {
+ return socket_;
+ }
+
+ tcp::socket& socket()
+ {
+ return socket_;
+ }
+
+ tcp::endpoint remote_endpoint()
+ {
+ return socket_.remote_endpoint();
+ }
+
+ bool is_open()
+ {
+ return socket_.is_open();
+ }
+
+ void close()
+ {
+ socket_.close();
+ }
+
+ template <typename F>
+ void start(F f)
+ {
+ f(boost::system::error_code());
+ }
+
+ tcp::socket socket_;
+ };
+
+#ifdef CROW_ENABLE_SSL
+ struct SSLAdaptor
+ {
+ using context = boost::asio::ssl::context;
+ SSLAdaptor(boost::asio::io_service& io_service, context* ctx)
+ : ssl_socket_(io_service, *ctx)
+ {
+ }
+
+ boost::asio::ssl::stream<tcp::socket>& socket()
+ {
+ return ssl_socket_;
+ }
+
+ tcp::socket::lowest_layer_type&
+ raw_socket()
+ {
+ return ssl_socket_.lowest_layer();
+ }
+
+ tcp::endpoint remote_endpoint()
+ {
+ return raw_socket().remote_endpoint();
+ }
+
+ bool is_open()
+ {
+ return raw_socket().is_open();
+ }
+
+ void close()
+ {
+ raw_socket().close();
+ }
+
+ template <typename F>
+ void start(F f)
+ {
+ ssl_socket_.async_handshake(boost::asio::ssl::stream_base::server,
+ [f](const boost::system::error_code& ec) {
+ f(ec);
+ });
+ }
+
+ boost::asio::ssl::stream<tcp::socket> ssl_socket_;
+ };
+#endif
+}