#include "NetworkUtility.h" #include "BoostLog.h" #include "root_certificates.hpp" #include #include #include #include #include #include std::string Https::get(boost::asio::io_context &ioContext, const std::string &host, const std::string &port, const std::string &url, boost::system::error_code &error, Http::Version version) { Http::Client client(ioContext, Http::SSL, version); return client.get(host, port, url, error); } std::string Https::post(boost::asio::io_context &ioContext, const std::string &host, const std::string &port, const std::string &url, const std::string &body, boost::system::error_code &error, Http::Version version) { Http::Client client(ioContext, Http::SSL, version); return client.post(host, port, url, body, error); } std::string Https::put(boost::asio::io_context &ioContext, const std::string &host, const std::string &port, const std::string &url, const std::string &body, boost::system::error_code &error, Http::Version version) { Http::Client client(ioContext, Http::SSL, version); return client.put(host, port, url, body, error); } uint64_t Network::htonll(uint64_t val) { return (static_cast(htonl(static_cast(val))) << 32) + htonl(val >> 32); } uint64_t Network::ntohll(uint64_t val) { return (static_cast(ntohl(static_cast(val))) << 32) + ntohl(val >> 32); } bool Network::isConnected(const std::string_view &host, size_t size) { std::ostringstream oss; #ifdef __linux__ oss << "ping " << host << " -q -W2 -c" << size; #else oss << "ping -n " << size << " " << host; #endif auto ret = std::system(oss.str().data()); return ret == 0; } #ifdef WIN32 #include #endif Network::Network(int argc, char *argv[]) { #ifdef WIN32 WORD wVersionRequested = MAKEWORD(2, 2); WSADATA wsaData; ::WSAStartup(wVersionRequested, &wsaData); LOG(info) << "WinSock initialized complete."; #endif } Network::~Network() { #ifdef WIN32 ::WSACleanup(); #endif } namespace Http { std::vector parseFormData(const std::string_view &buffer) { std::vector ret; auto pos = buffer.find("\r\n"); std::string_view m_spliter = buffer.substr(0, pos); size_t m_end = buffer.rfind(m_spliter); pos = 0; while (pos != m_end) { pos = buffer.find(m_spliter, pos); if (pos == m_end) break; ParseItem item; auto dataSpliterPos = buffer.find("\r\n\r\n", pos); item.begin = dataSpliterPos + 4; item.end = buffer.find(m_spliter, pos + 1) - 2; auto meta = buffer.substr(pos, dataSpliterPos - pos); auto beginPos = meta.find("filename=\"") + 10; auto endPos = meta.find("\"", beginPos); item.filename = meta.substr(beginPos, endPos - beginPos); pos++; ret.push_back(item); } return ret; } class ClientPrivate { public: std::unique_ptr> sslStream; std::unique_ptr tcpStream; }; Client::Client(boost::asio::io_context &ioContext, Type type, Version version) : m_d(new ClientPrivate()), m_ioContext(ioContext) { m_request.version(static_cast(version)); using namespace boost::asio; using namespace boost::beast; m_request.set(http::field::user_agent, BOOST_BEAST_VERSION_STRING); if (type == SSL) { m_sslContext = std::make_shared(ssl::context::sslv23_client); } } Client::~Client() { boost::system::error_code error; shutdown(error); if (error) { LOG(error) << error.message(); } if (m_d != nullptr) delete m_d; } void Client::loadRootCertificates(boost::system::error_code &error) { if (m_sslContext) { load_root_certificates(*m_sslContext, error); if (!error) { m_certificateLocation = CertificateLocation::Default; } } } std::string Client::get(const std::string &host, const std::string &port, const std::string &url, boost::system::error_code &error) { using namespace boost::beast; m_request.method(http::verb::get); m_request.target(url); m_request.set(http::field::host, host); return execute(host, port, m_request, error); } std::string Client::post(const std::string &host, const std::string &port, const std::string &url, const std::string &body, boost::system::error_code &error) { using namespace boost::beast; m_request.method(http::verb::post); m_request.target(url); m_request.set(http::field::host, host); m_request.body() = body; m_request.prepare_payload(); return execute(host, port, m_request, error); } std::string Client::put(const std::string &host, const std::string &port, const std::string &url, const std::string &body, boost::system::error_code &error) { using namespace boost::beast; m_request.method(http::verb::put); m_request.target(url); m_request.set(http::field::host, host); m_request.body() = body; m_request.prepare_payload(); return execute(host, port, m_request, error); } void Client::addRequestField(boost::beast::http::field name, const std::string &value) { m_request.set(name, value); } std::string Client::execute(const std::string &host, const std::string &port, const Request &request, boost::system::error_code &error) { using namespace boost::beast; if ((m_host != host) || (m_port != port) || (!m_d->sslStream && !m_d->tcpStream)) { if (m_d->sslStream || m_d->tcpStream) { boost::system::error_code errorCode; shutdown(errorCode); if (errorCode) { LOG(error) << errorCode.message(); } } connect(host, port, error); if (error) { return std::string(); } } if (m_d->sslStream) { http::write(*m_d->sslStream, request, error); } else if (m_d->tcpStream) { http::write(*m_d->tcpStream, request, error); } http::response response; if (!error) { flat_buffer buffer; if (m_d->sslStream) { http::read(*m_d->sslStream, buffer, response, error); } else if (m_d->tcpStream) { http::read(*m_d->tcpStream, buffer, response, error); } } return boost::beast::buffers_to_string(response.body().data()); } void Client::connect(const std::string &host, const std::string &port, boost::system::error_code &error) { using namespace boost::asio::ip; using namespace boost::beast; tcp::resolver resolver(m_ioContext); auto const results = resolver.resolve(host, port, error); if (error) { return; } if (m_sslContext) { if (m_certificateLocation == CertificateLocation::None) { m_sslContext->set_default_verify_paths(error); if (!error) m_certificateLocation = CertificateLocation::SystemDependent; } m_d->sslStream = std::make_unique>(m_ioContext, *m_sslContext); get_lowest_layer(*m_d->sslStream).connect(results, error); if (error) { return; } m_d->sslStream->handshake(ssl::stream_base::client, error); } else { m_d->tcpStream = std::make_unique(m_ioContext); m_d->tcpStream->connect(results, error); } if (error) { return; } m_host = host; m_port = port; } void Client::shutdown(boost::system::error_code &error) { using namespace boost::asio::ip; if (m_d->sslStream) { m_d->sslStream->shutdown(error); m_d->sslStream.reset(); } else if (m_d->tcpStream) { m_d->tcpStream->socket().shutdown(tcp::socket::shutdown_both, error); m_d->tcpStream.reset(); } } } // namespace Http