From 9469e9fd97dca806ad78008d46d7e9889f9a966d Mon Sep 17 00:00:00 2001 From: qicosmos Date: Wed, 17 Jan 2024 19:57:27 +0800 Subject: [PATCH] [coro_http]update and fix (#571) --- .../thirdparty/cinatra/coro_http_client.hpp | 6 +- .../cinatra/coro_http_connection.hpp | 31 +++------- include/ylt/thirdparty/cinatra/define.h | 10 ---- .../thirdparty/cinatra/url_encode_decode.hpp | 14 ----- include/ylt/thirdparty/cinatra/utils.hpp | 59 ++----------------- include/ylt/thirdparty/cinatra/websocket.hpp | 47 --------------- src/coro_http/examples/example.cpp | 12 ++++ 7 files changed, 28 insertions(+), 151 deletions(-) diff --git a/include/ylt/thirdparty/cinatra/coro_http_client.hpp b/include/ylt/thirdparty/cinatra/coro_http_client.hpp index 8e0795a9f..3d8b46b29 100644 --- a/include/ylt/thirdparty/cinatra/coro_http_client.hpp +++ b/include/ylt/thirdparty/cinatra/coro_http_client.hpp @@ -1828,8 +1828,10 @@ class coro_http_client : public std::enable_shared_from_this { data_ptr = asio::buffer_cast(read_buf.data()); if (is_close_frame) { - payload_len -= 2; - data_ptr += sizeof(uint16_t); + if (payload_len >= 2) { + payload_len -= 2; + data_ptr += sizeof(uint16_t); + } } data.status = 200; diff --git a/include/ylt/thirdparty/cinatra/coro_http_connection.hpp b/include/ylt/thirdparty/cinatra/coro_http_connection.hpp index c8e575d47..8c47cdbbe 100644 --- a/include/ylt/thirdparty/cinatra/coro_http_connection.hpp +++ b/include/ylt/thirdparty/cinatra/coro_http_connection.hpp @@ -348,25 +348,6 @@ class coro_http_connection co_return true; } - async_simple::coro::Lazy write_chunked_data(std::string_view buf, - bool eof) { - std::vector buffers; - to_chunked_buffers(buffers, buf, eof); - auto [ec, _] = co_await async_write(std::move(buffers)); - if (ec) { - CINATRA_LOG_ERROR << "async_write error: " << ec.message(); - close(); - co_return false; - } - - if (!keep_alive_) { - // now in io thread, so can close socket immediately. - close(); - } - - co_return true; - } - bool sync_reply() { return async_simple::coro::syncAwait(reply()); } async_simple::coro::Lazy begin_chunked() { @@ -560,6 +541,7 @@ class coro_http_connection case cinatra::ws_frame_type::WS_CLOSE_FRAME: { close_frame close_frame = ws_.parse_close_payload(payload.data(), payload.size()); + result.eof = true; result.data = {close_frame.message, close_frame.length}; std::string close_msg = ws_.format_close_payload( @@ -570,16 +552,16 @@ class coro_http_connection close(); } break; case cinatra::ws_frame_type::WS_PING_FRAME: { - auto ec = co_await write_websocket({payload.data(), payload.size()}, - opcode::pong); + result.data = {payload.data(), payload.size()}; + auto ec = co_await write_websocket("pong", opcode::pong); if (ec) { close(); result.ec = ec; } } break; case cinatra::ws_frame_type::WS_PONG_FRAME: { + result.data = {payload.data(), payload.size()}; auto ec = co_await write_websocket("ping", opcode::ping); - close(); result.ec = ec; } break; default: @@ -618,7 +600,10 @@ class coro_http_connection void set_ws_max_size(uint64_t max_size) { max_part_size_ = max_size; } - void set_shrink_to_fit(bool r) { need_shrink_every_time_ = r; } + void set_shrink_to_fit(bool r) { + need_shrink_every_time_ = r; + response_.set_shrink_to_fit(r); + } template async_simple::coro::Lazy> async_read( diff --git a/include/ylt/thirdparty/cinatra/define.h b/include/ylt/thirdparty/cinatra/define.h index bca137af2..46907cf97 100644 --- a/include/ylt/thirdparty/cinatra/define.h +++ b/include/ylt/thirdparty/cinatra/define.h @@ -35,34 +35,24 @@ inline constexpr std::string_view method_name(http_method mthd) { switch (mthd) { case cinatra::http_method::DEL: return "DELETE"sv; - break; case cinatra::http_method::GET: return "GET"sv; - break; case cinatra::http_method::HEAD: return "HEAD"sv; - break; case cinatra::http_method::POST: return "POST"sv; - break; case cinatra::http_method::PUT: return "PUT"sv; - break; case cinatra::http_method::PATCH: return "PATCH"sv; - break; case cinatra::http_method::CONNECT: return "CONNECT"sv; - break; case cinatra::http_method::OPTIONS: return "OPTIONS"sv; - break; case cinatra::http_method::TRACE: return "TRACE"sv; - break; default: return "UNKONWN"sv; - break; } } diff --git a/include/ylt/thirdparty/cinatra/url_encode_decode.hpp b/include/ylt/thirdparty/cinatra/url_encode_decode.hpp index 75efacefc..b39a558dd 100644 --- a/include/ylt/thirdparty/cinatra/url_encode_decode.hpp +++ b/include/ylt/thirdparty/cinatra/url_encode_decode.hpp @@ -115,23 +115,9 @@ inline size_t base64_encode(char *_dst, const void *_src, size_t len, return dst - _dst; } -inline static std::string u8wstring_to_string(const std::wstring &wstr) { - std::wstring_convert> conv; - return conv.to_bytes(wstr); -} - -inline static std::wstring u8string_to_wstring(const std::string &str) { - std::wstring_convert> conv; - return conv.from_bytes(str); -} - inline static std::string get_string_by_urldecode(std::string_view content) { return url_decode(std::string(content.data(), content.size())); } -inline static bool is_url_encode(std::string_view str) { - return str.find("%") != std::string_view::npos || - str.find("+") != std::string_view::npos; -} } // namespace code_utils #endif // CPPWEBSERVER_URL_ENCODE_DECODE_HPP \ No newline at end of file diff --git a/include/ylt/thirdparty/cinatra/utils.hpp b/include/ylt/thirdparty/cinatra/utils.hpp index 8e7bdd836..4daf2ea97 100644 --- a/include/ylt/thirdparty/cinatra/utils.hpp +++ b/include/ylt/thirdparty/cinatra/utils.hpp @@ -34,12 +34,6 @@ struct ci_less { } }; - bool operator()(const std::string &s1, const std::string &s2) const { - return std::lexicographical_compare(s1.begin(), s1.end(), // source range - s2.begin(), s2.end(), // dest range - nocase_compare()); // comparison - } - bool operator()(std::string_view s1, std::string_view s2) const { return std::lexicographical_compare(s1.begin(), s1.end(), // source range s2.begin(), s2.end(), // dest range @@ -173,10 +167,6 @@ static const std::string base64_chars = "abcdefghijklmnopqrstuvwxyz" "0123456789+/"; -static inline bool is_base64(char c) { - return (isalnum(c) || (c == '+') || (c == '/')); -} - inline std::string base64_encode(const std::string &str) { std::string ret; int i = 0; @@ -220,51 +210,10 @@ inline std::string base64_encode(const std::string &str) { } // from h2o -inline const char *MAP = - "ABCDEFGHIJKLMNOPQRSTUVWXYZ" - "abcdefghijklmnopqrstuvwxyz" - "0123456789+/"; - -inline const char *MAP_URL_ENCODED = - "ABCDEFGHIJKLMNOPQRSTUVWXYZ" - "abcdefghijklmnopqrstuvwxyz" - "0123456789-_"; -inline size_t base64_encode(char *_dst, const void *_src, size_t len, - int url_encoded) { - char *dst = _dst; - const uint8_t *src = reinterpret_cast(_src); - const char *map = url_encoded ? MAP_URL_ENCODED : MAP; - uint32_t quad; - - for (; len >= 3; src += 3, len -= 3) { - quad = ((uint32_t)src[0] << 16) | ((uint32_t)src[1] << 8) | src[2]; - *dst++ = map[quad >> 18]; - *dst++ = map[(quad >> 12) & 63]; - *dst++ = map[(quad >> 6) & 63]; - *dst++ = map[quad & 63]; - } - if (len != 0) { - quad = (uint32_t)src[0] << 16; - *dst++ = map[quad >> 18]; - if (len == 2) { - quad |= (uint32_t)src[1] << 8; - *dst++ = map[(quad >> 12) & 63]; - *dst++ = map[(quad >> 6) & 63]; - if (!url_encoded) - *dst++ = '='; - } - else { - *dst++ = map[(quad >> 12) & 63]; - if (!url_encoded) { - *dst++ = '='; - *dst++ = '='; - } - } - } - - *dst = '\0'; - return dst - _dst; -} +// inline const char *MAP = +// "ABCDEFGHIJKLMNOPQRSTUVWXYZ" +// "abcdefghijklmnopqrstuvwxyz" +// "0123456789+/"; inline bool is_valid_utf8(unsigned char *s, size_t length) { for (unsigned char *e = s + length; s != e;) { diff --git a/include/ylt/thirdparty/cinatra/websocket.hpp b/include/ylt/thirdparty/cinatra/websocket.hpp index bb0509e27..8327ef2e2 100644 --- a/include/ylt/thirdparty/cinatra/websocket.hpp +++ b/include/ylt/thirdparty/cinatra/websocket.hpp @@ -121,58 +121,11 @@ class websocket { return ws_frame_type::WS_BINARY_FRAME; } - ws_frame_type parse_payload(const char *buf, size_t size, - std::string &outbuf) { - const unsigned char *inp = (const unsigned char *)(buf); - if (payload_length_ > size) - return ws_frame_type::WS_INCOMPLETE_FRAME; - - if (payload_length_ > outbuf.size()) { - outbuf.resize((size_t)payload_length_); - } - - if (*(uint32_t *)mask_ == 0) { - memcpy(&outbuf[0], (void *)(inp), payload_length_); - } - else { - // unmask data: - for (size_t i = 0; i < payload_length_; i++) { - outbuf[i] = inp[i] ^ mask_[i % 4]; - } - } - - if (msg_opcode_ == 0x0) - return (msg_fin_) - ? ws_frame_type::WS_TEXT_FRAME - : ws_frame_type::WS_INCOMPLETE_TEXT_FRAME; // continuation - // frame ? - if (msg_opcode_ == 0x1) - return (msg_fin_) ? ws_frame_type::WS_TEXT_FRAME - : ws_frame_type::WS_INCOMPLETE_TEXT_FRAME; - if (msg_opcode_ == 0x2) - return (msg_fin_) ? ws_frame_type::WS_BINARY_FRAME - : ws_frame_type::WS_INCOMPLETE_BINARY_FRAME; - if (msg_opcode_ == 0x8) - return ws_frame_type::WS_CLOSE_FRAME; - if (msg_opcode_ == 0x9) - 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; - } - std::string format_header(size_t length, opcode code) { size_t header_length = encode_header(length, code); return {msg_header_, header_length}; } - std::vector format_message(const char *src, size_t length, - opcode code) { - size_t header_length = encode_header(length, code); - return {asio::buffer(msg_header_, header_length), - asio::buffer(src, length)}; - } - std::string encode_frame(std::span &data, opcode op, bool need_mask, bool eof = true) { std::string header; diff --git a/src/coro_http/examples/example.cpp b/src/coro_http/examples/example.cpp index 857852a2e..9ba4fb353 100644 --- a/src/coro_http/examples/example.cpp +++ b/src/coro_http/examples/example.cpp @@ -184,6 +184,18 @@ async_simple::coro::Lazy use_websocket() { std::cout << result.data << "\n"; } + if (result.type == ws_frame_type::WS_PING_FRAME || + result.type == ws_frame_type::WS_PONG_FRAME) { + // ping pong frame just need to continue, no need echo anything, + // because framework has reply ping/pong msg to client + // automatically. + continue; + } + else { + // error frame + break; + } + auto ec = co_await req.get_conn()->write_websocket(result.data); if (ec) { break;