add http use default certificates api.
This commit is contained in:
parent
20750d1a80
commit
df14b67695
@ -1,5 +1,6 @@
|
||||
project(HttpProxy
|
||||
DESCRIPTION "router api is copy of boost_1_84_0/libs/url/example/router"
|
||||
DESCRIPTION "router api is copy of boost_1_84_0/libs/url/example/router
|
||||
root_certificates.hpp is copy of boost_1_84_0/libs/beast/example/common/root_certificates.hpp"
|
||||
)
|
||||
|
||||
find_package(Boost COMPONENTS url REQUIRED)
|
||||
@ -9,18 +10,23 @@ add_library(HttpProxy
|
||||
ProxyHttpSession.h ProxyHttpSession.cpp
|
||||
ProxyListener.h ProxyListener.cpp
|
||||
ProxyTcpSession.h ProxyTcpSession.cpp
|
||||
|
||||
root_certificates.hpp
|
||||
router.hpp
|
||||
detail/impl/router.cpp
|
||||
impl/matches.cpp
|
||||
)
|
||||
|
||||
target_include_directories(HttpProxy
|
||||
INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}
|
||||
PRIVATE ${OpenSSL_INCLUDE_DIR}
|
||||
PRIVATE ${OPENSSL_INCLUDE_DIR}
|
||||
)
|
||||
|
||||
target_link_directories(HttpProxy
|
||||
PUBLIC ${OPENSSL_LIBRARY_DIRS}
|
||||
)
|
||||
|
||||
target_link_libraries(HttpProxy
|
||||
PUBLIC ${Boost_LIBRARIES}
|
||||
PUBLIC Universal
|
||||
PRIVATE ${OpenSSL_LIBRARY}
|
||||
PRIVATE ${OPENSSL_LIBRARIES}
|
||||
)
|
@ -1,166 +1,32 @@
|
||||
#include "NetworkUtility.h"
|
||||
#include "BoostLog.h"
|
||||
#include "root_certificates.hpp"
|
||||
#include <boost/beast/core.hpp>
|
||||
#include <boost/beast/http.hpp>
|
||||
#include <boost/beast/ssl.hpp>
|
||||
#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>
|
||||
#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::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_view &host, const std::string_view &port,
|
||||
const std::string_view &url, const std::string_view &body, boost::system::error_code &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) {
|
||||
|
||||
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());
|
||||
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) {
|
||||
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;
|
||||
Http::Client client(ioContext, Http::SSL, version);
|
||||
return client.put(host, port, url, body, error);
|
||||
}
|
||||
|
||||
uint64_t Network::htonll(uint64_t val) {
|
||||
@ -200,3 +66,144 @@ Network::~Network() {
|
||||
::WSACleanup();
|
||||
#endif
|
||||
}
|
||||
|
||||
namespace Http {
|
||||
|
||||
std::vector<ParseItem> 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;
|
||||
}
|
||||
|
||||
Client::Client(boost::asio::io_context &ioContext, Type type, Version version) : m_ioContext(ioContext) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
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::put);
|
||||
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::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);
|
||||
}
|
||||
|
||||
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::asio::ip;
|
||||
using namespace boost::beast;
|
||||
|
||||
tcp::resolver resolver(m_ioContext);
|
||||
auto const results = resolver.resolve(host, port, error);
|
||||
if (error) {
|
||||
return std::string();
|
||||
}
|
||||
|
||||
std::unique_ptr<ssl_stream<tcp_stream>> sslStream;
|
||||
std::unique_ptr<tcp_stream> tcpStream;
|
||||
if (m_sslContext) {
|
||||
if (m_certificateLocation == CertificateLocation::None) {
|
||||
m_sslContext->set_default_verify_paths(error);
|
||||
if (!error) m_certificateLocation = CertificateLocation::SystemDependent;
|
||||
}
|
||||
sslStream = std::make_unique<ssl_stream<tcp_stream>>(m_ioContext, *m_sslContext);
|
||||
get_lowest_layer(*sslStream).connect(results, error);
|
||||
if (error) {
|
||||
return std::string();
|
||||
}
|
||||
sslStream->handshake(ssl::stream_base::client, error);
|
||||
} else {
|
||||
tcpStream = std::make_unique<tcp_stream>(m_ioContext);
|
||||
tcpStream->connect(results, error);
|
||||
}
|
||||
if (error) {
|
||||
return std::string();
|
||||
}
|
||||
|
||||
if (sslStream) {
|
||||
http::write(*sslStream, request, error);
|
||||
} else if (tcpStream) {
|
||||
http::write(*tcpStream, request, error);
|
||||
}
|
||||
|
||||
http::response<http::dynamic_body> response;
|
||||
if (!error) {
|
||||
flat_buffer buffer;
|
||||
if (sslStream) {
|
||||
http::read(*sslStream, buffer, response, error);
|
||||
error_code ec;
|
||||
sslStream->shutdown(ec);
|
||||
} else if (tcpStream) {
|
||||
http::read(*tcpStream, buffer, response, error);
|
||||
error_code ec;
|
||||
tcpStream->socket().shutdown(tcp::socket::shutdown_both, ec);
|
||||
}
|
||||
}
|
||||
|
||||
return boost::beast::buffers_to_string(response.body().data());
|
||||
}
|
||||
|
||||
} // namespace Http
|
||||
|
@ -1,12 +1,21 @@
|
||||
#ifndef __NETWORKUTILITY_H__
|
||||
#ifndef __NETWORKUTILITY_H__
|
||||
#define __NETWORKUTILITY_H__
|
||||
|
||||
#include "Singleton.h"
|
||||
#include <boost/asio/io_context.hpp>
|
||||
#include <boost/beast/http/string_body.hpp>
|
||||
#include <boost/system/error_code.hpp>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
|
||||
namespace boost {
|
||||
namespace asio {
|
||||
namespace ssl {
|
||||
class context;
|
||||
}
|
||||
} // namespace asio
|
||||
} // namespace boost
|
||||
|
||||
class Network {
|
||||
friend class Amass::Singleton<Network, Amass::GlobalInstance>;
|
||||
|
||||
@ -20,18 +29,28 @@ protected:
|
||||
~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;
|
||||
};
|
||||
namespace Http {
|
||||
using Request = boost::beast::http::request<boost::beast::http::string_body>;
|
||||
enum Type {
|
||||
Transparent,
|
||||
SSL,
|
||||
};
|
||||
enum CertificateLocation {
|
||||
None,
|
||||
Default,
|
||||
SystemDependent,
|
||||
};
|
||||
|
||||
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
|
||||
@ -48,17 +67,42 @@ public:
|
||||
* }
|
||||
*/
|
||||
static std::vector<ParseItem> parseFormData(const std::string_view &buffer);
|
||||
};
|
||||
|
||||
class Client {
|
||||
public:
|
||||
Client(boost::asio::io_context &ioContext, Type type, Version version = Version_1_1);
|
||||
void loadRootCertificates(boost::system::error_code &error);
|
||||
std::string get(const std::string &host, const std::string &port, const std::string &url,
|
||||
boost::system::error_code &error);
|
||||
std::string post(const std::string &host, const std::string &port, const std::string &url,
|
||||
const std::string &body, boost::system::error_code &error);
|
||||
std::string put(const std::string &host, const std::string &port, const std::string &url,
|
||||
const std::string &body, boost::system::error_code &error);
|
||||
|
||||
void addRequestField(boost::beast::http::field name, const std::string &value);
|
||||
|
||||
protected:
|
||||
std::string execute(const std::string &host, const std::string &port, const Request &request,
|
||||
boost::system::error_code &error);
|
||||
|
||||
private:
|
||||
boost::asio::io_context &m_ioContext;
|
||||
std::shared_ptr<boost::asio::ssl::context> m_sslContext;
|
||||
CertificateLocation m_certificateLocation = CertificateLocation::None;
|
||||
Request m_request;
|
||||
};
|
||||
|
||||
} // namespace Http
|
||||
|
||||
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,
|
||||
static std::string 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::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 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::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,
|
||||
|
3963
HttpProxy/root_certificates.hpp
Normal file
3963
HttpProxy/root_certificates.hpp
Normal file
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user