#pragma once #include #include #include #include #include #include #include "parser.h" #include "http_response.h" namespace flask { using namespace boost; using tcp = asio::ip::tcp; template class Connection { public: Connection(tcp::socket&& socket, Handler* handler) : socket_(std::move(socket)), handler_(handler), parser_(this) { } void start() { do_read(); } void handle() { request req = parser_.to_request(); res = handler_->handle(req); static std::string seperator = ": "; static std::string crlf = "\r\n"; std::vector buffers; buffers.push_back(boost::asio::buffer(statusCodes[res.status])); bool has_content_length = 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)); if (boost::iequals(kv.first, "content-length")) has_content_length = true; } if (!has_content_length) close_connection_ = true; buffers.push_back(boost::asio::buffer(crlf)); buffers.push_back(boost::asio::buffer(res.body)); do_write(buffers); } private: void do_read() { life_++; socket_.async_read_some(boost::asio::buffer(buffer_), [this](boost::system::error_code ec, std::size_t bytes_transferred) { if (!ec) { bool ret = parser_.feed(buffer_.data(), bytes_transferred); do_read(); } else { bool ret = parser_.done(); socket_.close(); life_--; if ((int)life_ == 0) { delete this; } } }); } void do_write(const std::vector& buffers) { life_++; boost::asio::async_write(socket_, buffers, [this](const boost::system::error_code& ec, std::size_t bytes_transferred) { bool should_close = false; if (!ec) { if (close_connection_) { should_close = true; } } else { should_close = true; } if (should_close) { socket_.close(); life_--; if ((int)life_ == 0) { delete this; } } }); } private: tcp::socket socket_; Handler* handler_; boost::array buffer_; HTTPParser parser_; response res; std::atomic life_; bool close_connection_ = false; }; }