add library 'HttpProxy'.
This commit is contained in:
parent
bf5854addf
commit
64c387aba9
@ -2,4 +2,5 @@ cmake_minimum_required(VERSION 3.15)
|
||||
|
||||
project(Kylin)
|
||||
|
||||
add_subdirectory(HttpProxy)
|
||||
add_subdirectory(Universal)
|
11
HttpProxy/CMakeLists.txt
Normal file
11
HttpProxy/CMakeLists.txt
Normal file
@ -0,0 +1,11 @@
|
||||
add_library(HttpProxy
|
||||
NetworkUtility.h NetworkUtility.cpp
|
||||
)
|
||||
|
||||
target_include_directories(HttpProxy
|
||||
INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}
|
||||
)
|
||||
|
||||
target_link_libraries(HttpProxy
|
||||
PUBLIC Universal
|
||||
)
|
202
HttpProxy/NetworkUtility.cpp
Normal file
202
HttpProxy/NetworkUtility.cpp
Normal file
@ -0,0 +1,202 @@
|
||||
#include "NetworkUtility.h"
|
||||
#include "BoostLog.h"
|
||||
#include <boost/beast/core.hpp>
|
||||
#include <boost/beast/http.hpp>
|
||||
#include <boost/beast/ssl.hpp>
|
||||
#include <boost/beast/version.hpp>
|
||||
#include <optional>
|
||||
|
||||
static std::optional<boost::beast::ssl_stream<boost::beast::tcp_stream>>
|
||||
makeSslStream(boost::asio::io_context &ioContext, const std::string_view &host, const std::string_view &port,
|
||||
boost::system::error_code &error);
|
||||
|
||||
std::string Https::get(boost::asio::io_context &ioContext, const std::string_view &host, const std::string_view &port,
|
||||
const std::string_view &url, boost::system::error_code &error, Http::Version version) {
|
||||
namespace beast = boost::beast;
|
||||
namespace http = boost::beast::http;
|
||||
|
||||
auto stream = makeSslStream(ioContext, host, port, error);
|
||||
if (!stream) return std::string();
|
||||
|
||||
http::request<http::string_body> req{http::verb::get, url, static_cast<unsigned>(version)};
|
||||
req.set(http::field::host, host);
|
||||
req.set(http::field::user_agent, BOOST_BEAST_VERSION_STRING);
|
||||
http::write(*stream, req, error);
|
||||
if (error) {
|
||||
// LOG(error) << error.message();
|
||||
return std::string();
|
||||
}
|
||||
beast::flat_buffer buffer;
|
||||
http::response_parser<http::dynamic_body> parser;
|
||||
parser.body_limit(std::numeric_limits<std::uint64_t>::max());
|
||||
http::read(*stream, buffer, parser, error);
|
||||
if (error) {
|
||||
LOG(error) << error.message();
|
||||
return std::string();
|
||||
}
|
||||
beast::error_code ec;
|
||||
stream->shutdown(ec);
|
||||
return boost::beast::buffers_to_string(parser.get().body().data());
|
||||
}
|
||||
|
||||
std::string Https::post(boost::asio::io_context &ioContext, const std::string_view &host, const std::string_view &port,
|
||||
const std::string_view &url, const std::string_view &body, boost::system::error_code &error,
|
||||
Http::Version version) {
|
||||
|
||||
namespace beast = boost::beast;
|
||||
namespace http = boost::beast::http;
|
||||
|
||||
auto stream = makeSslStream(ioContext, host, port, error);
|
||||
if (!stream) return std::string();
|
||||
|
||||
http::request<http::string_body> req{http::verb::post, url.data(), static_cast<unsigned>(version)};
|
||||
req.set(http::field::host, host);
|
||||
req.set(http::field::user_agent, BOOST_BEAST_VERSION_STRING);
|
||||
req.body() = body;
|
||||
req.prepare_payload();
|
||||
http::write(*stream, req, error);
|
||||
if (error) {
|
||||
LOG(error) << error.message();
|
||||
return std::string();
|
||||
}
|
||||
beast::flat_buffer buffer;
|
||||
http::response<boost::beast::http::dynamic_body> response;
|
||||
http::read(*stream, buffer, response, error);
|
||||
if (error) {
|
||||
LOG(error) << error.message();
|
||||
return std::string();
|
||||
}
|
||||
|
||||
beast::error_code ec;
|
||||
stream->shutdown(ec);
|
||||
return boost::beast::buffers_to_string(response.body().data());
|
||||
}
|
||||
|
||||
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) {
|
||||
namespace beast = boost::beast;
|
||||
namespace http = boost::beast::http;
|
||||
|
||||
auto stream = makeSslStream(ioContext, host, port, error);
|
||||
if (!stream) return std::string();
|
||||
|
||||
http::request<http::string_body> req{http::verb::put, url.data(), static_cast<unsigned>(version)};
|
||||
req.set(http::field::host, host);
|
||||
req.set(http::field::user_agent, BOOST_BEAST_VERSION_STRING);
|
||||
req.body() = body;
|
||||
req.prepare_payload();
|
||||
http::write(*stream, req, error);
|
||||
if (error) {
|
||||
LOG(error) << error.message();
|
||||
return std::string();
|
||||
}
|
||||
beast::flat_buffer buffer;
|
||||
http::response<boost::beast::http::dynamic_body> response;
|
||||
http::read(*stream, buffer, response, error);
|
||||
if (error) {
|
||||
LOG(error) << error.message();
|
||||
return std::string();
|
||||
}
|
||||
|
||||
beast::error_code ec;
|
||||
stream->shutdown(ec);
|
||||
return boost::beast::buffers_to_string(response.body().data());
|
||||
}
|
||||
|
||||
static std::optional<boost::beast::ssl_stream<boost::beast::tcp_stream>>
|
||||
makeSslStream(boost::asio::io_context &ioContext, const std::string_view &host, const std::string_view &port,
|
||||
boost::system::error_code &error) {
|
||||
namespace beast = boost::beast;
|
||||
namespace http = boost::beast::http;
|
||||
|
||||
namespace asio = boost::asio; // from <boost/asio.hpp>
|
||||
using tcp = asio::ip::tcp;
|
||||
|
||||
namespace ssl = asio::ssl;
|
||||
|
||||
ssl::context sslContext(ssl::context::sslv23_client);
|
||||
sslContext.set_default_verify_paths(error);
|
||||
if (error) {
|
||||
LOG(error) << error.message();
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
boost::asio::ip::tcp::resolver resolver(ioContext);
|
||||
|
||||
beast::ssl_stream<beast::tcp_stream> stream(ioContext, sslContext);
|
||||
|
||||
auto const results = resolver.resolve(host, port, error);
|
||||
if (error) {
|
||||
LOG(error) << error.message();
|
||||
return std::nullopt;
|
||||
}
|
||||
beast::get_lowest_layer(stream).connect(results);
|
||||
stream.handshake(ssl::stream_base::client);
|
||||
return std::make_optional(std::move(stream));
|
||||
}
|
||||
|
||||
std::vector<Http::ParseItem> Http::parseFormData(const std::string_view &buffer) {
|
||||
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;
|
||||
}
|
||||
|
||||
uint64_t Network::htonll(uint64_t val) {
|
||||
return (static_cast<uint64_t>(htonl(static_cast<uint32_t>(val))) << 32) + htonl(val >> 32);
|
||||
}
|
||||
|
||||
uint64_t Network::ntohll(uint64_t val) {
|
||||
return (static_cast<uint64_t>(ntohl(static_cast<uint32_t>(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 <winsock.h>
|
||||
#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
|
||||
}
|
68
HttpProxy/NetworkUtility.h
Normal file
68
HttpProxy/NetworkUtility.h
Normal file
@ -0,0 +1,68 @@
|
||||
#ifndef __NETWORKUTILITY_H__
|
||||
#define __NETWORKUTILITY_H__
|
||||
|
||||
#include "Singleton.h"
|
||||
#include <boost/asio/io_context.hpp>
|
||||
#include <boost/system/error_code.hpp>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
|
||||
class Network {
|
||||
friend class Amass::Singleton<Network, Amass::GlobalInstance>;
|
||||
|
||||
public:
|
||||
static bool isConnected(const std::string_view &host, size_t size);
|
||||
static uint64_t htonll(uint64_t val);
|
||||
static uint64_t ntohll(uint64_t val);
|
||||
|
||||
protected:
|
||||
Network(int argc, char *argv[]);
|
||||
~Network();
|
||||
};
|
||||
|
||||
class Http {
|
||||
public:
|
||||
enum Version : unsigned {
|
||||
Version_1_1 = 11,
|
||||
};
|
||||
struct ParseItem {
|
||||
std::string filename;
|
||||
// std::string::const_iterator begin;
|
||||
// std::string::const_iterator end;
|
||||
size_t begin;
|
||||
size_t end;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief
|
||||
*
|
||||
* @param buffer
|
||||
* @return std::vector<ParseItem>
|
||||
* @example auto items = parseFormData(request.body());
|
||||
* for (auto &item : items) {
|
||||
* std::string filename("E:/");
|
||||
* filename += item.filename;
|
||||
* std::ofstream ofs(filename.c_str(), std::ios::binary);
|
||||
* ofs.write(buffer.data() + item.begin, item.end - item.begin);
|
||||
* ofs.close();
|
||||
* }
|
||||
*/
|
||||
static std::vector<ParseItem> parseFormData(const std::string_view &buffer);
|
||||
};
|
||||
|
||||
class Https {
|
||||
public:
|
||||
static std::string get(boost::asio::io_context &ioContext, const std::string_view &host,
|
||||
const std::string_view &port, const std::string_view &url, boost::system::error_code &error,
|
||||
Http::Version version = Http::Version_1_1);
|
||||
|
||||
static std::string post(boost::asio::io_context &ioContext, const std::string_view &host,
|
||||
const std::string_view &port, const std::string_view &url, const std::string_view &body,
|
||||
boost::system::error_code &error, Http::Version version = Http::Version_1_1);
|
||||
|
||||
static std::string 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::Version_1_1);
|
||||
};
|
||||
|
||||
#endif // __NETWORKUTILITY_H__
|
@ -2,6 +2,8 @@ find_package(Boost REQUIRED COMPONENTS log log_setup)
|
||||
|
||||
add_library(Universal
|
||||
BoostLog.h BoostLog.inl BoostLog.cpp
|
||||
DateTime.h DateTime.cpp
|
||||
FunctionTraits.h
|
||||
IoContext.h IoContext.cpp
|
||||
MessageManager.h MessageManager.inl MessageManager.cpp
|
||||
Singleton.h
|
||||
|
180
Universal/DateTime.cpp
Normal file
180
Universal/DateTime.cpp
Normal file
@ -0,0 +1,180 @@
|
||||
#include "DateTime.h"
|
||||
#include "BoostLog.h"
|
||||
#include <boost/algorithm/string/split.hpp>
|
||||
#include <boost/algorithm/string/trim.hpp>
|
||||
#include <iomanip>
|
||||
#include <sstream>
|
||||
#include <time.h>
|
||||
#ifdef __linux__
|
||||
#include <sys/time.h>
|
||||
#endif
|
||||
|
||||
DateTime::DateTime(const std::chrono::time_point<std::chrono::system_clock> &time) {
|
||||
auto t = std::chrono::system_clock::to_time_t(time);
|
||||
// auto tc = std::gmtime(&t);
|
||||
auto tc = std::localtime(&t);
|
||||
|
||||
m_year = tc->tm_year + 1900;
|
||||
m_month = tc->tm_mon + 1;
|
||||
m_day = tc->tm_mday;
|
||||
m_hour = tc->tm_hour;
|
||||
m_minute = tc->tm_min;
|
||||
m_second = tc->tm_sec;
|
||||
m_week = static_cast<Week>(tc->tm_wday);
|
||||
}
|
||||
|
||||
DateTime::DateTime(size_t year, size_t month, size_t day, size_t hour, size_t minute, size_t second)
|
||||
: m_year(year), m_month(month), m_day(day), m_hour(hour), m_minute(minute), m_second(second) {
|
||||
}
|
||||
|
||||
int64_t DateTime::currentMSecsSinceEpoch() {
|
||||
#ifdef __linux__
|
||||
timespec time;
|
||||
|
||||
clock_gettime(CLOCK_REALTIME, &time);
|
||||
return time.tv_sec * 1000 + time.tv_nsec * 1e-6;
|
||||
#else
|
||||
return std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch()).count();
|
||||
#endif
|
||||
}
|
||||
|
||||
int64_t DateTime::currentSecsSinceEpoch() {
|
||||
return std::chrono::duration_cast<std::chrono::seconds>(std::chrono::system_clock::now().time_since_epoch())
|
||||
.count();
|
||||
}
|
||||
|
||||
size_t DateTime::year() const {
|
||||
return m_year;
|
||||
}
|
||||
|
||||
size_t DateTime::month() const {
|
||||
return m_month;
|
||||
}
|
||||
|
||||
size_t DateTime::day() const {
|
||||
return m_day;
|
||||
}
|
||||
|
||||
DateTime::Week DateTime::week() const {
|
||||
return m_week;
|
||||
}
|
||||
|
||||
std::chrono::time_point<std::chrono::system_clock> DateTime::operator()() {
|
||||
return makeDateTime(m_year, m_month, m_day, m_hour, m_minute, m_second);
|
||||
}
|
||||
|
||||
size_t DateTime::hour() const {
|
||||
return m_hour;
|
||||
}
|
||||
|
||||
void DateTime::setHour(size_t hour) {
|
||||
if (m_hour == hour || hour > 23) return;
|
||||
m_hour = hour;
|
||||
}
|
||||
|
||||
size_t DateTime::minute() const {
|
||||
return m_minute;
|
||||
}
|
||||
|
||||
void DateTime::setMinute(size_t minute) {
|
||||
if (m_minute == minute || minute > 59) return;
|
||||
m_minute = minute;
|
||||
}
|
||||
|
||||
size_t DateTime::second() const {
|
||||
return m_second;
|
||||
}
|
||||
|
||||
void DateTime::setSecond(size_t second) {
|
||||
if (m_second == second || second > 60) return;
|
||||
m_second = second;
|
||||
}
|
||||
|
||||
DateTime DateTime::currentDateTime() {
|
||||
return DateTime(std::chrono::system_clock::now());
|
||||
}
|
||||
|
||||
std::string DateTime::toString(const std::string_view &format) const {
|
||||
auto time = makeTime(m_year, m_month, m_day, m_hour, m_minute, m_second);
|
||||
std::ostringstream oss;
|
||||
oss << std::put_time(std::localtime(&time), format.data());
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
std::string DateTime::toString(const std::chrono::time_point<std::chrono::system_clock> &time, const std::string_view &format) {
|
||||
|
||||
auto now_c = std::chrono::system_clock::to_time_t(time);
|
||||
std::ostringstream oss;
|
||||
oss << std::put_time(std::localtime(&now_c), format.data());
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
DateTime DateTime::tomorrow() {
|
||||
DateTime ret(*this);
|
||||
size_t currentMonthDays = days(ret.m_year, ret.m_month);
|
||||
ret.m_day++;
|
||||
if (ret.m_day <= currentMonthDays) return ret;
|
||||
ret.m_day = 1;
|
||||
ret.m_month++;
|
||||
if (m_month <= 12) return ret;
|
||||
ret.m_month = 1;
|
||||
ret.m_year++;
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool DateTime::isLeapYear(size_t year) {
|
||||
return ((year % 4 == 0) && (year % 100 != 0)) || (year % 400 == 0);
|
||||
}
|
||||
|
||||
size_t DateTime::days(size_t year, size_t month) {
|
||||
switch (month) {
|
||||
case 1:
|
||||
case 3:
|
||||
case 5:
|
||||
case 7:
|
||||
case 8:
|
||||
case 10:
|
||||
case 12:
|
||||
return 31;
|
||||
case 4:
|
||||
case 6:
|
||||
case 9:
|
||||
case 11:
|
||||
return 30;
|
||||
case 2:
|
||||
return isLeapYear(year) ? 29 : 28;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
std::chrono::time_point<std::chrono::system_clock> DateTime::makeDateTime(size_t year, size_t month, size_t day, size_t hour, size_t minute,
|
||||
size_t second) {
|
||||
return std::chrono::system_clock::from_time_t(makeTime(year, month, day, hour, minute, second));
|
||||
}
|
||||
|
||||
std::time_t DateTime::makeTime(size_t year, size_t month, size_t day, size_t hour, size_t minute, size_t second) {
|
||||
time_t rawtime;
|
||||
time(&rawtime);
|
||||
auto timepoint = localtime(&rawtime);
|
||||
timepoint->tm_year = static_cast<int>(year - 1900);
|
||||
timepoint->tm_mon = static_cast<int>(month - 1);
|
||||
timepoint->tm_mday = static_cast<int>(day);
|
||||
timepoint->tm_hour = static_cast<int>(hour);
|
||||
timepoint->tm_min = static_cast<int>(minute);
|
||||
timepoint->tm_sec = static_cast<int>(second);
|
||||
|
||||
return std::mktime(timepoint);
|
||||
}
|
||||
|
||||
std::tuple<uint8_t, uint8_t, uint8_t> DateTime::parseTime(const std::string &text) {
|
||||
auto timeStr = boost::algorithm::trim_copy(text);
|
||||
std::vector<std::string> result;
|
||||
boost::algorithm::split(result, timeStr, boost::algorithm::is_any_of(":"));
|
||||
if (result.size() > 3 || result.size() < 2) return {(uint8_t)-1, (uint8_t)-1, (uint8_t)-1};
|
||||
|
||||
auto hour = std::stoi(result.at(0));
|
||||
auto minute = std::stoi(result.at(1));
|
||||
auto second = result.size() > 2 ? std::stoi(result.at(2)) : 0;
|
||||
return std::make_tuple(hour, minute, second);
|
||||
}
|
73
Universal/DateTime.h
Normal file
73
Universal/DateTime.h
Normal file
@ -0,0 +1,73 @@
|
||||
#ifndef DATETIME_H
|
||||
#define DATETIME_H
|
||||
|
||||
#include <chrono>
|
||||
#include <ctime>
|
||||
#include <stdint.h>
|
||||
#include <string_view>
|
||||
|
||||
class DateTime {
|
||||
public:
|
||||
enum Week {
|
||||
Sunday = 0,
|
||||
Monday,
|
||||
Tuesday,
|
||||
Wednesday,
|
||||
Thursday,
|
||||
Friday,
|
||||
Saturday,
|
||||
};
|
||||
DateTime(const std::chrono::time_point<std::chrono::system_clock> &time);
|
||||
DateTime(size_t year, size_t month, size_t day, size_t hour, size_t minute, size_t second);
|
||||
size_t year() const;
|
||||
size_t month() const;
|
||||
size_t day() const;
|
||||
|
||||
size_t hour() const;
|
||||
void setHour(size_t hour);
|
||||
|
||||
size_t minute() const;
|
||||
void setMinute(size_t minute);
|
||||
|
||||
size_t second() const;
|
||||
void setSecond(size_t second);
|
||||
|
||||
Week week() const;
|
||||
std::chrono::time_point<std::chrono::system_clock> operator()();
|
||||
std::string toString(const std::string_view &format = "%F %T") const;
|
||||
|
||||
DateTime tomorrow();
|
||||
|
||||
// Returns the number of milliseconds since 1970-01-01T00:00:00 Universal Coordinated Time. This number is like the
|
||||
// POSIX time_t variable, but expressed in milliseconds instead.
|
||||
static int64_t currentMSecsSinceEpoch();
|
||||
static int64_t currentSecsSinceEpoch();
|
||||
static DateTime currentDateTime();
|
||||
static std::string toString(const std::chrono::time_point<std::chrono::system_clock> &time,
|
||||
const std::string_view &format = "%F %T");
|
||||
static std::chrono::time_point<std::chrono::system_clock> makeDateTime(size_t year, size_t month, size_t day,
|
||||
size_t hour, size_t minute, size_t second);
|
||||
static bool isLeapYear(size_t year);
|
||||
static size_t days(size_t year, size_t month);
|
||||
|
||||
/**
|
||||
* @brief parse time like "12:34:56"、"23:56"
|
||||
*
|
||||
* @return std::tuple<uint8_t,uint8_t,uint8_t>
|
||||
*/
|
||||
static std::tuple<uint8_t, uint8_t, uint8_t> parseTime(const std::string &text);
|
||||
|
||||
protected:
|
||||
static std::time_t makeTime(size_t year, size_t month, size_t day, size_t hour, size_t minute, size_t second);
|
||||
|
||||
private:
|
||||
size_t m_year{1990};
|
||||
size_t m_month{1};
|
||||
size_t m_day{0};
|
||||
size_t m_hour{0};
|
||||
size_t m_minute{0};
|
||||
size_t m_second{0};
|
||||
Week m_week;
|
||||
};
|
||||
|
||||
#endif // DATETIME_H
|
Loading…
Reference in New Issue
Block a user