Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[coro_http]fix and update #679

Merged
merged 1 commit into from
May 21, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
80 changes: 3 additions & 77 deletions include/ylt/standalone/cinatra/coro_http_client.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -288,7 +288,7 @@ class coro_http_client : public std::enable_shared_from_this<coro_http_client> {
reset();
}
else {
should_reset_ = false;
should_reset_ = true;
}
resp_data data{};
bool no_schema = !has_schema(uri);
Expand Down Expand Up @@ -515,7 +515,6 @@ class coro_http_client : public std::enable_shared_from_this<coro_http_client> {

#ifdef BENCHMARK_TEST
void set_bench_stop() { stop_bench_ = true; }
void set_read_fix() { read_fix_ = 1; }
#endif

async_simple::coro::Lazy<resp_data> async_patch(
Expand Down Expand Up @@ -558,73 +557,6 @@ class coro_http_client : public std::enable_shared_from_this<coro_http_client> {
std::string uri,
std::unordered_map<std::string, std::string> 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<const char *>(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));
Expand Down Expand Up @@ -892,7 +824,6 @@ class coro_http_client : public std::enable_shared_from_this<coro_http_client> {
}
#endif
#ifdef BENCHMARK_TEST
req_str_.clear();
total_len_ = 0;
#endif

Expand Down Expand Up @@ -1160,9 +1091,6 @@ class coro_http_client : public std::enable_shared_from_this<coro_http_client> {
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
Expand Down Expand Up @@ -1640,7 +1568,7 @@ class coro_http_client : public std::enable_shared_from_this<coro_http_client> {
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;
}
Expand Down Expand Up @@ -2120,14 +2048,14 @@ class coro_http_client : public std::enable_shared_from_this<coro_http_client> {
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_ =
std::chrono::seconds(60);
bool enable_tcp_no_delay_ = true;
std::string resp_chunk_str_;
std::span<char> out_buf_;
bool should_reset_ = false;

#ifdef CINATRA_ENABLE_GZIP
bool enable_ws_deflate_ = false;
Expand All @@ -2136,10 +2064,8 @@ class coro_http_client : public std::enable_shared_from_this<coro_http_client> {
#endif

#ifdef BENCHMARK_TEST
std::string req_str_;
bool stop_bench_ = false;
size_t total_len_ = 0;
int read_fix_ = 0;
#endif
};
} // namespace cinatra
16 changes: 14 additions & 2 deletions include/ylt/standalone/cinatra/coro_http_connection.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down Expand Up @@ -343,6 +354,7 @@ class coro_http_connection
co_return;
}
}
head_buf_.consume(head_buf_.size());
}
else {
handle_session_for_response();
Expand Down
10 changes: 8 additions & 2 deletions include/ylt/standalone/cinatra/coro_http_request.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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_; }
Expand Down Expand Up @@ -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<std::string> aspect_data_;
std::string cached_session_id_;
};
Expand Down
7 changes: 6 additions & 1 deletion include/ylt/standalone/cinatra/multipart.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,12 @@ class multipart_reader_t {
head_buf_(conn_->head_buf_),
chunked_buf_(conn_->chunked_buf_) {}

async_simple::coro::Lazy<part_head_t> read_part_head() {
async_simple::coro::Lazy<part_head_t> 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<const char *>(head_buf_.data());
chunked_buf_.sputn(data_ptr, head_buf_.size());
Expand Down
10 changes: 5 additions & 5 deletions website/docs/zh/coro_http/coro_http_introduction.md
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand All @@ -754,14 +754,14 @@ int main() {

server.set_http_handler<GET, POST>(
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<GET, POST>(
"/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;
Expand Down
Loading