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
 | ||||
							
								
								
									
										193
									
								
								main.cpp
									
									
									
									
									
								
							
							
						
						
									
										193
									
								
								main.cpp
									
									
									
									
									
								
							| @ -9,10 +9,12 @@ | ||||
| 
 | ||||
| #include <boost/thread.hpp> | ||||
| 
 | ||||
| 
 | ||||
| #if 0 | ||||
| #define SSL_R_SHORT_READ 219 | ||||
| #include "ssl/ssl_locl.h" | ||||
| #include <boost/asio/ssl.hpp> | ||||
| 
 | ||||
| #endif | ||||
| 
 | ||||
| #if defined(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 : | ||||
| 	public std::enable_shared_from_this<ProxySession> | ||||
| { | ||||
| 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) | ||||
| 		, mSocket(socket) | ||||
| 		, mSocket(std::move(inSocket)) | ||||
| 		, outsideConnectSocket(ioService) | ||||
| 	{ | ||||
| 		std::cout << "ProxySession Create" << std::endl; | ||||
| @ -102,61 +100,18 @@ public: | ||||
| 	void start() | ||||
| 	{ | ||||
| 		std::cout << "ProxySession::start" << std::endl; | ||||
| 		asyncHandshake(); | ||||
| 		//readClientVersion();
 | ||||
| 		//asyncHandshake();
 | ||||
| 		readClientVersion(); | ||||
| 	} | ||||
| 
 | ||||
| 
 | ||||
| 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; | ||||
| 	 | ||||
| @ -184,14 +139,14 @@ private: | ||||
| 				{ | ||||
| 					std::string msg = ec.message(); | ||||
| 					std::cout << msg << std::endl; | ||||
| 					lowerSocket().close(); | ||||
| 					socket().close(); | ||||
| 				} | ||||
| 			} | ||||
| 			else | ||||
| 			{ | ||||
| 				std::string msg = ec.message(); | ||||
| 				std::cout << msg << std::endl; | ||||
| 				lowerSocket().close(); | ||||
| 				socket().close(); | ||||
| 			} | ||||
| 		}); | ||||
| 	} | ||||
| @ -219,7 +174,7 @@ private: | ||||
| 			{ | ||||
| 				std::string msg = ec.message(); | ||||
| 				std::cout << msg << std::endl; | ||||
| 				lowerSocket().close(); | ||||
| 				socket().close(); | ||||
| 			} | ||||
| 		}); | ||||
| 	} | ||||
| @ -247,7 +202,7 @@ private: | ||||
| 			{ | ||||
| 				std::string msg = ec.message(); | ||||
| 				std::cout << msg << std::endl; | ||||
| 				lowerSocket().close(); | ||||
| 				socket().close(); | ||||
| 
 | ||||
| 			} | ||||
| 		}); | ||||
| @ -288,14 +243,14 @@ private: | ||||
| 				{ | ||||
| 					std::string msg = ec.message(); | ||||
| 					std::cout << msg << std::endl; | ||||
| 					lowerSocket().close(); | ||||
| 					socket().close(); | ||||
| 				} | ||||
| 			} | ||||
| 			else | ||||
| 			{ | ||||
| 				std::string msg = ec.message(); | ||||
| 				std::cout << msg << std::endl; | ||||
| 				lowerSocket().close(); | ||||
| 				socket().close(); | ||||
| 			} | ||||
| 		}); | ||||
| 
 | ||||
| @ -322,7 +277,7 @@ private: | ||||
| 			{ | ||||
| 				std::string msg = ec.message(); | ||||
| 				std::cout << msg << std::endl; | ||||
| 				lowerSocket().close(); | ||||
| 				socket().close(); | ||||
| 			} | ||||
| 		}); | ||||
| 	} | ||||
| @ -362,14 +317,14 @@ private: | ||||
| 				{ | ||||
| 					std::string msg = ec.message(); | ||||
| 					std::cout << msg << std::endl; | ||||
| 					lowerSocket().close(); | ||||
| 					socket().close(); | ||||
| 				} | ||||
| 			} | ||||
| 			else | ||||
| 			{ | ||||
| 				std::string msg = ec.message(); | ||||
| 				std::cout << msg << std::endl; | ||||
| 				lowerSocket().close(); | ||||
| 				socket().close(); | ||||
| 			} | ||||
| 		}); | ||||
| 
 | ||||
| @ -411,7 +366,7 @@ private: | ||||
| 			{ | ||||
| 				std::string msg = ec.message(); | ||||
| 				std::cout << msg << std::endl; | ||||
| 				lowerSocket().close(); | ||||
| 				socket().close(); | ||||
| 			} | ||||
| 		}); | ||||
| 
 | ||||
| @ -455,7 +410,7 @@ private: | ||||
| 			{ | ||||
| 				std::string msg = ec.message(); | ||||
| 				std::cout << msg << std::endl; | ||||
| 				lowerSocket().close(); | ||||
| 				socket().close(); | ||||
| 			} | ||||
| 		}); | ||||
| 
 | ||||
| @ -477,7 +432,7 @@ private: | ||||
| 			{ | ||||
| 				std::string msg = ec.message(); | ||||
| 				std::cout << msg << std::endl; | ||||
| 				lowerSocket().close(); | ||||
| 				socket().close(); | ||||
| 				outsideConnectSocket.close(); | ||||
| 			} | ||||
| 		}); | ||||
| @ -498,7 +453,7 @@ private: | ||||
| 			{ | ||||
| 				std::string msg = ec.message(); | ||||
| 				std::cout << msg << std::endl; | ||||
| 				lowerSocket().close(); | ||||
| 				socket().close(); | ||||
| 				outsideConnectSocket.close(); | ||||
| 			} | ||||
| 		}); | ||||
| @ -536,7 +491,7 @@ private: | ||||
| 			{ | ||||
| 				std::string msg = ec.message(); | ||||
| 				std::cout << msg << std::endl; | ||||
| 				lowerSocket().close(); | ||||
| 				socket().close(); | ||||
| 				outsideConnectSocket.close(); | ||||
| 			} | ||||
| 		}); | ||||
| @ -577,7 +532,7 @@ private: | ||||
| 			{ | ||||
| 				std::string msg = ec.message(); | ||||
| 				std::cout << msg << std::endl; | ||||
| 				lowerSocket().close(); | ||||
| 				socket().close(); | ||||
| 				outsideConnectSocket.close(); | ||||
| 			} | ||||
| 		}); | ||||
| @ -606,6 +561,12 @@ private: | ||||
| 
 | ||||
| 				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::buffer(*data), | ||||
| @ -614,6 +575,7 @@ private: | ||||
| 
 | ||||
| 					if (!ec) | ||||
| 					{ | ||||
| 						std::cout << "Forward Sent, now read again!\n"; | ||||
| 						transferDataForward(); | ||||
| 					} | ||||
| 					else | ||||
| @ -621,7 +583,7 @@ private: | ||||
| 						std::string msg = ec.message(); | ||||
| 						std::cout << msg << std::endl; | ||||
| 						outsideConnectSocket.close(); | ||||
| 						lowerSocket().close(); | ||||
| 						socket().close(); | ||||
| 					} | ||||
| 				}); | ||||
| 			} | ||||
| @ -639,7 +601,7 @@ private: | ||||
| 				std::string msg = ec.message(); | ||||
| 				std::cout << msg << std::endl; | ||||
| 				outsideConnectSocket.close(); | ||||
| 				lowerSocket().close(); | ||||
| 				socket().close(); | ||||
| 			} | ||||
| 		}); | ||||
| 	} | ||||
| @ -659,6 +621,13 @@ private: | ||||
| 
 | ||||
| 				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), | ||||
| @ -667,6 +636,7 @@ private: | ||||
| 
 | ||||
| 					if (!ec) | ||||
| 					{ | ||||
| 						std::cout << "Backward Sent, now read again!\n"; | ||||
| 						transferDataBackward(); | ||||
| 					} | ||||
| 					else | ||||
| @ -674,7 +644,7 @@ private: | ||||
| 						std::string msg = ec.message(); | ||||
| 						std::cout << msg << std::endl; | ||||
| 						outsideConnectSocket.close(); | ||||
| 						lowerSocket().close(); | ||||
| 						socket().close(); | ||||
| 					} | ||||
| 				}); | ||||
| 			} | ||||
| @ -692,14 +662,14 @@ private: | ||||
| 				std::string msg = ec.message(); | ||||
| 				std::cout << msg << std::endl; | ||||
| 				outsideConnectSocket.close(); | ||||
| 				lowerSocket().close(); | ||||
| 				socket().close(); | ||||
| 			} | ||||
| 		}); | ||||
| 	} | ||||
| 
 | ||||
| 	boost::asio::io_service& ioService; | ||||
| 
 | ||||
| 	std::shared_ptr<ssl_socket> mSocket; | ||||
| 	boost::asio::ip::tcp::socket mSocket; | ||||
| 
 | ||||
| 	boost::asio::ip::tcp::socket outsideConnectSocket; | ||||
| 
 | ||||
| @ -714,12 +684,10 @@ class ProxyServer | ||||
| { | ||||
| public: | ||||
| 	ProxyServer(boost::asio::io_service& inIoService, | ||||
| 		const boost::asio::ip::tcp::endpoint& endpoint, | ||||
| 		boost::asio::ssl::context& inSslContext) | ||||
| 		const boost::asio::ip::tcp::endpoint& endpoint) | ||||
| 		: ioService(inIoService) | ||||
| 		, acceptor(inIoService, endpoint) | ||||
| 		, socket(std::make_shared<ssl_socket>(inIoService, inSslContext)) | ||||
| 		, sslContext(inSslContext) | ||||
| 		, socket(inIoService) | ||||
| 	{ | ||||
| 		doAccept(); | ||||
| 	} | ||||
| @ -727,17 +695,17 @@ public: | ||||
| private: | ||||
| 	void doAccept() | ||||
| 	{ | ||||
| 		acceptor.async_accept(socket->lowest_layer(), | ||||
| 		acceptor.async_accept(socket, | ||||
| 			[this](boost::system::error_code ec) | ||||
| 		{ | ||||
| 			if (!ec) | ||||
| 			{ | ||||
| 				std::make_shared<ProxySession>(socket, ioService)->start(); | ||||
| 				std::make_shared<ProxySession>(std::move(socket), ioService)->start(); | ||||
| 			} | ||||
| 
 | ||||
| 			counter++; | ||||
| 
 | ||||
| 			socket = std::make_shared<ssl_socket>(ioService, sslContext); | ||||
| 			socket = boost::asio::ip::tcp::socket(ioService); | ||||
| 
 | ||||
| 			doAccept(); | ||||
| 		}); | ||||
| @ -746,17 +714,36 @@ private: | ||||
| 	boost::asio::io_service& ioService; | ||||
| 
 | ||||
| 	boost::asio::ip::tcp::acceptor acceptor; | ||||
| 	std::shared_ptr<ssl_socket> socket; | ||||
| 
 | ||||
| 	boost::asio::ssl::context& sslContext; | ||||
| 
 | ||||
| 	//std::map<size_t, ProxySession> proxySessionMap;
 | ||||
| 	boost::asio::ip::tcp::socket socket; | ||||
| 
 | ||||
| 	size_t counter = 0; | ||||
| }; | ||||
| 
 | ||||
| 
 | ||||
| #include "http/server.hpp" | ||||
| 
 | ||||
| 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 | ||||
| @ -766,42 +753,13 @@ int main() | ||||
| 
 | ||||
| 		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; | ||||
| 		/*
 | ||||
| 		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( | ||||
| 			boost::bind(&boost::asio::io_service::run, &ioService) | ||||
| 		); | ||||
| @ -821,3 +779,4 @@ int main() | ||||
| 	return 0; | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -132,8 +132,27 @@ | ||||
|     </Link> | ||||
|   </ItemDefinitionGroup> | ||||
|   <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" /> | ||||
|   </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" /> | ||||
|   <ImportGroup Label="ExtensionTargets"> | ||||
|   </ImportGroup> | ||||
|  | ||||
| @ -13,10 +13,66 @@ | ||||
|       <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> | ||||
|     </Filter> | ||||
|     <Filter Include="Source Files\http"> | ||||
|       <UniqueIdentifier>{24b9a1fb-1821-48c8-958f-b07830316f3e}</UniqueIdentifier> | ||||
|     </Filter> | ||||
|   </ItemGroup> | ||||
|   <ItemGroup> | ||||
|     <ClCompile Include="main.cpp"> | ||||
|       <Filter>Source Files</Filter> | ||||
|     </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> | ||||
| </Project> | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user