Skip to content

Commit

Permalink
[coro_http_server][feat]update coro_http server (#578)
Browse files Browse the repository at this point in the history
  • Loading branch information
qicosmos authored Jan 26, 2024
1 parent 679cbac commit af945af
Show file tree
Hide file tree
Showing 9 changed files with 723 additions and 36 deletions.
128 changes: 128 additions & 0 deletions include/ylt/thirdparty/cinatra/cookie.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
#pragma once

#include <chrono>
#include <ctime>
#include <string>

#include "time_util.hpp"

namespace cinatra {

class cookie {
public:
cookie() = default;
cookie(const std::string &name, const std::string &value)
: name_(name), value_(value) {}

void set_version(int version) { version_ = version; }

void set_name(const std::string &name) { name_ = name; }

std::string get_name() const { return name_; }

void set_value(const std::string &value) { value_ = value; }

std::string get_value() const { return value_; }

void set_comment(const std::string &comment) { comment_ = comment; }

void set_domain(const std::string &domain) { domain_ = domain; }

void set_path(const std::string &path) { path_ = path; }

void set_priority(const std::string &priority) { priority_ = priority; }

void set_secure(bool secure) { secure_ = secure; }

void set_max_age(std::time_t seconds) { max_age_ = seconds; }

void set_http_only(bool http_only) { http_only_ = http_only; }

std::string to_string() const {
std::string result;
result.reserve(256);
result.append(name_);
result.append("=");
if (version_ == 0) {
// Netscape cookie
result.append(value_);
if (!domain_.empty()) {
result.append("; domain=");
result.append(domain_);
}
if (!path_.empty()) {
result.append("; path=");
result.append(path_);
}
if (!priority_.empty()) {
result.append("; Priority=");
result.append(priority_);
}
if (max_age_ != -1) {
result.append("; expires=");
result.append(get_gmt_time_str(std::chrono::system_clock::from_time_t(
max_age_ + std::time(nullptr))));
}
if (secure_) {
result.append("; secure");
}
if (http_only_) {
result.append("; HttpOnly");
}
}
else {
// RFC 2109 cookie
result.append("\"");
result.append(value_);
result.append("\"");
if (!comment_.empty()) {
result.append("; Comment=\"");
result.append(comment_);
result.append("\"");
}
if (!domain_.empty()) {
result.append("; Domain=\"");
result.append(domain_);
result.append("\"");
}
if (!path_.empty()) {
result.append("; Path=\"");
result.append(path_);
result.append("\"");
}
if (!priority_.empty()) {
result.append("; Priority=\"");
result.append(priority_);
result.append("\"");
}

if (max_age_ != -1) {
result.append("; Max-Age=\"");
result.append(std::to_string(max_age_));
result.append("\"");
}
if (secure_) {
result.append("; secure");
}
if (http_only_) {
result.append("; HttpOnly");
}
result.append("; Version=\"1\"");
}
return result;
}

private:
std::string name_ = "";
std::string value_ = "";
std::string comment_ = "";
std::string domain_ = "";
std::string priority_ = "";
std::string path_ = "";
std::time_t max_age_ = -1;
int version_ = 0;
bool secure_ = false;
bool http_only_ = false;
};

} // namespace cinatra
81 changes: 78 additions & 3 deletions include/ylt/thirdparty/cinatra/coro_http_connection.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,13 @@
#include "async_simple/coro/Lazy.h"
#include "cinatra/cinatra_log_wrapper.hpp"
#include "cinatra/response_cv.hpp"
#include "cookie.hpp"
#include "coro_http_request.hpp"
#include "coro_http_router.hpp"
#include "define.h"
#include "http_parser.hpp"
#include "multipart.hpp"
#include "session_manager.hpp"
#include "sha1.hpp"
#include "string_resize.hpp"
#include "websocket.hpp"
Expand Down Expand Up @@ -218,7 +220,7 @@ class coro_http_connection

if (is_coro_exist) {
if (coro_handler) {
co_await (coro_handler)(request_, response_);
co_await coro_handler(request_, response_);
}
else {
response_.set_status(status_type::not_found);
Expand All @@ -236,7 +238,7 @@ class coro_http_connection
std::get<0>(pair))) {
auto coro_handler = std::get<1>(pair);
if (coro_handler) {
co_await (coro_handler)(request_, response_);
co_await coro_handler(request_, response_);
is_matched_regex_router = true;
}
}
Expand Down Expand Up @@ -268,12 +270,73 @@ 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 {
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 @@ -684,6 +747,17 @@ class coro_http_connection

void set_check_timeout(bool r) { checkout_timeout_ = r; }

void handle_session_for_response() {
if (request_.has_session()) {
auto session =
session_manager::get().get_session(request_.get_cached_session_id());
if (session != nullptr && session->get_need_set_to_client()) {
response_.add_cookie(session->get_session_cookie());
session->set_need_set_to_client(false);
}
}
}

private:
bool check_keep_alive() {
bool keep_alive = true;
Expand Down Expand Up @@ -739,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
37 changes: 37 additions & 0 deletions include/ylt/thirdparty/cinatra/coro_http_request.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
#include "async_simple/coro/Lazy.h"
#include "define.h"
#include "http_parser.hpp"
#include "session.hpp"
#include "session_manager.hpp"
#include "utils.hpp"
#include "ws_define.h"

Expand Down Expand Up @@ -224,6 +226,40 @@ class coro_http_request {
}
}

std::unordered_map<std::string_view, std::string_view> get_cookies(
std::string_view cookie_str) const {
auto cookies = get_cookies_map(cookie_str);
return cookies;
}

std::shared_ptr<session> get_session(bool create = true) {
auto &session_manager = session_manager::get();

auto cookies = get_cookies(get_header_value("Cookie"));
std::string session_id;
auto iter = cookies.find(CSESSIONID);
if (iter == cookies.end() && !create) {
return nullptr;
}
else if (iter == cookies.end()) {
session_id = session_manager.generate_session_id();
}
else {
session_id = iter->second;
}

cached_session_id_ = session_id;
return session_manager.get_session(session_id);
}

std::string get_cached_session_id() {
std::string temp_session_id = "";
cached_session_id_.swap(temp_session_id);
return temp_session_id;
}

bool has_session() { return !cached_session_id_.empty(); }

std::unordered_map<std::string, std::string> params_;
std::smatch matches_;

Expand All @@ -233,5 +269,6 @@ class coro_http_request {
coro_http_connection *conn_;
bool is_websocket_;
std::unordered_map<std::string, std::any> aspect_data_;
std::string cached_session_id_;
};
} // namespace cinatra
Loading

0 comments on commit af945af

Please sign in to comment.