Skip to content

Commit

Permalink
Pipeling (#503)
Browse files Browse the repository at this point in the history
  • Loading branch information
qicosmos authored Jan 23, 2024
1 parent 12a283e commit 3f50010
Show file tree
Hide file tree
Showing 3 changed files with 137 additions and 6 deletions.
1 change: 1 addition & 0 deletions example/benchmark.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ int main() {
coro_http_server server(std::thread::hardware_concurrency(), 8090);
server.set_http_handler<GET>(
"/", [](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();
Expand Down
66 changes: 63 additions & 3 deletions include/cinatra/coro_http_connection.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -269,15 +269,74 @@ class coro_http_connection
}
}

handle_session_for_response();

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 {
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<const char *>(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);
resp.need_date_head(response_.need_date());
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 {
handle_session_for_response();
co_await reply();
}
}

response_.clear();
buffers_.clear();
body_.clear();
resp_str_.clear();
if (need_shrink_every_time_) {
body_.shrink_to_fit();
}
Expand Down Expand Up @@ -754,6 +813,7 @@ class coro_http_connection
bool checkout_timeout_ = false;
std::atomic<std::chrono::system_clock::time_point> last_rwtime_;
uint64_t max_part_size_ = 8 * 1024 * 1024;
std::string resp_str_;

websocket ws_;
#ifdef CINATRA_ENABLE_SSL
Expand Down
76 changes: 73 additions & 3 deletions include/cinatra/coro_http_response.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -55,12 +55,18 @@ 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)});
}

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_; }
Expand All @@ -78,6 +84,67 @@ 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);
}
}

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();
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<asio::const_buffer> &buffers) {
bool has_len = false;
bool has_host = false;
Expand Down Expand Up @@ -123,9 +190,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();
Expand Down Expand Up @@ -179,6 +248,7 @@ class coro_http_response {
std::string boundary_;
bool has_set_content_ = false;
bool need_shrink_every_time_ = false;
bool need_date_ = true;
std::unordered_map<std::string, cookie> cookies_;
};
} // namespace cinatra

0 comments on commit 3f50010

Please sign in to comment.