From 5c2a075a95f578bdd4f97e5a58100878c4b73bec Mon Sep 17 00:00:00 2001 From: qicosmos Date: Sun, 7 Apr 2024 17:26:16 +0800 Subject: [PATCH] do some fix --- .../standalone/cinatra/coro_http_request.hpp | 2 + .../standalone/cinatra/coro_http_server.hpp | 63 ++++++++------ .../ylt/standalone/cinatra/http_parser.hpp | 4 + src/coro_http/examples/example.cpp | 32 +++---- .../zh/coro_http/coro_http_introduction.md | 83 ++++++++++++++----- 5 files changed, 122 insertions(+), 62 deletions(-) diff --git a/include/ylt/standalone/cinatra/coro_http_request.hpp b/include/ylt/standalone/cinatra/coro_http_request.hpp index f5788d31b..36309a128 100644 --- a/include/ylt/standalone/cinatra/coro_http_request.hpp +++ b/include/ylt/standalone/cinatra/coro_http_request.hpp @@ -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(); diff --git a/include/ylt/standalone/cinatra/coro_http_server.hpp b/include/ylt/standalone/cinatra/coro_http_server.hpp index 68fae10fd..162c2af6d 100644 --- a/include/ylt/standalone/cinatra/coro_http_server.hpp +++ b/include/ylt/standalone/cinatra/coro_http_server.hpp @@ -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 async_start() { + async_simple::Future async_start() { errc_ = listen(); - async_simple::Promise promise; + async_simple::Promise 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::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 { co_await channel->send_request( [this, &req, &response]( coro_http_client &client, std::string_view host) -> async_simple::coro::Lazy { - 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 accept() { + async_simple::coro::Lazy 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 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 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{.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> 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 acceptor_close_waiter_; diff --git a/include/ylt/standalone/cinatra/http_parser.hpp b/include/ylt/standalone/cinatra/http_parser.hpp index 15e1e2f55..79b3cc7a8 100644 --- a/include/ylt/standalone/cinatra/http_parser.hpp +++ b/include/ylt/standalone/cinatra/http_parser.hpp @@ -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 headers_; std::string_view method_; std::string_view url_; + std::string_view full_url_; std::unordered_map queries_; }; } // namespace cinatra \ No newline at end of file diff --git a/src/coro_http/examples/example.cpp b/src/coro_http/examples/example.cpp index 25ca99e15..c6472f0c6 100644 --- a/src/coro_http/examples/example.cpp +++ b/src/coro_http/examples/example.cpp @@ -482,21 +482,21 @@ void http_proxy() { coro_http_server proxy_wrr(2, 8090); proxy_wrr.set_http_proxy_handler( - "/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( - "/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( - "/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()); diff --git a/website/docs/zh/coro_http/coro_http_introduction.md b/website/docs/zh/coro_http/coro_http_introduction.md index e9eb0aafe..d32949372 100644 --- a/website/docs/zh/coro_http/coro_http_introduction.md +++ b/website/docs/zh/coro_http/coro_http_introduction.md @@ -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( - "/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); + + web_one.set_http_handler( + "/", + [](coro_http_request &req, + coro_http_response &response) -> async_simple::coro::Lazy { + 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( + "/", + [](coro_http_request &req, + coro_http_response &response) -> async_simple::coro::Lazy { + 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( + "/", [](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( + "/", {"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( - "/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_wrr(2, 8090); - proxy_wrr.set_http_proxy_handler( - "/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}); + coro_http_server proxy_random(2, 8092); + proxy_random.set_http_proxy_handler( + "/", {"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()); - ``` +} +```