diff --git a/example/main.cpp b/example/main.cpp index 54763bdd..348f0e96 100644 --- a/example/main.cpp +++ b/example/main.cpp @@ -7,10 +7,8 @@ #include #include "../include/cinatra.hpp" -#include "cinatra/metric_conf.hpp" using namespace cinatra; -using namespace ylt::metric; using namespace std::chrono_literals; void create_file(std::string filename, size_t file_size = 64) { @@ -372,8 +370,6 @@ async_simple::coro::Lazy basic_usage() { response.set_status_and_content(status_type::ok, "ok"); }); - server.use_metrics(); - person_t person{}; server.set_http_handler("/person", &person_t::foo, person); @@ -427,121 +423,12 @@ async_simple::coro::Lazy basic_usage() { result.net_err.value() assert(result.status == 200); #endif } - -void use_metric() { - using namespace ylt::metric; - auto c = std::make_shared("request_count", "request count"); - auto failed = std::make_shared("not_found_request_count", - "not found request count"); - auto total = - std::make_shared("total_request_count", "total request count"); - - auto h = - std::make_shared(std::string("test"), std::string("help"), - std::vector{5.0, 10.0, 20.0, 50.0, 100.0}); - - auto summary = std::make_shared(std::string("test_summary"), - std::string("summary help"), - std::vector{0.5, 0.9, 0.95, 0.99}); - - default_static_metric_manager::instance().register_metric(c); - default_static_metric_manager::instance().register_metric(total); - default_static_metric_manager::instance().register_metric(failed); - default_static_metric_manager::instance().register_metric(h); - default_static_metric_manager::instance().register_metric(summary); - - std::random_device rd; - std::mt19937 gen(rd()); - std::uniform_int_distribution<> distr(1, 100); - - std::thread thd([&] { - while (true) { - c->inc(); - total->inc(); - h->observe(distr(gen)); - summary->observe(distr(gen)); - std::this_thread::sleep_for(1s); - } - }); - thd.detach(); - - coro_http_server server(1, 9001); - server.set_default_handler( - [&](coro_http_request &req, - coro_http_response &resp) -> async_simple::coro::Lazy { - failed->inc(); - total->inc(); - resp.set_status_and_content(status_type::not_found, "not found"); - co_return; - }); - - server.set_http_handler( - "/get", [&](coro_http_request &req, coro_http_response &resp) { - resp.set_status_and_content(status_type::ok, "ok"); - c->inc(); - total->inc(); - }); - - server.set_http_handler( - "/test", [&](coro_http_request &req, coro_http_response &resp) { - resp.set_status_and_content(status_type::ok, "ok"); - c->inc(); - total->inc(); - }); - - server.set_http_handler( - "/", [&](coro_http_request &req, coro_http_response &resp) { - resp.set_status_and_content(status_type::ok, "ok"); - total->inc(); - }); - - server.set_http_handler( - "/metrics", [](coro_http_request &req, coro_http_response &resp) { - resp.need_date_head(false); - resp.set_status_and_content(status_type::ok, ""); - }); - server.sync_start(); -} - -void metrics_example() { - auto get_req_counter = std::make_shared( - "get_req_count", "get req count", - std::map{{"url", "/get"}}); - auto get_req_qps = std::make_shared("get_req_qps", "get req qps"); - // default_static_metric_manager::instance().register_metric_static(get_req_counter, - // get_req_qps); - int64_t last = 0; - std::thread thd([&] { - while (true) { - std::this_thread::sleep_for(1s); - auto value = get_req_counter->value(); - get_req_qps->update(value - last); - last = value; - } - }); - thd.detach(); - - coro_http_server server(1, 9001); - server.set_http_handler( - "/get", [&](coro_http_request &req, coro_http_response &resp) { - // get_req_counter->inc({"/get"}); - resp.set_status_and_content(status_type::ok, "ok"); - }); - server.set_http_handler( - "/", [&](coro_http_request &req, coro_http_response &resp) { - resp.set_status_and_content(status_type::ok, "hello world"); - }); - server.use_metrics(true, "/metrics"); - server.sync_start(); -} - async_simple::coro::Lazy use_channel() { coro_http_server server(1, 9001); server.set_http_handler( "/", [&](coro_http_request &req, coro_http_response &resp) { resp.set_status_and_content(status_type::ok, "hello world"); }); - server.use_metrics(); server.async_start(); std::this_thread::sleep_for(100ms); @@ -564,15 +451,8 @@ async_simple::coro::Lazy use_pool() { "/", [&](coro_http_request &req, coro_http_response &resp) { resp.set_status_and_content(status_type::ok, "hello world"); }); - server.use_metrics(); server.async_start(); - auto map = default_static_metric_manager::instance().metric_map(); - for (auto &[k, m] : map) { - std::cout << k << ", "; - std::cout << m->help() << "\n"; - } - std::string url = "http://127.0.0.1:9001/"; auto pool = coro_io::client_pool::create( @@ -600,8 +480,6 @@ async_simple::coro::Lazy use_pool() { } int main() { - // use_metric(); - // metrics_example(); async_simple::coro::syncAwait(use_channel()); async_simple::coro::syncAwait(use_pool()); async_simple::coro::syncAwait(basic_usage()); diff --git a/include/cinatra/coro_http_client.hpp b/include/cinatra/coro_http_client.hpp index 00a1db32..f38cf362 100644 --- a/include/cinatra/coro_http_client.hpp +++ b/include/cinatra/coro_http_client.hpp @@ -1372,6 +1372,40 @@ class coro_http_client : public std::enable_shared_from_this { #endif } +#ifdef INJECT_FOR_HTTP_CLIENT_TEST + async_simple::coro::Lazy async_write_raw( + std::string_view data) { + auto [ec, _] = co_await async_write(asio::buffer(data)); + co_return ec; + } + + async_simple::coro::Lazy async_read_raw( + http_method method, bool clear_buffer = false) { + if (clear_buffer) { + body_.clear(); + } + + char buf[1024]; + std::error_code ec{}; + size_t size{}; +#ifdef CINATRA_ENABLE_SSL + if (has_init_ssl_) { + std::tie(ec, size) = co_await coro_io::async_read_some( + *socket_->ssl_stream_, asio::buffer(buf, 1024)); + } + else { +#endif + std::tie(ec, size) = co_await coro_io::async_read_some( + socket_->impl_, asio::buffer(buf, 1024)); +#ifdef CINATRA_ENABLE_SSL + } +#endif + body_.append(buf, size); + + co_return resp_data{ec, {}, {}, body_}; + } +#endif + inline void set_proxy(const std::string &host, const std::string &port) { proxy_host_ = host; proxy_port_ = port; diff --git a/include/cinatra/coro_http_connection.hpp b/include/cinatra/coro_http_connection.hpp index 8b2c24f7..2ec5d163 100644 --- a/include/cinatra/coro_http_connection.hpp +++ b/include/cinatra/coro_http_connection.hpp @@ -21,14 +21,9 @@ #include "sha1.hpp" #include "string_resize.hpp" #include "websocket.hpp" -#include "ylt/metric/counter.hpp" -#include "ylt/metric/gauge.hpp" -#include "ylt/metric/histogram.hpp" -#include "ylt/metric/metric.hpp" #ifdef CINATRA_ENABLE_GZIP #include "gzip.hpp" #endif -#include "metric_conf.hpp" #include "ylt/coro_io/coro_file.hpp" #include "ylt/coro_io/coro_io.hpp" @@ -52,14 +47,9 @@ class coro_http_connection request_(parser_, this), response_(this) { buffers_.reserve(3); - - cinatra_metric_conf::server_total_fd_inc(); } - ~coro_http_connection() { - cinatra_metric_conf::server_total_fd_dec(); - close(); - } + ~coro_http_connection() { close(); } #ifdef CINATRA_ENABLE_SSL bool init_ssl(const std::string &cert_file, const std::string &key_file, @@ -126,21 +116,17 @@ class coro_http_connection CINATRA_LOG_WARNING << "read http header error: " << ec.message(); } - cinatra_metric_conf::server_failed_req_inc(); close(); break; } - if (cinatra_metric_conf::enable_metric) { - start = std::chrono::system_clock::now(); - cinatra_metric_conf::server_total_req_inc(); - } - const char *data_ptr = asio::buffer_cast(head_buf_.data()); int head_len = parser_.parse_request(data_ptr, size, 0); if (head_len <= 0) { - cinatra_metric_conf::server_failed_req_inc(); CINATRA_LOG_ERROR << "parse http header error"; + response_.set_status_and_content(status_type::bad_request, + "invalid http protocol"); + co_await reply(); close(); break; } @@ -153,9 +139,6 @@ class coro_http_connection if (type != content_type::chunked && type != content_type::multipart) { size_t body_len = parser_.body_len(); if (body_len == 0) { - if (cinatra_metric_conf::enable_metric) { - cinatra_metric_conf::server_total_recv_bytes_inc(head_len); - } if (parser_.method() == "GET"sv) { if (request_.is_upgrade()) { #ifdef CINATRA_ENABLE_GZIP @@ -175,16 +158,6 @@ class coro_http_connection } response_.set_delay(true); } - else { - if (cinatra_metric_conf::enable_metric) { - mid = std::chrono::system_clock::now(); - double count = - std::chrono::duration_cast(mid - - start) - .count(); - cinatra_metric_conf::server_read_latency_observe(count); - } - } } } else if (body_len <= head_buf_.size()) { @@ -194,7 +167,6 @@ class coro_http_connection memcpy(body_.data(), data_ptr, body_len); head_buf_.consume(head_buf_.size()); } - cinatra_metric_conf::server_total_recv_bytes_inc(head_len + body_len); } else { size_t part_size = head_buf_.size(); @@ -209,22 +181,9 @@ class coro_http_connection size_to_read); if (ec) { CINATRA_LOG_ERROR << "async_read error: " << ec.message(); - cinatra_metric_conf::server_failed_req_inc(); close(); break; } - else { - if (cinatra_metric_conf::enable_metric) { - cinatra_metric_conf::server_total_recv_bytes_inc(head_len + - body_len); - mid = std::chrono::system_clock::now(); - double count = - std::chrono::duration_cast(mid - - start) - .count(); - cinatra_metric_conf::server_read_latency_observe(count); - } - } } } @@ -358,37 +317,44 @@ class coro_http_connection 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}; + auto next_data_ptr = + asio::buffer_cast(head_buf_.data()); + std::string_view left_content{next_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); + int head_len = parser.parse_request(next_data_ptr, left_size, 0); if (head_len <= 0) { CINATRA_LOG_ERROR << "parse http header error"; + response_.set_status_and_content(status_type::bad_request, + "invalid http protocol"); + co_await reply(); close(); break; } head_buf_.consume(pos + TWO_CRCF.length()); - std::string_view key = { - parser_.method().data(), - parser_.method().length() + 1 + parser_.url().length()}; + std::string_view next_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) { + if (auto handler = router_.get_handler(next_key); handler) { router_.route(handler, req, resp, key); } else { - if (auto coro_handler = router_.get_coro_handler(key); + if (auto coro_handler = router_.get_coro_handler(next_key); coro_handler) { co_await router_.route_coro(coro_handler, req, resp, key); } + else { + resp.set_status(status_type::not_found); + } } resp.build_resp_str(resp_str_); @@ -409,14 +375,6 @@ class coro_http_connection } } - if (cinatra_metric_conf::enable_metric) { - mid = std::chrono::system_clock::now(); - double count = - std::chrono::duration_cast(mid - start) - .count(); - cinatra_metric_conf::server_req_latency_observe(count); - } - response_.clear(); request_.clear(); buffers_.clear(); @@ -430,10 +388,6 @@ class coro_http_connection } async_simple::coro::Lazy reply(bool need_to_bufffer = true) { - if (response_.status() >= status_type::bad_request) { - if (cinatra_metric_conf::enable_metric) - cinatra_metric_conf::server_failed_req_inc(); - } std::error_code ec; size_t size; if (multi_buf_) { @@ -444,18 +398,12 @@ class coro_http_connection for (auto &buf : buffers_) { send_size += buf.size(); } - if (cinatra_metric_conf::enable_metric) { - cinatra_metric_conf::server_total_send_bytes_inc(send_size); - } std::tie(ec, size) = co_await async_write(buffers_); } else { if (need_to_bufffer) { response_.build_resp_str(resp_str_); } - if (cinatra_metric_conf::enable_metric) { - cinatra_metric_conf::server_total_send_bytes_inc(resp_str_.size()); - } std::tie(ec, size) = co_await async_write(asio::buffer(resp_str_)); } @@ -513,8 +461,6 @@ class coro_http_connection co_return true; } - bool sync_reply() { return async_simple::coro::syncAwait(reply()); } - async_simple::coro::Lazy begin_chunked() { response_.set_delay(true); response_.set_status(status_type::ok); @@ -709,6 +655,7 @@ class coro_http_connection switch (type) { case cinatra::ws_frame_type::WS_ERROR_FRAME: + close(); result.ec = std::make_error_code(std::errc::protocol_error); break; case cinatra::ws_frame_type::WS_OPENING_FRAME: @@ -790,7 +737,7 @@ class coro_http_connection inflate_str_.clear(); if (!cinatra::gzip_codec::inflate({payload.data(), payload.size()}, inflate_str_)) { - CINATRA_LOG_ERROR << "uncompuress data error"; + CINATRA_LOG_ERROR << "compress data error"; result.ec = std::make_error_code(std::errc::protocol_error); return false; } diff --git a/include/cinatra/coro_http_server.hpp b/include/cinatra/coro_http_server.hpp index 4b16c9ae..f6fa5f8a 100644 --- a/include/cinatra/coro_http_server.hpp +++ b/include/cinatra/coro_http_server.hpp @@ -11,7 +11,6 @@ #include "ylt/coro_io/coro_io.hpp" #include "ylt/coro_io/io_context_pool.hpp" #include "ylt/coro_io/load_blancer.hpp" -#include "ylt/metric/system_metric.hpp" namespace cinatra { enum class file_resp_format_type { @@ -182,29 +181,6 @@ class coro_http_server { } } - void use_metrics(bool enable_json = false, - std::string url_path = "/metrics") { - init_metrics(); - using root = ylt::metric::metric_collector_t< - ylt::metric::default_static_metric_manager, - ylt::metric::system_metric_manager>; - set_http_handler( - url_path, - [enable_json](coro_http_request &req, coro_http_response &res) { - std::string str; -#ifdef CINATRA_ENABLE_METRIC_JSON - if (enable_json) { - str = root::serialize_to_json(); - res.set_content_type(); - } - else -#endif - str = root::serialize(); - - res.set_status_and_content(status_type::ok, std::move(str)); - }); - } - template void set_http_proxy_handler(std::string url_path, std::vector hosts, @@ -277,25 +253,29 @@ class coro_http_server { break; } - co_await load_blancer->send_request( - [&req, result]( - coro_http_client &client, - std::string_view host) -> async_simple::coro::Lazy { + auto ret = co_await load_blancer->send_request( + [&req, result](coro_http_client &client, std::string_view host) + -> async_simple::coro::Lazy { auto r = co_await client.write_websocket(std::string(result.data)); if (r.net_err) { - co_return; + co_return r.net_err; } auto data = co_await client.read_websocket(); if (data.net_err) { - co_return; + co_return data.net_err; } auto ec = co_await req.get_conn()->write_websocket( std::string(result.data)); if (ec) { - co_return; + co_return ec; } + co_return std::error_code{}; }); + if (!ret.has_value()) { + req.get_conn()->close(); + break; + } } }, std::forward(aspects)...); @@ -932,32 +912,6 @@ class coro_http_server { address_ = std::move(address); } - private: - void init_metrics() { - using namespace ylt::metric; - - cinatra_metric_conf::enable_metric = true; - default_static_metric_manager::instance().create_metric_static( - cinatra_metric_conf::server_total_req, ""); - default_static_metric_manager::instance().create_metric_static( - cinatra_metric_conf::server_failed_req, ""); - default_static_metric_manager::instance().create_metric_static( - cinatra_metric_conf::server_total_recv_bytes, ""); - default_static_metric_manager::instance().create_metric_static( - cinatra_metric_conf::server_total_send_bytes, ""); - default_static_metric_manager::instance().create_metric_static( - cinatra_metric_conf::server_total_fd, ""); - default_static_metric_manager::instance().create_metric_static( - cinatra_metric_conf::server_req_latency, "", - std::vector{30, 40, 50, 60, 70, 80, 90, 100, 150}); - default_static_metric_manager::instance().create_metric_static( - cinatra_metric_conf::server_read_latency, "", - std::vector{3, 5, 7, 9, 13, 18, 23, 35, 50}); -#if defined(__GNUC__) - ylt::metric::start_system_metric(); -#endif - } - private: std::unique_ptr pool_; asio::io_context *out_ctx_ = nullptr; diff --git a/include/cinatra/metric_conf.hpp b/include/cinatra/metric_conf.hpp deleted file mode 100644 index 3114fbb7..00000000 --- a/include/cinatra/metric_conf.hpp +++ /dev/null @@ -1,130 +0,0 @@ -#pragma once -#include -#include - -#include "ylt/metric/counter.hpp" -#include "ylt/metric/gauge.hpp" -#include "ylt/metric/histogram.hpp" -#include "ylt/metric/metric.hpp" -#include "ylt/metric/metric_manager.hpp" -#include "ylt/metric/summary.hpp" -#include "ylt/metric/system_metric.hpp" - -namespace cinatra { -struct cinatra_metric_conf { - inline static std::string server_total_req = "server_total_req"; - inline static std::string server_failed_req = "server_failed_req"; - inline static std::string server_total_fd = "server_total_fd"; - inline static std::string server_total_recv_bytes = "server_total_recv_bytes"; - inline static std::string server_total_send_bytes = "server_total_send_bytes"; - inline static std::string server_req_latency = "server_req_latency"; - inline static std::string server_read_latency = "server_read_latency"; - inline static std::string server_total_thread_num = "server_total_thread_num"; - inline static bool enable_metric = false; - - inline static void server_total_req_inc() { - if (!enable_metric) { - return; - } - - static auto m = - ylt::metric::default_static_metric_manager::instance() - .get_metric_static(server_total_req); - if (m == nullptr) { - return; - } - m->inc(); - } - - inline static void server_failed_req_inc() { - if (!enable_metric) { - return; - } - static auto m = - ylt::metric::default_static_metric_manager::instance() - .get_metric_static(server_failed_req); - if (m == nullptr) { - return; - } - m->inc(); - } - - inline static void server_total_fd_inc() { - if (!enable_metric) { - return; - } - static auto m = - ylt::metric::default_static_metric_manager::instance() - .get_metric_static(server_total_fd); - if (m == nullptr) { - return; - } - m->inc(); - } - - inline static void server_total_fd_dec() { - if (!enable_metric) { - return; - } - static auto m = - ylt::metric::default_static_metric_manager::instance() - .get_metric_static(server_total_fd); - if (m == nullptr) { - return; - } - m->dec(); - } - - inline static void server_total_recv_bytes_inc(double val) { - if (!enable_metric) { - return; - } - static auto m = - ylt::metric::default_static_metric_manager::instance() - .get_metric_static(server_total_recv_bytes); - if (m == nullptr) { - return; - } - m->inc(val); - } - - inline static void server_total_send_bytes_inc(double val) { - if (!enable_metric) { - return; - } - static auto m = - ylt::metric::default_static_metric_manager::instance() - .get_metric_static(server_total_send_bytes); - if (m == nullptr) { - return; - } - m->inc(val); - } - - inline static void server_req_latency_observe(double val) { - if (!enable_metric) { - return; - } - static auto m = - ylt::metric::default_static_metric_manager::instance() - .get_metric_static(server_req_latency); - if (m == nullptr) { - return; - } - m->observe(val); - } - - inline static void server_read_latency_observe(double val) { - if (!enable_metric) { - return; - } - static auto m = - ylt::metric::default_static_metric_manager::instance() - .get_metric_static(server_read_latency); - if (m == nullptr) { - return; - } - m->observe(val); - } -}; -} // namespace cinatra diff --git a/include/cinatra/websocket.hpp b/include/cinatra/websocket.hpp index 5f4e76c2..50a6d791 100644 --- a/include/cinatra/websocket.hpp +++ b/include/cinatra/websocket.hpp @@ -118,7 +118,7 @@ class websocket { return ws_frame_type::WS_PING_FRAME; if (msg_opcode_ == 0xA) return ws_frame_type::WS_PONG_FRAME; - return ws_frame_type::WS_BINARY_FRAME; + return ws_frame_type::WS_ERROR_FRAME; } std::string_view encode_ws_header(size_t size, opcode op, bool eof, diff --git a/tests/test_cinatra.cpp b/tests/test_cinatra.cpp index e184acb5..88bf3fb9 100644 --- a/tests/test_cinatra.cpp +++ b/tests/test_cinatra.cpp @@ -654,6 +654,146 @@ TEST_CASE("test response") { CHECK(result.resp_body.empty()); } +#ifdef INJECT_FOR_HTTP_CLIENT_TEST +TEST_CASE("test pipeline") { + coro_http_server server(1, 9001); + server.set_http_handler( + "/test", [](coro_http_request &req, coro_http_response &res) { + res.set_status_and_content(status_type::ok, "hello world"); + }); + server.set_http_handler( + "/coro", + [](coro_http_request &req, + coro_http_response &res) -> async_simple::coro::Lazy { + res.set_status_and_content(status_type::ok, "hello coro"); + co_return; + }); + server.async_start(); + + { + coro_http_client client{}; + std::string uri = "http://127.0.0.1:9001"; + async_simple::coro::syncAwait(client.connect(uri)); + auto ec = async_simple::coro::syncAwait(client.async_write_raw( + "GET /test HTTP/1.1\r\nHost: 127.0.0.1:8090\r\n\r\n")); + CHECK(!ec); + + auto result = + async_simple::coro::syncAwait(client.async_read_raw(http_method::GET)); + CHECK(!result.resp_body.empty()); + ec = async_simple::coro::syncAwait(client.async_write_raw( + "GET /test HTTP/1.1\r\nHost: 127.0.0.1:8090\r\n\r\nGET /test " + "HTTP/1.1\r\nHost: 127.0.0.1:8090\r\n\r\n")); + CHECK(!ec); + result = async_simple::coro::syncAwait( + client.async_read_raw(http_method::GET, true)); + CHECK(!result.resp_body.empty()); + auto data = result.resp_body; + http_parser parser{}; + int r = parser.parse_response(data.data(), data.size(), 0); + if (r) { + std::string_view body(data.data() + r, parser.body_len()); + CHECK(body == "hello world"); + CHECK(data.size() > parser.total_len()); + } + } + + { + http_parser p1{}; + std::string str = "GET /coro1 HTTP/1.1\r\nHost: 127.0.0.1:8090\r\n\r\n"; + int ret = p1.parse_request(str.data(), str.size(), 0); + + coro_http_client client{}; + std::string uri = "http://127.0.0.1:9001"; + async_simple::coro::syncAwait(client.connect(uri)); + auto ec = async_simple::coro::syncAwait(client.async_write_raw( + "GET /coro HTTP/1.1\r\nHost: 127.0.0.1:8090\r\n\r\nGET /test " + "HTTP/1.1\r\nHost: 127.0.0.1:8090\r\n\r\nGET /coro1 HTTP/1.1\r\nHost: " + "127.0.0.1:8090\r\n\r\nGET /coro HTTP/1.1\r\nHost: " + "127.0.0.1:8090\r\n\r\n")); + CHECK(!ec); + auto result = async_simple::coro::syncAwait( + client.async_read_raw(http_method::GET, true)); + http_parser parser{}; + int r = parser.parse_response(result.resp_body.data(), + result.resp_body.size(), 0); + CHECK(parser.status() == 200); + } + + { + coro_http_client client{}; + std::string uri = "http://127.0.0.1:9001"; + async_simple::coro::syncAwait(client.connect(uri)); + auto ec = async_simple::coro::syncAwait(client.async_write_raw( + "GET /test HTTP/1.1\r\nHost: 127.0.0.1:8090\r\nContent-Type: " + "multipart/form-data\r\n\r\nGET /test HTTP/1.1\r\nHost: " + "127.0.0.1:8090\r\nContent-Type: multipart/form-data\r\n\r\n")); + CHECK(!ec); + + auto result = + async_simple::coro::syncAwait(client.async_read_raw(http_method::GET)); + http_parser parser{}; + int r = parser.parse_response(result.resp_body.data(), + result.resp_body.size(), 0); + CHECK(parser.status() != 200); + } + + { + coro_http_client client{}; + std::string uri = "http://127.0.0.1:9001"; + async_simple::coro::syncAwait(client.connect(uri)); + auto ec = async_simple::coro::syncAwait(client.async_write_raw( + "POST /test HTTP/1.1\r\nHost: 127.0.0.1:8090\r\n\r\nGET /test " + "HTTP/1.1\r\nHost: " + "127.0.0.1:8090\r\n\r\n")); + CHECK(!ec); + + auto result = + async_simple::coro::syncAwait(client.async_read_raw(http_method::POST)); + http_parser parser{}; + int r = parser.parse_response(result.resp_body.data(), + result.resp_body.size(), 0); + CHECK(parser.status() != 200); + } + + { + coro_http_client client{}; + std::string uri = "http://127.0.0.1:9001"; + async_simple::coro::syncAwait(client.connect(uri)); + auto ec = async_simple::coro::syncAwait(client.async_write_raw( + "GET HTTP/1.1\r\nHost: 127.0.0.1:8090\r\n\r\nGET /test " + "HTTP/1.1\r\nHost: " + "127.0.0.1:8090\r\n\r\n")); + CHECK(!ec); + + auto result = + async_simple::coro::syncAwait(client.async_read_raw(http_method::GET)); + http_parser parser{}; + int r = parser.parse_response(result.resp_body.data(), + result.resp_body.size(), 0); + CHECK(parser.status() != 200); + } + + { + coro_http_client client{}; + std::string uri = "http://127.0.0.1:9001"; + async_simple::coro::syncAwait(client.connect(uri)); + auto ec = async_simple::coro::syncAwait( + client.async_write_raw("GET /test HTTP/1.1\r\nHost: " + "127.0.0.1:8090\r\n\r\nGET HTTP/1.1\r\nHost: " + "127.0.0.1:8090\r\n\r\n")); + CHECK(!ec); + + auto result = + async_simple::coro::syncAwait(client.async_read_raw(http_method::GET)); + http_parser parser{}; + int r = parser.parse_response(result.resp_body.data(), + result.resp_body.size(), 0); + CHECK(parser.status() != 200); + } +} +#endif + async_simple::coro::Lazy send_data(auto &ch, size_t count) { for (int i = 0; i < count; i++) { co_await coro_io::async_send(ch, i); @@ -1338,6 +1478,7 @@ TEST_CASE("test ranges download") { create_file("test_range.txt", 64); coro_http_server server(1, 8090); server.set_static_res_dir("", "./"); + server.set_static_res_dir("", "./www"); server.async_start(); coro_http_client client{}; diff --git a/tests/test_cinatra_websocket.cpp b/tests/test_cinatra_websocket.cpp index 8417c64e..25795278 100644 --- a/tests/test_cinatra_websocket.cpp +++ b/tests/test_cinatra_websocket.cpp @@ -61,7 +61,7 @@ async_simple::coro::Lazy test_websocket(coro_http_client &client) { co_return; } - auto result = co_await client.write_websocket("hello websocket"); + co_await client.write_websocket("hello websocket"); auto data = co_await client.read_websocket(); CHECK(data.resp_body == "hello websocket"); co_await client.write_websocket("test again"); @@ -73,6 +73,25 @@ async_simple::coro::Lazy test_websocket(coro_http_client &client) { CHECK(data.net_err == asio::error::eof); } +#ifdef CINATRA_ENABLE_GZIP +async_simple::coro::Lazy test_gzip_websocket(coro_http_client &client) { + auto r = co_await client.connect("ws://localhost:8090/ws"); + if (r.net_err) { + co_return; + } + + std::string str = "hello websocket"; + co_await client.write_websocket(str.data(), str.size()); + auto data = co_await client.read_websocket(); + CHECK(data.resp_body == "hello websocket"); + + co_await client.write_websocket_close("ws close"); + data = co_await client.read_websocket(); + CHECK(data.resp_body == "ws close"); + CHECK(data.net_err == asio::error::eof); +} +#endif + TEST_CASE("test websocket") { cinatra::coro_http_server server(1, 8090); server.set_http_handler( @@ -102,6 +121,47 @@ TEST_CASE("test websocket") { async_simple::coro::syncAwait(test_websocket(client)); +#ifdef INJECT_FOR_HTTP_CLIENT_TEST + { + auto lazy1 = []() -> async_simple::coro::Lazy { + coro_http_client client{}; + co_await client.connect("ws://localhost:8090/ws"); + std::string send_str = "test"; + websocket ws{}; + // msg too long + auto header = ws.encode_ws_header(9 * 1024 * 1024, opcode::text, true); + co_await client.async_write_raw(header); + co_await client.async_write_raw(send_str); + auto data = co_await client.read_websocket(); + CHECK(data.status != 200); + std::cout << data.resp_body << std::endl; + }; + async_simple::coro::syncAwait(lazy1()); + } + + { + auto lazy1 = []() -> async_simple::coro::Lazy { + coro_http_client client{}; + co_await client.connect("ws://localhost:8090/ws"); + std::string send_str = "test"; + websocket ws{}; + // error frame + auto header = ws.encode_ws_header(send_str.size(), (opcode)15, true); + co_await client.async_write_raw(header); + co_await client.async_write_raw(send_str); + auto data = co_await client.read_websocket(); + CHECK(data.status != 200); + }; + async_simple::coro::syncAwait(lazy1()); + } +#endif + +#ifdef CINATRA_ENABLE_GZIP + coro_http_client client1{}; + client1.set_ws_deflate(true); + async_simple::coro::syncAwait(test_gzip_websocket(client1)); +#endif + std::this_thread::sleep_for(std::chrono::milliseconds(300)); // client->async_close(); diff --git a/tests/test_coro_http_server.cpp b/tests/test_coro_http_server.cpp index b6d4f1f9..4caa7f3c 100644 --- a/tests/test_coro_http_server.cpp +++ b/tests/test_coro_http_server.cpp @@ -446,6 +446,8 @@ TEST_CASE("get post") { CHECK(req.get_method() == "POST"); CHECK(req.get_url() == "/test1"); CHECK(req.get_conn()->local_address() == "127.0.0.1:9001"); + CHECK(req.get_conn()->remote_address().find("127.0.0.1:") != + std::string::npos); CHECK(req.get_conn()->remote_address().find("127.0.0.1:") != std::string::npos); resp.add_header("Host", "Cinatra"); @@ -472,6 +474,9 @@ TEST_CASE("get post") { "/close", [](coro_http_request &req, coro_http_response &resp) { resp.set_keepalive(false); resp.set_status_and_content(cinatra::status_type::ok, "hello"); + resp.get_conn()->close(); + auto s = req.get_conn()->local_address(); + CHECK(s.empty()); }); server.async_start(); @@ -507,7 +512,7 @@ TEST_CASE("get post") { client.add_header("Connection", "close"); result = client.get("http://127.0.0.1:9001/close"); - CHECK(result.status == 200); + CHECK(result.status != 200); server.stop(); } @@ -639,35 +644,6 @@ TEST_CASE("use out context") { thd.join(); } -TEST_CASE("use metric") { - asio::io_context out_ctx; - auto work = std::make_unique(out_ctx); - std::thread thd([&] { - out_ctx.run(); - }); - - cinatra::coro_http_server server(out_ctx, "0.0.0.0:9007"); - server.set_no_delay(true); - auto addr = server.address(); - auto port = server.port(); - CHECK(addr == "0.0.0.0"); - CHECK(port == 9007); - server.use_metrics(); - server.async_start(); - - { - coro_http_client client1{}; - auto result = client1.get("http://127.0.0.1:9007/metrics"); - CHECK(result.status == 200); - CHECK(!result.resp_body.empty()); - } - - server.stop(); - - work.reset(); - thd.join(); -} - TEST_CASE("delay reply, server stop, form-urlencode, qureies, throw") { cinatra::coro_http_server server(1, 9001); @@ -1013,7 +989,6 @@ TEST_CASE("test websocket binary data") { } } }); - server.set_http_handler( "/medium_binary", [](coro_http_request &req, @@ -1112,7 +1087,7 @@ TEST_CASE("check connecton timeout") { } TEST_CASE("test websocket with different message size") { - cinatra::coro_http_server server(1, 9003); + cinatra::coro_http_server server(1, 9008); server.set_http_handler( "/ws_echo1", [](cinatra::coro_http_request &req, @@ -1143,7 +1118,7 @@ TEST_CASE("test websocket with different message size") { auto lazy = [](std::string str) -> async_simple::coro::Lazy { coro_http_client client{}; - auto ret = co_await client.connect("ws://127.0.0.1:9003/ws_echo1"); + auto ret = co_await client.connect("ws://127.0.0.1:9008/ws_echo1"); if (ret.status != 101) { std::cout << ret.net_err.message() << "\n"; } @@ -1202,11 +1177,11 @@ TEST_CASE("test ssl server") { #endif TEST_CASE("test http download server") { - cinatra::coro_http_server server(1, 9001); + cinatra::coro_http_server server(1, 9006); std::string filename = "test_download.txt"; create_file(filename, 1010); - // curl http://127.0.0.1:9001/download/test_download.txt will download + // curl http://127.0.0.1:9006/download/test_download.txt will download // test_download.txt file server.set_transfer_chunked_size(100); server.set_static_res_dir("download", ""); @@ -1216,7 +1191,7 @@ TEST_CASE("test http download server") { { coro_http_client client{}; auto result = async_simple::coro::syncAwait(client.async_download( - "http://127.0.0.1:9001/download/test_download.txt", "download.txt")); + "http://127.0.0.1:9006/download/test_download.txt", "download.txt")); CHECK(result.status == 200); std::string download_file = fs::absolute("download.txt").string(); @@ -1230,7 +1205,7 @@ TEST_CASE("test http download server") { { coro_http_client client{}; auto result = async_simple::coro::syncAwait(client.async_download( - "http://127.0.0.1:9001/download/test_download.txt", "download1.txt", + "http://127.0.0.1:9006/download/test_download.txt", "download1.txt", "0-")); CHECK(result.status == 200); @@ -1480,7 +1455,7 @@ TEST_CASE("test reverse proxy") { coro_http_server proxy_wrr(2, 8090); proxy_wrr.set_http_proxy_handler( - "/", {"http://127.0.0.1:9004", "127.0.0.1:9002", "127.0.0.1:9003"}, + "/", {"127.0.0.1:9004", "127.0.0.1:9002", "127.0.0.1:9003"}, coro_io::load_blance_algorithm::WRR, {10, 5, 5}, log_t{}, check_t{}); coro_http_server proxy_rr(2, 8091); @@ -1546,7 +1521,7 @@ TEST_CASE("test reverse proxy websocket") { CHECK_THROWS_AS(proxy_server.set_websocket_proxy_handler("/ws_echo", {}), std::invalid_argument); } - coro_http_server server(1, 9001); + coro_http_server server(1, 9005); server.set_http_handler( "/ws_echo", [](coro_http_request &req, @@ -1567,15 +1542,15 @@ TEST_CASE("test reverse proxy websocket") { }); server.async_start(); - coro_http_server proxy_server(1, 9005); + coro_http_server proxy_server(1, 9002); proxy_server.set_websocket_proxy_handler("/ws_echo", - {"ws://127.0.0.1:9001/ws_echo"}); + {"ws://127.0.0.1:9005/ws_echo"}); proxy_server.async_start(); std::this_thread::sleep_for(200ms); coro_http_client client{}; auto r = async_simple::coro::syncAwait( - client.connect("ws://127.0.0.1:9005/ws_echo")); + client.connect("ws://127.0.0.1:9002/ws_echo")); CHECK(!r.net_err); for (int i = 0; i < 10; i++) { async_simple::coro::syncAwait(client.write_websocket("test websocket"));