From d184ea1e608c4ca0c595bfd1948833f0f261673c Mon Sep 17 00:00:00 2001 From: qicosmos Date: Tue, 21 May 2024 16:54:19 +0800 Subject: [PATCH] fix and update --- .../standalone/cinatra/coro_http_client.hpp | 80 +------------------ .../cinatra/coro_http_connection.hpp | 16 +++- .../standalone/cinatra/coro_http_request.hpp | 10 ++- include/ylt/standalone/cinatra/multipart.hpp | 7 +- .../zh/coro_http/coro_http_introduction.md | 10 +-- 5 files changed, 36 insertions(+), 87 deletions(-) diff --git a/include/ylt/standalone/cinatra/coro_http_client.hpp b/include/ylt/standalone/cinatra/coro_http_client.hpp index acbb2b742..ce76a3572 100644 --- a/include/ylt/standalone/cinatra/coro_http_client.hpp +++ b/include/ylt/standalone/cinatra/coro_http_client.hpp @@ -288,7 +288,7 @@ class coro_http_client : public std::enable_shared_from_this { reset(); } else { - should_reset_ = false; + should_reset_ = true; } resp_data data{}; bool no_schema = !has_schema(uri); @@ -515,7 +515,6 @@ class coro_http_client : public std::enable_shared_from_this { #ifdef BENCHMARK_TEST void set_bench_stop() { stop_bench_ = true; } - void set_read_fix() { read_fix_ = 1; } #endif async_simple::coro::Lazy async_patch( @@ -558,73 +557,6 @@ class coro_http_client : public std::enable_shared_from_this { std::string uri, std::unordered_map headers = {}) { resp_data data{}; -#ifdef BENCHMARK_TEST - if (!req_str_.empty()) { - if (has_closed()) { - data.net_err = std::make_error_code(std::errc::not_connected); - data.status = 404; - co_return data; - } - - std::error_code ec{}; - size_t size = 0; - if (std::tie(ec, size) = co_await async_write(asio::buffer(req_str_)); - ec) { - data.net_err = ec; - data.status = 404; - close_socket(*socket_); - co_return data; - } - - if (read_fix_ == 0) { - req_context<> ctx{}; - bool is_keep_alive = true; - data = co_await handle_read(ec, size, is_keep_alive, std::move(ctx), - http_method::GET); - handle_result(data, ec, is_keep_alive); - if (ec) { - if (!stop_bench_) - CINATRA_LOG_ERROR << "do_bench_read error:" << ec.message(); - data.net_err = ec; - data.status = 404; - } - else { - data.status = 200; - data.total = total_len_; - } - - co_return data; - } - - std::tie(ec, size) = co_await async_read(head_buf_, total_len_); - - if (ec) { - if (!stop_bench_) - CINATRA_LOG_ERROR << "do_bench_read error:" << ec.message(); - data.net_err = ec; - data.status = 404; - close_socket(*socket_); - co_return data; - } - else { - const char *data_ptr = - asio::buffer_cast(head_buf_.data()); - head_buf_.consume(total_len_); - // check status - if (data_ptr[9] > '3') { - data.status = 404; - co_return data; - } - } - - head_buf_.consume(total_len_); - data.status = 200; - data.total = total_len_; - - co_return data; - } -#endif - req_context<> ctx{}; data = co_await async_request(std::move(uri), http_method::GET, std::move(ctx), std::move(headers)); @@ -892,7 +824,6 @@ class coro_http_client : public std::enable_shared_from_this { } #endif #ifdef BENCHMARK_TEST - req_str_.clear(); total_len_ = 0; #endif @@ -1160,9 +1091,6 @@ class coro_http_client : public std::enable_shared_from_this { vec.push_back(asio::buffer(ctx.content.data(), ctx.content.size())); } -#ifdef BENCHMARK_TEST - req_str_ = req_head_str; -#endif #ifdef CORO_HTTP_PRINT_REQ_HEAD CINATRA_LOG_DEBUG << req_head_str; #endif @@ -1640,7 +1568,7 @@ class coro_http_client : public std::enable_shared_from_this { std::string boundary = std::string{parser_.get_boundary()}; multipart_reader_t multipart(this); while (true) { - auto part_head = co_await multipart.read_part_head(); + auto part_head = co_await multipart.read_part_head(boundary); if (part_head.ec) { co_return part_head.ec; } @@ -2120,7 +2048,6 @@ class coro_http_client : public std::enable_shared_from_this { std::string redirect_uri_; bool enable_follow_redirect_ = false; bool enable_timeout_ = false; - bool should_reset_ = false; std::chrono::steady_clock::duration conn_timeout_duration_ = std::chrono::seconds(8); std::chrono::steady_clock::duration req_timeout_duration_ = @@ -2128,6 +2055,7 @@ class coro_http_client : public std::enable_shared_from_this { bool enable_tcp_no_delay_ = true; std::string resp_chunk_str_; std::span out_buf_; + bool should_reset_ = false; #ifdef CINATRA_ENABLE_GZIP bool enable_ws_deflate_ = false; @@ -2136,10 +2064,8 @@ class coro_http_client : public std::enable_shared_from_this { #endif #ifdef BENCHMARK_TEST - std::string req_str_; bool stop_bench_ = false; size_t total_len_ = 0; - int read_fix_ = 0; #endif }; } // namespace cinatra diff --git a/include/ylt/standalone/cinatra/coro_http_connection.hpp b/include/ylt/standalone/cinatra/coro_http_connection.hpp index 3fdd794ac..356fc4562 100644 --- a/include/ylt/standalone/cinatra/coro_http_connection.hpp +++ b/include/ylt/standalone/cinatra/coro_http_connection.hpp @@ -288,8 +288,19 @@ class coro_http_connection if (!response_.get_delay()) { if (head_buf_.size()) { - // handle pipeling, only support GET and HEAD method now. - if (parser_.method()[0] != 'G' && parser_.method()[0] != 'H') { + if (type == content_type::multipart) { + response_.set_status_and_content( + status_type::not_implemented, + "mutipart handler not implemented or incorrect implemented"); + co_await reply(); + close(); + CINATRA_LOG_ERROR + << "mutipart handler not implemented or incorrect implemented" + << ec.message(); + break; + } + else if (parser_.method()[0] != 'G' && parser_.method()[0] != 'H') { + // handle pipeling, only support GET and HEAD method now. response_.set_status_and_content(status_type::method_not_allowed, "method not allowed"); co_await reply(); @@ -343,6 +354,7 @@ class coro_http_connection co_return; } } + head_buf_.consume(head_buf_.size()); } else { handle_session_for_response(); diff --git a/include/ylt/standalone/cinatra/coro_http_request.hpp b/include/ylt/standalone/cinatra/coro_http_request.hpp index ea6574fd8..a41df18e3 100644 --- a/include/ylt/standalone/cinatra/coro_http_request.hpp +++ b/include/ylt/standalone/cinatra/coro_http_request.hpp @@ -184,7 +184,13 @@ class coro_http_request { if (content_type.empty()) { return {}; } - return content_type.substr(content_type.rfind("=") + 1); + + auto pos = content_type.rfind("="); + if (pos == std::string_view::npos) { + return ""; + } + + return content_type.substr(pos + 1); } coro_http_connection *get_conn() { return conn_; } @@ -278,7 +284,7 @@ class coro_http_request { http_parser &parser_; std::string_view body_; coro_http_connection *conn_; - bool is_websocket_; + bool is_websocket_ = false; std::vector aspect_data_; std::string cached_session_id_; }; diff --git a/include/ylt/standalone/cinatra/multipart.hpp b/include/ylt/standalone/cinatra/multipart.hpp index d40aaa711..b85b5001f 100644 --- a/include/ylt/standalone/cinatra/multipart.hpp +++ b/include/ylt/standalone/cinatra/multipart.hpp @@ -11,7 +11,12 @@ class multipart_reader_t { head_buf_(conn_->head_buf_), chunked_buf_(conn_->chunked_buf_) {} - async_simple::coro::Lazy read_part_head() { + async_simple::coro::Lazy read_part_head( + std::string_view boundary) { + if (boundary.empty()) { + co_return part_head_t{std::make_error_code(std::errc::protocol_error)}; + } + if (head_buf_.size() > 0) { const char *data_ptr = asio::buffer_cast(head_buf_.data()); chunked_buf_.sputn(data_ptr, head_buf_.size()); diff --git a/website/docs/zh/coro_http/coro_http_introduction.md b/website/docs/zh/coro_http/coro_http_introduction.md index d1e3ec7ce..20075a982 100644 --- a/website/docs/zh/coro_http/coro_http_introduction.md +++ b/website/docs/zh/coro_http/coro_http_introduction.md @@ -739,9 +739,9 @@ int main() { 见[example中的例子](example/main.cpp) ### 示例5:RESTful服务端路径参数设置 -本代码演示如何使用RESTful路径参数。下面设置了两个RESTful API。第一个API当访问,比如访问这样的url`http://127.0.0.1:8080/numbers/1234/test/5678`时服务器可以获取到1234和5678这两个参数,第一个RESTful API的参数是`(\d+)`是一个正则表达式表明只能参数只能为数字。获取第一个参数的代码是`req.get_matches()[1]`。因为每一个req不同所以每一个匹配到的参数都放在`request`结构体中。 +本代码演示如何使用RESTful路径参数。下面设置了两个RESTful API。第一个API当访问,比如访问这样的url`http://127.0.0.1:8080/numbers/1234/test/5678`时服务器可以获取到1234和5678这两个参数,第一个RESTful API的参数是`(\d+)`是一个正则表达式表明只能参数只能为数字。获取第一个参数的代码是`req.matches_[1]`。因为每一个req不同所以每一个匹配到的参数都放在`request`结构体中。 -同时还支持任意字符的RESTful API,即示例的第二种RESTful API`"/string/{:id}/test/{:name}"`,要获取到对应的参数使用`req.get_query_value`函数即可,其参数只能为注册的变量(如果不为依然运行但是有报错),例子中参数名是id和name,要获取id参数调用`req.get_query_value("id")`即可。示例代码运行后,当访问`http://127.0.0.1:8080/string/params_1/test/api_test`时,浏览器会返回`api_test`字符串。 +同时还支持任意字符的RESTful API,即示例的第二种RESTful API`"/string/:id/test/:name"`,要获取到对应的参数使用`req.get_query_value`函数即可,其参数只能为注册的变量(如果不为依然运行但是有报错),例子中参数名是id和name,要获取id参数调用`req.get_query_value("id")`即可。示例代码运行后,当访问`http://127.0.0.1:8080/string/params_1/test/api_test`时,浏览器会返回`api_test`字符串。 ```c++ #include "ylt/coro_http/coro_http_client.hpp" @@ -754,14 +754,14 @@ int main() { server.set_http_handler( R"(/numbers/(\d+)/test/(\d+))", [](request &req, response &res) { - std::cout << " matches[1] is : " << req.get_matches()[1] - << " matches[2] is: " << req.get_matches()[2] << std::endl; + std::cout << " matches[1] is : " << req.matches_[1] + << " matches[2] is: " << req.matches_[2] << std::endl; res.set_status_and_content(status_type::ok, "hello world"); }); server.set_http_handler( - "/string/{:id}/test/{:name}", [](request &req, response &res) { + "/string/:id/test/:name", [](request &req, response &res) { std::string id = req.get_query_value("id"); std::cout << "id value is: " << id << std::endl; std::cout << "name value is: " << std::string(req.get_query_value("name")) << std::endl;