Now http support added
This commit is contained in:
		
							parent
							
								
									bcb714ee04
								
							
						
					
					
						commit
						0a14ec2fff
					
				
							
								
								
									
										326
									
								
								http/connection.cpp
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										326
									
								
								http/connection.cpp
									
									
									
									
									
										Executable file
									
								
							| @ -0,0 +1,326 @@ | |||||||
|  | //
 | ||||||
|  | // 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
 | ||||||
							
								
								
									
										93
									
								
								http/connection.hpp
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										93
									
								
								http/connection.hpp
									
									
									
									
									
										Executable file
									
								
							| @ -0,0 +1,93 @@ | |||||||
|  | //
 | ||||||
|  | // connection.hpp
 | ||||||
|  | // ~~~~~~~~~~~~~~
 | ||||||
|  | //
 | ||||||
|  | // 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)
 | ||||||
|  | //
 | ||||||
|  | 
 | ||||||
|  | #ifndef HTTP_CONNECTION_HPP | ||||||
|  | #define HTTP_CONNECTION_HPP | ||||||
|  | 
 | ||||||
|  | #include <array> | ||||||
|  | #include <memory> | ||||||
|  | #include <boost/asio.hpp> | ||||||
|  | #include "reply.hpp" | ||||||
|  | #include "request.hpp" | ||||||
|  | #include "request_handler.hpp" | ||||||
|  | #include "request_parser.hpp" | ||||||
|  | 
 | ||||||
|  | namespace http { | ||||||
|  | namespace server { | ||||||
|  | 
 | ||||||
|  | class connection_manager; | ||||||
|  | 
 | ||||||
|  | /// Represents a single connection from a client.
 | ||||||
|  | class connection | ||||||
|  |   : public std::enable_shared_from_this<connection> | ||||||
|  | { | ||||||
|  | public: | ||||||
|  |   connection(const connection&) = delete; | ||||||
|  |   connection& operator=(const connection&) = delete; | ||||||
|  | 
 | ||||||
|  |   /// Construct a connection with the given socket.
 | ||||||
|  |   explicit connection(boost::asio::ip::tcp::socket socket, | ||||||
|  |       connection_manager& manager, request_handler& handler, boost::asio::io_context& io_context); | ||||||
|  | 
 | ||||||
|  |   /// Start the first asynchronous operation for the connection.
 | ||||||
|  |   void start(); | ||||||
|  | 
 | ||||||
|  |   /// Stop all asynchronous operations associated with the connection.
 | ||||||
|  |   void stop(); | ||||||
|  | 
 | ||||||
|  | private: | ||||||
|  |   /// Perform an asynchronous read operation.
 | ||||||
|  |   void do_read(); | ||||||
|  | 
 | ||||||
|  |   /// Perform an asynchronous write operation.
 | ||||||
|  |   void do_write(); | ||||||
|  | 
 | ||||||
|  |   /// Socket for the connection.
 | ||||||
|  |   boost::asio::ip::tcp::socket socket_; | ||||||
|  | 
 | ||||||
|  |   /// The manager for this connection.
 | ||||||
|  |   connection_manager& connection_manager_; | ||||||
|  | 
 | ||||||
|  |   /// The handler used to process the incoming request.
 | ||||||
|  |   request_handler& request_handler_; | ||||||
|  | 
 | ||||||
|  |   /// Buffer for incoming data.
 | ||||||
|  |   std::array<char, 8192> buffer_; | ||||||
|  | 
 | ||||||
|  |   /// The incoming request.
 | ||||||
|  |   request request_; | ||||||
|  | 
 | ||||||
|  |   /// The parser for the incoming request.
 | ||||||
|  |   request_parser request_parser_; | ||||||
|  | 
 | ||||||
|  |   /// The reply to be sent back to the client.
 | ||||||
|  |   reply reply_; | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  |   boost::asio::io_context& io_context_; | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  |   boost::asio::ip::tcp::socket outsideSocket_; | ||||||
|  | 
 | ||||||
|  |   std::array<unsigned char, 8192> forwardBuffer; | ||||||
|  |   std::array<unsigned char, 8192> backwardBuffer; | ||||||
|  | 
 | ||||||
|  |   void do_try_connect_remote(std::string host, std::string port); | ||||||
|  | 
 | ||||||
|  |   void transferDataForward(); | ||||||
|  |   void transferDataBackward(); | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | typedef std::shared_ptr<connection> connection_ptr; | ||||||
|  | 
 | ||||||
|  | } // namespace server
 | ||||||
|  | } // namespace http
 | ||||||
|  | 
 | ||||||
|  | #endif // HTTP_CONNECTION_HPP
 | ||||||
							
								
								
									
										40
									
								
								http/connection_manager.cpp
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										40
									
								
								http/connection_manager.cpp
									
									
									
									
									
										Executable file
									
								
							| @ -0,0 +1,40 @@ | |||||||
|  | //
 | ||||||
|  | // connection_manager.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_manager.hpp" | ||||||
|  | 
 | ||||||
|  | namespace http { | ||||||
|  | namespace server { | ||||||
|  | 
 | ||||||
|  | connection_manager::connection_manager() | ||||||
|  | { | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void connection_manager::start(connection_ptr c) | ||||||
|  | { | ||||||
|  |   connections_.insert(c); | ||||||
|  |   c->start(); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void connection_manager::stop(connection_ptr c) | ||||||
|  | { | ||||||
|  |   connections_.erase(c); | ||||||
|  |   c->stop(); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void connection_manager::stop_all() | ||||||
|  | { | ||||||
|  |   for (auto c: connections_) | ||||||
|  |     c->stop(); | ||||||
|  |   connections_.clear(); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | } // namespace server
 | ||||||
|  | } // namespace http
 | ||||||
							
								
								
									
										48
									
								
								http/connection_manager.hpp
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										48
									
								
								http/connection_manager.hpp
									
									
									
									
									
										Executable file
									
								
							| @ -0,0 +1,48 @@ | |||||||
|  | //
 | ||||||
|  | // connection_manager.hpp
 | ||||||
|  | // ~~~~~~~~~~~~~~~~~~~~~~
 | ||||||
|  | //
 | ||||||
|  | // 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)
 | ||||||
|  | //
 | ||||||
|  | 
 | ||||||
|  | #ifndef HTTP_CONNECTION_MANAGER_HPP | ||||||
|  | #define HTTP_CONNECTION_MANAGER_HPP | ||||||
|  | 
 | ||||||
|  | #include <set> | ||||||
|  | #include "connection.hpp" | ||||||
|  | 
 | ||||||
|  | namespace http { | ||||||
|  | namespace server { | ||||||
|  | 
 | ||||||
|  | /// Manages open connections so that they may be cleanly stopped when the server
 | ||||||
|  | /// needs to shut down.
 | ||||||
|  | class connection_manager | ||||||
|  | { | ||||||
|  | public: | ||||||
|  |   connection_manager(const connection_manager&) = delete; | ||||||
|  |   connection_manager& operator=(const connection_manager&) = delete; | ||||||
|  | 
 | ||||||
|  |   /// Construct a connection manager.
 | ||||||
|  |   connection_manager(); | ||||||
|  | 
 | ||||||
|  |   /// Add the specified connection to the manager and start it.
 | ||||||
|  |   void start(connection_ptr c); | ||||||
|  | 
 | ||||||
|  |   /// Stop the specified connection.
 | ||||||
|  |   void stop(connection_ptr c); | ||||||
|  | 
 | ||||||
|  |   /// Stop all connections.
 | ||||||
|  |   void stop_all(); | ||||||
|  | 
 | ||||||
|  | private: | ||||||
|  |   /// The managed connections.
 | ||||||
|  |   std::set<connection_ptr> connections_; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | } // namespace server
 | ||||||
|  | } // namespace http
 | ||||||
|  | 
 | ||||||
|  | #endif // HTTP_CONNECTION_MANAGER_HPP
 | ||||||
							
								
								
									
										28
									
								
								http/header.hpp
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										28
									
								
								http/header.hpp
									
									
									
									
									
										Executable file
									
								
							| @ -0,0 +1,28 @@ | |||||||
|  | //
 | ||||||
|  | // header.hpp
 | ||||||
|  | // ~~~~~~~~~~
 | ||||||
|  | //
 | ||||||
|  | // 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)
 | ||||||
|  | //
 | ||||||
|  | 
 | ||||||
|  | #ifndef HTTP_HEADER_HPP | ||||||
|  | #define HTTP_HEADER_HPP | ||||||
|  | 
 | ||||||
|  | #include <string> | ||||||
|  | 
 | ||||||
|  | namespace http { | ||||||
|  | namespace server { | ||||||
|  | 
 | ||||||
|  | struct header | ||||||
|  | { | ||||||
|  |   std::string name; | ||||||
|  |   std::string value; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | } // namespace server
 | ||||||
|  | } // namespace http
 | ||||||
|  | 
 | ||||||
|  | #endif // HTTP_HEADER_HPP
 | ||||||
							
								
								
									
										43
									
								
								http/main_http.cpp
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										43
									
								
								http/main_http.cpp
									
									
									
									
									
										Executable file
									
								
							| @ -0,0 +1,43 @@ | |||||||
|  | //
 | ||||||
|  | // main.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 <iostream> | ||||||
|  | #include <string> | ||||||
|  | #include <boost/asio.hpp> | ||||||
|  | #include "server.hpp" | ||||||
|  | 
 | ||||||
|  | int main_http(int argc, char* argv[]) | ||||||
|  | { | ||||||
|  |   try | ||||||
|  |   { | ||||||
|  |     // Check command line arguments.
 | ||||||
|  |     if (argc != 4) | ||||||
|  |     { | ||||||
|  |       std::cerr << "Usage: http_server <address> <port> <doc_root>\n"; | ||||||
|  |       std::cerr << "  For IPv4, try:\n"; | ||||||
|  |       std::cerr << "    receiver 0.0.0.0 80 .\n"; | ||||||
|  |       std::cerr << "  For IPv6, try:\n"; | ||||||
|  |       std::cerr << "    receiver 0::0 80 .\n"; | ||||||
|  |       return 1; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     // Initialise the server.
 | ||||||
|  |     http::server::server s(argv[1], argv[2], argv[3]); | ||||||
|  | 
 | ||||||
|  |     // Run the server until stopped.
 | ||||||
|  |     s.run(); | ||||||
|  |   } | ||||||
|  |   catch (std::exception& e) | ||||||
|  |   { | ||||||
|  |     std::cerr << "exception: " << e.what() << "\n"; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   return 0; | ||||||
|  | } | ||||||
							
								
								
									
										45
									
								
								http/mime_types.cpp
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										45
									
								
								http/mime_types.cpp
									
									
									
									
									
										Executable file
									
								
							| @ -0,0 +1,45 @@ | |||||||
|  | //
 | ||||||
|  | // mime_types.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 "mime_types.hpp" | ||||||
|  | 
 | ||||||
|  | namespace http { | ||||||
|  | namespace server { | ||||||
|  | namespace mime_types { | ||||||
|  | 
 | ||||||
|  | struct mapping | ||||||
|  | { | ||||||
|  |   const char* extension; | ||||||
|  |   const char* mime_type; | ||||||
|  | } mappings[] = | ||||||
|  | { | ||||||
|  |   { "gif", "image/gif" }, | ||||||
|  |   { "htm", "text/html" }, | ||||||
|  |   { "html", "text/html" }, | ||||||
|  |   { "jpg", "image/jpeg" }, | ||||||
|  |   { "png", "image/png" } | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | std::string extension_to_type(const std::string& extension) | ||||||
|  | { | ||||||
|  |   for (mapping m: mappings) | ||||||
|  |   { | ||||||
|  |     if (m.extension == extension) | ||||||
|  |     { | ||||||
|  |       return m.mime_type; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   return "text/plain"; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | } // namespace mime_types
 | ||||||
|  | } // namespace server
 | ||||||
|  | } // namespace http
 | ||||||
							
								
								
									
										27
									
								
								http/mime_types.hpp
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										27
									
								
								http/mime_types.hpp
									
									
									
									
									
										Executable file
									
								
							| @ -0,0 +1,27 @@ | |||||||
|  | //
 | ||||||
|  | // mime_types.hpp
 | ||||||
|  | // ~~~~~~~~~~~~~~
 | ||||||
|  | //
 | ||||||
|  | // 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)
 | ||||||
|  | //
 | ||||||
|  | 
 | ||||||
|  | #ifndef HTTP_MIME_TYPES_HPP | ||||||
|  | #define HTTP_MIME_TYPES_HPP | ||||||
|  | 
 | ||||||
|  | #include <string> | ||||||
|  | 
 | ||||||
|  | namespace http { | ||||||
|  | namespace server { | ||||||
|  | namespace mime_types { | ||||||
|  | 
 | ||||||
|  | /// Convert a file extension into a MIME type.
 | ||||||
|  | std::string extension_to_type(const std::string& extension); | ||||||
|  | 
 | ||||||
|  | } // namespace mime_types
 | ||||||
|  | } // namespace server
 | ||||||
|  | } // namespace http
 | ||||||
|  | 
 | ||||||
|  | #endif // HTTP_MIME_TYPES_HPP
 | ||||||
							
								
								
									
										255
									
								
								http/reply.cpp
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										255
									
								
								http/reply.cpp
									
									
									
									
									
										Executable file
									
								
							| @ -0,0 +1,255 @@ | |||||||
|  | //
 | ||||||
|  | // reply.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 "reply.hpp" | ||||||
|  | #include <string> | ||||||
|  | 
 | ||||||
|  | namespace http { | ||||||
|  | namespace server { | ||||||
|  | 
 | ||||||
|  | namespace status_strings { | ||||||
|  | 
 | ||||||
|  | const std::string ok = | ||||||
|  |   "HTTP/1.0 200 OK\r\n"; | ||||||
|  | const std::string created = | ||||||
|  |   "HTTP/1.0 201 Created\r\n"; | ||||||
|  | const std::string accepted = | ||||||
|  |   "HTTP/1.0 202 Accepted\r\n"; | ||||||
|  | const std::string no_content = | ||||||
|  |   "HTTP/1.0 204 No Content\r\n"; | ||||||
|  | const std::string multiple_choices = | ||||||
|  |   "HTTP/1.0 300 Multiple Choices\r\n"; | ||||||
|  | const std::string moved_permanently = | ||||||
|  |   "HTTP/1.0 301 Moved Permanently\r\n"; | ||||||
|  | const std::string moved_temporarily = | ||||||
|  |   "HTTP/1.0 302 Moved Temporarily\r\n"; | ||||||
|  | const std::string not_modified = | ||||||
|  |   "HTTP/1.0 304 Not Modified\r\n"; | ||||||
|  | const std::string bad_request = | ||||||
|  |   "HTTP/1.0 400 Bad Request\r\n"; | ||||||
|  | const std::string unauthorized = | ||||||
|  |   "HTTP/1.0 401 Unauthorized\r\n"; | ||||||
|  | const std::string forbidden = | ||||||
|  |   "HTTP/1.0 403 Forbidden\r\n"; | ||||||
|  | const std::string not_found = | ||||||
|  |   "HTTP/1.0 404 Not Found\r\n"; | ||||||
|  | const std::string internal_server_error = | ||||||
|  |   "HTTP/1.0 500 Internal Server Error\r\n"; | ||||||
|  | const std::string not_implemented = | ||||||
|  |   "HTTP/1.0 501 Not Implemented\r\n"; | ||||||
|  | const std::string bad_gateway = | ||||||
|  |   "HTTP/1.0 502 Bad Gateway\r\n"; | ||||||
|  | const std::string service_unavailable = | ||||||
|  |   "HTTP/1.0 503 Service Unavailable\r\n"; | ||||||
|  | 
 | ||||||
|  | boost::asio::const_buffer to_buffer(reply::status_type status) | ||||||
|  | { | ||||||
|  |   switch (status) | ||||||
|  |   { | ||||||
|  |   case reply::ok: | ||||||
|  |     return boost::asio::buffer(ok); | ||||||
|  |   case reply::created: | ||||||
|  |     return boost::asio::buffer(created); | ||||||
|  |   case reply::accepted: | ||||||
|  |     return boost::asio::buffer(accepted); | ||||||
|  |   case reply::no_content: | ||||||
|  |     return boost::asio::buffer(no_content); | ||||||
|  |   case reply::multiple_choices: | ||||||
|  |     return boost::asio::buffer(multiple_choices); | ||||||
|  |   case reply::moved_permanently: | ||||||
|  |     return boost::asio::buffer(moved_permanently); | ||||||
|  |   case reply::moved_temporarily: | ||||||
|  |     return boost::asio::buffer(moved_temporarily); | ||||||
|  |   case reply::not_modified: | ||||||
|  |     return boost::asio::buffer(not_modified); | ||||||
|  |   case reply::bad_request: | ||||||
|  |     return boost::asio::buffer(bad_request); | ||||||
|  |   case reply::unauthorized: | ||||||
|  |     return boost::asio::buffer(unauthorized); | ||||||
|  |   case reply::forbidden: | ||||||
|  |     return boost::asio::buffer(forbidden); | ||||||
|  |   case reply::not_found: | ||||||
|  |     return boost::asio::buffer(not_found); | ||||||
|  |   case reply::internal_server_error: | ||||||
|  |     return boost::asio::buffer(internal_server_error); | ||||||
|  |   case reply::not_implemented: | ||||||
|  |     return boost::asio::buffer(not_implemented); | ||||||
|  |   case reply::bad_gateway: | ||||||
|  |     return boost::asio::buffer(bad_gateway); | ||||||
|  |   case reply::service_unavailable: | ||||||
|  |     return boost::asio::buffer(service_unavailable); | ||||||
|  |   default: | ||||||
|  |     return boost::asio::buffer(internal_server_error); | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | } // namespace status_strings
 | ||||||
|  | 
 | ||||||
|  | namespace misc_strings { | ||||||
|  | 
 | ||||||
|  | const char name_value_separator[] = { ':', ' ' }; | ||||||
|  | const char crlf[] = { '\r', '\n' }; | ||||||
|  | 
 | ||||||
|  | } // namespace misc_strings
 | ||||||
|  | 
 | ||||||
|  | std::vector<boost::asio::const_buffer> reply::to_buffers() | ||||||
|  | { | ||||||
|  |   std::vector<boost::asio::const_buffer> buffers; | ||||||
|  |   buffers.push_back(status_strings::to_buffer(status)); | ||||||
|  |   for (std::size_t i = 0; i < headers.size(); ++i) | ||||||
|  |   { | ||||||
|  |     header& h = headers[i]; | ||||||
|  |     buffers.push_back(boost::asio::buffer(h.name)); | ||||||
|  |     buffers.push_back(boost::asio::buffer(misc_strings::name_value_separator)); | ||||||
|  |     buffers.push_back(boost::asio::buffer(h.value)); | ||||||
|  |     buffers.push_back(boost::asio::buffer(misc_strings::crlf)); | ||||||
|  |   } | ||||||
|  |   buffers.push_back(boost::asio::buffer(misc_strings::crlf)); | ||||||
|  |   buffers.push_back(boost::asio::buffer(content)); | ||||||
|  |   return buffers; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | namespace stock_replies { | ||||||
|  | 
 | ||||||
|  | const char ok[] = ""; | ||||||
|  | const char created[] = | ||||||
|  |   "<html>" | ||||||
|  |   "<head><title>Created</title></head>" | ||||||
|  |   "<body><h1>201 Created</h1></body>" | ||||||
|  |   "</html>"; | ||||||
|  | const char accepted[] = | ||||||
|  |   "<html>" | ||||||
|  |   "<head><title>Accepted</title></head>" | ||||||
|  |   "<body><h1>202 Accepted</h1></body>" | ||||||
|  |   "</html>"; | ||||||
|  | const char no_content[] = | ||||||
|  |   "<html>" | ||||||
|  |   "<head><title>No Content</title></head>" | ||||||
|  |   "<body><h1>204 Content</h1></body>" | ||||||
|  |   "</html>"; | ||||||
|  | const char multiple_choices[] = | ||||||
|  |   "<html>" | ||||||
|  |   "<head><title>Multiple Choices</title></head>" | ||||||
|  |   "<body><h1>300 Multiple Choices</h1></body>" | ||||||
|  |   "</html>"; | ||||||
|  | const char moved_permanently[] = | ||||||
|  |   "<html>" | ||||||
|  |   "<head><title>Moved Permanently</title></head>" | ||||||
|  |   "<body><h1>301 Moved Permanently</h1></body>" | ||||||
|  |   "</html>"; | ||||||
|  | const char moved_temporarily[] = | ||||||
|  |   "<html>" | ||||||
|  |   "<head><title>Moved Temporarily</title></head>" | ||||||
|  |   "<body><h1>302 Moved Temporarily</h1></body>" | ||||||
|  |   "</html>"; | ||||||
|  | const char not_modified[] = | ||||||
|  |   "<html>" | ||||||
|  |   "<head><title>Not Modified</title></head>" | ||||||
|  |   "<body><h1>304 Not Modified</h1></body>" | ||||||
|  |   "</html>"; | ||||||
|  | const char bad_request[] = | ||||||
|  |   "<html>" | ||||||
|  |   "<head><title>Bad Request</title></head>" | ||||||
|  |   "<body><h1>400 Bad Request</h1></body>" | ||||||
|  |   "</html>"; | ||||||
|  | const char unauthorized[] = | ||||||
|  |   "<html>" | ||||||
|  |   "<head><title>Unauthorized</title></head>" | ||||||
|  |   "<body><h1>401 Unauthorized</h1></body>" | ||||||
|  |   "</html>"; | ||||||
|  | const char forbidden[] = | ||||||
|  |   "<html>" | ||||||
|  |   "<head><title>Forbidden</title></head>" | ||||||
|  |   "<body><h1>403 Forbidden</h1></body>" | ||||||
|  |   "</html>"; | ||||||
|  | const char not_found[] = | ||||||
|  |   "<html>" | ||||||
|  |   "<head><title>Not Found</title></head>" | ||||||
|  |   "<body><h1>404 Not Found</h1></body>" | ||||||
|  |   "</html>"; | ||||||
|  | const char internal_server_error[] = | ||||||
|  |   "<html>" | ||||||
|  |   "<head><title>Internal Server Error</title></head>" | ||||||
|  |   "<body><h1>500 Internal Server Error</h1></body>" | ||||||
|  |   "</html>"; | ||||||
|  | const char not_implemented[] = | ||||||
|  |   "<html>" | ||||||
|  |   "<head><title>Not Implemented</title></head>" | ||||||
|  |   "<body><h1>501 Not Implemented</h1></body>" | ||||||
|  |   "</html>"; | ||||||
|  | const char bad_gateway[] = | ||||||
|  |   "<html>" | ||||||
|  |   "<head><title>Bad Gateway</title></head>" | ||||||
|  |   "<body><h1>502 Bad Gateway</h1></body>" | ||||||
|  |   "</html>"; | ||||||
|  | const char service_unavailable[] = | ||||||
|  |   "<html>" | ||||||
|  |   "<head><title>Service Unavailable</title></head>" | ||||||
|  |   "<body><h1>503 Service Unavailable</h1></body>" | ||||||
|  |   "</html>"; | ||||||
|  | 
 | ||||||
|  | std::string to_string(reply::status_type status) | ||||||
|  | { | ||||||
|  |   switch (status) | ||||||
|  |   { | ||||||
|  |   case reply::ok: | ||||||
|  |     return ok; | ||||||
|  |   case reply::created: | ||||||
|  |     return created; | ||||||
|  |   case reply::accepted: | ||||||
|  |     return accepted; | ||||||
|  |   case reply::no_content: | ||||||
|  |     return no_content; | ||||||
|  |   case reply::multiple_choices: | ||||||
|  |     return multiple_choices; | ||||||
|  |   case reply::moved_permanently: | ||||||
|  |     return moved_permanently; | ||||||
|  |   case reply::moved_temporarily: | ||||||
|  |     return moved_temporarily; | ||||||
|  |   case reply::not_modified: | ||||||
|  |     return not_modified; | ||||||
|  |   case reply::bad_request: | ||||||
|  |     return bad_request; | ||||||
|  |   case reply::unauthorized: | ||||||
|  |     return unauthorized; | ||||||
|  |   case reply::forbidden: | ||||||
|  |     return forbidden; | ||||||
|  |   case reply::not_found: | ||||||
|  |     return not_found; | ||||||
|  |   case reply::internal_server_error: | ||||||
|  |     return internal_server_error; | ||||||
|  |   case reply::not_implemented: | ||||||
|  |     return not_implemented; | ||||||
|  |   case reply::bad_gateway: | ||||||
|  |     return bad_gateway; | ||||||
|  |   case reply::service_unavailable: | ||||||
|  |     return service_unavailable; | ||||||
|  |   default: | ||||||
|  |     return internal_server_error; | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | } // namespace stock_replies
 | ||||||
|  | 
 | ||||||
|  | reply reply::stock_reply(reply::status_type status) | ||||||
|  | { | ||||||
|  |   reply rep; | ||||||
|  |   rep.status = status; | ||||||
|  |   rep.content = stock_replies::to_string(status); | ||||||
|  |   rep.headers.resize(2); | ||||||
|  |   rep.headers[0].name = "Content-Length"; | ||||||
|  |   rep.headers[0].value = std::to_string(rep.content.size()); | ||||||
|  |   rep.headers[1].name = "Content-Type"; | ||||||
|  |   rep.headers[1].value = "text/html"; | ||||||
|  |   return rep; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | } // namespace server
 | ||||||
|  | } // namespace http
 | ||||||
							
								
								
									
										64
									
								
								http/reply.hpp
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										64
									
								
								http/reply.hpp
									
									
									
									
									
										Executable file
									
								
							| @ -0,0 +1,64 @@ | |||||||
|  | //
 | ||||||
|  | // reply.hpp
 | ||||||
|  | // ~~~~~~~~~
 | ||||||
|  | //
 | ||||||
|  | // 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)
 | ||||||
|  | //
 | ||||||
|  | 
 | ||||||
|  | #ifndef HTTP_REPLY_HPP | ||||||
|  | #define HTTP_REPLY_HPP | ||||||
|  | 
 | ||||||
|  | #include <string> | ||||||
|  | #include <vector> | ||||||
|  | #include <boost/asio.hpp> | ||||||
|  | #include "header.hpp" | ||||||
|  | 
 | ||||||
|  | namespace http { | ||||||
|  | namespace server { | ||||||
|  | 
 | ||||||
|  | /// A reply to be sent to a client.
 | ||||||
|  | struct reply | ||||||
|  | { | ||||||
|  |   /// The status of the reply.
 | ||||||
|  |   enum status_type | ||||||
|  |   { | ||||||
|  |     ok = 200, | ||||||
|  |     created = 201, | ||||||
|  |     accepted = 202, | ||||||
|  |     no_content = 204, | ||||||
|  |     multiple_choices = 300, | ||||||
|  |     moved_permanently = 301, | ||||||
|  |     moved_temporarily = 302, | ||||||
|  |     not_modified = 304, | ||||||
|  |     bad_request = 400, | ||||||
|  |     unauthorized = 401, | ||||||
|  |     forbidden = 403, | ||||||
|  |     not_found = 404, | ||||||
|  |     internal_server_error = 500, | ||||||
|  |     not_implemented = 501, | ||||||
|  |     bad_gateway = 502, | ||||||
|  |     service_unavailable = 503 | ||||||
|  |   } status; | ||||||
|  | 
 | ||||||
|  |   /// The headers to be included in the reply.
 | ||||||
|  |   std::vector<header> headers; | ||||||
|  | 
 | ||||||
|  |   /// The content to be sent in the reply.
 | ||||||
|  |   std::string content; | ||||||
|  | 
 | ||||||
|  |   /// Convert the reply into a vector of buffers. The buffers do not own the
 | ||||||
|  |   /// underlying memory blocks, therefore the reply object must remain valid and
 | ||||||
|  |   /// not be changed until the write operation has completed.
 | ||||||
|  |   std::vector<boost::asio::const_buffer> to_buffers(); | ||||||
|  | 
 | ||||||
|  |   /// Get a stock reply.
 | ||||||
|  |   static reply stock_reply(status_type status); | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | } // namespace server
 | ||||||
|  | } // namespace http
 | ||||||
|  | 
 | ||||||
|  | #endif // HTTP_REPLY_HPP
 | ||||||
							
								
								
									
										34
									
								
								http/request.hpp
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										34
									
								
								http/request.hpp
									
									
									
									
									
										Executable file
									
								
							| @ -0,0 +1,34 @@ | |||||||
|  | //
 | ||||||
|  | // request.hpp
 | ||||||
|  | // ~~~~~~~~~~~
 | ||||||
|  | //
 | ||||||
|  | // 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)
 | ||||||
|  | //
 | ||||||
|  | 
 | ||||||
|  | #ifndef HTTP_REQUEST_HPP | ||||||
|  | #define HTTP_REQUEST_HPP | ||||||
|  | 
 | ||||||
|  | #include <string> | ||||||
|  | #include <vector> | ||||||
|  | #include "header.hpp" | ||||||
|  | 
 | ||||||
|  | namespace http { | ||||||
|  | namespace server { | ||||||
|  | 
 | ||||||
|  | /// A request received from a client.
 | ||||||
|  | struct request | ||||||
|  | { | ||||||
|  |   std::string method; | ||||||
|  |   std::string uri; | ||||||
|  |   int http_version_major; | ||||||
|  |   int http_version_minor; | ||||||
|  |   std::vector<header> headers; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | } // namespace server
 | ||||||
|  | } // namespace http
 | ||||||
|  | 
 | ||||||
|  | #endif // HTTP_REQUEST_HPP
 | ||||||
							
								
								
									
										121
									
								
								http/request_handler.cpp
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										121
									
								
								http/request_handler.cpp
									
									
									
									
									
										Executable file
									
								
							| @ -0,0 +1,121 @@ | |||||||
|  | //
 | ||||||
|  | // request_handler.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 "request_handler.hpp" | ||||||
|  | #include <fstream> | ||||||
|  | #include <sstream> | ||||||
|  | #include <string> | ||||||
|  | #include "mime_types.hpp" | ||||||
|  | #include "reply.hpp" | ||||||
|  | #include "request.hpp" | ||||||
|  | 
 | ||||||
|  | namespace http { | ||||||
|  | namespace server { | ||||||
|  | 
 | ||||||
|  | request_handler::request_handler(const std::string& doc_root) | ||||||
|  |   : doc_root_(doc_root) | ||||||
|  | { | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void request_handler::handle_request(const request& req, reply& rep) | ||||||
|  | { | ||||||
|  |   // Decode url to path.
 | ||||||
|  |   std::string request_path; | ||||||
|  |   if (!url_decode(req.uri, request_path)) | ||||||
|  |   { | ||||||
|  |     rep = reply::stock_reply(reply::bad_request); | ||||||
|  |     return; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   // Request path must be absolute and not contain "..".
 | ||||||
|  |   if (request_path.empty() || request_path[0] != '/' | ||||||
|  |       || request_path.find("..") != std::string::npos) | ||||||
|  |   { | ||||||
|  |     rep = reply::stock_reply(reply::bad_request); | ||||||
|  |     return; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   // If path ends in slash (i.e. is a directory) then add "index.html".
 | ||||||
|  |   if (request_path[request_path.size() - 1] == '/') | ||||||
|  |   { | ||||||
|  |     request_path += "index.html"; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   // Determine the file extension.
 | ||||||
|  |   std::size_t last_slash_pos = request_path.find_last_of("/"); | ||||||
|  |   std::size_t last_dot_pos = request_path.find_last_of("."); | ||||||
|  |   std::string extension; | ||||||
|  |   if (last_dot_pos != std::string::npos && last_dot_pos > last_slash_pos) | ||||||
|  |   { | ||||||
|  |     extension = request_path.substr(last_dot_pos + 1); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   // Open the file to send back.
 | ||||||
|  |   std::string full_path = doc_root_ + request_path; | ||||||
|  |   std::ifstream is(full_path.c_str(), std::ios::in | std::ios::binary); | ||||||
|  |   if (!is) | ||||||
|  |   { | ||||||
|  |     rep = reply::stock_reply(reply::not_found); | ||||||
|  |     return; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   // Fill out the reply to be sent to the client.
 | ||||||
|  |   rep.status = reply::ok; | ||||||
|  |   char buf[512]; | ||||||
|  |   while (is.read(buf, sizeof(buf)).gcount() > 0) | ||||||
|  |     rep.content.append(buf, is.gcount()); | ||||||
|  |   rep.headers.resize(2); | ||||||
|  |   rep.headers[0].name = "Content-Length"; | ||||||
|  |   rep.headers[0].value = std::to_string(rep.content.size()); | ||||||
|  |   rep.headers[1].name = "Content-Type"; | ||||||
|  |   rep.headers[1].value = mime_types::extension_to_type(extension); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool request_handler::url_decode(const std::string& in, std::string& out) | ||||||
|  | { | ||||||
|  |   out.clear(); | ||||||
|  |   out.reserve(in.size()); | ||||||
|  |   for (std::size_t i = 0; i < in.size(); ++i) | ||||||
|  |   { | ||||||
|  |     if (in[i] == '%') | ||||||
|  |     { | ||||||
|  |       if (i + 3 <= in.size()) | ||||||
|  |       { | ||||||
|  |         int value = 0; | ||||||
|  |         std::istringstream is(in.substr(i + 1, 2)); | ||||||
|  |         if (is >> std::hex >> value) | ||||||
|  |         { | ||||||
|  |           out += static_cast<char>(value); | ||||||
|  |           i += 2; | ||||||
|  |         } | ||||||
|  |         else | ||||||
|  |         { | ||||||
|  |           return false; | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |       else | ||||||
|  |       { | ||||||
|  |         return false; | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |     else if (in[i] == '+') | ||||||
|  |     { | ||||||
|  |       out += ' '; | ||||||
|  |     } | ||||||
|  |     else | ||||||
|  |     { | ||||||
|  |       out += in[i]; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |   return true; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | } // namespace server
 | ||||||
|  | } // namespace http
 | ||||||
							
								
								
									
										47
									
								
								http/request_handler.hpp
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										47
									
								
								http/request_handler.hpp
									
									
									
									
									
										Executable file
									
								
							| @ -0,0 +1,47 @@ | |||||||
|  | //
 | ||||||
|  | // request_handler.hpp
 | ||||||
|  | // ~~~~~~~~~~~~~~~~~~~
 | ||||||
|  | //
 | ||||||
|  | // 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)
 | ||||||
|  | //
 | ||||||
|  | 
 | ||||||
|  | #ifndef HTTP_REQUEST_HANDLER_HPP | ||||||
|  | #define HTTP_REQUEST_HANDLER_HPP | ||||||
|  | 
 | ||||||
|  | #include <string> | ||||||
|  | 
 | ||||||
|  | namespace http { | ||||||
|  | namespace server { | ||||||
|  | 
 | ||||||
|  | struct reply; | ||||||
|  | struct request; | ||||||
|  | 
 | ||||||
|  | /// The common handler for all incoming requests.
 | ||||||
|  | class request_handler | ||||||
|  | { | ||||||
|  | public: | ||||||
|  |   request_handler(const request_handler&) = delete; | ||||||
|  |   request_handler& operator=(const request_handler&) = delete; | ||||||
|  | 
 | ||||||
|  |   /// Construct with a directory containing files to be served.
 | ||||||
|  |   explicit request_handler(const std::string& doc_root); | ||||||
|  | 
 | ||||||
|  |   /// Handle a request and produce a reply.
 | ||||||
|  |   void handle_request(const request& req, reply& rep); | ||||||
|  | 
 | ||||||
|  | private: | ||||||
|  |   /// The directory containing the files to be served.
 | ||||||
|  |   std::string doc_root_; | ||||||
|  | 
 | ||||||
|  |   /// Perform URL-decoding on a string. Returns false if the encoding was
 | ||||||
|  |   /// invalid.
 | ||||||
|  |   static bool url_decode(const std::string& in, std::string& out); | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | } // namespace server
 | ||||||
|  | } // namespace http
 | ||||||
|  | 
 | ||||||
|  | #endif // HTTP_REQUEST_HANDLER_HPP
 | ||||||
							
								
								
									
										315
									
								
								http/request_parser.cpp
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										315
									
								
								http/request_parser.cpp
									
									
									
									
									
										Executable file
									
								
							| @ -0,0 +1,315 @@ | |||||||
|  | //
 | ||||||
|  | // request_parser.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 "request_parser.hpp" | ||||||
|  | #include "request.hpp" | ||||||
|  | 
 | ||||||
|  | namespace http { | ||||||
|  | namespace server { | ||||||
|  | 
 | ||||||
|  | request_parser::request_parser() | ||||||
|  |   : state_(method_start) | ||||||
|  | { | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void request_parser::reset() | ||||||
|  | { | ||||||
|  |   state_ = method_start; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | request_parser::result_type request_parser::consume(request& req, char input) | ||||||
|  | { | ||||||
|  |   switch (state_) | ||||||
|  |   { | ||||||
|  |   case method_start: | ||||||
|  |     if (!is_char(input) || is_ctl(input) || is_tspecial(input)) | ||||||
|  |     { | ||||||
|  |       return bad; | ||||||
|  |     } | ||||||
|  |     else | ||||||
|  |     { | ||||||
|  |       state_ = method; | ||||||
|  |       req.method.push_back(input); | ||||||
|  |       return indeterminate; | ||||||
|  |     } | ||||||
|  |   case method: | ||||||
|  |     if (input == ' ') | ||||||
|  |     { | ||||||
|  |       state_ = uri; | ||||||
|  |       return indeterminate; | ||||||
|  |     } | ||||||
|  |     else if (!is_char(input) || is_ctl(input) || is_tspecial(input)) | ||||||
|  |     { | ||||||
|  |       return bad; | ||||||
|  |     } | ||||||
|  |     else | ||||||
|  |     { | ||||||
|  |       req.method.push_back(input); | ||||||
|  |       return indeterminate; | ||||||
|  |     } | ||||||
|  |   case uri: | ||||||
|  |     if (input == ' ') | ||||||
|  |     { | ||||||
|  |       state_ = http_version_h; | ||||||
|  |       return indeterminate; | ||||||
|  |     } | ||||||
|  |     else if (is_ctl(input)) | ||||||
|  |     { | ||||||
|  |       return bad; | ||||||
|  |     } | ||||||
|  |     else | ||||||
|  |     { | ||||||
|  |       req.uri.push_back(input); | ||||||
|  |       return indeterminate; | ||||||
|  |     } | ||||||
|  |   case http_version_h: | ||||||
|  |     if (input == 'H') | ||||||
|  |     { | ||||||
|  |       state_ = http_version_t_1; | ||||||
|  |       return indeterminate; | ||||||
|  |     } | ||||||
|  |     else | ||||||
|  |     { | ||||||
|  |       return bad; | ||||||
|  |     } | ||||||
|  |   case http_version_t_1: | ||||||
|  |     if (input == 'T') | ||||||
|  |     { | ||||||
|  |       state_ = http_version_t_2; | ||||||
|  |       return indeterminate; | ||||||
|  |     } | ||||||
|  |     else | ||||||
|  |     { | ||||||
|  |       return bad; | ||||||
|  |     } | ||||||
|  |   case http_version_t_2: | ||||||
|  |     if (input == 'T') | ||||||
|  |     { | ||||||
|  |       state_ = http_version_p; | ||||||
|  |       return indeterminate; | ||||||
|  |     } | ||||||
|  |     else | ||||||
|  |     { | ||||||
|  |       return bad; | ||||||
|  |     } | ||||||
|  |   case http_version_p: | ||||||
|  |     if (input == 'P') | ||||||
|  |     { | ||||||
|  |       state_ = http_version_slash; | ||||||
|  |       return indeterminate; | ||||||
|  |     } | ||||||
|  |     else | ||||||
|  |     { | ||||||
|  |       return bad; | ||||||
|  |     } | ||||||
|  |   case http_version_slash: | ||||||
|  |     if (input == '/') | ||||||
|  |     { | ||||||
|  |       req.http_version_major = 0; | ||||||
|  |       req.http_version_minor = 0; | ||||||
|  |       state_ = http_version_major_start; | ||||||
|  |       return indeterminate; | ||||||
|  |     } | ||||||
|  |     else | ||||||
|  |     { | ||||||
|  |       return bad; | ||||||
|  |     } | ||||||
|  |   case http_version_major_start: | ||||||
|  |     if (is_digit(input)) | ||||||
|  |     { | ||||||
|  |       req.http_version_major = req.http_version_major * 10 + input - '0'; | ||||||
|  |       state_ = http_version_major; | ||||||
|  |       return indeterminate; | ||||||
|  |     } | ||||||
|  |     else | ||||||
|  |     { | ||||||
|  |       return bad; | ||||||
|  |     } | ||||||
|  |   case http_version_major: | ||||||
|  |     if (input == '.') | ||||||
|  |     { | ||||||
|  |       state_ = http_version_minor_start; | ||||||
|  |       return indeterminate; | ||||||
|  |     } | ||||||
|  |     else if (is_digit(input)) | ||||||
|  |     { | ||||||
|  |       req.http_version_major = req.http_version_major * 10 + input - '0'; | ||||||
|  |       return indeterminate; | ||||||
|  |     } | ||||||
|  |     else | ||||||
|  |     { | ||||||
|  |       return bad; | ||||||
|  |     } | ||||||
|  |   case http_version_minor_start: | ||||||
|  |     if (is_digit(input)) | ||||||
|  |     { | ||||||
|  |       req.http_version_minor = req.http_version_minor * 10 + input - '0'; | ||||||
|  |       state_ = http_version_minor; | ||||||
|  |       return indeterminate; | ||||||
|  |     } | ||||||
|  |     else | ||||||
|  |     { | ||||||
|  |       return bad; | ||||||
|  |     } | ||||||
|  |   case http_version_minor: | ||||||
|  |     if (input == '\r') | ||||||
|  |     { | ||||||
|  |       state_ = expecting_newline_1; | ||||||
|  |       return indeterminate; | ||||||
|  |     } | ||||||
|  |     else if (is_digit(input)) | ||||||
|  |     { | ||||||
|  |       req.http_version_minor = req.http_version_minor * 10 + input - '0'; | ||||||
|  |       return indeterminate; | ||||||
|  |     } | ||||||
|  |     else | ||||||
|  |     { | ||||||
|  |       return bad; | ||||||
|  |     } | ||||||
|  |   case expecting_newline_1: | ||||||
|  |     if (input == '\n') | ||||||
|  |     { | ||||||
|  |       state_ = header_line_start; | ||||||
|  |       return indeterminate; | ||||||
|  |     } | ||||||
|  |     else | ||||||
|  |     { | ||||||
|  |       return bad; | ||||||
|  |     } | ||||||
|  |   case header_line_start: | ||||||
|  |     if (input == '\r') | ||||||
|  |     { | ||||||
|  |       state_ = expecting_newline_3; | ||||||
|  |       return indeterminate; | ||||||
|  |     } | ||||||
|  |     else if (!req.headers.empty() && (input == ' ' || input == '\t')) | ||||||
|  |     { | ||||||
|  |       state_ = header_lws; | ||||||
|  |       return indeterminate; | ||||||
|  |     } | ||||||
|  |     else if (!is_char(input) || is_ctl(input) || is_tspecial(input)) | ||||||
|  |     { | ||||||
|  |       return bad; | ||||||
|  |     } | ||||||
|  |     else | ||||||
|  |     { | ||||||
|  |       req.headers.push_back(header()); | ||||||
|  |       req.headers.back().name.push_back(input); | ||||||
|  |       state_ = header_name; | ||||||
|  |       return indeterminate; | ||||||
|  |     } | ||||||
|  |   case header_lws: | ||||||
|  |     if (input == '\r') | ||||||
|  |     { | ||||||
|  |       state_ = expecting_newline_2; | ||||||
|  |       return indeterminate; | ||||||
|  |     } | ||||||
|  |     else if (input == ' ' || input == '\t') | ||||||
|  |     { | ||||||
|  |       return indeterminate; | ||||||
|  |     } | ||||||
|  |     else if (is_ctl(input)) | ||||||
|  |     { | ||||||
|  |       return bad; | ||||||
|  |     } | ||||||
|  |     else | ||||||
|  |     { | ||||||
|  |       state_ = header_value; | ||||||
|  |       req.headers.back().value.push_back(input); | ||||||
|  |       return indeterminate; | ||||||
|  |     } | ||||||
|  |   case header_name: | ||||||
|  |     if (input == ':') | ||||||
|  |     { | ||||||
|  |       state_ = space_before_header_value; | ||||||
|  |       return indeterminate; | ||||||
|  |     } | ||||||
|  |     else if (!is_char(input) || is_ctl(input) || is_tspecial(input)) | ||||||
|  |     { | ||||||
|  |       return bad; | ||||||
|  |     } | ||||||
|  |     else | ||||||
|  |     { | ||||||
|  |       req.headers.back().name.push_back(input); | ||||||
|  |       return indeterminate; | ||||||
|  |     } | ||||||
|  |   case space_before_header_value: | ||||||
|  |     if (input == ' ') | ||||||
|  |     { | ||||||
|  |       state_ = header_value; | ||||||
|  |       return indeterminate; | ||||||
|  |     } | ||||||
|  |     else | ||||||
|  |     { | ||||||
|  |       return bad; | ||||||
|  |     } | ||||||
|  |   case header_value: | ||||||
|  |     if (input == '\r') | ||||||
|  |     { | ||||||
|  |       state_ = expecting_newline_2; | ||||||
|  |       return indeterminate; | ||||||
|  |     } | ||||||
|  |     else if (is_ctl(input)) | ||||||
|  |     { | ||||||
|  |       return bad; | ||||||
|  |     } | ||||||
|  |     else | ||||||
|  |     { | ||||||
|  |       req.headers.back().value.push_back(input); | ||||||
|  |       return indeterminate; | ||||||
|  |     } | ||||||
|  |   case expecting_newline_2: | ||||||
|  |     if (input == '\n') | ||||||
|  |     { | ||||||
|  |       state_ = header_line_start; | ||||||
|  |       return indeterminate; | ||||||
|  |     } | ||||||
|  |     else | ||||||
|  |     { | ||||||
|  |       return bad; | ||||||
|  |     } | ||||||
|  |   case expecting_newline_3: | ||||||
|  |     return (input == '\n') ? good : bad; | ||||||
|  |   default: | ||||||
|  |     return bad; | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool request_parser::is_char(int c) | ||||||
|  | { | ||||||
|  |   return c >= 0 && c <= 127; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool request_parser::is_ctl(int c) | ||||||
|  | { | ||||||
|  |   return (c >= 0 && c <= 31) || (c == 127); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool request_parser::is_tspecial(int c) | ||||||
|  | { | ||||||
|  |   switch (c) | ||||||
|  |   { | ||||||
|  |   case '(': case ')': case '<': case '>': case '@': | ||||||
|  |   case ',': case ';': case ':': case '\\': case '"': | ||||||
|  |   case '/': case '[': case ']': case '?': case '=': | ||||||
|  |   case '{': case '}': case ' ': case '\t': | ||||||
|  |     return true; | ||||||
|  |   default: | ||||||
|  |     return false; | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool request_parser::is_digit(int c) | ||||||
|  | { | ||||||
|  |   return c >= '0' && c <= '9'; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | } // namespace server
 | ||||||
|  | } // namespace http
 | ||||||
							
								
								
									
										96
									
								
								http/request_parser.hpp
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										96
									
								
								http/request_parser.hpp
									
									
									
									
									
										Executable file
									
								
							| @ -0,0 +1,96 @@ | |||||||
|  | //
 | ||||||
|  | // request_parser.hpp
 | ||||||
|  | // ~~~~~~~~~~~~~~~~~~
 | ||||||
|  | //
 | ||||||
|  | // 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)
 | ||||||
|  | //
 | ||||||
|  | 
 | ||||||
|  | #ifndef HTTP_REQUEST_PARSER_HPP | ||||||
|  | #define HTTP_REQUEST_PARSER_HPP | ||||||
|  | 
 | ||||||
|  | #include <tuple> | ||||||
|  | 
 | ||||||
|  | namespace http { | ||||||
|  | namespace server { | ||||||
|  | 
 | ||||||
|  | struct request; | ||||||
|  | 
 | ||||||
|  | /// Parser for incoming requests.
 | ||||||
|  | class request_parser | ||||||
|  | { | ||||||
|  | public: | ||||||
|  |   /// Construct ready to parse the request method.
 | ||||||
|  |   request_parser(); | ||||||
|  | 
 | ||||||
|  |   /// Reset to initial parser state.
 | ||||||
|  |   void reset(); | ||||||
|  | 
 | ||||||
|  |   /// Result of parse.
 | ||||||
|  |   enum result_type { good, bad, indeterminate }; | ||||||
|  | 
 | ||||||
|  |   /// Parse some data. The enum return value is good when a complete request has
 | ||||||
|  |   /// been parsed, bad if the data is invalid, indeterminate when more data is
 | ||||||
|  |   /// required. The InputIterator return value indicates how much of the input
 | ||||||
|  |   /// has been consumed.
 | ||||||
|  |   template <typename InputIterator> | ||||||
|  |   std::tuple<result_type, InputIterator> parse(request& req, | ||||||
|  |       InputIterator begin, InputIterator end) | ||||||
|  |   { | ||||||
|  |     while (begin != end) | ||||||
|  |     { | ||||||
|  |       result_type result = consume(req, *begin++); | ||||||
|  |       if (result == good || result == bad) | ||||||
|  |         return std::make_tuple(result, begin); | ||||||
|  |     } | ||||||
|  |     return std::make_tuple(indeterminate, begin); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  | private: | ||||||
|  |   /// Handle the next character of input.
 | ||||||
|  |   result_type consume(request& req, char input); | ||||||
|  | 
 | ||||||
|  |   /// Check if a byte is an HTTP character.
 | ||||||
|  |   static bool is_char(int c); | ||||||
|  | 
 | ||||||
|  |   /// Check if a byte is an HTTP control character.
 | ||||||
|  |   static bool is_ctl(int c); | ||||||
|  | 
 | ||||||
|  |   /// Check if a byte is defined as an HTTP tspecial character.
 | ||||||
|  |   static bool is_tspecial(int c); | ||||||
|  | 
 | ||||||
|  |   /// Check if a byte is a digit.
 | ||||||
|  |   static bool is_digit(int c); | ||||||
|  | 
 | ||||||
|  |   /// The current state of the parser.
 | ||||||
|  |   enum state | ||||||
|  |   { | ||||||
|  |     method_start, | ||||||
|  |     method, | ||||||
|  |     uri, | ||||||
|  |     http_version_h, | ||||||
|  |     http_version_t_1, | ||||||
|  |     http_version_t_2, | ||||||
|  |     http_version_p, | ||||||
|  |     http_version_slash, | ||||||
|  |     http_version_major_start, | ||||||
|  |     http_version_major, | ||||||
|  |     http_version_minor_start, | ||||||
|  |     http_version_minor, | ||||||
|  |     expecting_newline_1, | ||||||
|  |     header_line_start, | ||||||
|  |     header_lws, | ||||||
|  |     header_name, | ||||||
|  |     space_before_header_value, | ||||||
|  |     header_value, | ||||||
|  |     expecting_newline_2, | ||||||
|  |     expecting_newline_3 | ||||||
|  |   } state_; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | } // namespace server
 | ||||||
|  | } // namespace http
 | ||||||
|  | 
 | ||||||
|  | #endif // HTTP_REQUEST_PARSER_HPP
 | ||||||
							
								
								
									
										85
									
								
								http/server.cpp
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										85
									
								
								http/server.cpp
									
									
									
									
									
										Executable file
									
								
							| @ -0,0 +1,85 @@ | |||||||
|  | //
 | ||||||
|  | // server.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 "server.hpp" | ||||||
|  | #include <signal.h> | ||||||
|  | #include <utility> | ||||||
|  | 
 | ||||||
|  | namespace http { | ||||||
|  | namespace server { | ||||||
|  | 
 | ||||||
|  | server::server(const std::string& address, const std::string& port, | ||||||
|  |     const std::string& doc_root) | ||||||
|  |   : io_context_(1), | ||||||
|  |     signals_(io_context_), | ||||||
|  |     acceptor_(io_context_, boost::asio::ip::tcp::endpoint(boost::asio::ip::tcp::v4(), 8043)), | ||||||
|  |     connection_manager_(), | ||||||
|  |     request_handler_(doc_root) | ||||||
|  | { | ||||||
|  |   // Register to handle the signals that indicate when the server should exit.
 | ||||||
|  |   // It is safe to register for the same signal multiple times in a program,
 | ||||||
|  |   // provided all registration for the specified signal is made through Asio.
 | ||||||
|  |   signals_.add(SIGINT); | ||||||
|  |   signals_.add(SIGTERM); | ||||||
|  | #if defined(SIGQUIT) | ||||||
|  |   signals_.add(SIGQUIT); | ||||||
|  | #endif // defined(SIGQUIT)
 | ||||||
|  | 
 | ||||||
|  |   do_await_stop(); | ||||||
|  | 
 | ||||||
|  |   do_accept(); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void server::run() | ||||||
|  | { | ||||||
|  |   // The io_context::run() call will block until all asynchronous operations
 | ||||||
|  |   // have finished. While the server is running, there is always at least one
 | ||||||
|  |   // asynchronous operation outstanding: the asynchronous accept call waiting
 | ||||||
|  |   // for new incoming connections.
 | ||||||
|  |   io_context_.run(); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void server::do_accept() | ||||||
|  | { | ||||||
|  |   acceptor_.async_accept( | ||||||
|  |       [this](boost::system::error_code ec, boost::asio::ip::tcp::socket socket) | ||||||
|  |       { | ||||||
|  |         // Check whether the server was stopped by a signal before this
 | ||||||
|  |         // completion handler had a chance to run.
 | ||||||
|  |         if (!acceptor_.is_open()) | ||||||
|  |         { | ||||||
|  |           return; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         if (!ec) | ||||||
|  |         { | ||||||
|  |           connection_manager_.start(std::make_shared<connection>( | ||||||
|  |               std::move(socket), connection_manager_, request_handler_, io_context_)); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         do_accept(); | ||||||
|  |       }); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void server::do_await_stop() | ||||||
|  | { | ||||||
|  |   signals_.async_wait( | ||||||
|  |       [this](boost::system::error_code /*ec*/, int /*signo*/) | ||||||
|  |       { | ||||||
|  |         // The server is stopped by cancelling all outstanding asynchronous
 | ||||||
|  |         // operations. Once all operations have finished the io_context::run()
 | ||||||
|  |         // call will exit.
 | ||||||
|  |         acceptor_.close(); | ||||||
|  |         connection_manager_.stop_all(); | ||||||
|  |       }); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | } // namespace server
 | ||||||
|  | } // namespace http
 | ||||||
							
								
								
									
										64
									
								
								http/server.hpp
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										64
									
								
								http/server.hpp
									
									
									
									
									
										Executable file
									
								
							| @ -0,0 +1,64 @@ | |||||||
|  | //
 | ||||||
|  | // server.hpp
 | ||||||
|  | // ~~~~~~~~~~
 | ||||||
|  | //
 | ||||||
|  | // 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)
 | ||||||
|  | //
 | ||||||
|  | 
 | ||||||
|  | #ifndef HTTP_SERVER_HPP | ||||||
|  | #define HTTP_SERVER_HPP | ||||||
|  | 
 | ||||||
|  | #include <boost/asio.hpp> | ||||||
|  | #include <string> | ||||||
|  | #include "connection.hpp" | ||||||
|  | #include "connection_manager.hpp" | ||||||
|  | #include "request_handler.hpp" | ||||||
|  | 
 | ||||||
|  | namespace http { | ||||||
|  | namespace server { | ||||||
|  | 
 | ||||||
|  | /// The top-level class of the HTTP server.
 | ||||||
|  | class server | ||||||
|  | { | ||||||
|  | public: | ||||||
|  |   server(const server&) = delete; | ||||||
|  |   server& operator=(const server&) = delete; | ||||||
|  | 
 | ||||||
|  |   /// Construct the server to listen on the specified TCP address and port, and
 | ||||||
|  |   /// serve up files from the given directory.
 | ||||||
|  |   explicit server(const std::string& address, const std::string& port, | ||||||
|  |       const std::string& doc_root); | ||||||
|  | 
 | ||||||
|  |   /// Run the server's io_context loop.
 | ||||||
|  |   void run(); | ||||||
|  | 
 | ||||||
|  | private: | ||||||
|  |   /// Perform an asynchronous accept operation.
 | ||||||
|  |   void do_accept(); | ||||||
|  | 
 | ||||||
|  |   /// Wait for a request to stop the server.
 | ||||||
|  |   void do_await_stop(); | ||||||
|  | 
 | ||||||
|  |   /// The io_context used to perform asynchronous operations.
 | ||||||
|  |   boost::asio::io_context io_context_; | ||||||
|  | 
 | ||||||
|  |   /// The signal_set is used to register for process termination notifications.
 | ||||||
|  |   boost::asio::signal_set signals_; | ||||||
|  | 
 | ||||||
|  |   /// Acceptor used to listen for incoming connections.
 | ||||||
|  |   boost::asio::ip::tcp::acceptor acceptor_; | ||||||
|  | 
 | ||||||
|  |   /// The connection manager which owns all live connections.
 | ||||||
|  |   connection_manager connection_manager_; | ||||||
|  | 
 | ||||||
|  |   /// The handler for all incoming requests.
 | ||||||
|  |   request_handler request_handler_; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | } // namespace server
 | ||||||
|  | } // namespace http
 | ||||||
|  | 
 | ||||||
|  | #endif // HTTP_SERVER_HPP
 | ||||||
							
								
								
									
										195
									
								
								main.cpp
									
									
									
									
									
								
							
							
						
						
									
										195
									
								
								main.cpp
									
									
									
									
									
								
							| @ -9,10 +9,12 @@ | |||||||
| 
 | 
 | ||||||
| #include <boost/thread.hpp> | #include <boost/thread.hpp> | ||||||
| 
 | 
 | ||||||
|  | 
 | ||||||
|  | #if 0 | ||||||
| #define SSL_R_SHORT_READ 219 | #define SSL_R_SHORT_READ 219 | ||||||
| #include "ssl/ssl_locl.h" | #include "ssl/ssl_locl.h" | ||||||
| #include <boost/asio/ssl.hpp> | #include <boost/asio/ssl.hpp> | ||||||
| 
 | #endif | ||||||
| 
 | 
 | ||||||
| #if defined(close) | #if defined(close) | ||||||
| #undef close | #undef close | ||||||
| @ -78,17 +80,13 @@ std::string ConnectRequestRecord::getRequestData() | |||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| 
 |  | ||||||
| typedef boost::asio::ssl::stream<boost::asio::ip::tcp::socket> ssl_socket; |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| class ProxySession : | class ProxySession : | ||||||
| 	public std::enable_shared_from_this<ProxySession> | 	public std::enable_shared_from_this<ProxySession> | ||||||
| { | { | ||||||
| public: | public: | ||||||
| 	ProxySession(std::shared_ptr<ssl_socket> socket, boost::asio::io_service& inIoService) | 	ProxySession(boost::asio::ip::tcp::socket inSocket, boost::asio::io_service& inIoService) | ||||||
| 		: ioService(inIoService) | 		: ioService(inIoService) | ||||||
| 		, mSocket(socket) | 		, mSocket(std::move(inSocket)) | ||||||
| 		, outsideConnectSocket(ioService) | 		, outsideConnectSocket(ioService) | ||||||
| 	{ | 	{ | ||||||
| 		std::cout << "ProxySession Create" << std::endl; | 		std::cout << "ProxySession Create" << std::endl; | ||||||
| @ -102,61 +100,18 @@ public: | |||||||
| 	void start() | 	void start() | ||||||
| 	{ | 	{ | ||||||
| 		std::cout << "ProxySession::start" << std::endl; | 		std::cout << "ProxySession::start" << std::endl; | ||||||
| 		asyncHandshake(); | 		//asyncHandshake();
 | ||||||
| 		//readClientVersion();
 | 		readClientVersion(); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| private: | private: | ||||||
| 
 | 
 | ||||||
| 	ssl_socket& socket() | 	boost::asio::ip::tcp::socket& socket() | ||||||
| 	{ | 	{ | ||||||
| 		return *mSocket; | 		return mSocket; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	ssl_socket::lowest_layer_type& lowerSocket() |  | ||||||
| 	{ |  | ||||||
| 		return mSocket->lowest_layer(); |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| 	void asyncHandshake() |  | ||||||
| 	{ |  | ||||||
| 		std::cout << "ProxySession::asyncHandshake" << std::endl; |  | ||||||
| 		auto self(shared_from_this()); |  | ||||||
| 
 |  | ||||||
| 		socket().async_handshake(boost::asio::ssl::stream_base::server, |  | ||||||
| 			[this, self](boost::system::error_code ec) { |  | ||||||
| 		 |  | ||||||
| 			std::cout << "ProxySession::asyncHandshake inner" << std::endl; |  | ||||||
| 
 |  | ||||||
| 			if (!ec) |  | ||||||
| 			{ |  | ||||||
| 				readClientVersion(); |  | ||||||
| 			} |  | ||||||
| 			else |  | ||||||
| 			{ |  | ||||||
| 				std::string msg = ec.message(); |  | ||||||
| 				std::cout << msg << std::endl; |  | ||||||
| 				lowerSocket().close(); |  | ||||||
| 			} |  | ||||||
| 		 |  | ||||||
| 		}); |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	/*
 |  | ||||||
| 	void handleHandshake(const boost::system::error_code& error) |  | ||||||
| 	{ |  | ||||||
| 		if (!error) |  | ||||||
| 		{ |  | ||||||
| 			readClientVersion(); |  | ||||||
| 		} |  | ||||||
| 		else |  | ||||||
| 		{ |  | ||||||
| 			lowerSocket().close(); |  | ||||||
| 		} |  | ||||||
| 	}*/ |  | ||||||
| 
 |  | ||||||
| 
 | 
 | ||||||
| 	std::array<unsigned char, 3> clientVersion; | 	std::array<unsigned char, 3> clientVersion; | ||||||
| 	 | 	 | ||||||
| @ -184,14 +139,14 @@ private: | |||||||
| 				{ | 				{ | ||||||
| 					std::string msg = ec.message(); | 					std::string msg = ec.message(); | ||||||
| 					std::cout << msg << std::endl; | 					std::cout << msg << std::endl; | ||||||
| 					lowerSocket().close(); | 					socket().close(); | ||||||
| 				} | 				} | ||||||
| 			} | 			} | ||||||
| 			else | 			else | ||||||
| 			{ | 			{ | ||||||
| 				std::string msg = ec.message(); | 				std::string msg = ec.message(); | ||||||
| 				std::cout << msg << std::endl; | 				std::cout << msg << std::endl; | ||||||
| 				lowerSocket().close(); | 				socket().close(); | ||||||
| 			} | 			} | ||||||
| 		}); | 		}); | ||||||
| 	} | 	} | ||||||
| @ -219,7 +174,7 @@ private: | |||||||
| 			{ | 			{ | ||||||
| 				std::string msg = ec.message(); | 				std::string msg = ec.message(); | ||||||
| 				std::cout << msg << std::endl; | 				std::cout << msg << std::endl; | ||||||
| 				lowerSocket().close(); | 				socket().close(); | ||||||
| 			} | 			} | ||||||
| 		}); | 		}); | ||||||
| 	} | 	} | ||||||
| @ -247,7 +202,7 @@ private: | |||||||
| 			{ | 			{ | ||||||
| 				std::string msg = ec.message(); | 				std::string msg = ec.message(); | ||||||
| 				std::cout << msg << std::endl; | 				std::cout << msg << std::endl; | ||||||
| 				lowerSocket().close(); | 				socket().close(); | ||||||
| 
 | 
 | ||||||
| 			} | 			} | ||||||
| 		}); | 		}); | ||||||
| @ -288,14 +243,14 @@ private: | |||||||
| 				{ | 				{ | ||||||
| 					std::string msg = ec.message(); | 					std::string msg = ec.message(); | ||||||
| 					std::cout << msg << std::endl; | 					std::cout << msg << std::endl; | ||||||
| 					lowerSocket().close(); | 					socket().close(); | ||||||
| 				} | 				} | ||||||
| 			} | 			} | ||||||
| 			else | 			else | ||||||
| 			{ | 			{ | ||||||
| 				std::string msg = ec.message(); | 				std::string msg = ec.message(); | ||||||
| 				std::cout << msg << std::endl; | 				std::cout << msg << std::endl; | ||||||
| 				lowerSocket().close(); | 				socket().close(); | ||||||
| 			} | 			} | ||||||
| 		}); | 		}); | ||||||
| 
 | 
 | ||||||
| @ -322,7 +277,7 @@ private: | |||||||
| 			{ | 			{ | ||||||
| 				std::string msg = ec.message(); | 				std::string msg = ec.message(); | ||||||
| 				std::cout << msg << std::endl; | 				std::cout << msg << std::endl; | ||||||
| 				lowerSocket().close(); | 				socket().close(); | ||||||
| 			} | 			} | ||||||
| 		}); | 		}); | ||||||
| 	} | 	} | ||||||
| @ -362,14 +317,14 @@ private: | |||||||
| 				{ | 				{ | ||||||
| 					std::string msg = ec.message(); | 					std::string msg = ec.message(); | ||||||
| 					std::cout << msg << std::endl; | 					std::cout << msg << std::endl; | ||||||
| 					lowerSocket().close(); | 					socket().close(); | ||||||
| 				} | 				} | ||||||
| 			} | 			} | ||||||
| 			else | 			else | ||||||
| 			{ | 			{ | ||||||
| 				std::string msg = ec.message(); | 				std::string msg = ec.message(); | ||||||
| 				std::cout << msg << std::endl; | 				std::cout << msg << std::endl; | ||||||
| 				lowerSocket().close(); | 				socket().close(); | ||||||
| 			} | 			} | ||||||
| 		}); | 		}); | ||||||
| 
 | 
 | ||||||
| @ -411,7 +366,7 @@ private: | |||||||
| 			{ | 			{ | ||||||
| 				std::string msg = ec.message(); | 				std::string msg = ec.message(); | ||||||
| 				std::cout << msg << std::endl; | 				std::cout << msg << std::endl; | ||||||
| 				lowerSocket().close(); | 				socket().close(); | ||||||
| 			} | 			} | ||||||
| 		}); | 		}); | ||||||
| 
 | 
 | ||||||
| @ -455,7 +410,7 @@ private: | |||||||
| 			{ | 			{ | ||||||
| 				std::string msg = ec.message(); | 				std::string msg = ec.message(); | ||||||
| 				std::cout << msg << std::endl; | 				std::cout << msg << std::endl; | ||||||
| 				lowerSocket().close(); | 				socket().close(); | ||||||
| 			} | 			} | ||||||
| 		}); | 		}); | ||||||
| 
 | 
 | ||||||
| @ -477,7 +432,7 @@ private: | |||||||
| 			{ | 			{ | ||||||
| 				std::string msg = ec.message(); | 				std::string msg = ec.message(); | ||||||
| 				std::cout << msg << std::endl; | 				std::cout << msg << std::endl; | ||||||
| 				lowerSocket().close(); | 				socket().close(); | ||||||
| 				outsideConnectSocket.close(); | 				outsideConnectSocket.close(); | ||||||
| 			} | 			} | ||||||
| 		}); | 		}); | ||||||
| @ -498,7 +453,7 @@ private: | |||||||
| 			{ | 			{ | ||||||
| 				std::string msg = ec.message(); | 				std::string msg = ec.message(); | ||||||
| 				std::cout << msg << std::endl; | 				std::cout << msg << std::endl; | ||||||
| 				lowerSocket().close(); | 				socket().close(); | ||||||
| 				outsideConnectSocket.close(); | 				outsideConnectSocket.close(); | ||||||
| 			} | 			} | ||||||
| 		}); | 		}); | ||||||
| @ -536,7 +491,7 @@ private: | |||||||
| 			{ | 			{ | ||||||
| 				std::string msg = ec.message(); | 				std::string msg = ec.message(); | ||||||
| 				std::cout << msg << std::endl; | 				std::cout << msg << std::endl; | ||||||
| 				lowerSocket().close(); | 				socket().close(); | ||||||
| 				outsideConnectSocket.close(); | 				outsideConnectSocket.close(); | ||||||
| 			} | 			} | ||||||
| 		}); | 		}); | ||||||
| @ -577,7 +532,7 @@ private: | |||||||
| 			{ | 			{ | ||||||
| 				std::string msg = ec.message(); | 				std::string msg = ec.message(); | ||||||
| 				std::cout << msg << std::endl; | 				std::cout << msg << std::endl; | ||||||
| 				lowerSocket().close(); | 				socket().close(); | ||||||
| 				outsideConnectSocket.close(); | 				outsideConnectSocket.close(); | ||||||
| 			} | 			} | ||||||
| 		}); | 		}); | ||||||
| @ -605,6 +560,12 @@ private: | |||||||
| 				data->resize(length); | 				data->resize(length); | ||||||
| 
 | 
 | ||||||
| 				std::copy(&forwardBuffer[0], &forwardBuffer[0] + length, &(*data)[0]); | 				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(outsideConnectSocket, | 				boost::asio::async_write(outsideConnectSocket, | ||||||
| @ -614,6 +575,7 @@ private: | |||||||
| 
 | 
 | ||||||
| 					if (!ec) | 					if (!ec) | ||||||
| 					{ | 					{ | ||||||
|  | 						std::cout << "Forward Sent, now read again!\n"; | ||||||
| 						transferDataForward(); | 						transferDataForward(); | ||||||
| 					} | 					} | ||||||
| 					else | 					else | ||||||
| @ -621,7 +583,7 @@ private: | |||||||
| 						std::string msg = ec.message(); | 						std::string msg = ec.message(); | ||||||
| 						std::cout << msg << std::endl; | 						std::cout << msg << std::endl; | ||||||
| 						outsideConnectSocket.close(); | 						outsideConnectSocket.close(); | ||||||
| 						lowerSocket().close(); | 						socket().close(); | ||||||
| 					} | 					} | ||||||
| 				}); | 				}); | ||||||
| 			} | 			} | ||||||
| @ -639,7 +601,7 @@ private: | |||||||
| 				std::string msg = ec.message(); | 				std::string msg = ec.message(); | ||||||
| 				std::cout << msg << std::endl; | 				std::cout << msg << std::endl; | ||||||
| 				outsideConnectSocket.close(); | 				outsideConnectSocket.close(); | ||||||
| 				lowerSocket().close(); | 				socket().close(); | ||||||
| 			} | 			} | ||||||
| 		}); | 		}); | ||||||
| 	} | 	} | ||||||
| @ -659,6 +621,13 @@ private: | |||||||
| 
 | 
 | ||||||
| 				std::copy(&backwardBuffer[0], &backwardBuffer[0] + length, &(*data)[0]); | 				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::async_write(socket(), | ||||||
| 					boost::asio::buffer(*data), | 					boost::asio::buffer(*data), | ||||||
| @ -667,6 +636,7 @@ private: | |||||||
| 
 | 
 | ||||||
| 					if (!ec) | 					if (!ec) | ||||||
| 					{ | 					{ | ||||||
|  | 						std::cout << "Backward Sent, now read again!\n"; | ||||||
| 						transferDataBackward(); | 						transferDataBackward(); | ||||||
| 					} | 					} | ||||||
| 					else | 					else | ||||||
| @ -674,7 +644,7 @@ private: | |||||||
| 						std::string msg = ec.message(); | 						std::string msg = ec.message(); | ||||||
| 						std::cout << msg << std::endl; | 						std::cout << msg << std::endl; | ||||||
| 						outsideConnectSocket.close(); | 						outsideConnectSocket.close(); | ||||||
| 						lowerSocket().close(); | 						socket().close(); | ||||||
| 					} | 					} | ||||||
| 				}); | 				}); | ||||||
| 			} | 			} | ||||||
| @ -692,14 +662,14 @@ private: | |||||||
| 				std::string msg = ec.message(); | 				std::string msg = ec.message(); | ||||||
| 				std::cout << msg << std::endl; | 				std::cout << msg << std::endl; | ||||||
| 				outsideConnectSocket.close(); | 				outsideConnectSocket.close(); | ||||||
| 				lowerSocket().close(); | 				socket().close(); | ||||||
| 			} | 			} | ||||||
| 		}); | 		}); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	boost::asio::io_service& ioService; | 	boost::asio::io_service& ioService; | ||||||
| 
 | 
 | ||||||
| 	std::shared_ptr<ssl_socket> mSocket; | 	boost::asio::ip::tcp::socket mSocket; | ||||||
| 
 | 
 | ||||||
| 	boost::asio::ip::tcp::socket outsideConnectSocket; | 	boost::asio::ip::tcp::socket outsideConnectSocket; | ||||||
| 
 | 
 | ||||||
| @ -714,12 +684,10 @@ class ProxyServer | |||||||
| { | { | ||||||
| public: | public: | ||||||
| 	ProxyServer(boost::asio::io_service& inIoService, | 	ProxyServer(boost::asio::io_service& inIoService, | ||||||
| 		const boost::asio::ip::tcp::endpoint& endpoint, | 		const boost::asio::ip::tcp::endpoint& endpoint) | ||||||
| 		boost::asio::ssl::context& inSslContext) |  | ||||||
| 		: ioService(inIoService) | 		: ioService(inIoService) | ||||||
| 		, acceptor(inIoService, endpoint) | 		, acceptor(inIoService, endpoint) | ||||||
| 		, socket(std::make_shared<ssl_socket>(inIoService, inSslContext)) | 		, socket(inIoService) | ||||||
| 		, sslContext(inSslContext) |  | ||||||
| 	{ | 	{ | ||||||
| 		doAccept(); | 		doAccept(); | ||||||
| 	} | 	} | ||||||
| @ -727,17 +695,17 @@ public: | |||||||
| private: | private: | ||||||
| 	void doAccept() | 	void doAccept() | ||||||
| 	{ | 	{ | ||||||
| 		acceptor.async_accept(socket->lowest_layer(), | 		acceptor.async_accept(socket, | ||||||
| 			[this](boost::system::error_code ec) | 			[this](boost::system::error_code ec) | ||||||
| 		{ | 		{ | ||||||
| 			if (!ec) | 			if (!ec) | ||||||
| 			{ | 			{ | ||||||
| 				std::make_shared<ProxySession>(socket, ioService)->start(); | 				std::make_shared<ProxySession>(std::move(socket), ioService)->start(); | ||||||
| 			} | 			} | ||||||
| 
 | 
 | ||||||
| 			counter++; | 			counter++; | ||||||
| 
 | 
 | ||||||
| 			socket = std::make_shared<ssl_socket>(ioService, sslContext); | 			socket = boost::asio::ip::tcp::socket(ioService); | ||||||
| 
 | 
 | ||||||
| 			doAccept(); | 			doAccept(); | ||||||
| 		}); | 		}); | ||||||
| @ -746,17 +714,36 @@ private: | |||||||
| 	boost::asio::io_service& ioService; | 	boost::asio::io_service& ioService; | ||||||
| 
 | 
 | ||||||
| 	boost::asio::ip::tcp::acceptor acceptor; | 	boost::asio::ip::tcp::acceptor acceptor; | ||||||
| 	std::shared_ptr<ssl_socket> socket; | 	boost::asio::ip::tcp::socket socket; | ||||||
| 
 |  | ||||||
| 	boost::asio::ssl::context& sslContext; |  | ||||||
| 
 |  | ||||||
| 	//std::map<size_t, ProxySession> proxySessionMap;
 |  | ||||||
| 
 | 
 | ||||||
| 	size_t counter = 0; | 	size_t counter = 0; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | #include "http/server.hpp" | ||||||
|  | 
 | ||||||
| int main() | int main() | ||||||
|  | { | ||||||
|  | 
 | ||||||
|  | 	try | ||||||
|  | 	{ | ||||||
|  | 
 | ||||||
|  | 		// Initialise the server.
 | ||||||
|  | 		http::server::server s("0.0.0.0", "8043", "."); | ||||||
|  | 
 | ||||||
|  | 		// Run the server until stopped.
 | ||||||
|  | 		s.run(); | ||||||
|  | 	} | ||||||
|  | 	catch (std::exception& e) | ||||||
|  | 	{ | ||||||
|  | 		std::cerr << "exception: " << e.what() << "\n"; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return 0; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | int main_0() | ||||||
| { | { | ||||||
| 
 | 
 | ||||||
| 	try | 	try | ||||||
| @ -766,42 +753,13 @@ int main() | |||||||
| 
 | 
 | ||||||
| 		boost::asio::ip::tcp::endpoint endpoint(boost::asio::ip::tcp::v4(), 8043); | 		boost::asio::ip::tcp::endpoint endpoint(boost::asio::ip::tcp::v4(), 8043); | ||||||
| 
 | 
 | ||||||
| 		boost::asio::ssl::context sslContext(boost::asio::ssl::context::tls_server); |  | ||||||
| 
 |  | ||||||
| 		SSL_CTX_set_cipher_list(sslContext.native_handle(), "EECDH+AES128:DH+AES:RSA+AESGCM:RSA+AES:!aNULL:!MD5:!DSS"); |  | ||||||
| 
 |  | ||||||
| 		sslContext.set_options(boost::asio::ssl::context::default_workarounds |  | ||||||
| 			| boost::asio::ssl::context::verify_none |  | ||||||
| 			| boost::asio::ssl::context::no_sslv2 |  | ||||||
| 			| boost::asio::ssl::context::no_sslv3 |  | ||||||
| 			| boost::asio::ssl::context::no_tlsv1 |  | ||||||
| 			| boost::asio::ssl::context::single_dh_use |  | ||||||
| 		); |  | ||||||
| 
 |  | ||||||
| 		std::function<std::string(std::size_t, boost::asio::ssl::context_base::password_purpose)> f = [](std::size_t, boost::asio::ssl::context_base::password_purpose) -> std::string { return ""; }; |  | ||||||
| 		sslContext.set_password_callback(f); |  | ||||||
| 
 |  | ||||||
| 		sslContext.use_certificate_chain_file("server.crt"); |  | ||||||
| 
 |  | ||||||
| 		sslContext.use_private_key_file("server.key", boost::asio::ssl::context::pem); |  | ||||||
| 
 |  | ||||||
| 		sslContext.use_tmp_dh_file("dh2048.pem"); |  | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| 		ProxyServer proxyServer(ioService, endpoint, sslContext); | 		ProxyServer proxyServer(ioService, endpoint); | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| 		boost::thread_group threadpool; | 		boost::thread_group threadpool; | ||||||
| 		/*
 | 
 | ||||||
| 		threadpool.create_thread( |  | ||||||
| 			boost::bind(&boost::asio::io_service::run, &ioService) |  | ||||||
| 		); |  | ||||||
| 		threadpool.create_thread( |  | ||||||
| 			boost::bind(&boost::asio::io_service::run, &ioService) |  | ||||||
| 		); |  | ||||||
| 		threadpool.create_thread( |  | ||||||
| 			boost::bind(&boost::asio::io_service::run, &ioService) |  | ||||||
| 		);*/ |  | ||||||
| 		threadpool.create_thread( | 		threadpool.create_thread( | ||||||
| 			boost::bind(&boost::asio::io_service::run, &ioService) | 			boost::bind(&boost::asio::io_service::run, &ioService) | ||||||
| 		); | 		); | ||||||
| @ -820,4 +778,5 @@ int main() | |||||||
| 
 | 
 | ||||||
| 	return 0; | 	return 0; | ||||||
| 
 | 
 | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | |||||||
| @ -132,8 +132,27 @@ | |||||||
|     </Link> |     </Link> | ||||||
|   </ItemDefinitionGroup> |   </ItemDefinitionGroup> | ||||||
|   <ItemGroup> |   <ItemGroup> | ||||||
|  |     <ClCompile Include="http\connection.cpp" /> | ||||||
|  |     <ClCompile Include="http\connection_manager.cpp" /> | ||||||
|  |     <ClCompile Include="http\main_http.cpp" /> | ||||||
|  |     <ClCompile Include="http\mime_types.cpp" /> | ||||||
|  |     <ClCompile Include="http\reply.cpp" /> | ||||||
|  |     <ClCompile Include="http\request_handler.cpp" /> | ||||||
|  |     <ClCompile Include="http\request_parser.cpp" /> | ||||||
|  |     <ClCompile Include="http\server.cpp" /> | ||||||
|     <ClCompile Include="main.cpp" /> |     <ClCompile Include="main.cpp" /> | ||||||
|   </ItemGroup> |   </ItemGroup> | ||||||
|  |   <ItemGroup> | ||||||
|  |     <ClInclude Include="http\connection.hpp" /> | ||||||
|  |     <ClInclude Include="http\connection_manager.hpp" /> | ||||||
|  |     <ClInclude Include="http\header.hpp" /> | ||||||
|  |     <ClInclude Include="http\mime_types.hpp" /> | ||||||
|  |     <ClInclude Include="http\reply.hpp" /> | ||||||
|  |     <ClInclude Include="http\request.hpp" /> | ||||||
|  |     <ClInclude Include="http\request_handler.hpp" /> | ||||||
|  |     <ClInclude Include="http\request_parser.hpp" /> | ||||||
|  |     <ClInclude Include="http\server.hpp" /> | ||||||
|  |   </ItemGroup> | ||||||
|   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> |   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> | ||||||
|   <ImportGroup Label="ExtensionTargets"> |   <ImportGroup Label="ExtensionTargets"> | ||||||
|   </ImportGroup> |   </ImportGroup> | ||||||
|  | |||||||
| @ -13,10 +13,66 @@ | |||||||
|       <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier> |       <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier> | ||||||
|       <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions> |       <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions> | ||||||
|     </Filter> |     </Filter> | ||||||
|  |     <Filter Include="Source Files\http"> | ||||||
|  |       <UniqueIdentifier>{24b9a1fb-1821-48c8-958f-b07830316f3e}</UniqueIdentifier> | ||||||
|  |     </Filter> | ||||||
|   </ItemGroup> |   </ItemGroup> | ||||||
|   <ItemGroup> |   <ItemGroup> | ||||||
|     <ClCompile Include="main.cpp"> |     <ClCompile Include="main.cpp"> | ||||||
|       <Filter>Source Files</Filter> |       <Filter>Source Files</Filter> | ||||||
|     </ClCompile> |     </ClCompile> | ||||||
|  |     <ClCompile Include="http\connection.cpp"> | ||||||
|  |       <Filter>Source Files\http</Filter> | ||||||
|  |     </ClCompile> | ||||||
|  |     <ClCompile Include="http\connection_manager.cpp"> | ||||||
|  |       <Filter>Source Files\http</Filter> | ||||||
|  |     </ClCompile> | ||||||
|  |     <ClCompile Include="http\main_http.cpp"> | ||||||
|  |       <Filter>Source Files\http</Filter> | ||||||
|  |     </ClCompile> | ||||||
|  |     <ClCompile Include="http\mime_types.cpp"> | ||||||
|  |       <Filter>Source Files\http</Filter> | ||||||
|  |     </ClCompile> | ||||||
|  |     <ClCompile Include="http\reply.cpp"> | ||||||
|  |       <Filter>Source Files\http</Filter> | ||||||
|  |     </ClCompile> | ||||||
|  |     <ClCompile Include="http\request_handler.cpp"> | ||||||
|  |       <Filter>Source Files\http</Filter> | ||||||
|  |     </ClCompile> | ||||||
|  |     <ClCompile Include="http\request_parser.cpp"> | ||||||
|  |       <Filter>Source Files\http</Filter> | ||||||
|  |     </ClCompile> | ||||||
|  |     <ClCompile Include="http\server.cpp"> | ||||||
|  |       <Filter>Source Files\http</Filter> | ||||||
|  |     </ClCompile> | ||||||
|  |   </ItemGroup> | ||||||
|  |   <ItemGroup> | ||||||
|  |     <ClInclude Include="http\server.hpp"> | ||||||
|  |       <Filter>Source Files\http</Filter> | ||||||
|  |     </ClInclude> | ||||||
|  |     <ClInclude Include="http\connection.hpp"> | ||||||
|  |       <Filter>Source Files\http</Filter> | ||||||
|  |     </ClInclude> | ||||||
|  |     <ClInclude Include="http\connection_manager.hpp"> | ||||||
|  |       <Filter>Source Files\http</Filter> | ||||||
|  |     </ClInclude> | ||||||
|  |     <ClInclude Include="http\header.hpp"> | ||||||
|  |       <Filter>Source Files\http</Filter> | ||||||
|  |     </ClInclude> | ||||||
|  |     <ClInclude Include="http\mime_types.hpp"> | ||||||
|  |       <Filter>Source Files\http</Filter> | ||||||
|  |     </ClInclude> | ||||||
|  |     <ClInclude Include="http\reply.hpp"> | ||||||
|  |       <Filter>Source Files\http</Filter> | ||||||
|  |     </ClInclude> | ||||||
|  |     <ClInclude Include="http\request.hpp"> | ||||||
|  |       <Filter>Source Files\http</Filter> | ||||||
|  |     </ClInclude> | ||||||
|  |     <ClInclude Include="http\request_handler.hpp"> | ||||||
|  |       <Filter>Source Files\http</Filter> | ||||||
|  |     </ClInclude> | ||||||
|  |     <ClInclude Include="http\request_parser.hpp"> | ||||||
|  |       <Filter>Source Files\http</Filter> | ||||||
|  |     </ClInclude> | ||||||
|   </ItemGroup> |   </ItemGroup> | ||||||
| </Project> | </Project> | ||||||
		Loading…
	
		Reference in New Issue
	
	Block a user