do some fix (#656)

This commit is contained in:
qicosmos 2024-04-08 10:33:31 +08:00 committed by GitHub
parent dfe3544cc2
commit 31b6e46971
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 123 additions and 63 deletions

View File

@ -127,6 +127,8 @@ class coro_http_request {
const auto &get_queries() const { return parser_.queries(); }
std::string_view full_url() { return parser_.full_url(); }
void set_body(std::string &body) {
body_ = body;
auto type = get_content_type();

View File

@ -69,20 +69,20 @@ class coro_http_server {
#endif
// only call once, not thread safe.
std::errc sync_start() noexcept {
std::error_code sync_start() noexcept {
auto ret = async_start();
ret.wait();
return ret.value();
}
// only call once, not thread safe.
async_simple::Future<std::errc> async_start() {
async_simple::Future<std::error_code> async_start() {
errc_ = listen();
async_simple::Promise<std::errc> promise;
async_simple::Promise<std::error_code> promise;
auto future = promise.getFuture();
if (errc_ == std::errc{}) {
if (!errc_) {
if (out_ctx_ == nullptr) {
thd_ = std::thread([this] {
pool_->run();
@ -91,7 +91,7 @@ class coro_http_server {
accept().start([p = std::move(promise), this](auto &&res) mutable {
if (res.hasError()) {
errc_ = std::errc::io_error;
errc_ = std::make_error_code(std::errc::io_error);
p.setValue(errc_);
}
else {
@ -196,16 +196,14 @@ class coro_http_server {
coro_io::channel<coro_http_client>::create(hosts, {.lba = type},
weights));
auto handler =
[this, channel, type, url_path](
[this, channel, type](
coro_http_request &req,
coro_http_response &response) -> async_simple::coro::Lazy<void> {
co_await channel->send_request(
[this, &req, &response](
coro_http_client &client,
std::string_view host) -> async_simple::coro::Lazy<void> {
uri_t uri;
uri.parse_from(host.data());
co_await reply(client, uri.get_path(), req, response);
co_await reply(client, host, req, response);
});
};
@ -503,10 +501,10 @@ class coro_http_server {
}
std::string_view address() { return address_; }
std::errc get_errc() { return errc_; }
std::error_code get_errc() { return errc_; }
private:
std::errc listen() {
std::error_code listen() {
CINATRA_LOG_INFO << "begin to listen";
using asio::ip::tcp;
asio::error_code ec;
@ -519,7 +517,10 @@ class coro_http_server {
if (ec || it == it_end) {
CINATRA_LOG_ERROR << "bad address: " << address_
<< " error: " << ec.message();
return std::errc::bad_address;
if (ec) {
return ec;
}
return std::make_error_code(std::errc::address_not_available);
}
auto endpoint = it->endpoint();
@ -527,7 +528,7 @@ class coro_http_server {
if (ec) {
CINATRA_LOG_ERROR << "acceptor open failed"
<< " error: " << ec.message();
return std::errc::io_error;
return ec;
}
#ifdef __GNUC__
acceptor_.set_option(tcp::acceptor::reuse_address(true), ec);
@ -535,9 +536,10 @@ class coro_http_server {
acceptor_.bind(endpoint, ec);
if (ec) {
CINATRA_LOG_ERROR << "bind port: " << port_ << " error: " << ec.message();
acceptor_.cancel(ec);
acceptor_.close(ec);
return std::errc::address_in_use;
std::error_code ignore_ec;
acceptor_.cancel(ignore_ec);
acceptor_.close(ignore_ec);
return ec;
}
#ifdef _MSC_VER
acceptor_.set_option(tcp::acceptor::reuse_address(true));
@ -546,14 +548,14 @@ class coro_http_server {
if (ec) {
CINATRA_LOG_ERROR << "get local endpoint port: " << port_
<< " listen error: " << ec.message();
return std::errc::io_error;
return ec;
}
auto end_point = acceptor_.local_endpoint(ec);
if (ec) {
CINATRA_LOG_ERROR << "get local endpoint port: " << port_
<< " error: " << ec.message();
return std::errc::address_in_use;
return ec;
}
port_ = end_point.port();
@ -561,7 +563,7 @@ class coro_http_server {
return {};
}
async_simple::coro::Lazy<std::errc> accept() {
async_simple::coro::Lazy<std::error_code> accept() {
for (;;) {
coro_io::ExecutorWrapper<> *executor;
if (out_ctx_ == nullptr) {
@ -580,7 +582,7 @@ class coro_http_server {
if (error == asio::error::operation_aborted ||
error == asio::error::bad_descriptor) {
acceptor_close_waiter_.set_value();
co_return std::errc::operation_canceled;
co_return error;
}
continue;
}
@ -765,17 +767,28 @@ class coro_http_server {
}
async_simple::coro::Lazy<void> reply(coro_http_client &client,
std::string url_path,
std::string_view host,
coro_http_request &req,
coro_http_response &response) {
uri_t uri;
std::string proxy_host;
if (host.find("//") == std::string_view::npos) {
proxy_host.append("http://").append(host);
uri.parse_from(proxy_host.data());
}
else {
uri.parse_from(host.data());
}
std::unordered_map<std::string, std::string> req_headers;
for (auto &[k, v] : req_headers) {
for (auto &[k, v] : req.get_headers()) {
req_headers.emplace(k, v);
}
req_headers["Host"] = uri.host;
auto ctx = req_context<std::string_view>{.content = req.get_body()};
auto result = co_await client.async_request(
std::move(url_path), method_type(req.get_method()), std::move(ctx),
req.full_url(), method_type(req.get_method()), std::move(ctx),
std::move(req_headers));
for (auto &[k, v] : result.resp_headers) {
@ -789,6 +802,8 @@ class coro_http_server {
}
void init_address(std::string address) {
CINATRA_LOG_ERROR << "init log"; // init easylog singleton to make sure
// server destruct before easylog.
if (size_t pos = address.find(':'); pos != std::string::npos) {
auto port_sv = std::string_view(address).substr(pos + 1);
@ -813,7 +828,7 @@ class coro_http_server {
std::unique_ptr<coro_io::ExecutorWrapper<>> out_executor_ = nullptr;
uint16_t port_;
std::string address_;
std::errc errc_ = {};
std::error_code errc_ = {};
asio::ip::tcp::acceptor acceptor_;
std::thread thd_;
std::promise<void> acceptor_close_waiter_;

View File

@ -100,6 +100,7 @@ class http_parser {
}
}
full_url_ = url_;
if (has_query) {
size_t pos = url_.find('?');
parse_query(url_.substr(pos + 1, url_len - pos - 1));
@ -125,6 +126,8 @@ class http_parser {
const auto &queries() const { return queries_; }
std::string_view full_url() { return full_url_; }
std::string_view get_query_value(std::string_view key) {
if (auto it = queries_.find(key); it != queries_.end()) {
return it->second;
@ -270,6 +273,7 @@ class http_parser {
std::array<http_header, CINATRA_MAX_HTTP_HEADER_FIELD_SIZE> headers_;
std::string_view method_;
std::string_view url_;
std::string_view full_url_;
std::unordered_map<std::string_view, std::string_view> queries_;
};
} // namespace cinatra

View File

@ -482,21 +482,21 @@ void http_proxy() {
coro_http_server proxy_wrr(2, 8090);
proxy_wrr.set_http_proxy_handler<GET, POST>(
"/wrr", {"127.0.0.1:9001", "127.0.0.1:9002", "127.0.0.1:9003"},
"/", {"127.0.0.1:9001", "127.0.0.1:9002", "127.0.0.1:9003"},
coro_io::load_blance_algorithm::WRR, {10, 5, 5});
coro_http_server proxy_rr(2, 8091);
proxy_rr.set_http_proxy_handler<GET, POST>(
"/rr", {"127.0.0.1:9001", "127.0.0.1:9002", "127.0.0.1:9003"},
"/", {"127.0.0.1:9001", "127.0.0.1:9002", "127.0.0.1:9003"},
coro_io::load_blance_algorithm::RR);
coro_http_server proxy_random(2, 8092);
proxy_random.set_http_proxy_handler<GET, POST>(
"/random", {"127.0.0.1:9001", "127.0.0.1:9002", "127.0.0.1:9003"});
"/", {"127.0.0.1:9001", "127.0.0.1:9002", "127.0.0.1:9003"});
coro_http_server proxy_all(2, 8093);
proxy_all.set_http_proxy_handler(
"/all", {"127.0.0.1:9001", "127.0.0.1:9002", "127.0.0.1:9003"});
"/", {"127.0.0.1:9001", "127.0.0.1:9002", "127.0.0.1:9003"});
proxy_wrr.async_start();
proxy_rr.async_start();
@ -506,37 +506,37 @@ void http_proxy() {
std::this_thread::sleep_for(200ms);
coro_http_client client_rr;
resp_data resp_rr = client_rr.get("http://127.0.0.1:8091/rr");
resp_data resp_rr = client_rr.get("http://127.0.0.1:8091/");
assert(resp_rr.resp_body == "web1");
resp_rr = client_rr.get("http://127.0.0.1:8091/rr");
resp_rr = client_rr.get("http://127.0.0.1:8091/");
assert(resp_rr.resp_body == "web2");
resp_rr = client_rr.get("http://127.0.0.1:8091/rr");
resp_rr = client_rr.get("http://127.0.0.1:8091/");
assert(resp_rr.resp_body == "web3");
resp_rr = client_rr.get("http://127.0.0.1:8091/rr");
resp_rr = client_rr.get("http://127.0.0.1:8091/");
assert(resp_rr.resp_body == "web1");
resp_rr = client_rr.get("http://127.0.0.1:8091/rr");
resp_rr = client_rr.get("http://127.0.0.1:8091/");
assert(resp_rr.resp_body == "web2");
resp_rr = client_rr.post("http://127.0.0.1:8091/rr", "test content",
resp_rr = client_rr.post("http://127.0.0.1:8091/", "test content",
req_content_type::text);
assert(resp_rr.resp_body == "web3");
coro_http_client client_wrr;
resp_data resp = client_wrr.get("http://127.0.0.1:8090/wrr");
resp_data resp = client_wrr.get("http://127.0.0.1:8090/");
assert(resp.resp_body == "web1");
resp = client_wrr.get("http://127.0.0.1:8090/wrr");
resp = client_wrr.get("http://127.0.0.1:8090/");
assert(resp.resp_body == "web1");
resp = client_wrr.get("http://127.0.0.1:8090/wrr");
resp = client_wrr.get("http://127.0.0.1:8090/");
assert(resp.resp_body == "web2");
resp = client_wrr.get("http://127.0.0.1:8090/wrr");
resp = client_wrr.get("http://127.0.0.1:8090/");
assert(resp.resp_body == "web3");
coro_http_client client_random;
resp_data resp_random = client_random.get("http://127.0.0.1:8092/random");
resp_data resp_random = client_random.get("http://127.0.0.1:8092/");
std::cout << resp_random.resp_body << "\n";
assert(!resp_random.resp_body.empty());
coro_http_client client_all;
resp_random = client_all.post("http://127.0.0.1:8093/all", "test content",
resp_random = client_all.post("http://127.0.0.1:8093/", "test content",
req_content_type::text);
std::cout << resp_random.resp_body << "\n";
assert(!resp_random.resp_body.empty());

View File

@ -788,23 +788,61 @@ int main() {
假设需要代理的服务器有三个,分别是"127.0.0.1:9001", "127.0.0.1:9002", "127.0.0.1:9003"coro_http_server设置路径、代理服务器列表和算法类型即可实现反向代理。
```c++
coro_http_server proxy_random(2, 8092);
proxy_random.set_http_proxy_handler<GET, POST>(
"/random", {"127.0.0.1:9001", "127.0.0.1:9002", "127.0.0.1:9003"});
void http_proxy() {
cinatra::coro_http_server web_one(1, 9001);
coro_http_server proxy_rr(2, 8091);
proxy_rr.set_http_proxy_handler<GET, POST>(
"/rr", {"127.0.0.1:9001", "127.0.0.1:9002", "127.0.0.1:9003"},
coro_io::load_blance_algorithm::RR);
web_one.set_http_handler<cinatra::GET, cinatra::POST>(
"/",
[](coro_http_request &req,
coro_http_response &response) -> async_simple::coro::Lazy<void> {
co_await coro_io::post([&]() {
response.set_status_and_content(status_type::ok, "web1");
});
});
web_one.async_start();
cinatra::coro_http_server web_two(1, 9002);
web_two.set_http_handler<cinatra::GET, cinatra::POST>(
"/",
[](coro_http_request &req,
coro_http_response &response) -> async_simple::coro::Lazy<void> {
co_await coro_io::post([&]() {
response.set_status_and_content(status_type::ok, "web2");
});
});
web_two.async_start();
cinatra::coro_http_server web_three(1, 9003);
web_three.set_http_handler<cinatra::GET, cinatra::POST>(
"/", [](coro_http_request &req, coro_http_response &response) {
response.set_status_and_content(status_type::ok, "web3");
});
web_three.async_start();
std::this_thread::sleep_for(200ms);
coro_http_server proxy_wrr(2, 8090);
proxy_wrr.set_http_proxy_handler<GET, POST>(
"/wrr", {"127.0.0.1:9001", "127.0.0.1:9002", "127.0.0.1:9003"},
coro_io::load_blance_algorithm::WRR, {10, 5, 5});
"/", {"127.0.0.1:9001", "127.0.0.1:9002", "127.0.0.1:9003"},
coro_io::load_blance_algorithm::WRR, {10, 5, 5});
coro_http_server proxy_rr(2, 8091);
proxy_rr.set_http_proxy_handler<GET, POST>(
"/", {"127.0.0.1:9001", "127.0.0.1:9002", "127.0.0.1:9003"},
coro_io::load_blance_algorithm::RR);
coro_http_server proxy_random(2, 8092);
proxy_random.set_http_proxy_handler<GET, POST>(
"/", {"127.0.0.1:9001", "127.0.0.1:9002", "127.0.0.1:9003"});
coro_http_server proxy_all(2, 8093);
proxy_all.set_http_proxy_handler(
"/all", {"127.0.0.1:9001", "127.0.0.1:9002", "127.0.0.1:9003"});
"/", {"127.0.0.1:9001", "127.0.0.1:9002", "127.0.0.1:9003"});
proxy_wrr.async_start();
proxy_rr.async_start();
@ -814,38 +852,39 @@ int main() {
std::this_thread::sleep_for(200ms);
coro_http_client client_rr;
resp_data resp_rr = client_rr.get("http://127.0.0.1:8091/rr");
resp_data resp_rr = client_rr.get("http://127.0.0.1:8091/");
assert(resp_rr.resp_body == "web1");
resp_rr = client_rr.get("http://127.0.0.1:8091/rr");
resp_rr = client_rr.get("http://127.0.0.1:8091/");
assert(resp_rr.resp_body == "web2");
resp_rr = client_rr.get("http://127.0.0.1:8091/rr");
resp_rr = client_rr.get("http://127.0.0.1:8091/");
assert(resp_rr.resp_body == "web3");
resp_rr = client_rr.get("http://127.0.0.1:8091/rr");
resp_rr = client_rr.get("http://127.0.0.1:8091/");
assert(resp_rr.resp_body == "web1");
resp_rr = client_rr.get("http://127.0.0.1:8091/rr");
resp_rr = client_rr.get("http://127.0.0.1:8091/");
assert(resp_rr.resp_body == "web2");
resp_rr = client_rr.post("http://127.0.0.1:8091/rr", "test content",
resp_rr = client_rr.post("http://127.0.0.1:8091/", "test content",
req_content_type::text);
assert(resp_rr.resp_body == "web3");
coro_http_client client_wrr;
resp_data resp = client_wrr.get("http://127.0.0.1:8090/wrr");
resp_data resp = client_wrr.get("http://127.0.0.1:8090/");
assert(resp.resp_body == "web1");
resp = client_wrr.get("http://127.0.0.1:8090/wrr");
resp = client_wrr.get("http://127.0.0.1:8090/");
assert(resp.resp_body == "web1");
resp = client_wrr.get("http://127.0.0.1:8090/wrr");
resp = client_wrr.get("http://127.0.0.1:8090/");
assert(resp.resp_body == "web2");
resp = client_wrr.get("http://127.0.0.1:8090/wrr");
resp = client_wrr.get("http://127.0.0.1:8090/");
assert(resp.resp_body == "web3");
coro_http_client client_random;
resp_data resp_random = client_random.get("http://127.0.0.1:8092/random");
resp_data resp_random = client_random.get("http://127.0.0.1:8092/");
std::cout << resp_random.resp_body << "\n";
assert(!resp_random.resp_body.empty());
coro_http_client client_all;
resp_random = client_all.post("http://127.0.0.1:8093/all", "test content",
resp_random = client_all.post("http://127.0.0.1:8093/", "test content",
req_content_type::text);
std::cout << resp_random.resp_body << "\n";
assert(!resp_random.resp_body.empty());
```
}
```