From 60c54dbb4c8ab11ba5c0d0fe54be26974e67641e Mon Sep 17 00:00:00 2001 From: qicosmos Date: Tue, 23 Jan 2024 16:46:27 +0800 Subject: [PATCH 1/3] support pipeling --- include/cinatra/coro_http_connection.hpp | 61 ++++++++++++++++++++++- include/cinatra/coro_http_response.hpp | 62 ++++++++++++++++++++++++ 2 files changed, 122 insertions(+), 1 deletion(-) diff --git a/include/cinatra/coro_http_connection.hpp b/include/cinatra/coro_http_connection.hpp index 8c47cdbb..3e09f281 100644 --- a/include/cinatra/coro_http_connection.hpp +++ b/include/cinatra/coro_http_connection.hpp @@ -268,7 +268,66 @@ class coro_http_connection } if (!response_.get_delay()) { - co_await reply(); + if (head_buf_.size()) { + // handle pipeling, only support GET and HEAD method now. + if (parser_.method()[0] != 'G' && parser_.method()[0] != 'H') { + response_.set_status_and_content(status_type::method_not_allowed, + "method not allowed"); + co_await reply(); + } + else { + std::string resp_str; + resp_str.reserve(512); + response_.build_resp_str(resp_str); + + while (true) { + size_t left_size = head_buf_.size(); + auto data_ptr = asio::buffer_cast(head_buf_.data()); + std::string_view left_content{data_ptr, left_size}; + size_t pos = left_content.find(TWO_CRCF); + if (pos == std::string_view::npos) { + break; + } + http_parser parser; + int head_len = parser.parse_request(data_ptr, size, 0); + if (head_len <= 0) { + CINATRA_LOG_ERROR << "parse http header error"; + close(); + break; + } + + head_buf_.consume(pos + TWO_CRCF.length()); + + std::string_view key = { + parser_.method().data(), + parser_.method().length() + 1 + parser_.url().length()}; + + coro_http_request req(parser, this); + coro_http_response resp(this); + if (auto handler = router_.get_handler(key); handler) { + router_.route(handler, req, resp, key); + } + else { + if (auto coro_handler = router_.get_coro_handler(key); + coro_handler) { + co_await router_.route_coro(coro_handler, req, resp, key); + } + } + + resp.build_resp_str(resp_str); + } + + auto [write_ec, _] = co_await async_write(asio::buffer(resp_str)); + if (write_ec) { + CINATRA_LOG_ERROR << "async_write error: " << write_ec.message(); + close(); + co_return; + } + } + } + else { + co_await reply(); + } } response_.clear(); diff --git a/include/cinatra/coro_http_response.hpp b/include/cinatra/coro_http_response.hpp index ee627ae0..7fb03dbc 100644 --- a/include/cinatra/coro_http_response.hpp +++ b/include/cinatra/coro_http_response.hpp @@ -54,6 +54,9 @@ class coro_http_response { bool get_delay() const { return delay_; } void set_format_type(format_type type) { fmt_type_ = type; } + status_type status() { return status_; } + std::string_view content() { return content_; } + void add_header(auto k, auto v) { resp_headers_.emplace_back(resp_header{std::move(k), std::move(v)}); } @@ -77,6 +80,65 @@ class coro_http_response { } } + void build_resp_str(std::string &resp_str) { + resp_str.append(to_http_status_string(status_)); + bool has_len = false; + bool has_host = false; + for (auto &[k, v] : resp_headers_) { + if (k == "Host") { + has_host = true; + } + if (k == "Content-Length") { + has_len = true; + } + } + + if (!has_host) { + resp_str.append(CINATRA_HOST_SV); + } + + if (content_.empty() && !has_set_content_ && + fmt_type_ != format_type::chunked) { + content_.append(default_status_content(status_)); + } + + if (fmt_type_ == format_type::chunked) { + resp_str.append(TRANSFER_ENCODING_SV); + } + else { + if (!content_.empty()) { + auto [ptr, ec] = std::to_chars(buf_, buf_ + 32, content_.size()); + resp_str.append(CONTENT_LENGTH_SV); + resp_str.append(std::string_view(buf_, std::distance(buf_, ptr))); + resp_str.append(CRCF); + } + else { + if (!has_len && boundary_.empty()) + resp_str.append(ZERO_LENGTH_SV); + } + } + + resp_str.append(DATE_SV); + resp_str.append(get_gmt_time_str()); + resp_str.append(CRCF); + + if (keepalive_.has_value()) { + bool keepalive = keepalive_.value(); + keepalive ? resp_str.append(CONN_KEEP_SV) + : resp_str.append(CONN_CLOSE_SV); + } + + for (auto &[k, v] : resp_headers_) { + resp_str.append(k); + resp_str.append(COLON_SV); + resp_str.append(v); + resp_str.append(CRCF); + } + + resp_str.append(CRCF); + resp_str.append(content_); + } + void build_resp_head(std::vector &buffers) { bool has_len = false; bool has_host = false; From 60e8b28067c9ce218bba936468d1d3b864176221 Mon Sep 17 00:00:00 2001 From: qicosmos Date: Tue, 23 Jan 2024 17:27:20 +0800 Subject: [PATCH 2/3] date --- example/benchmark.cpp | 1 + include/cinatra/coro_http_connection.hpp | 12 +++++++----- include/cinatra/coro_http_response.hpp | 20 ++++++++++++++------ 3 files changed, 22 insertions(+), 11 deletions(-) diff --git a/example/benchmark.cpp b/example/benchmark.cpp index 604ccda6..c4916c80 100644 --- a/example/benchmark.cpp +++ b/example/benchmark.cpp @@ -7,6 +7,7 @@ int main() { coro_http_server server(std::thread::hardware_concurrency(), 8090); server.set_http_handler( "/", [](coro_http_request& req, coro_http_response& resp) { + resp.need_date_head(false); resp.set_status_and_content(status_type::ok, "Hello, world!"); }); server.sync_start(); diff --git a/include/cinatra/coro_http_connection.hpp b/include/cinatra/coro_http_connection.hpp index 3e09f281..008d8a2a 100644 --- a/include/cinatra/coro_http_connection.hpp +++ b/include/cinatra/coro_http_connection.hpp @@ -276,9 +276,8 @@ class coro_http_connection co_await reply(); } else { - std::string resp_str; - resp_str.reserve(512); - response_.build_resp_str(resp_str); + resp_str_.reserve(512); + response_.build_resp_str(resp_str_); while (true) { size_t left_size = head_buf_.size(); @@ -304,6 +303,7 @@ class coro_http_connection coro_http_request req(parser, this); coro_http_response resp(this); + resp.need_date_head(response_.need_date()); if (auto handler = router_.get_handler(key); handler) { router_.route(handler, req, resp, key); } @@ -314,10 +314,10 @@ class coro_http_connection } } - resp.build_resp_str(resp_str); + resp.build_resp_str(resp_str_); } - auto [write_ec, _] = co_await async_write(asio::buffer(resp_str)); + auto [write_ec, _] = co_await async_write(asio::buffer(resp_str_)); if (write_ec) { CINATRA_LOG_ERROR << "async_write error: " << write_ec.message(); close(); @@ -333,6 +333,7 @@ class coro_http_connection response_.clear(); buffers_.clear(); body_.clear(); + resp_str_.clear(); if (need_shrink_every_time_) { body_.shrink_to_fit(); } @@ -798,6 +799,7 @@ class coro_http_connection bool checkout_timeout_ = false; std::atomic last_rwtime_; uint64_t max_part_size_ = 8 * 1024 * 1024; + std::string resp_str_; websocket ws_; #ifdef CINATRA_ENABLE_SSL diff --git a/include/cinatra/coro_http_response.hpp b/include/cinatra/coro_http_response.hpp index 7fb03dbc..d5d9df47 100644 --- a/include/cinatra/coro_http_response.hpp +++ b/include/cinatra/coro_http_response.hpp @@ -63,6 +63,9 @@ class coro_http_response { void set_keepalive(bool r) { keepalive_ = r; } + void need_date_head(bool r) { need_date_ = r; } + bool need_date() { return need_date_; } + void set_boundary(std::string_view boundary) { boundary_ = boundary; } std::string_view get_boundary() { return boundary_; } @@ -118,9 +121,11 @@ class coro_http_response { } } - resp_str.append(DATE_SV); - resp_str.append(get_gmt_time_str()); - resp_str.append(CRCF); + if (need_date_) { + resp_str.append(DATE_SV); + resp_str.append(get_gmt_time_str()); + resp_str.append(CRCF); + } if (keepalive_.has_value()) { bool keepalive = keepalive_.value(); @@ -177,9 +182,11 @@ class coro_http_response { } } - buffers.emplace_back(asio::buffer(DATE_SV)); - buffers.emplace_back(asio::buffer(get_gmt_time_str())); - buffers.emplace_back(asio::buffer(CRCF)); + if (need_date_) { + buffers.emplace_back(asio::buffer(DATE_SV)); + buffers.emplace_back(asio::buffer(get_gmt_time_str())); + buffers.emplace_back(asio::buffer(CRCF)); + } if (keepalive_.has_value()) { bool keepalive = keepalive_.value(); @@ -228,5 +235,6 @@ class coro_http_response { std::string boundary_; bool has_set_content_ = false; bool need_shrink_every_time_ = false; + bool need_date_ = true; }; } // namespace cinatra \ No newline at end of file From a6680d598a748e05953e017b868ff559381af6d2 Mon Sep 17 00:00:00 2001 From: qicosmos Date: Tue, 23 Jan 2024 17:51:42 +0800 Subject: [PATCH 3/3] update --- include/cinatra/coro_http_connection.hpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/include/cinatra/coro_http_connection.hpp b/include/cinatra/coro_http_connection.hpp index 7b13ece1..6826a10a 100644 --- a/include/cinatra/coro_http_connection.hpp +++ b/include/cinatra/coro_http_connection.hpp @@ -269,8 +269,6 @@ class coro_http_connection } } - handle_session_for_response(); - if (!response_.get_delay()) { if (head_buf_.size()) { // handle pipeling, only support GET and HEAD method now. @@ -330,6 +328,7 @@ class coro_http_connection } } else { + handle_session_for_response(); co_await reply(); } }