95 lines
3.3 KiB
C++
95 lines
3.3 KiB
C++
|
#include "ProxyHttpSession.h"
|
||
|
#include "BoostLog.h"
|
||
|
#include "ProxyTcpSession.h"
|
||
|
#include <boost/asio/strand.hpp>
|
||
|
#include <boost/beast/http/read.hpp>
|
||
|
#include <boost/beast/http/write.hpp>
|
||
|
|
||
|
ProxyHttpSession::ProxyHttpSession(boost::asio::io_context &ioContext, boost::asio::ip::tcp::socket &&socket)
|
||
|
: m_resolver(ioContext), m_clientStream(std::move(socket)), m_serverStream(boost::asio::make_strand(ioContext)) {
|
||
|
}
|
||
|
|
||
|
void ProxyHttpSession::run() {
|
||
|
doRead();
|
||
|
}
|
||
|
|
||
|
void ProxyHttpSession::doRead() {
|
||
|
// Construct a new parser for each message
|
||
|
m_parser.emplace();
|
||
|
|
||
|
// Apply a reasonable limit to the allowed size
|
||
|
// of the body in bytes to prevent abuse.
|
||
|
m_parser->body_limit(std::numeric_limits<std::uint64_t>::max());
|
||
|
m_parser->header_limit(std::numeric_limits<std::uint32_t>::max());
|
||
|
m_buffer.clear();
|
||
|
|
||
|
// Set the timeout.
|
||
|
// m_stream.expires_after(std::chrono::seconds(30));
|
||
|
m_clientStream.expires_never();
|
||
|
boost::beast::http::async_read(
|
||
|
m_clientStream, m_buffer, *m_parser,
|
||
|
[self{shared_from_this()}](const boost::system::error_code &ec, std::size_t bytes_transferred) {
|
||
|
self->onRead(ec, bytes_transferred);
|
||
|
});
|
||
|
}
|
||
|
|
||
|
void ProxyHttpSession::onRead(boost::beast::error_code ec, size_t) { // This means they closed the connection
|
||
|
if (ec == boost::beast::http::error::end_of_stream) {
|
||
|
LOG(info) << ec << " : " << ec.message();
|
||
|
m_clientStream.socket().shutdown(boost::asio::ip::tcp::socket::shutdown_send, ec);
|
||
|
return;
|
||
|
}
|
||
|
if (ec) {
|
||
|
if (ec == boost::asio::error::operation_aborted) return;
|
||
|
LOG(info) << ec << " : " << ec.message();
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
auto request = m_parser->release();
|
||
|
if (request.count("Host") <= 0) return;
|
||
|
auto host = request.at("Host");
|
||
|
if (host.empty()) {
|
||
|
LOG(error) << "Host field not existed.";
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
auto colonPos = host.find_first_of(':');
|
||
|
|
||
|
std::string_view serverAddress;
|
||
|
std::string_view serverPort;
|
||
|
if (colonPos != std::string_view::npos) {
|
||
|
serverAddress = host.substr(0, colonPos);
|
||
|
serverPort = host.substr(colonPos + 1);
|
||
|
} else {
|
||
|
serverAddress = host;
|
||
|
serverPort = "80";
|
||
|
}
|
||
|
|
||
|
boost::system::error_code ee;
|
||
|
auto const results = m_resolver.resolve(serverAddress, serverPort, ee);
|
||
|
if (ee) {
|
||
|
LOG(error) << ee.message();
|
||
|
return;
|
||
|
}
|
||
|
m_serverStream.connect(results, ee);
|
||
|
if (ee) {
|
||
|
LOG(error) << ee.message();
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if (request.method() == boost::beast::http::verb::connect) {
|
||
|
LOG(info) << "proxy host [" << serverAddress << "], port [" << serverPort << "]";
|
||
|
boost::beast::http::response<boost::beast::http::string_body> res{boost::beast::http::status::ok,
|
||
|
request.version()};
|
||
|
res.reason("Connection Established");
|
||
|
res.keep_alive(request.keep_alive());
|
||
|
res.set("Proxy-agent", "amass");
|
||
|
res.prepare_payload();
|
||
|
boost::beast::http::write(m_clientStream, res);
|
||
|
} else {
|
||
|
boost::beast::http::write(m_serverStream, request);
|
||
|
}
|
||
|
auto tcp = std::make_shared<ProxyTcpSession>(m_clientStream.release_socket(), m_serverStream.release_socket());
|
||
|
tcp->run();
|
||
|
}
|