mirror of
				https://github.com/PurpleI2P/i2pd.git
				synced 2025-11-04 00:20:46 +00:00 
			
		
		
		
	Started rewrite of HTTPServer.
This commit is contained in:
		
							parent
							
								
									3d30b4bbbc
								
							
						
					
					
						commit
						e7350a3af4
					
				
					 6 changed files with 269 additions and 1066 deletions
				
			
		
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							| 
						 | 
				
			
			@ -6,119 +6,71 @@
 | 
			
		|||
#include <memory>
 | 
			
		||||
#include <boost/asio.hpp>
 | 
			
		||||
#include <boost/array.hpp>
 | 
			
		||||
#include "util/HTTP.h"
 | 
			
		||||
 | 
			
		||||
namespace i2p
 | 
			
		||||
{
 | 
			
		||||
namespace util
 | 
			
		||||
{
 | 
			
		||||
    const size_t HTTP_CONNECTION_BUFFER_SIZE = 8192;    
 | 
			
		||||
    const int HTTP_DESTINATION_REQUEST_TIMEOUT = 10; // in seconds
 | 
			
		||||
    class HTTPConnection: public std::enable_shared_from_this<HTTPConnection>
 | 
			
		||||
    {
 | 
			
		||||
        protected:
 | 
			
		||||
namespace i2p {
 | 
			
		||||
namespace util {
 | 
			
		||||
 | 
			
		||||
            struct header
 | 
			
		||||
            {
 | 
			
		||||
              std::string name;
 | 
			
		||||
              std::string value;
 | 
			
		||||
            };
 | 
			
		||||
const size_t HTTP_CONNECTION_BUFFER_SIZE = 8192;    
 | 
			
		||||
const int HTTP_DESTINATION_REQUEST_TIMEOUT = 10; // in seconds
 | 
			
		||||
 | 
			
		||||
            struct request
 | 
			
		||||
            {
 | 
			
		||||
              std::string method;
 | 
			
		||||
              std::string uri;
 | 
			
		||||
              std::string host;
 | 
			
		||||
              int port; 
 | 
			
		||||
              int http_version_major;
 | 
			
		||||
              int http_version_minor;
 | 
			
		||||
              std::vector<header> headers;
 | 
			
		||||
            };
 | 
			
		||||
class HTTPConnection: public std::enable_shared_from_this<HTTPConnection> {
 | 
			
		||||
public:
 | 
			
		||||
 | 
			
		||||
            struct reply
 | 
			
		||||
            {
 | 
			
		||||
                std::vector<header> headers;
 | 
			
		||||
                std::string content;
 | 
			
		||||
 | 
			
		||||
                std::vector<boost::asio::const_buffer> to_buffers (int status);
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
        public:
 | 
			
		||||
 | 
			
		||||
            HTTPConnection (boost::asio::ip::tcp::socket * socket): 
 | 
			
		||||
                m_Socket (socket), m_Timer (socket->get_io_service ()), 
 | 
			
		||||
                m_BufferLen (0) {};
 | 
			
		||||
            ~HTTPConnection() { delete m_Socket; }
 | 
			
		||||
            void Receive ();
 | 
			
		||||
            
 | 
			
		||||
        private:
 | 
			
		||||
 | 
			
		||||
            void Terminate ();
 | 
			
		||||
            void HandleReceive (const boost::system::error_code& ecode, std::size_t bytes_transferred);
 | 
			
		||||
            void HandleWriteReply(const boost::system::error_code& ecode);
 | 
			
		||||
            void SendReply (const std::string& content, int status = 200);
 | 
			
		||||
 | 
			
		||||
            void HandleRequest (const std::string& address);
 | 
			
		||||
            void HandleCommand (const std::string& command, std::stringstream& s);
 | 
			
		||||
            void ShowTransports (std::stringstream& s);
 | 
			
		||||
            void ShowTunnels (std::stringstream& s);
 | 
			
		||||
            void ShowTransitTunnels (std::stringstream& s);
 | 
			
		||||
            void ShowLocalDestinations (std::stringstream& s);
 | 
			
		||||
            void ShowLocalDestination (const std::string& b32, std::stringstream& s);
 | 
			
		||||
            void ShowSAMSessions (std::stringstream& s);
 | 
			
		||||
            void ShowSAMSession (const std::string& id, std::stringstream& s);
 | 
			
		||||
            void StartAcceptingTunnels (std::stringstream& s);
 | 
			
		||||
            void StopAcceptingTunnels (std::stringstream& s);
 | 
			
		||||
            void FillContent (std::stringstream& s);
 | 
			
		||||
            std::string ExtractAddress ();
 | 
			
		||||
            void ExtractParams (const std::string& str, std::map<std::string, std::string>& params);
 | 
			
		||||
            
 | 
			
		||||
            
 | 
			
		||||
        protected:
 | 
			
		||||
 | 
			
		||||
            boost::asio::ip::tcp::socket * m_Socket;
 | 
			
		||||
            boost::asio::deadline_timer m_Timer;
 | 
			
		||||
            char m_Buffer[HTTP_CONNECTION_BUFFER_SIZE + 1], m_StreamBuffer[HTTP_CONNECTION_BUFFER_SIZE + 1];
 | 
			
		||||
            size_t m_BufferLen;
 | 
			
		||||
            request m_Request;
 | 
			
		||||
            reply m_Reply;
 | 
			
		||||
 | 
			
		||||
        protected:
 | 
			
		||||
    HTTPConnection(boost::asio::ip::tcp::socket * socket)
 | 
			
		||||
        : m_Socket(socket), m_Timer(socket->get_io_service()), 
 | 
			
		||||
        m_BufferLen(0) {};
 | 
			
		||||
    ~HTTPConnection() { delete m_Socket; }
 | 
			
		||||
    void Receive();
 | 
			
		||||
    
 | 
			
		||||
            virtual void RunRequest ();
 | 
			
		||||
private:
 | 
			
		||||
 | 
			
		||||
        public:
 | 
			
		||||
    void Terminate();
 | 
			
		||||
    void HandleReceive(const boost::system::error_code& ecode, std::size_t bytes_transferred);
 | 
			
		||||
    void RunRequest();
 | 
			
		||||
    void HandleWriteReply(const boost::system::error_code& ecode);
 | 
			
		||||
    void SendReply();
 | 
			
		||||
 | 
			
		||||
            static const std::string itoopieImage;
 | 
			
		||||
            static const std::string itoopieFavicon;
 | 
			
		||||
    };
 | 
			
		||||
    void HandleRequest();
 | 
			
		||||
    void ExtractParams(const std::string& str, std::map<std::string, std::string>& params);
 | 
			
		||||
    
 | 
			
		||||
    bool isAllowed(const std::string& address);
 | 
			
		||||
private:
 | 
			
		||||
    boost::asio::ip::tcp::socket* m_Socket;
 | 
			
		||||
    boost::asio::deadline_timer m_Timer;
 | 
			
		||||
    char m_Buffer[HTTP_CONNECTION_BUFFER_SIZE + 1];
 | 
			
		||||
    char m_StreamBuffer[HTTP_CONNECTION_BUFFER_SIZE + 1];
 | 
			
		||||
    size_t m_BufferLen;
 | 
			
		||||
    util::http::Request m_Request;
 | 
			
		||||
    util::http::Response m_Reply;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
    class HTTPServer
 | 
			
		||||
    {
 | 
			
		||||
        public:
 | 
			
		||||
class HTTPServer {
 | 
			
		||||
public:
 | 
			
		||||
 | 
			
		||||
            HTTPServer (const std::string& address, int port);
 | 
			
		||||
            virtual ~HTTPServer ();
 | 
			
		||||
    HTTPServer(const std::string& address, int port);
 | 
			
		||||
    virtual ~HTTPServer();
 | 
			
		||||
 | 
			
		||||
            void Start ();
 | 
			
		||||
            void Stop ();
 | 
			
		||||
    void Start();
 | 
			
		||||
    void Stop();
 | 
			
		||||
 | 
			
		||||
        private:
 | 
			
		||||
private:
 | 
			
		||||
 | 
			
		||||
            void Run ();
 | 
			
		||||
            void Accept ();
 | 
			
		||||
            void HandleAccept(const boost::system::error_code& ecode);
 | 
			
		||||
            
 | 
			
		||||
        private:
 | 
			
		||||
    void Run();
 | 
			
		||||
    void Accept();
 | 
			
		||||
    void HandleAccept(const boost::system::error_code& ecode);
 | 
			
		||||
    
 | 
			
		||||
private:
 | 
			
		||||
 | 
			
		||||
            std::thread * m_Thread;
 | 
			
		||||
            boost::asio::io_service m_Service;
 | 
			
		||||
            boost::asio::io_service::work m_Work;
 | 
			
		||||
            boost::asio::ip::tcp::acceptor m_Acceptor;
 | 
			
		||||
            boost::asio::ip::tcp::socket * m_NewSocket;
 | 
			
		||||
    std::thread * m_Thread;
 | 
			
		||||
    boost::asio::io_service m_Service;
 | 
			
		||||
    boost::asio::io_service::work m_Work;
 | 
			
		||||
    boost::asio::ip::tcp::acceptor m_Acceptor;
 | 
			
		||||
    boost::asio::ip::tcp::socket * m_NewSocket;
 | 
			
		||||
 | 
			
		||||
        protected:
 | 
			
		||||
            virtual void CreateConnection(boost::asio::ip::tcp::socket * m_NewSocket);
 | 
			
		||||
    };
 | 
			
		||||
protected:
 | 
			
		||||
    virtual void CreateConnection(boost::asio::ip::tcp::socket * m_NewSocket);
 | 
			
		||||
};
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -55,8 +55,8 @@ std::string Request::getHeader(const std::string& name) const
 | 
			
		|||
    return headers.at(name);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Response::Response(int status)
 | 
			
		||||
    : status(status), headers()
 | 
			
		||||
Response::Response(int status, const std::string& content)
 | 
			
		||||
    : status(status), content(content), headers()
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -72,7 +72,7 @@ std::string Response::toString() const
 | 
			
		|||
    ss << "HTTP/1.1 " << status << ' ' << getStatusMessage() << "\r\n";
 | 
			
		||||
    for(auto& pair : headers)
 | 
			
		||||
        ss << pair.first << ": " << pair.second << "\r\n";
 | 
			
		||||
    ss << "\r\n"; 
 | 
			
		||||
    ss << "\r\n" << content; 
 | 
			
		||||
    return ss.str();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -99,6 +99,12 @@ std::string Response::getStatusMessage() const
 | 
			
		|||
            return std::string();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Response::setContentLength()
 | 
			
		||||
{
 | 
			
		||||
    setHeader("Content-Length", std::to_string(content.size()));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -14,9 +14,9 @@ class Request {
 | 
			
		|||
 | 
			
		||||
    void parseHeaderLine(const std::string& line);
 | 
			
		||||
public:
 | 
			
		||||
    Request(const std::string& data);
 | 
			
		||||
    Request() = default;
 | 
			
		||||
 | 
			
		||||
    Request();
 | 
			
		||||
    Request(const std::string& data);
 | 
			
		||||
 | 
			
		||||
    std::string getMethod() const;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -41,8 +41,9 @@ private:
 | 
			
		|||
 | 
			
		||||
class Response {
 | 
			
		||||
public:
 | 
			
		||||
    Response() = default;
 | 
			
		||||
 | 
			
		||||
    Response(int status);
 | 
			
		||||
    Response(int status, const std::string& content = "");
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @note overrides existing header values with the same name
 | 
			
		||||
| 
						 | 
				
			
			@ -57,8 +58,11 @@ public:
 | 
			
		|||
     */
 | 
			
		||||
    std::string getStatusMessage() const;
 | 
			
		||||
 | 
			
		||||
    void setContentLength();
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    int status;
 | 
			
		||||
    std::string content;
 | 
			
		||||
    std::map<std::string, std::string> headers;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -125,6 +125,7 @@ BOOST_AUTO_TEST_CASE(HTTPResponseStatusMessage)
 | 
			
		|||
    BOOST_CHECK_EQUAL(Response(502).getStatusMessage(), "Not Implemented");
 | 
			
		||||
    BOOST_CHECK_EQUAL(Response(504).getStatusMessage(), "Gateway Timeout");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
BOOST_AUTO_TEST_CASE(WriteHTTPResponse)
 | 
			
		||||
{
 | 
			
		||||
    Response rsp(200);
 | 
			
		||||
| 
						 | 
				
			
			@ -136,5 +137,16 @@ BOOST_AUTO_TEST_CASE(WriteHTTPResponse)
 | 
			
		|||
    );
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
BOOST_AUTO_TEST_CASE(WriteHTTPResponseWithContent)
 | 
			
		||||
{
 | 
			
		||||
    Response rsp(200, "Test content.");
 | 
			
		||||
    rsp.setHeader("Connection", "close");
 | 
			
		||||
    BOOST_CHECK_EQUAL(
 | 
			
		||||
        rsp.toString(),
 | 
			
		||||
        "HTTP/1.1 200 OK\r\n"
 | 
			
		||||
        "Connection: close\r\n\r\n"
 | 
			
		||||
        "Test content."
 | 
			
		||||
    );
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
BOOST_AUTO_TEST_SUITE_END()
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1 +1,11 @@
 | 
			
		|||
Nothing here yet.
 | 
			
		||||
<!DOCTYPE html>
 | 
			
		||||
<html lang="en">
 | 
			
		||||
<head>
 | 
			
		||||
<title>Purple I2P 0.10.0 Webconsole</title>
 | 
			
		||||
<meta charset="utf-8">
 | 
			
		||||
<meta name="viewport" content="width=device-width, initial-scale=1">
 | 
			
		||||
</head>
 | 
			
		||||
<body>
 | 
			
		||||
    <p>Nothing here yet.</p>
 | 
			
		||||
</body>
 | 
			
		||||
</html>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue