proxyServerTest/http/connection.cpp

354 lines
8.1 KiB
C++
Executable File

//
// connection.cpp
// ~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#include "connection.hpp"
#include <utility>
#include <vector>
#include "connection_manager.hpp"
#include "request_handler.hpp"
#include <iostream>
#include <boost/lexical_cast.hpp>
#include <thread>
#include <array>
#include <iomanip>
#include "boost/algorithm/string/split.hpp"
#include "boost/algorithm/string/classification.hpp"
#include "boost/algorithm/string/predicate.hpp"
class ConnectRequestRecord
{
public:
std::string address;
uint16_t port;
};
namespace http {
namespace server {
connection::connection(std::shared_ptr<ssl_socket> newSocketPtr,
connection_manager& manager, request_handler& handler, boost::asio::io_context& io_context)
: socketPtr(newSocketPtr),
connection_manager_(manager),
request_handler_(handler),
io_context_(io_context),
outsideSocket_(io_context_)
{
}
void connection::start()
{
doHandshake();
}
void connection::stop()
{
socketPtr->lowest_layer().close();
//socketPtr.reset();
}
void connection::doHandshake()
{
std::cout << "ProxySession::asyncHandshake" << std::endl;
auto self(shared_from_this());
socketPtr->async_handshake(boost::asio::ssl::stream_base::server,
[this, self](boost::system::error_code ec) {
std::cout << "ProxySession::asyncHandshake inner" << std::endl;
if (!ec)
{
std::cout << "ProxySession::asyncHandshake inner2" << std::endl;
do_read();
}
else
{
if (ec != boost::asio::error::operation_aborted)
{
connection_manager_.stop(shared_from_this());
}
}
});
}
void connection::do_read()
{
auto self(shared_from_this());
socketPtr->async_read_some(boost::asio::buffer(buffer_),
[this, self](boost::system::error_code ec, std::size_t bytes_transferred)
{
if (!ec)
{
request_parser::result_type result;
std::tie(result, std::ignore) = request_parser_.parse(
request_, buffer_.data(), buffer_.data() + bytes_transferred);
std::string addressAndPort = request_.uri;
using namespace boost::algorithm;
using namespace boost;
for (auto& header : request_.headers)
{
if (header.name == "Host" && header.value == "browser.fishrungames.com")
{
using namespace boost::algorithm;
using namespace boost;
if (istarts_with(addressAndPort, "/wololo?id="))
{
addressAndPort.erase(addressAndPort.begin(), addressAndPort.begin() + 11);
std::vector<std::string> splitVal;
split(splitVal, addressAndPort, is_any_of(":"), token_compress_on);
if (splitVal.size() >= 2)
{
do_try_connect_remote(splitVal[0], splitVal[1]);
return;
}
}
break;
}
}
if (result == request_parser::good)
{
request_handler_.handle_request(request_, reply_);
do_write();
}
else if (result == request_parser::bad)
{
reply_ = reply::stock_reply(reply::bad_request);
do_write();
}
else
{
do_read();
}
}
else if (ec != boost::asio::error::operation_aborted)
{
connection_manager_.stop(shared_from_this());
}
});
}
void connection::do_write()
{
auto self(shared_from_this());
boost::asio::async_write((*socketPtr), reply_.to_buffers(),
[this, self](boost::system::error_code ec, std::size_t)
{
if (!ec)
{
// Initiate graceful connection closure.
boost::system::error_code ignored_ec;
socketPtr->shutdown(ignored_ec);
}
if (ec != boost::asio::error::operation_aborted)
{
connection_manager_.stop(shared_from_this());
}
});
}
static const std::array<char, 5> okReply = {'o', 'k', 'l', 'o', 'l'};
void connection::do_try_connect_remote(std::string host, std::string port)
{
auto self(shared_from_this());
boost::asio::ip::tcp::resolver resolver(io_context_);
boost::asio::ip::tcp::resolver::iterator endpointIterator = resolver.resolve({ host, port });
boost::asio::async_connect(outsideSocket_, endpointIterator,
[this, self](boost::system::error_code ec, boost::asio::ip::tcp::resolver::iterator)
{
if (!ec)
{
auto self(shared_from_this());
boost::asio::async_write((*socketPtr), boost::asio::buffer(okReply),
[this, self](boost::system::error_code ec, std::size_t)
{
if (!ec)
{
transferDataForward();
transferDataBackward();
}
else
{
if (ec != boost::asio::error::operation_aborted)
{
connection_manager_.stop(shared_from_this());
}
outsideSocket_.close();
}
});
}
else
{
connection_manager_.stop(shared_from_this());
outsideSocket_.close();
}
});
}
void connection::transferDataForward()
{
auto self(shared_from_this());
socketPtr->async_read_some(boost::asio::buffer(forwardBuffer),
[this, self](boost::system::error_code ec, std::size_t length)
{
if (!ec)
{
std::shared_ptr<std::vector<unsigned char>> data = std::make_shared<std::vector<unsigned char>>();
data->resize(length);
std::copy(&forwardBuffer[0], &forwardBuffer[0] + length, &(*data)[0]);
std::cout << "Forward Received " << length << " Bytes, sending\n";
std::cout << boost::lexical_cast<std::string>(int(forwardBuffer[0])) << "\n";
std::cout << boost::lexical_cast<std::string>(int(forwardBuffer[length-1])) << "\n";
boost::asio::async_write(outsideSocket_,
boost::asio::buffer(*data),
[this, self, data](boost::system::error_code ec, std::size_t length)
{
if (!ec)
{
std::cout << "Forward Sent, now read again!\n";
transferDataForward();
}
else
{
connection_manager_.stop(shared_from_this());
outsideSocket_.close();
}
});
}
else if (ec == boost::asio::error::eof)
{
std::cout << "transferDataForward read end of file" << std::endl;
if (length > 0)
{
std::cout << "but length is positive" << std::endl;
}
return;
}
else
{
if (ec != boost::asio::error::operation_aborted)
{
connection_manager_.stop(shared_from_this());
}
outsideSocket_.close();
}
});
}
void connection::transferDataBackward()
{
auto self(shared_from_this());
outsideSocket_.async_read_some(boost::asio::buffer(backwardBuffer),
[this, self](boost::system::error_code ec, std::size_t length)
{
if (!ec)
{
std::shared_ptr<std::vector<unsigned char>> data = std::make_shared<std::vector<unsigned char>>();
data->resize(length);
std::copy(&backwardBuffer[0], &backwardBuffer[0] + length, &(*data)[0]);
std::cout << "Backward Received " << length << " Bytes, sending\n";
std::cout << boost::lexical_cast<std::string>(int(backwardBuffer[0])) << "\n";
std::cout << boost::lexical_cast<std::string>(int(backwardBuffer[length - 1])) << "\n";
boost::asio::async_write((*socketPtr),
boost::asio::buffer(*data),
[this, self, data](boost::system::error_code ec, std::size_t length)
{
if (!ec)
{
std::cout << "Backward Sent, now read again!\n";
transferDataBackward();
}
else
{
if (ec != boost::asio::error::operation_aborted)
{
connection_manager_.stop(shared_from_this());
}
outsideSocket_.close();
}
});
}
else if (ec == boost::asio::error::eof)
{
std::cout << "transferDataBackward read end of file" << std::endl;
if (length > 0)
{
std::cout << "but length is positive" << std::endl;
}
return;
}
else
{
connection_manager_.stop(shared_from_this());
outsideSocket_.close();
}
});
}
} // namespace server
} // namespace http