diff --git a/include/ylt/thirdparty/cinatra/coro_http_client.hpp b/include/ylt/thirdparty/cinatra/coro_http_client.hpp index cb40abfd7..54d31b6a4 100644 --- a/include/ylt/thirdparty/cinatra/coro_http_client.hpp +++ b/include/ylt/thirdparty/cinatra/coro_http_client.hpp @@ -1,11 +1,4 @@ #pragma once -#include -#include -#include -#include - -#include -#include #include #include #include @@ -19,14 +12,21 @@ #include #include #include -#include -#include -#include +#include "asio/dispatch.hpp" +#include "asio/error.hpp" +#include "asio/streambuf.hpp" +#include "async_simple/Future.h" +#include "async_simple/Unit.h" +#include "async_simple/coro/FutureAwaiter.h" +#include "async_simple/coro/Lazy.h" #include "http_parser.hpp" #include "response_cv.hpp" #include "uri.hpp" #include "websocket.hpp" +#include "ylt/coro_io/coro_file.hpp" +#include "ylt/coro_io/coro_io.hpp" +#include "ylt/coro_io/io_context_pool.hpp" namespace coro_io { template @@ -236,10 +236,9 @@ class coro_http_client { } #ifdef CINATRA_ENABLE_SSL - [[nodiscard]] bool init_ssl(const std::string &base_path, - const std::string &cert_file, - int verify_mode = asio::ssl::verify_none, - const std::string &domain = "localhost") { + bool init_ssl(const std::string &base_path, const std::string &cert_file, + int verify_mode = asio::ssl::verify_none, + const std::string &domain = "localhost") { try { ssl_init_ret_ = false; auto full_cert_file = std::filesystem::path(base_path).append(cert_file); @@ -260,6 +259,11 @@ class coro_http_client { ssl_stream_ = std::make_unique>( socket_->impl_, ssl_ctx_); + // Set SNI Hostname (many hosts need this to handshake successfully) + if (!sni_hostname_.empty()) { + SSL_set_tlsext_host_name(ssl_stream_->native_handle(), + sni_hostname_.c_str()); + } use_ssl_ = true; ssl_init_ret_ = true; } catch (std::exception &e) { @@ -296,7 +300,13 @@ class coro_http_client { // only make socket connet(or handshake) to the host async_simple::coro::Lazy connect(std::string uri) { resp_data data{}; - auto [ok, u] = handle_uri(data, uri); + bool no_schema = !has_schema(uri); + std::string append_uri; + if (no_schema) { + append_uri.append("http://").append(uri); + } + + auto [ok, u] = handle_uri(data, no_schema ? append_uri : uri); if (!ok) { co_return resp_data{{}, 404}; } @@ -784,7 +794,6 @@ class coro_http_client { std::string header_str = build_request_header(u, method, ctx, true, std::move(headers)); - std::cout << header_str; std::error_code ec{}; size_t size = 0; @@ -850,17 +859,21 @@ class coro_http_client { bool is_keep_alive = true; do { - bool no_schema = !has_schema(uri); + uri_t u; std::string append_uri; - if (no_schema) { - append_uri.append("http://").append(uri); - } - auto [ok, u] = handle_uri(data, no_schema ? append_uri : uri); - if (!ok) { - break; - } - if (socket_->has_closed_) { + if (socket_->has_closed_ || (!uri.empty() && uri[0] != '/')) { + bool no_schema = !has_schema(uri); + + if (no_schema) { + append_uri.append("http://").append(uri); + } + bool ok = false; + std::tie(ok, u) = handle_uri(data, no_schema ? append_uri : uri); + if (!ok) { + break; + } + auto conn_future = start_timer(conn_timeout_duration_, "connect timer"); std::string host = proxy_host_.empty() ? u.get_host() : proxy_host_; std::string port = proxy_port_.empty() ? u.get_port() : proxy_port_; @@ -870,6 +883,8 @@ class coro_http_client { break; } + socket_->impl_.set_option(asio::ip::tcp::no_delay(true)); + if (u.is_ssl) { if (ec = co_await handle_shake(); ec) { break; @@ -880,6 +895,9 @@ class coro_http_client { break; } } + else { + u.path = uri; + } std::vector vec; std::string req_head_str = @@ -981,6 +999,10 @@ class coro_http_client { req_timeout_duration_ = timeout_duration; } +#ifdef CINATRA_ENABLE_SSL + void set_sni_hostname(const std::string &host) { sni_hostname_ = host; } +#endif + template friend class coro_io::client_pool; @@ -1369,6 +1391,8 @@ class coro_http_client { co_return resp_data{ec, 404}; } + socket_->impl_.set_option(asio::ip::tcp::no_delay(true)); + if (u.is_ssl) { if (auto ec = co_await handle_shake(); ec) { co_return resp_data{ec, 404}; @@ -1485,6 +1509,7 @@ class coro_http_client { if (auto [ec, _] = co_await async_read(read_buf_, header_size); ec) { data.net_err = ec; data.status = 404; + close_socket(*socket_); if (on_ws_msg_) on_ws_msg_(data); co_return; @@ -1508,6 +1533,7 @@ class coro_http_client { ec) { data.net_err = ec; data.status = 404; + close_socket(*socket_); if (on_ws_msg_) on_ws_msg_(data); co_return; @@ -1531,6 +1557,11 @@ class coro_http_client { on_ws_close_(data.resp_body); co_await async_send_ws("close", false, opcode::close); async_close(); + + data.net_err = asio::error::eof; + data.status = 404; + if (on_ws_msg_) + on_ws_msg_(data); co_return; } if (on_ws_msg_) @@ -1609,10 +1640,10 @@ class coro_http_client { template bool has_schema(const S &url) { - size_t pos_http = url.find_first_of("http://"); - size_t pos_https = url.find_first_of("https://"); - size_t pos_ws = url.find_first_of("ws://"); - size_t pos_wss = url.find_first_of("wss://"); + size_t pos_http = url.find("http://"); + size_t pos_https = url.find("https://"); + size_t pos_ws = url.find("ws://"); + size_t pos_wss = url.find("wss://"); bool has_http_scheme = ((pos_http != std::string::npos) && pos_http == 0) || ((pos_https != std::string::npos) && pos_https == 0) || @@ -1651,6 +1682,7 @@ class coro_http_client { std::unique_ptr> ssl_stream_; bool ssl_init_ret_ = true; bool use_ssl_ = false; + std::string sni_hostname_ = ""; #endif std::string redirect_uri_; bool enable_follow_redirect_ = false; diff --git a/include/ylt/thirdparty/cinatra/picohttpparser.h b/include/ylt/thirdparty/cinatra/picohttpparser.h index 6118f5952..19b81ded7 100644 --- a/include/ylt/thirdparty/cinatra/picohttpparser.h +++ b/include/ylt/thirdparty/cinatra/picohttpparser.h @@ -29,15 +29,6 @@ #include #include #include -#ifdef __SSE4_2__ -#ifdef _MSC_VER -#include -#else -#include -#endif -#endif - -#include #ifdef _MSC_VER #define ssize_t intptr_t @@ -172,31 +163,10 @@ static const char *findchar_fast(const char *buf, const char *buf_end, const char *ranges, int ranges_size, int *found) { *found = 0; -#if __SSE4_2__ - if (likely(buf_end - buf >= 16)) { - __m128i ranges16 = _mm_loadu_si128((const __m128i *)ranges); - - size_t left = (buf_end - buf) & ~15; - do { - __m128i b16 = _mm_loadu_si128((const __m128i *)buf); - int r = _mm_cmpestri( - ranges16, ranges_size, b16, 16, - _SIDD_LEAST_SIGNIFICANT | _SIDD_CMP_RANGES | _SIDD_UBYTE_OPS); - if (unlikely(r != 16)) { - buf += r; - *found = 1; - break; - } - buf += 16; - left -= 16; - } while (likely(left != 0)); - } -#else /* suppress unused parameter warning */ (void)buf_end; (void)ranges; (void)ranges_size; -#endif return buf; } @@ -205,20 +175,6 @@ static const char *get_token_to_eol(const char *buf, const char *buf_end, int *ret) { const char *token_start = buf; -#ifdef __SSE4_2__ - static const char ranges1[] = - "\0\010" - /* allow HT */ - "\012\037" - /* allow SP and up to but not including DEL */ - "\177\177" - /* allow chars w. MSB set */ - ; - int found; - buf = findchar_fast(buf, buf_end, ranges1, sizeof(ranges1) - 1, &found); - if (found) - goto FOUND_CTL; -#else /* find non-printable char within the next 8 bytes, this is the hottest code; * manually inlined */ while (likely(buf_end - buf >= 8)) { @@ -245,7 +201,7 @@ static const char *get_token_to_eol(const char *buf, const char *buf_end, } ++buf; } -#endif + for (;; ++buf) { CHECK_EOF(); if (unlikely(!IS_PRINTABLE_ASCII(*buf))) {