2023-07-21 11:53:19 +08:00
|
|
|
#include "NetworkUtility.h"
|
|
|
|
#include "BoostLog.h"
|
2024-01-14 17:54:26 +08:00
|
|
|
#include "root_certificates.hpp"
|
2023-07-21 11:53:19 +08:00
|
|
|
#include <boost/beast/core.hpp>
|
2024-01-14 17:54:26 +08:00
|
|
|
#include <boost/beast/http/dynamic_body.hpp>
|
|
|
|
#include <boost/beast/http/read.hpp>
|
|
|
|
#include <boost/beast/http/write.hpp>
|
|
|
|
#include <boost/beast/ssl/ssl_stream.hpp>
|
2023-07-21 11:53:19 +08:00
|
|
|
#include <boost/beast/version.hpp>
|
|
|
|
|
2024-01-14 17:54:26 +08:00
|
|
|
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);
|
2023-07-21 11:53:19 +08:00
|
|
|
}
|
|
|
|
|
2024-01-14 17:54:26 +08:00
|
|
|
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,
|
2023-07-21 11:53:19 +08:00
|
|
|
Http::Version version) {
|
|
|
|
|
2024-01-14 17:54:26 +08:00
|
|
|
Http::Client client(ioContext, Http::SSL, version);
|
|
|
|
return client.post(host, port, url, body, error);
|
2023-07-21 11:53:19 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
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) {
|
2024-01-14 17:54:26 +08:00
|
|
|
Http::Client client(ioContext, Http::SSL, version);
|
|
|
|
return client.put(host, port, url, body, error);
|
2023-07-21 11:53:19 +08:00
|
|
|
}
|
|
|
|
|
2024-01-14 17:54:26 +08:00
|
|
|
uint64_t Network::htonll(uint64_t val) {
|
|
|
|
return (static_cast<uint64_t>(htonl(static_cast<uint32_t>(val))) << 32) + htonl(val >> 32);
|
|
|
|
}
|
2023-07-21 11:53:19 +08:00
|
|
|
|
2024-01-14 17:54:26 +08:00
|
|
|
uint64_t Network::ntohll(uint64_t val) {
|
|
|
|
return (static_cast<uint64_t>(ntohl(static_cast<uint32_t>(val))) << 32) + ntohl(val >> 32);
|
|
|
|
}
|
2023-07-21 11:53:19 +08:00
|
|
|
|
2024-01-14 17:54:26 +08:00
|
|
|
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;
|
|
|
|
}
|
2023-07-21 11:53:19 +08:00
|
|
|
|
2024-01-14 17:54:26 +08:00
|
|
|
#ifdef WIN32
|
|
|
|
#include <winsock.h>
|
|
|
|
#endif
|
2023-07-21 11:53:19 +08:00
|
|
|
|
2024-01-14 17:54:26 +08:00
|
|
|
Network::Network(int argc, char *argv[]) {
|
|
|
|
#ifdef WIN32
|
|
|
|
WORD wVersionRequested = MAKEWORD(2, 2);
|
|
|
|
WSADATA wsaData;
|
|
|
|
::WSAStartup(wVersionRequested, &wsaData);
|
|
|
|
LOG(info) << "WinSock initialized complete.";
|
|
|
|
#endif
|
|
|
|
}
|
2023-07-21 11:53:19 +08:00
|
|
|
|
2024-01-14 17:54:26 +08:00
|
|
|
Network::~Network() {
|
|
|
|
#ifdef WIN32
|
|
|
|
::WSACleanup();
|
|
|
|
#endif
|
2023-07-21 11:53:19 +08:00
|
|
|
}
|
|
|
|
|
2024-01-14 17:54:26 +08:00
|
|
|
namespace Http {
|
|
|
|
|
|
|
|
std::vector<ParseItem> parseFormData(const std::string_view &buffer) {
|
2023-07-21 11:53:19 +08:00
|
|
|
std::vector<ParseItem> 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;
|
|
|
|
}
|
|
|
|
|
2024-01-17 11:56:24 +08:00
|
|
|
class ClientPrivate {
|
|
|
|
public:
|
|
|
|
std::unique_ptr<boost::beast::ssl_stream<boost::beast::tcp_stream>> sslStream;
|
|
|
|
std::unique_ptr<boost::beast::tcp_stream> tcpStream;
|
|
|
|
};
|
|
|
|
|
|
|
|
Client::Client(boost::asio::io_context &ioContext, Type type, Version version)
|
|
|
|
: m_d(new ClientPrivate()), m_ioContext(ioContext) {
|
2024-01-14 17:54:26 +08:00
|
|
|
m_request.version(static_cast<unsigned>(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>(ssl::context::sslv23_client);
|
|
|
|
}
|
2023-07-21 11:53:19 +08:00
|
|
|
}
|
|
|
|
|
2024-01-17 11:56:24 +08:00
|
|
|
Client::~Client() {
|
|
|
|
boost::system::error_code error;
|
|
|
|
shutdown(error);
|
|
|
|
if (error) {
|
|
|
|
LOG(error) << error.message();
|
|
|
|
}
|
|
|
|
if (m_d != nullptr) delete m_d;
|
|
|
|
}
|
|
|
|
|
2024-01-14 17:54:26 +08:00
|
|
|
void Client::loadRootCertificates(boost::system::error_code &error) {
|
|
|
|
if (m_sslContext) {
|
|
|
|
load_root_certificates(*m_sslContext, error);
|
|
|
|
if (!error) {
|
|
|
|
m_certificateLocation = CertificateLocation::Default;
|
|
|
|
}
|
|
|
|
}
|
2023-07-21 11:53:19 +08:00
|
|
|
}
|
|
|
|
|
2024-01-14 17:54:26 +08:00
|
|
|
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;
|
2024-05-03 21:39:01 +08:00
|
|
|
m_request.method(http::verb::get);
|
2024-01-14 17:54:26 +08:00
|
|
|
m_request.target(url);
|
|
|
|
m_request.set(http::field::host, host);
|
|
|
|
return execute(host, port, m_request, error);
|
2023-07-21 11:53:19 +08:00
|
|
|
}
|
|
|
|
|
2024-01-14 17:54:26 +08:00
|
|
|
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;
|
2024-05-03 21:39:01 +08:00
|
|
|
m_request.method(http::verb::post);
|
2024-01-14 17:54:26 +08:00
|
|
|
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);
|
|
|
|
}
|
2023-07-21 11:53:19 +08:00
|
|
|
|
2024-01-14 17:54:26 +08:00
|
|
|
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);
|
2023-07-21 11:53:19 +08:00
|
|
|
}
|
|
|
|
|
2024-01-14 17:54:26 +08:00
|
|
|
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;
|
|
|
|
|
2024-01-17 11:56:24 +08:00
|
|
|
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<http::dynamic_body> 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;
|
2024-01-14 17:54:26 +08:00
|
|
|
tcp::resolver resolver(m_ioContext);
|
|
|
|
auto const results = resolver.resolve(host, port, error);
|
|
|
|
if (error) {
|
2024-01-17 11:56:24 +08:00
|
|
|
return;
|
2024-01-14 17:54:26 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
if (m_sslContext) {
|
|
|
|
if (m_certificateLocation == CertificateLocation::None) {
|
|
|
|
m_sslContext->set_default_verify_paths(error);
|
|
|
|
if (!error) m_certificateLocation = CertificateLocation::SystemDependent;
|
|
|
|
}
|
2024-01-17 11:56:24 +08:00
|
|
|
m_d->sslStream = std::make_unique<ssl_stream<tcp_stream>>(m_ioContext, *m_sslContext);
|
|
|
|
get_lowest_layer(*m_d->sslStream).connect(results, error);
|
2024-01-14 17:54:26 +08:00
|
|
|
if (error) {
|
2024-01-17 11:56:24 +08:00
|
|
|
return;
|
2024-01-14 17:54:26 +08:00
|
|
|
}
|
2024-01-17 11:56:24 +08:00
|
|
|
m_d->sslStream->handshake(ssl::stream_base::client, error);
|
2024-01-14 17:54:26 +08:00
|
|
|
} else {
|
2024-01-17 11:56:24 +08:00
|
|
|
m_d->tcpStream = std::make_unique<tcp_stream>(m_ioContext);
|
|
|
|
m_d->tcpStream->connect(results, error);
|
2024-01-14 17:54:26 +08:00
|
|
|
}
|
|
|
|
if (error) {
|
2024-01-17 11:56:24 +08:00
|
|
|
return;
|
2024-01-14 17:54:26 +08:00
|
|
|
}
|
2024-01-17 11:56:24 +08:00
|
|
|
m_host = host;
|
|
|
|
m_port = port;
|
|
|
|
}
|
2024-01-14 17:54:26 +08:00
|
|
|
|
2024-01-17 11:56:24 +08:00
|
|
|
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();
|
2024-01-14 17:54:26 +08:00
|
|
|
}
|
2023-07-21 11:53:19 +08:00
|
|
|
}
|
2024-01-14 17:54:26 +08:00
|
|
|
|
|
|
|
} // namespace Http
|