// // 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 #include #include "connection_manager.hpp" #include "request_handler.hpp" #include #include #include #include #include #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 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 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> data = std::make_shared>(); 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(int(forwardBuffer[0])) << "\n"; std::cout << boost::lexical_cast(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> data = std::make_shared>(); 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(int(backwardBuffer[0])) << "\n"; std::cout << boost::lexical_cast(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