精通
英语
和
开源
,
擅长
开发
与
培训
,
胸怀四海
第一信赖
HTTPS协议就是HTTP+SSL,SSL一般是用OpenSSL实现,HTTPS协议在证书和加密套件基础上实现了一定程度上的数据安全,另外HTTPS协议的网站比HTTP协议的网站权重好评分一些。对于SSL开发,锐英源软件有丰富的经验,对于HTTPS通信相关的代理IP开发也做过,最近看httplib的代码,觉得里面的代码是HTTPS协议经典代码,里面有一些技巧和不常见的函数调用方式,就想注释下自己研究,觉得非常有用,也分享给大家。
CPPHTTPLIB_OPENSSL_SUPPORT是httplib里的SSL预编译宏,这个宏下面的代码就是SSL部分。
本文介绍两段代码,第一段是SSL的创建初始化和释放,第二段是客户端代理IP模式下的请求处理。
第一段SSL的创建初始化和释放:
template <typename U, typename V> inline SSL *ssl_new(socket_t sock, SSL_CTX *ctx, std::mutex &ctx_mutex, U SSL_connect_or_accept, V setup) { SSL *ssl = nullptr; { std::lock_guard<std::mutex> guard(ctx_mutex); ssl = SSL_new(ctx);//ctx是全局的,所以要lock_guard保护 } if (ssl) { set_nonblocking(sock, true);//先设置为非阻塞 auto bio = BIO_new_socket(static_cast(sock), BIO_NOCLOSE);//显式转换更安全 BIO_set_nbio(bio, 1);//bio设置为非阻塞 SSL_set_bio(ssl, bio, bio);//bio和ssl绑定 if (!setup(ssl) || SSL_connect_or_accept(ssl) != 1) { SSL_shutdown(ssl); { std::lock_guard<std::mutex> guard(ctx_mutex); SSL_free(ssl); } set_nonblocking(sock, false); return nullptr; } BIO_set_nbio(bio, 0);//bio设置为阻塞 set_nonblocking(sock, false);//sock设置为非阻塞 } return ssl; } inline void ssl_delete(std::mutex &ctx_mutex, SSL *ssl, socket_t sock, bool shutdown_gracefully) { // sometimes we may want to skip this to try to avoid SIGPIPE if we know // the remote has closed the network connection // Note that it is not always possible to avoid SIGPIPE, this is merely a // best-efforts. if (shutdown_gracefully) {//优雅关闭 #ifdef _WIN32 SSL_shutdown(ssl); #else timeval tv; tv.tv_sec = 1; tv.tv_usec = 0; setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, reinterpret_cast<const void *>(&tv), sizeof(tv)); auto ret = SSL_shutdown(ssl); while (ret == 0) {//非windows还要用循环判断 std::this_thread::sleep_for(std::chrono::milliseconds(100)); ret = SSL_shutdown(ssl); } #endif } std::lock_guard<std::mutex> guard(ctx_mutex); SSL_free(ssl);//保护下关闭 }
这里面ctx的保护和非阻塞阻塞切换有借鉴意义。
第二段客户端代理IP模式下的请求处理:
inline bool ClientImpl::process_request(Stream &strm, Request &req, Response &res, bool close_connection, Error &error) { // Send request if (!write_request(strm, req, close_connection, error)) { return false; } #ifdef CPPHTTPLIB_OPENSSL_SUPPORT if (is_ssl()) { auto is_proxy_enabled = !proxy_host_.empty() && proxy_port_ != -1;//判断是否开启代理模式 if (!is_proxy_enabled) {//不是代理模式 char buf[1]; if (SSL_peek(socket_.ssl, buf, 1) == 0 && SSL_get_error(socket_.ssl, 0) == SSL_ERROR_ZERO_RETURN) {//灵巧地判断和服务器通信是否正常 error = Error::SSLPeerCouldBeClosed_; return false; } } } #endif // Receive response and headers if (!read_response_line(strm, req, res) || !detail::read_headers(strm, res.headers)) { error = Error::Read; return false; }
这里面灵巧地判断和服务器通信是否正常有借鉴意义。
HTTPS协议现在是主流,因为现在服务器的能力都强了,HTTP明文协议在逐渐淘汰。小公司有的买不起证书,HTTPS的配置也比较麻烦,一般不愿意升级到HTTPS。HTTPS好处明显,有资源和精力的站长建议升级到HTTPS上吧。