diff --git a/applications/http-mandelbrot/src/main.cpp b/applications/http-mandelbrot/src/main.cpp index 1b1f9de..37973b3 100644 --- a/applications/http-mandelbrot/src/main.cpp +++ b/applications/http-mandelbrot/src/main.cpp @@ -132,13 +132,12 @@ void fractal( { // Other methods are not supported for directory acces // - boost::beast::http::response bad_request{boost::beast::http::status::bad_request, req.version()}; + auto& bad_request = promise.CreateResponse>(boost::beast::http::status::bad_request, req.version()); bad_request.set(boost::beast::http::field::server, BOOST_BEAST_VERSION_STRING); bad_request.set(boost::beast::http::field::content_type, "text/plain"); bad_request.prepare_payload(); bad_request.body() = "Bad request type.\nOnly GET and HEAD are expected for this URL."; bad_request.keep_alive(req.keep_alive()); - promise.SendResponse(std::move(bad_request)); return; } @@ -155,7 +154,7 @@ void fractal( std::cout << "HTTP inside render function " << target << std::endl; constexpr int pixel_width = 256; constexpr int pixel_height = 256; - constexpr int max_iterations = 100; + constexpr int max_iterations = 255; boost::gil::gray8_image_t image(pixel_width,pixel_height); @@ -189,13 +188,12 @@ void fractal( boost::gil::view(image), boost::gil::image_write_info(95)); - boost::beast::http::response ok{boost::beast::http::status::ok, req.version()}; + auto& ok = promise.CreateResponse>(boost::beast::http::status::ok, req.version()); ok.set(boost::beast::http::field::server, BOOST_BEAST_VERSION_STRING); ok.set(boost::beast::http::field::content_type, "image/jpeg"); ok.body() = out_buffer.str(); ok.keep_alive(req.keep_alive()); ok.prepare_payload(); - promise.SendResponse(std::move(ok)); std::cout << " DONE HTTP inside render function " << target << std::endl; }; @@ -250,7 +248,7 @@ int main(int argc, char **argv) }); std::vector threads; - while(threads.size() < 20) + while(threads.size() < 4) { threads.emplace_back([&ioc]{ioc.run();}); } diff --git a/bmrshared-web/include/bmrshared/response_promise.hpp b/bmrshared-web/include/bmrshared/response_promise.hpp index 2d239d0..e3b4a47 100644 --- a/bmrshared-web/include/bmrshared/response_promise.hpp +++ b/bmrshared-web/include/bmrshared/response_promise.hpp @@ -10,32 +10,66 @@ #include #include #include +#include namespace bmrshared::web { class response_promise final { +private: + class response_writer_interface + { + public: + virtual ~response_writer_interface() = default; + virtual void write_response(boost::beast::tcp_stream&) = 0; + }; + + template + class response_writer : public response_writer_interface + { + public: + template + response_writer(TArgs... args) + : m_response(args...) + {} + + ~response_writer() override = default; + + void write_response(boost::beast::tcp_stream& stream) override + { + boost::beast::http::write(stream, m_response); + } + + TResponse& response() + { + return m_response; + } + + private: + TResponse m_response; + }; + + public: using response_sender = std::function; - using callback_on_response = std::function; + using callback_on_response = std::function; response_promise() = delete; explicit response_promise(callback_on_response cbOnResponse); ~response_promise(); - template - void SendResponse(boost::beast::http::response response) + template + TResponse& CreateResponse(TArgs&&... args) { - response_sender responder = [r = std::move(response)](boost::beast::tcp_stream& stream) - { - boost::beast::http::write(stream, r); - }; - - m_call_on_response(std::move(responder)); + auto created = std::make_unique>(std::forward(args)...); + auto& resp = created->response(); + m_response_writer = std::move(created); + return resp; } private: callback_on_response m_call_on_response; + std::shared_ptr m_response_writer; }; } // namespace bmrshared::web diff --git a/bmrshared-web/lib/directory_request_handler.cpp b/bmrshared-web/lib/directory_request_handler.cpp index 7f405dd..7bab0f8 100644 --- a/bmrshared-web/lib/directory_request_handler.cpp +++ b/bmrshared-web/lib/directory_request_handler.cpp @@ -50,13 +50,12 @@ void directory_request_handler::handle_request_http(const address_type& address, { // Other methods are not supported for directory acces // - http::response bad_request{http::status::bad_request, req.version()}; + auto& bad_request = promise.CreateResponse>(http::status::bad_request, req.version()); bad_request.set(http::field::server, BOOST_BEAST_VERSION_STRING); bad_request.set(http::field::content_type, "text/plain"); bad_request.prepare_payload(); bad_request.body() = "Bad request type.\nOnly GET and HEAD are expected for this URL."; bad_request.keep_alive(req.keep_alive()); - promise.SendResponse(std::move(bad_request)); return; } @@ -86,13 +85,12 @@ void directory_request_handler::handle_request_http(const address_type& address, if (!found_file) { - http::response not_found{http::status::not_found, req.version()}; + auto& not_found = promise.CreateResponse>(http::status::not_found, req.version()); not_found.set(http::field::server, BOOST_BEAST_VERSION_STRING); not_found.set(http::field::content_type, "text/plain"); not_found.prepare_payload(); not_found.body() = "File not found."; not_found.keep_alive(req.keep_alive()); - promise.SendResponse(std::move(not_found)); return; } @@ -102,13 +100,12 @@ void directory_request_handler::handle_request_http(const address_type& address, body.open(found_file->native().c_str(), beast::file_mode::scan, ec); if (ec) { - http::response internal{http::status::internal_server_error, req.version()}; + auto& internal = promise.CreateResponse>(http::status::internal_server_error, req.version()); internal.set(http::field::server, BOOST_BEAST_VERSION_STRING); internal.set(http::field::content_type, "text/plain"); internal.prepare_payload(); internal.body() = "Internal server error."; internal.keep_alive(req.keep_alive()); - promise.SendResponse(std::move(internal)); return; } @@ -119,10 +116,9 @@ void directory_request_handler::handle_request_http(const address_type& address, if (req.count(http::field::if_modified_since) != 0 && (req[http::field::if_modified_since] == last_modified)) { - http::response head{http::status::not_modified, req.version()}; + auto& head = promise.CreateResponse>(http::status::not_modified, req.version()); head.set(http::field::server, BOOST_BEAST_VERSION_STRING); head.keep_alive(req.keep_alive()); - promise.SendResponse(std::move(head)); return; } @@ -130,29 +126,27 @@ void directory_request_handler::handle_request_http(const address_type& address, // Okay, we have a file so let us send the correct response. if (req.method() == http::verb::head) { - http::response head{http::status::ok, req.version()}; + auto& head = promise.CreateResponse>(http::status::ok, req.version()); head.set(http::field::server, BOOST_BEAST_VERSION_STRING); head.set(http::field::content_type, mime_type); head.set(http::field::last_modified, last_modified); head.set(http::field::cache_control, "public, max-age=360"); head.set(http::field::content_length, std::to_string(file_size)); head.keep_alive(req.keep_alive()); - promise.SendResponse(std::move(head)); return; } else if (req.method() == http::verb::get) - { - http::response head{std::piecewise_construct, + {/* + auto& head = promise.CreateResponse>(std::piecewise_construct, std::make_tuple(std::move(body)), - std::make_tuple(http::status::ok, req.version())}; + std::make_tuple(http::status::ok, req.version())); head.set(http::field::server, BOOST_BEAST_VERSION_STRING); head.set(http::field::content_type, mime_type); head.set(http::field::last_modified, last_modified); head.set(http::field::cache_control, "public, max-age=360"); head.set(http::field::content_length, std::to_string(file_size)); - head.keep_alive(req.keep_alive()); - //promise.SendResponse(std::move(head)); + head.keep_alive(req.keep_alive());*/ return; } } diff --git a/bmrshared-web/lib/response_promise.cpp b/bmrshared-web/lib/response_promise.cpp index 87dd9a2..e78d6c8 100644 --- a/bmrshared-web/lib/response_promise.cpp +++ b/bmrshared-web/lib/response_promise.cpp @@ -14,4 +14,14 @@ response_promise::response_promise(callback_on_response cbOnResponse) { } -response_promise::~response_promise() = default; +response_promise::~response_promise() +{ + if (m_response_writer) + { + m_call_on_response( + [r = m_response_writer](boost::beast::tcp_stream& stream) + { + r->write_response(stream); + }); + } +}