proxyServerTest/http/connection.cpp

327 lines
7.6 KiB
C++
Raw Permalink Normal View History

2018-08-25 18:23:54 +00:00
//
// 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(boost::asio::ip::tcp::socket socket,
connection_manager& manager, request_handler& handler, boost::asio::io_context& io_context)
: socket_(std::move(socket)),
connection_manager_(manager),
request_handler_(handler),
io_context_(io_context),
outsideSocket_(io_context_)
{
}
void connection::start()
{
do_read();
}
void connection::stop()
{
socket_.close();
}
void connection::do_read()
{
auto self(shared_from_this());
socket_.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(socket_, 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;
socket_.shutdown(boost::asio::ip::tcp::socket::shutdown_both,
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(socket_, 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());
socket_.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(socket_,
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