1- #include < asio/ssl/stream.hpp>
1+ // BUG 复现三次校验证书
2+
3+ #include < asio/ssl.hpp>
24#include < asio/ip/tcp.hpp>
35#include < asio/awaitable.hpp>
46#include < asio/use_awaitable.hpp>
7+ #include < asio/co_spawn.hpp>
8+ #include < asio/detached.hpp>
9+ #include < asio/connect.hpp>
10+ #include < asio/buffer.hpp>
511
612#include < spdlog/spdlog.h>
713
8- #include < print>
14+ #include < regex>
15+ #include < optional>
16+ #include < string>
17+ #include < string_view>
18+ #include < format>
19+ #include < iostream>
920
1021using namespace asio ;
1122using tcp_socket_co = use_awaitable_t <>::as_default_on_t <ip::tcp::socket>;
12- using ssl_stream_co=ssl::stream<tcp_socket_co>;
23+ using tcp_resolver_co = asio::use_awaitable_t <>::as_default_on_t <ip::tcp::resolver>;
24+ using ssl_stream_co = ssl::stream<tcp_socket_co>;
1325
1426// namespace log = spdlog;
1527
16- int main (int argc,char ** argv){
28+ struct endpoint
29+ {
30+ std::string host;
31+ std::string port;
32+ };
1733
18- if (argc!=2 ){
19- std::println (" Usage: {} <hostname>" , argv[0 ]);
20- return 1 ;
34+ inline std::optional<endpoint> check_http_url (std::string url)
35+ {
36+ // thread_local static std::regex re{R"(^https?://([^/]+)/.*)"};
37+ thread_local static std::regex re{R"( (https?)://([^/]+)(?::(\d+))?(/.*)?)" };
38+ std::smatch sm;
39+ endpoint ep{};
40+ if (std::regex_search (url, sm, re))
41+ {
42+ auto protocol = sm[1 ].str ();
43+ ep.host = sm[2 ].str ();
44+ if (sm[3 ].matched )
45+ {
46+ ep.port = sm[3 ].str ();
47+ }
48+ else
49+ {
50+ if (protocol.size () == 5 )
51+ {
52+ ep.port = " 443" ;
53+ }
54+ else
55+ {
56+ ep.port = " 80" ;
57+ }
58+ }
59+ return ep;
2160 }
61+ return std::nullopt ;
62+ }
63+
64+ int main (int argc, char **argv)
65+ {
66+
67+ if (argc != 2 )
68+ {
69+ spdlog::info (" Usage: {} <http url>" , argv[0 ]);
70+ return -1 ;
71+ }
72+
73+ io_context io_context;
74+
75+ auto task = [&io_context, url = argv[1 ]]() -> asio::awaitable<void >
76+ {
77+ auto ep = check_http_url (url);
78+ if (!ep)
79+ {
80+ spdlog::error (" Invalid url: {}" , url);
81+ co_return ;
82+ }
83+ asio::ssl::context ctx{asio::ssl::context::sslv23};
84+ // ctx.set_verify_mode(ssl::verify_peer);
85+ // ctx.set_default_verify_paths();
86+
87+ ssl_stream_co ssl_socket{io_context, ctx};
88+ ssl_socket.set_verify_mode (ssl::verify_peer);
89+ ssl_socket.set_verify_callback (
90+ [host = ep->host ](auto ok, auto &v_ctx)
91+ {
92+ // auto res=ssl::host_name_verification(host)(ok, v_ctx);
93+ // spdlog::info("{} verify result: {}",host, res);
94+ // return res;
95+ spdlog::info (" {} verify result: {}" , host, true );
96+ return true ;
97+ });
98+
99+ auto &socket = ssl_socket.lowest_layer ();
100+
101+ // tcp_socket_co socket(io_context);
102+
103+ tcp_resolver_co resolver (io_context);
104+ auto ip_list = co_await resolver.async_resolve (ep->host , ep->port );
105+ co_await async_connect (socket, ip_list, use_awaitable, 0 );
22106
23- asio::io_context io_context ;
107+ // ssl_stream_co ssl_socket{std::move(socket), ctx} ;
24108
25- asio::ssl::context ctx{asio::ssl::context::tlsv12};
26- ctx.set_verify_mode (ssl::verify_peer);
27- ctx.set_default_verify_paths ();
109+ co_await ssl_socket.async_handshake (ssl::stream_base::client);
110+ co_await async_write (ssl_socket, buffer (std::format (" GET / HTTP/1.0\r\n Host: {}\r\n\r\n " , ep->host )));
28111
29- ssl_stream_co ssl_socket{io_context, ctx};
112+ char bf[512 ];
113+ while (true )
114+ {
115+ try
116+ {
117+ auto rn = co_await ssl_socket.async_read_some (buffer (bf));
30118
31-
119+ if (rn == 0 )
120+ {
121+ spdlog::info (" 断开连接 " );
122+ break ;
123+ }
124+ std::cout << std::string_view{bf, rn};
125+ }
126+ catch (std::exception &e)
127+ {
128+ spdlog::info (" 异常 {}" , e.what ());
129+ break ;
130+ }
131+ }
132+ spdlog::info (" 退出" );
133+ };
134+ co_spawn (io_context, task, detached);
135+ io_context.run ();
32136 return 0 ;
33137}
0 commit comments