diff --git a/client_http.hpp b/client_http.hpp index baece6f5..e9b62291 100644 --- a/client_http.hpp +++ b/client_http.hpp @@ -8,6 +8,8 @@ #include #include +; // <- libclang bug workaround + #ifdef USE_STANDALONE_ASIO #include #include @@ -33,14 +35,11 @@ namespace SimpleWeb { #endif namespace SimpleWeb { - template - class Client; - - template class ClientBase { public: + class Response; class Content : public std::istream { - friend class ClientBase; + friend class Response; public: std::size_t size() noexcept { @@ -64,8 +63,10 @@ namespace SimpleWeb { }; class Response { - friend class ClientBase; - friend class Client; + template + friend class ClientTemplate; + template + friend class Client; asio::streambuf streambuf; @@ -80,7 +81,7 @@ namespace SimpleWeb { }; class Config { - friend class ClientBase; + friend class ClientBase; private: Config() noexcept {} @@ -97,66 +98,54 @@ namespace SimpleWeb { std::string proxy_server; }; - protected: - class Connection : public std::enable_shared_from_this { - public: - template - Connection(std::shared_ptr handler_runner, long timeout, Args &&... args) noexcept - : handler_runner(std::move(handler_runner)), timeout(timeout), socket(new socket_type(std::forward(args)...)) {} - - std::shared_ptr handler_runner; - long timeout; - - std::unique_ptr socket; // Socket must be unique_ptr since asio::ssl::stream is not movable - bool in_use = false; - bool attempt_reconnect = true; + /// Set before calling request + Config config; - std::unique_ptr timer; + /// If you have your own asio::io_service, store its pointer here before calling request(). + /// When using asynchronous requests, running the io_service is up to the programmer. + std::shared_ptr io_service; - void set_timeout(long seconds = 0) noexcept { - if(seconds == 0) - seconds = timeout; - if(seconds == 0) { - timer = nullptr; - return; - } - timer = std::unique_ptr(new asio::steady_timer(socket->get_io_service())); - timer->expires_from_now(std::chrono::seconds(seconds)); - auto self = this->shared_from_this(); - timer->async_wait([self](const error_code &ec) { - if(!ec) { - error_code ec; - self->socket->lowest_layer().cancel(ec); - } - }); - } + ClientBase(const std::string &host_port, unsigned short default_port) : default_port(default_port) { + auto parsed_host_port = parse_host_port(host_port, default_port); + host = parsed_host_port.first; + port = parsed_host_port.second; + } - void cancel_timeout() noexcept { - if(timer) { - error_code ec; - timer->cancel(ec); - } - } - }; + /// Asynchronous request where setting and/or running Client's io_service is required. + /// Do not use concurrently with the synchronous request functions. + virtual void request(const std::string &method, const std::string &path, string_view content, const CaseInsensitiveMultimap &header, + std::function, const error_code &)> &&request_callback_) = 0; + /// Asynchronous request where setting and/or running Client's io_service is required. + /// Do not use concurrently with the synchronous request functions. + virtual void request(const std::string &method, const std::string &path, std::istream &content, const CaseInsensitiveMultimap &header, + std::function, const error_code &)> &&request_callback_) = 0; - class Session { - public: - Session(std::size_t max_response_streambuf_size, std::shared_ptr connection, std::unique_ptr request_streambuf) noexcept - : connection(std::move(connection)), request_streambuf(std::move(request_streambuf)), response(new Response(max_response_streambuf_size)) {} + /// Asynchronous request where setting and/or running Client's io_service is required. + /// Do not use concurrently with the synchronous request functions. + void request(const std::string &method, const std::string &path, string_view content, + std::function, const error_code &)> &&request_callback) { + request(method, path, content, CaseInsensitiveMultimap(), std::move(request_callback)); + } - std::shared_ptr connection; - std::unique_ptr request_streambuf; - std::shared_ptr response; - std::function &, const error_code &)> callback; - }; + /// Asynchronous request where setting and/or running Client's io_service is required. + /// Do not use concurrently with the synchronous request functions. + void request(const std::string &method, const std::string &path, + std::function, const error_code &)> &&request_callback) { + request(method, path, std::string(), CaseInsensitiveMultimap(), std::move(request_callback)); + } - public: - /// Set before calling request - Config config; + /// Asynchronous request where setting and/or running Client's io_service is required. + /// Do not use concurrently with the synchronous request functions. + void request(const std::string &method, std::function, const error_code &)> &&request_callback) { + request(method, std::string("/"), std::string(), CaseInsensitiveMultimap(), std::move(request_callback)); + } - /// If you have your own asio::io_service, store its pointer here before calling request(). - /// When using asynchronous requests, running the io_service is up to the programmer. - std::shared_ptr io_service; + /// Asynchronous request where setting and/or running Client's io_service is required. + /// Do not use concurrently with the synchronous request functions. + void request(const std::string &method, const std::string &path, std::istream &content, + std::function, const error_code &)> &&request_callback) { + request(method, path, content, CaseInsensitiveMultimap(), std::move(request_callback)); + } /// Convenience function to perform synchronous request. The io_service is run within this function. /// If reusing the io_service for other tasks, use the asynchronous request functions instead. @@ -218,10 +207,100 @@ namespace SimpleWeb { return response; } + /// Close connections + virtual void stop() noexcept = 0; + + virtual ~ClientBase() {} + + protected: + bool internal_io_service = false; + + std::string host; + unsigned short port; + unsigned short default_port; + + std::unique_ptr query; + + std::size_t concurrent_synchronous_requests = 0; + std::mutex concurrent_synchronous_requests_mutex; + + std::pair parse_host_port(const std::string &host_port, unsigned short default_port) const noexcept { + std::pair parsed_host_port; + std::size_t host_end = host_port.find(':'); + if(host_end == std::string::npos) { + parsed_host_port.first = host_port; + parsed_host_port.second = default_port; + } + else { + parsed_host_port.first = host_port.substr(0, host_end); + parsed_host_port.second = static_cast(stoul(host_port.substr(host_end + 1))); + } + return parsed_host_port; + } + }; + + template + class ClientTemplate : public ClientBase { + protected: + class Connection : public std::enable_shared_from_this { + public: + template + Connection(std::shared_ptr handler_runner, long timeout, Args &&... args) noexcept + : handler_runner(std::move(handler_runner)), timeout(timeout), socket(new SocketType(std::forward(args)...)) {} + + std::shared_ptr handler_runner; + long timeout; + + std::unique_ptr socket; // Socket must be unique_ptr since asio::ssl::stream is not movable + bool in_use = false; + bool attempt_reconnect = true; + + std::unique_ptr timer; + + void set_timeout(long seconds = 0) noexcept { + if(seconds == 0) + seconds = timeout; + if(seconds == 0) { + timer = nullptr; + return; + } + timer = std::unique_ptr(new asio::steady_timer(socket->get_io_service())); + timer->expires_from_now(std::chrono::seconds(seconds)); + auto self = this->shared_from_this(); + timer->async_wait([self](const error_code &ec) { + if(!ec) { + error_code ec; + self->socket->lowest_layer().cancel(ec); + } + }); + } + + void cancel_timeout() noexcept { + if(timer) { + error_code ec; + timer->cancel(ec); + } + } + }; + + class Session { + public: + Session(std::size_t max_response_streambuf_size, std::shared_ptr connection, std::unique_ptr request_streambuf) noexcept + : connection(std::move(connection)), request_streambuf(std::move(request_streambuf)), response(new Response(max_response_streambuf_size)) {} + + std::shared_ptr connection; + std::unique_ptr request_streambuf; + std::shared_ptr response; + std::function &, const error_code &)> callback; + }; + + public: + using ClientBase::request; + /// Asynchronous request where setting and/or running Client's io_service is required. /// Do not use concurrently with the synchronous request functions. void request(const std::string &method, const std::string &path, string_view content, const CaseInsensitiveMultimap &header, - std::function, const error_code &)> &&request_callback_) { + std::function, const error_code &)> &&request_callback_) override { auto session = std::make_shared(config.max_response_streambuf_size, get_connection(), create_request_header(method, path, header)); auto response = session->response; auto request_callback = std::make_shared, const error_code &)>>(std::move(request_callback_)); @@ -268,25 +347,8 @@ namespace SimpleWeb { /// Asynchronous request where setting and/or running Client's io_service is required. /// Do not use concurrently with the synchronous request functions. - void request(const std::string &method, const std::string &path, string_view content, - std::function, const error_code &)> &&request_callback) { - request(method, path, content, CaseInsensitiveMultimap(), std::move(request_callback)); - } - - /// Asynchronous request where setting and/or running Client's io_service is required. - void request(const std::string &method, const std::string &path, - std::function, const error_code &)> &&request_callback) { - request(method, path, std::string(), CaseInsensitiveMultimap(), std::move(request_callback)); - } - - /// Asynchronous request where setting and/or running Client's io_service is required. - void request(const std::string &method, std::function, const error_code &)> &&request_callback) { - request(method, std::string("/"), std::string(), CaseInsensitiveMultimap(), std::move(request_callback)); - } - - /// Asynchronous request where setting and/or running Client's io_service is required. void request(const std::string &method, const std::string &path, std::istream &content, const CaseInsensitiveMultimap &header, - std::function, const error_code &)> &&request_callback_) { + std::function, const error_code &)> &&request_callback_) override { auto session = std::make_shared(config.max_response_streambuf_size, get_connection(), create_request_header(method, path, header)); auto response = session->response; auto request_callback = std::make_shared, const error_code &)>>(std::move(request_callback_)); @@ -335,14 +397,8 @@ namespace SimpleWeb { connect(session); } - /// Asynchronous request where setting and/or running Client's io_service is required. - void request(const std::string &method, const std::string &path, std::istream &content, - std::function, const error_code &)> &&request_callback) { - request(method, path, content, CaseInsensitiveMultimap(), std::move(request_callback)); - } - /// Close connections - void stop() noexcept { + void stop() noexcept override { std::unique_lock lock(connections_mutex); for(auto it = connections.begin(); it != connections.end();) { error_code ec; @@ -351,33 +407,18 @@ namespace SimpleWeb { } } - virtual ~ClientBase() noexcept { + ~ClientTemplate() { handler_runner->stop(); stop(); } protected: - bool internal_io_service = false; - - std::string host; - unsigned short port; - unsigned short default_port; - - std::unique_ptr query; - std::unordered_set> connections; std::mutex connections_mutex; std::shared_ptr handler_runner; - std::size_t concurrent_synchronous_requests = 0; - std::mutex concurrent_synchronous_requests_mutex; - - ClientBase(const std::string &host_port, unsigned short default_port) noexcept : default_port(default_port), handler_runner(new ScopeRunner()) { - auto parsed_host_port = parse_host_port(host_port, default_port); - host = parsed_host_port.first; - port = parsed_host_port.second; - } + ClientTemplate(const std::string &host_port, unsigned short default_port) noexcept : ClientBase(host_port, default_port), handler_runner(new ScopeRunner()) {} std::shared_ptr get_connection() noexcept { std::shared_ptr connection; @@ -420,7 +461,7 @@ namespace SimpleWeb { auto corrected_path = path; if(corrected_path == "") corrected_path = "/"; - if(!config.proxy_server.empty() && std::is_same::value) + if(!config.proxy_server.empty() && std::is_same::value) corrected_path = "http://" + host + ':' + std::to_string(port) + corrected_path; std::unique_ptr streambuf(new asio::streambuf()); @@ -435,20 +476,6 @@ namespace SimpleWeb { return streambuf; } - std::pair parse_host_port(const std::string &host_port, unsigned short default_port) const noexcept { - std::pair parsed_host_port; - std::size_t host_end = host_port.find(':'); - if(host_end == std::string::npos) { - parsed_host_port.first = host_port; - parsed_host_port.second = default_port; - } - else { - parsed_host_port.first = host_port.substr(0, host_end); - parsed_host_port.second = static_cast(stoul(host_port.substr(host_end + 1))); - } - return parsed_host_port; - } - void write(const std::shared_ptr &session) { session->connection->set_timeout(); asio::async_write(*session->connection->socket, session->request_streambuf->data(), [this, session](const error_code &ec, std::size_t /*bytes_transferred*/) { @@ -638,15 +665,15 @@ namespace SimpleWeb { } }; - template - class Client : public ClientBase {}; + template + class Client : public ClientBase {}; using HTTP = asio::ip::tcp::socket; template <> - class Client : public ClientBase { + class Client : public ClientTemplate { public: - Client(const std::string &server_port_path) noexcept : ClientBase::ClientBase(server_port_path, 80) {} + Client(const std::string &server_port_path) noexcept : ClientTemplate::ClientTemplate(server_port_path, 80) {} protected: std::shared_ptr create_connection() noexcept override { diff --git a/client_https.hpp b/client_https.hpp index 017cbf9b..cc2d85d3 100644 --- a/client_https.hpp +++ b/client_https.hpp @@ -13,11 +13,11 @@ namespace SimpleWeb { using HTTPS = asio::ssl::stream; template <> - class Client : public ClientBase { + class Client : public ClientTemplate { public: Client(const std::string &server_port_path, bool verify_certificate = true, const std::string &cert_file = std::string(), const std::string &private_key_file = std::string(), const std::string &verify_file = std::string()) - : ClientBase::ClientBase(server_port_path, 443), context(asio::ssl::context::tlsv12) { + : ClientTemplate::ClientTemplate(server_port_path, 443), context(asio::ssl::context::tlsv12) { if(cert_file.size() > 0 && private_key_file.size() > 0) { context.use_certificate_chain_file(cert_file); context.use_private_key_file(private_key_file, asio::ssl::context::pem); diff --git a/server_http.hpp b/server_http.hpp index 60cd760e..31c08039 100644 --- a/server_http.hpp +++ b/server_http.hpp @@ -11,6 +11,8 @@ #include #include +; // <- libclang bug workaround + #ifdef USE_STANDALONE_ASIO #include #include @@ -44,25 +46,81 @@ namespace SimpleWeb { #endif namespace SimpleWeb { - template - class Server; - - template class ServerBase { - protected: - class Session; - public: - class Response : public std::enable_shared_from_this, public std::ostream { - friend class ServerBase; - friend class Server; + class Content : public std::istream { + friend class ServerBase; + + public: + std::size_t size() noexcept { + return streambuf.size(); + } + /// Convenience function to return std::string. The stream buffer is consumed. + std::string string() noexcept { + try { + std::stringstream ss; + ss << rdbuf(); + return ss.str(); + } + catch(...) { + return std::string(); + } + } + + private: + asio::streambuf &streambuf; + Content(asio::streambuf &streambuf) noexcept : std::istream(&streambuf), streambuf(streambuf) {} + }; + + class Request { + template + friend class ServerTemplate; asio::streambuf streambuf; - std::shared_ptr session; + Request(std::size_t max_request_streambuf_size, std::shared_ptr remote_endpoint) noexcept + : streambuf(max_request_streambuf_size), content(streambuf), remote_endpoint(std::move(remote_endpoint)) {} + + public: + std::string method, path, query_string, http_version; + + Content content; + + CaseInsensitiveMultimap header; + + regex::smatch path_match; + + std::shared_ptr remote_endpoint; + + /// The time point when the request header was fully read. + std::chrono::system_clock::time_point header_read_time; + + std::string remote_endpoint_address() noexcept { + try { + return remote_endpoint->address().to_string(); + } + catch(...) { + return std::string(); + } + } + + unsigned short remote_endpoint_port() noexcept { + return remote_endpoint->port(); + } + + /// Returns query keys with percent-decoded values. + CaseInsensitiveMultimap parse_query_string() noexcept { + return SimpleWeb::QueryString::parse(query_string); + } + }; + + class Response : public std::ostream { + protected: + asio::streambuf streambuf; + long timeout_content; - Response(std::shared_ptr session, long timeout_content) noexcept : std::ostream(&streambuf), session(std::move(session)), timeout_content(timeout_content) {} + Response(long timeout_content) noexcept : std::ostream(&streambuf), timeout_content(timeout_content) {} template void write_header(const CaseInsensitiveMultimap &header, size_type size) { @@ -88,18 +146,7 @@ namespace SimpleWeb { } /// Use this function if you need to recursively send parts of a longer message - void send(const std::function &callback = nullptr) noexcept { - session->connection->set_timeout(timeout_content); - auto self = this->shared_from_this(); // Keep Response instance alive through the following async_write - asio::async_write(*session->connection->socket, streambuf, [self, callback](const error_code &ec, std::size_t /*bytes_transferred*/) { - self->session->connection->cancel_timeout(); - auto lock = self->session->connection->handler_runner->continue_lock(); - if(!lock) - return; - if(callback) - callback(ec); - }); - } + virtual void send(const std::function &callback = nullptr) noexcept = 0; /// Write directly to stream buffer using std::ostream::write void write(const char_type *ptr, std::streamsize n) { @@ -153,135 +200,9 @@ namespace SimpleWeb { bool close_connection_after_response = false; }; - class Content : public std::istream { - friend class ServerBase; - - public: - std::size_t size() noexcept { - return streambuf.size(); - } - /// Convenience function to return std::string. The stream buffer is consumed. - std::string string() noexcept { - try { - std::stringstream ss; - ss << rdbuf(); - return ss.str(); - } - catch(...) { - return std::string(); - } - } - - private: - asio::streambuf &streambuf; - Content(asio::streambuf &streambuf) noexcept : std::istream(&streambuf), streambuf(streambuf) {} - }; - - class Request { - friend class ServerBase; - friend class Server; - friend class Session; - - asio::streambuf streambuf; - - Request(std::size_t max_request_streambuf_size, std::shared_ptr remote_endpoint) noexcept - : streambuf(max_request_streambuf_size), content(streambuf), remote_endpoint(std::move(remote_endpoint)) {} - - public: - std::string method, path, query_string, http_version; - - Content content; - - CaseInsensitiveMultimap header; - - regex::smatch path_match; - - std::shared_ptr remote_endpoint; - - /// The time point when the request header was fully read. - std::chrono::system_clock::time_point header_read_time; - - std::string remote_endpoint_address() noexcept { - try { - return remote_endpoint->address().to_string(); - } - catch(...) { - return std::string(); - } - } - - unsigned short remote_endpoint_port() noexcept { - return remote_endpoint->port(); - } - - /// Returns query keys with percent-decoded values. - CaseInsensitiveMultimap parse_query_string() noexcept { - return SimpleWeb::QueryString::parse(query_string); - } - }; - - protected: - class Connection : public std::enable_shared_from_this { - public: - template - Connection(std::shared_ptr handler_runner, Args &&... args) noexcept : handler_runner(std::move(handler_runner)), socket(new socket_type(std::forward(args)...)) {} - - std::shared_ptr handler_runner; - - std::unique_ptr socket; // Socket must be unique_ptr since asio::ssl::stream is not movable - std::mutex socket_close_mutex; - - std::unique_ptr timer; - - std::shared_ptr remote_endpoint; - - void close() noexcept { - error_code ec; - std::unique_lock lock(socket_close_mutex); // The following operations seems to be needed to run sequentially - socket->lowest_layer().shutdown(asio::ip::tcp::socket::shutdown_both, ec); - socket->lowest_layer().close(ec); - } - - void set_timeout(long seconds) noexcept { - if(seconds == 0) { - timer = nullptr; - return; - } - - timer = std::unique_ptr(new asio::steady_timer(socket->get_io_service())); - timer->expires_from_now(std::chrono::seconds(seconds)); - auto self = this->shared_from_this(); - timer->async_wait([self](const error_code &ec) { - if(!ec) - self->close(); - }); - } - - void cancel_timeout() noexcept { - if(timer) { - error_code ec; - timer->cancel(ec); - } - } - }; - - class Session { - public: - Session(std::size_t max_request_streambuf_size, std::shared_ptr connection) noexcept : connection(std::move(connection)) { - if(!this->connection->remote_endpoint) { - error_code ec; - this->connection->remote_endpoint = std::make_shared(this->connection->socket->lowest_layer().remote_endpoint(ec)); - } - request = std::shared_ptr(new Request(max_request_streambuf_size, this->connection->remote_endpoint)); - } - - std::shared_ptr connection; - std::shared_ptr request; - }; - public: class Config { - friend class ServerBase; + friend class ServerBase; Config(unsigned short port) noexcept : port(port) {} @@ -319,19 +240,27 @@ namespace SimpleWeb { } }; + protected: + bool internal_io_service = false; + + std::unique_ptr acceptor; + std::vector threads; + + virtual void accept() = 0; + public: /// Warning: do not add or remove resources after start() is called - std::map::Response>, std::shared_ptr::Request>)>>> resource; - - std::map::Response>, std::shared_ptr::Request>)>> default_resource; + std::map, std::shared_ptr)>>> resource; - std::function::Request>, const error_code &)> on_error; + std::map, std::shared_ptr)>> default_resource; - std::function &, std::shared_ptr::Request>)> on_upgrade; + std::function, const error_code &)> on_error; /// If you have your own asio::io_service, store its pointer here before running start(). std::shared_ptr io_service; + ServerBase(unsigned short port) : config(port) {} + virtual void start() { if(!io_service) { io_service = std::make_shared(); @@ -376,7 +305,99 @@ namespace SimpleWeb { } /// Stop accepting new requests, and close current connections. - void stop() noexcept { + virtual void stop() noexcept = 0; + + virtual ~ServerBase() {} + }; // namespace SimpleWeb + + template + class ServerTemplate : public ServerBase { + protected: + class Connection : public std::enable_shared_from_this { + public: + template + Connection(std::shared_ptr handler_runner, Args &&... args) noexcept : handler_runner(std::move(handler_runner)), socket(new SocketType(std::forward(args)...)) {} + + std::shared_ptr handler_runner; + + std::unique_ptr socket; // Socket must be unique_ptr since asio::ssl::stream is not movable + std::mutex socket_close_mutex; + + std::unique_ptr timer; + + std::shared_ptr remote_endpoint; + + void close() noexcept { + error_code ec; + std::unique_lock lock(socket_close_mutex); // The following operations seems to be needed to run sequentially + socket->lowest_layer().shutdown(asio::ip::tcp::socket::shutdown_both, ec); + socket->lowest_layer().close(ec); + } + + void set_timeout(long seconds) noexcept { + if(seconds == 0) { + timer = nullptr; + return; + } + + timer = std::unique_ptr(new asio::steady_timer(socket->get_io_service())); + timer->expires_from_now(std::chrono::seconds(seconds)); + auto self = this->shared_from_this(); + timer->async_wait([self](const error_code &ec) { + if(!ec) + self->close(); + }); + } + + void cancel_timeout() noexcept { + if(timer) { + error_code ec; + timer->cancel(ec); + } + } + }; + + class Session { + public: + Session(std::size_t max_request_streambuf_size, std::shared_ptr connection) noexcept : connection(std::move(connection)) { + if(!this->connection->remote_endpoint) { + error_code ec; + this->connection->remote_endpoint = std::make_shared(this->connection->socket->lowest_layer().remote_endpoint(ec)); + } + request = std::shared_ptr(new Request(max_request_streambuf_size, this->connection->remote_endpoint)); + } + + std::shared_ptr connection; + std::shared_ptr request; + }; + + class ResponseExtended : public Response, public std::enable_shared_from_this { + friend class ServerTemplate; + + std::shared_ptr session; + + ResponseExtended(std::shared_ptr session, long timeout_content) noexcept : Response(timeout_content), session(std::move(session)) {} + + public: + void send(const std::function &callback = nullptr) noexcept override { + session->connection->set_timeout(timeout_content); + auto self = this->shared_from_this(); // Keep Response instance alive through the following async_write + asio::async_write(*session->connection->socket, streambuf, [self, callback](const error_code &ec, std::size_t /*bytes_transferred*/) { + self->session->connection->cancel_timeout(); + auto lock = self->session->connection->handler_runner->continue_lock(); + if(!lock) + return; + if(callback) + callback(ec); + }); + } + }; + + public: + std::function &, std::shared_ptr)> on_upgrade; + + /// Stop accepting new requests, and close current connections. + void stop() noexcept override { if(acceptor) { error_code ec; acceptor->close(ec); @@ -393,25 +414,18 @@ namespace SimpleWeb { } } - virtual ~ServerBase() noexcept { + ~ServerTemplate() { handler_runner->stop(); stop(); } protected: - bool internal_io_service = false; - - std::unique_ptr acceptor; - std::vector threads; - std::shared_ptr> connections; std::shared_ptr connections_mutex; std::shared_ptr handler_runner; - ServerBase(unsigned short port) noexcept : config(port), connections(new std::unordered_set()), connections_mutex(new std::mutex()), handler_runner(new ScopeRunner()) {} - - virtual void accept() = 0; + ServerTemplate(unsigned short port) noexcept : ServerBase(port), connections(new std::unordered_set()), connections_mutex(new std::mutex()), handler_runner(new ScopeRunner()) {} template std::shared_ptr create_connection(Args &&... args) noexcept { @@ -442,7 +456,7 @@ namespace SimpleWeb { return; session->request->header_read_time = std::chrono::system_clock::now(); if((!ec || ec == asio::error::not_found) && session->request->streambuf.size() == session->request->streambuf.max_size()) { - auto response = std::shared_ptr(new Response(session, this->config.timeout_content)); + auto response = std::shared_ptr(new ResponseExtended(session, this->config.timeout_content)); response->write(StatusCode::client_error_payload_too_large); response->send(); if(this->on_error) @@ -484,7 +498,7 @@ namespace SimpleWeb { return; if(!ec) { if(session->request->streambuf.size() == session->request->streambuf.max_size()) { - auto response = std::shared_ptr(new Response(session, this->config.timeout_content)); + auto response = std::shared_ptr(new ResponseExtended(session, this->config.timeout_content)); response->write(StatusCode::client_error_payload_too_large); response->send(); if(this->on_error) @@ -520,7 +534,7 @@ namespace SimpleWeb { if(!lock) return; if((!ec || ec == asio::error::not_found) && session->request->streambuf.size() == session->request->streambuf.max_size()) { - auto response = std::shared_ptr(new Response(session, this->config.timeout_content)); + auto response = std::shared_ptr(new ResponseExtended(session, this->config.timeout_content)); response->write(StatusCode::client_error_payload_too_large); response->send(); if(this->on_error) @@ -553,7 +567,7 @@ namespace SimpleWeb { return; if(!ec) { if(session->request->streambuf.size() == session->request->streambuf.max_size()) { - auto response = std::shared_ptr(new Response(session, this->config.timeout_content)); + auto response = std::shared_ptr(new ResponseExtended(session, this->config.timeout_content)); response->write(StatusCode::client_error_payload_too_large); response->send(); if(this->on_error) @@ -581,7 +595,7 @@ namespace SimpleWeb { session->request->content.read(buffer.get(), static_cast(length)); tmp_stream.write(buffer.get(), static_cast(length)); if(chunks_streambuf->size() == chunks_streambuf->max_size()) { - auto response = std::shared_ptr(new Response(session, this->config.timeout_content)); + auto response = std::shared_ptr(new ResponseExtended(session, this->config.timeout_content)); response->write(StatusCode::client_error_payload_too_large); response->send(); if(this->on_error) @@ -639,11 +653,10 @@ namespace SimpleWeb { write(session, it->second); } - void write(const std::shared_ptr &session, - std::function::Response>, std::shared_ptr::Request>)> &resource_function) { + void write(const std::shared_ptr &session, std::function, std::shared_ptr)> &resource_function) { session->connection->set_timeout(config.timeout_content); - auto response = std::shared_ptr(new Response(session, config.timeout_content), [this](Response *response_ptr) { - auto response = std::shared_ptr(response_ptr); + auto response = std::shared_ptr(new ResponseExtended(session, config.timeout_content), [this](ResponseExtended *response_ptr) { + auto response = std::shared_ptr(response_ptr); response->send([this, response](const error_code &ec) { if(!ec) { if(response->close_connection_after_response) @@ -681,15 +694,15 @@ namespace SimpleWeb { } }; - template - class Server : public ServerBase {}; - using HTTP = asio::ip::tcp::socket; + template + class Server : public ServerBase {}; + template <> - class Server : public ServerBase { + class Server : public ServerTemplate { public: - Server() noexcept : ServerBase::ServerBase(80) {} + Server() noexcept : ServerTemplate::ServerTemplate(80) {} protected: void accept() override { @@ -709,7 +722,7 @@ namespace SimpleWeb { if(!ec) { asio::ip::tcp::no_delay option(true); error_code ec; - session->connection->socket->set_option(option, ec); + connection->socket->set_option(option, ec); this->read(session); } diff --git a/server_https.hpp b/server_https.hpp index 4840b82c..122ebfd3 100644 --- a/server_https.hpp +++ b/server_https.hpp @@ -16,13 +16,13 @@ namespace SimpleWeb { using HTTPS = asio::ssl::stream; template <> - class Server : public ServerBase { + class Server : public ServerTemplate { std::string session_id_context; bool set_session_id_context = false; public: Server(const std::string &cert_file, const std::string &private_key_file, const std::string &verify_file = std::string()) - : ServerBase::ServerBase(443), context(asio::ssl::context::tlsv12) { + : ServerTemplate::ServerTemplate(443), context(asio::ssl::context::tlsv12) { context.use_certificate_chain_file(cert_file); context.use_private_key_file(private_key_file, asio::ssl::context::pem); @@ -63,10 +63,10 @@ namespace SimpleWeb { if(!ec) { asio::ip::tcp::no_delay option(true); error_code ec; - session->connection->socket->lowest_layer().set_option(option, ec); + connection->socket->lowest_layer().set_option(option, ec); - session->connection->set_timeout(config.timeout_request); - session->connection->socket->async_handshake(asio::ssl::stream_base::server, [this, session](const error_code &ec) { + connection->set_timeout(config.timeout_request); + connection->socket->async_handshake(asio::ssl::stream_base::server, [this, session](const error_code &ec) { session->connection->cancel_timeout(); auto lock = session->connection->handler_runner->continue_lock(); if(!lock) diff --git a/tests/parse_test.cpp b/tests/parse_test.cpp index 3bbd9b13..c044f726 100644 --- a/tests/parse_test.cpp +++ b/tests/parse_test.cpp @@ -6,9 +6,9 @@ using namespace std; using namespace SimpleWeb; -class ServerTest : public ServerBase { +class ServerTest : public ServerTemplate { public: - ServerTest() : ServerBase::ServerBase(8080) {} + ServerTest() : ServerTemplate::ServerTemplate(8080) {} void accept() noexcept override {} @@ -51,9 +51,9 @@ class ServerTest : public ServerBase { } }; -class ClientTest : public ClientBase { +class ClientTest : public ClientTemplate { public: - ClientTest(const std::string &server_port_path) : ClientBase::ClientBase(server_port_path, 80) {} + ClientTest(const std::string &server_port_path) : ClientTemplate::ClientTemplate(server_port_path, 80) {} std::shared_ptr create_connection() noexcept override { return nullptr;