From 7cf171671db8de9f7dfb34029d2ec7c1db94709c Mon Sep 17 00:00:00 2001 From: hagen Date: Wed, 27 Apr 2016 00:00:00 +0000 Subject: [PATCH 01/29] * HTTPConnection::reply : to_buffers() -> to_string() --- HTTPServer.cpp | 57 +++++++++++++++++++++----------------------------- HTTPServer.h | 4 ++-- 2 files changed, 26 insertions(+), 35 deletions(-) diff --git a/HTTPServer.cpp b/HTTPServer.cpp index 6c2c6112..6897a347 100644 --- a/HTTPServer.cpp +++ b/HTTPServer.cpp @@ -212,42 +212,32 @@ namespace util } // namespace misc_strings - std::vector HTTPConnection::reply::to_buffers(int status) + std::string HTTPConnection::reply::to_string(int code) { - std::vector buffers; + std::stringstream ss(""); if (headers.size () > 0) { - status_string = "HTTP/1.1 "; - status_string += std::to_string (status); - status_string += " "; - switch (status) + const char *status; + switch (code) { - case 105: status_string += "Name Not Resolved"; break; - case 200: status_string += "OK"; break; - case 400: status_string += "Bad Request"; break; - case 404: status_string += "Not Found"; break; - case 408: status_string += "Request Timeout"; break; - case 500: status_string += "Internal Server Error"; break; - case 502: status_string += "Bad Gateway"; break; - case 503: status_string += "Not Implemented"; break; - case 504: status_string += "Gateway Timeout"; break; - default: status_string += "WTF"; + case 105: status = "Name Not Resolved"; break; + case 200: status = "OK"; break; + case 400: status = "Bad Request"; break; + case 404: status = "Not Found"; break; + case 408: status = "Request Timeout"; break; + case 500: status = "Internal Server Error"; break; + case 502: status = "Bad Gateway"; break; + case 503: status = "Not Implemented"; break; + case 504: status = "Gateway Timeout"; break; + default: status = "WTF"; } - buffers.push_back(boost::asio::buffer(status_string, status_string.size())); - buffers.push_back(boost::asio::buffer(misc_strings::crlf)); - - 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; + ss << "HTTP/1.1 " << code << "" << status << HTTP_CRLF; + for (header & h : headers) { + ss << h.name << HTTP_HEADER_KV_SEP << h.value << HTTP_CRLF; + } + ss << HTTP_CRLF; /* end of headers */ + } + return ss.str(); } void HTTPConnection::Terminate () @@ -914,8 +904,9 @@ namespace util m_Reply.headers[2].name = "Content-Type"; m_Reply.headers[2].value = "text/html"; } - - boost::asio::async_write (*m_Socket, m_Reply.to_buffers(status), + std::string res = m_Reply.to_string(status); + + boost::asio::async_write (*m_Socket, res, std::bind (&HTTPConnection::HandleWriteReply, shared_from_this (), std::placeholders::_1)); } diff --git a/HTTPServer.h b/HTTPServer.h index 66083d85..889afca9 100644 --- a/HTTPServer.h +++ b/HTTPServer.h @@ -39,8 +39,8 @@ namespace util struct reply { std::vector
headers; - std::string status_string, content; - std::vector to_buffers (int status); + std::string status; + std::string to_string (int code); }; public: From 7a461c168490a98450e716d2972c46672740c6f0 Mon Sep 17 00:00:00 2001 From: hagen Date: Wed, 27 Apr 2016 00:00:00 +0000 Subject: [PATCH 02/29] * HTTPServer.{cpp,h}: move #include to one place --- HTTPServer.cpp | 7 +++++++ HTTPServer.h | 12 +----------- 2 files changed, 8 insertions(+), 11 deletions(-) diff --git a/HTTPServer.cpp b/HTTPServer.cpp index 6897a347..bf895ced 100644 --- a/HTTPServer.cpp +++ b/HTTPServer.cpp @@ -1,7 +1,13 @@ #include #include +#include +#include +#include + +#include #include #include + #include "Base.h" #include "FS.h" #include "Log.h" @@ -9,6 +15,7 @@ #include "TransitTunnel.h" #include "Transports.h" #include "NetDb.h" +#include "LeaseSet.h" #include "I2PEndian.h" #include "Streaming.h" #include "Destination.h" diff --git a/HTTPServer.h b/HTTPServer.h index 889afca9..ead03cde 100644 --- a/HTTPServer.h +++ b/HTTPServer.h @@ -1,14 +1,6 @@ #ifndef HTTP_SERVER_H__ #define HTTP_SERVER_H__ -#include -#include -#include -#include -#include -#include "LeaseSet.h" -#include "Streaming.h" - namespace i2p { namespace util @@ -135,6 +127,4 @@ namespace util } } -#endif - - +#endif /* HTTP_SERVER_H__ */ From 6ed709d6e6b2af7516de4ceea69753a73f82428c Mon Sep 17 00:00:00 2001 From: hagen Date: Wed, 27 Apr 2016 00:00:00 +0000 Subject: [PATCH 03/29] * HTTPServer.{cpp,h}: extract itoopie{Image,Favicon} from HTTPConnection (!) class --- HTTPServer.cpp | 10 ++++++---- HTTPServer.h | 4 ++-- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/HTTPServer.cpp b/HTTPServer.cpp index bf895ced..2c0f3ea5 100644 --- a/HTTPServer.cpp +++ b/HTTPServer.cpp @@ -30,7 +30,7 @@ namespace i2p { namespace util { - const std::string HTTPConnection::itoopieImage = + const char *itoopieImage = "\"ICToopie"; - const std::string HTTPConnection::itoopieFavicon = + const char *itoopieFavicon = "data:image/png;base64," "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv" "8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAYdEVYdFNvZnR3YXJlAFBhaW50Lk5FVCB2My4wOGVynO" @@ -357,7 +357,7 @@ namespace util // Html5 head start s << "\r\n"; // TODO: Add support for locale. s << "\r\n\r\n"; // TODO: Find something to parse html/template system. This is horrible. - s << "\r\n"; + s << "\r\n"; s << "Purple I2P " << VERSION " Webconsole\r\n"; s << "\r\n"; + + const char HTTP_PAGE_TUNNELS[] = "tunnels"; + const char HTTP_PAGE_TRANSIT_TUNNELS[] = "transit_tunnels"; + const char HTTP_PAGE_TRANSPORTS[] = "transports"; + const char HTTP_PAGE_LOCAL_DESTINATIONS[] = "local_destinations"; + const char HTTP_PAGE_LOCAL_DESTINATION[] = "local_destination"; + const char HTTP_PAGE_SAM_SESSIONS[] = "sam_sessions"; + const char HTTP_PAGE_SAM_SESSION[] = "sam_session"; + const char HTTP_PAGE_I2P_TUNNELS[] = "i2p_tunnels"; + const char HTTP_PAGE_JUMPSERVICES[] = "jumpservices"; const char HTTP_COMMAND_START_ACCEPTING_TUNNELS[] = "start_accepting_tunnels"; const char HTTP_COMMAND_STOP_ACCEPTING_TUNNELS[] = "stop_accepting_tunnels"; const char HTTP_COMMAND_RUN_PEER_TEST[] = "run_peer_test"; - const char HTTP_COMMAND_LOCAL_DESTINATIONS[] = "local_destinations"; - const char HTTP_COMMAND_LOCAL_DESTINATION[] = "local_destination"; const char HTTP_PARAM_BASE32_ADDRESS[] = "b32"; - const char HTTP_COMMAND_SAM_SESSIONS[] = "sam_sessions"; - const char HTTP_COMMAND_SAM_SESSION[] = "sam_session"; const char HTTP_PARAM_SAM_SESSION_ID[] = "id"; - const char HTTP_COMMAND_I2P_TUNNELS[] = "i2p_tunnels"; - const char HTTP_COMMAND_JUMPSERVICES[] = "jumpservices="; const char HTTP_PARAM_ADDRESS[] = "address"; void HTTPConnection::Terminate () @@ -282,52 +299,53 @@ namespace http { { std::stringstream s; // Html5 head start - s << "\r\n"; // TODO: Add support for locale. - s << "\r\n\r\n"; // TODO: Find something to parse html/template system. This is horrible. - s << "\r\n"; - s << "Purple I2P " << VERSION " Webconsole\r\n"; - s << "\r\n\r\n\r\n"; - s << "
i2pd webconsole
"; - s << "
"; - s << "
\r\n"; - s << "Main page
\r\n
\r\n"; - s << "Local destinations
\r\n"; - s << "Tunnels
\r\n"; - s << "Transit tunnels
\r\n"; - s << "Transports
\r\n
\r\n"; - s << "I2P tunnels
\r\n"; + s << + "\r\n" + "\r\n" /* TODO: Add support for locale */ + " \r\n" + " \r\n" /* TODO: Find something to parse html/template system. This is horrible. */ + " \r\n" + " Purple I2P " VERSION " Webconsole\r\n" + << cssStyles << + "\r\n"; + s << + "\r\n" + "
i2pd webconsole
\r\n" + "
\r\n" + "
\r\n" + " Main page
\r\n
\r\n" + " Local destinations
\r\n" + " Tunnels
\r\n" + " Transit tunnels
\r\n" + " Transports
\r\n" + " I2P tunnels
\r\n" + " Jump services
\r\n" + ; if (i2p::client::context.GetSAMBridge ()) - s << "SAM sessions
\r\n
\r\n"; + s << " SAM sessions
\r\n"; + /* commands */ + s << "
\r\n"; + s << " Run peer test
\r\n"; if (i2p::context.AcceptsTunnels ()) - s << "Stop accepting tunnels
\r\n
\r\n"; + s << " Stop accepting tunnels
\r\n"; else - s << "Start accepting tunnels
\r\n
\r\n"; - s << "Run peer test
\r\n
\r\n"; - s << "Jump services
\r\n
\r\n"; - s << "
"; - if (request.uri.find("cmd=") != std::string::npos) + s << " Start accepting tunnels
\r\n"; + s << "
\r\n"; + s << "
"; + if (request.uri.find("page=") != std::string::npos) + HandlePage (s, request.uri); + else if (request.uri.find("cmd=") != std::string::npos) HandleCommand (s, request.uri); else - FillContent (s); - s << "
\r\n\r\n"; + ShowStatus (s); + s << + "
\r\n" + "\r\n" + "\r\n"; SendReply (s.str ()); } - void HTTPConnection::FillContent (std::stringstream& s) + void HTTPConnection::ShowStatus (std::stringstream& s) { s << "Uptime: " << boost::posix_time::to_simple_string ( boost::posix_time::time_duration (boost::posix_time::seconds ( @@ -396,40 +414,56 @@ namespace http { s << "Transit Tunnels: " << std::to_string(transitTunnelCount) << "
\r\n"; } - void HTTPConnection::HandleCommand (std::stringstream& s, const std::string & uri) - { + void HTTPConnection::HandlePage (std::stringstream& s, const std::string & uri) + { std::map params; - std::string cmd(""); + std::string page(""); URL url; url.parse(uri); url.parse_query(params); - cmd = params["cmd"]; + page = params["page"]; - if (cmd == HTTP_COMMAND_TRANSPORTS) + if (page == HTTP_PAGE_TRANSPORTS) ShowTransports (s); - else if (cmd == HTTP_COMMAND_TUNNELS) + else if (page == HTTP_PAGE_TUNNELS) ShowTunnels (s); - else if (cmd == HTTP_COMMAND_JUMPSERVICES) + else if (page == HTTP_PAGE_JUMPSERVICES) ShowJumpServices (s, params["address"]); - else if (cmd == HTTP_COMMAND_TRANSIT_TUNNELS) + else if (page == HTTP_PAGE_TRANSIT_TUNNELS) ShowTransitTunnels (s); - else if (cmd == HTTP_COMMAND_START_ACCEPTING_TUNNELS) - StartAcceptingTunnels (s); - else if (cmd == HTTP_COMMAND_STOP_ACCEPTING_TUNNELS) - StopAcceptingTunnels (s); - else if (cmd == HTTP_COMMAND_RUN_PEER_TEST) - RunPeerTest (s); - else if (cmd == HTTP_COMMAND_LOCAL_DESTINATIONS) + else if (page == HTTP_PAGE_LOCAL_DESTINATIONS) ShowLocalDestinations (s); - else if (cmd == HTTP_COMMAND_LOCAL_DESTINATION) + else if (page == HTTP_PAGE_LOCAL_DESTINATION) ShowLocalDestination (s, params["b32"]); - else if (cmd == HTTP_COMMAND_SAM_SESSIONS) + else if (page == HTTP_PAGE_SAM_SESSIONS) ShowSAMSessions (s); - else if (cmd == HTTP_COMMAND_SAM_SESSION) + else if (page == HTTP_PAGE_SAM_SESSION) ShowSAMSession (s, params["sam_id"]); - else if (cmd == HTTP_COMMAND_I2P_TUNNELS) + else if (page == HTTP_PAGE_I2P_TUNNELS) ShowI2PTunnels (s); + else + SendError("Unknown page: " + page); + } + + void HTTPConnection::HandleCommand (std::stringstream& s, const std::string & uri) + { + std::map params; + std::string cmd(""); + URL url; + + url.parse(uri); + url.parse_query(params); + cmd = params["cmd"]; + + if (cmd == HTTP_COMMAND_START_ACCEPTING_TUNNELS) + StartAcceptingTunnels (s); + else if (cmd == HTTP_COMMAND_STOP_ACCEPTING_TUNNELS) + StopAcceptingTunnels (s); + else if (cmd == HTTP_COMMAND_RUN_PEER_TEST) + RunPeerTest (s); + else + SendError("Unknown command: " + cmd); } void HTTPConnection::ShowJumpServices (std::stringstream& s, const std::string& address) @@ -448,7 +482,7 @@ namespace http { for (auto& it: i2p::client::context.GetDestinations ()) { auto ident = it.second->GetIdentHash ();; - s << ""; + s << ""; s << i2p::client::context.GetAddressBook ().ToAddress(ident) << "
\r\n" << std::endl; } } @@ -548,9 +582,9 @@ namespace http { it->Print (s); auto state = it->GetState (); if (state == i2p::tunnel::eTunnelStateFailed) - s << " " << "Failed"; + s << " " << "Failed"; else if (state == i2p::tunnel::eTunnelStateExpiring) - s << " " << "Exp"; + s << " " << "Expiring"; s << " " << (int)it->GetNumSentBytes () << "
\r\n"; s << std::endl; } @@ -560,9 +594,9 @@ namespace http { it->Print (s); auto state = it->GetState (); if (state == i2p::tunnel::eTunnelStateFailed) - s << " " << "Failed"; + s << " " << "Failed"; else if (state == i2p::tunnel::eTunnelStateExpiring) - s << " " << "Exp"; + s << " " << "Expiring"; s << " " << (int)it->GetNumReceivedBytes () << "
\r\n"; s << std::endl; } @@ -640,7 +674,7 @@ namespace http { { for (auto& it: sam->GetSessions ()) { - s << ""; + s << ""; s << it.first << "
\r\n" << std::endl; } } @@ -656,7 +690,7 @@ namespace http { if (session) { auto& ident = session->localDestination->GetIdentHash(); - s << ""; + s << ""; s << i2p::client::context.GetAddressBook ().ToAddress(ident) << "
\r\n" << std::endl; s << "Streams:
\r\n"; for (auto it: session->ListSockets()) @@ -688,7 +722,7 @@ namespace http { for (auto& it: i2p::client::context.GetClientTunnels ()) { auto& ident = it.second->GetLocalDestination ()->GetIdentHash(); - s << ""; + s << ""; s << it.second->GetName () << " ⇐ "; s << i2p::client::context.GetAddressBook ().ToAddress(ident); s << "
\r\n"<< std::endl; @@ -697,7 +731,7 @@ namespace http { for (auto& it: i2p::client::context.GetServerTunnels ()) { auto& ident = it.second->GetLocalDestination ()->GetIdentHash(); - s << ""; + s << ""; s << it.second->GetName () << " ⇒ "; s << i2p::client::context.GetAddressBook ().ToAddress(ident); s << ":" << it.second->GetLocalPort (); diff --git a/HTTPServer.h b/HTTPServer.h index 89df8fb5..57d6fa59 100644 --- a/HTTPServer.h +++ b/HTTPServer.h @@ -29,21 +29,24 @@ namespace http { void SendError (const std::string& message); void HandleRequest (const HTTPReq & request); - void HandleCommand (std::stringstream& s, const std::string& request); + void HandlePage (std::stringstream& s, const std::string& request); + void HandleCommand (std::stringstream& s, const std::string& request); + /* pages */ void ShowJumpServices (std::stringstream& s, const std::string& address); void ShowTransports (std::stringstream& s); void ShowTunnels (std::stringstream& s); + void ShowStatus (std::stringstream& s); void ShowTransitTunnels (std::stringstream& s); void ShowLocalDestinations (std::stringstream& s); void ShowLocalDestination (std::stringstream& s, const std::string& b32); void ShowSAMSessions (std::stringstream& s); void ShowSAMSession (std::stringstream& s, const std::string& id); void ShowI2PTunnels (std::stringstream& s); + /* commands */ void StartAcceptingTunnels (std::stringstream& s); void StopAcceptingTunnels (std::stringstream& s); void RunPeerTest (std::stringstream& s); - void FillContent (std::stringstream& s); protected: From 9bbff744e991cfa60cb4fa21684b84a06413d712 Mon Sep 17 00:00:00 2001 From: hagen Date: Wed, 27 Apr 2016 00:00:00 +0000 Subject: [PATCH 12/29] * HTTPServer.{cpp,h}: chg HandleRequest() signature --- HTTPServer.cpp | 12 ++++++------ HTTPServer.h | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/HTTPServer.cpp b/HTTPServer.cpp index 5673e468..80022897 100644 --- a/HTTPServer.cpp +++ b/HTTPServer.cpp @@ -271,7 +271,7 @@ namespace http { } if (ret == 0) return; /* need more data */ - HandleRequest (request); + HandleRequest (request.uri); } void HTTPConnection::HandleWriteReply (const boost::system::error_code& ecode) @@ -295,7 +295,7 @@ namespace http { AsyncStreamReceive (); } - void HTTPConnection::HandleRequest (const HTTPReq &request) + void HTTPConnection::HandleRequest (const std::string &uri) { std::stringstream s; // Html5 head start @@ -332,10 +332,10 @@ namespace http { s << " Start accepting tunnels
\r\n"; s << "\r\n"; s << "
"; - if (request.uri.find("page=") != std::string::npos) - HandlePage (s, request.uri); - else if (request.uri.find("cmd=") != std::string::npos) - HandleCommand (s, request.uri); + if (uri.find("page=") != std::string::npos) + HandlePage (s, uri); + else if (uri.find("cmd=") != std::string::npos) + HandleCommand (s, uri); else ShowStatus (s); s << diff --git a/HTTPServer.h b/HTTPServer.h index 57d6fa59..28962dde 100644 --- a/HTTPServer.h +++ b/HTTPServer.h @@ -28,7 +28,7 @@ namespace http { void SendReply (const std::string& content, int code = 200); void SendError (const std::string& message); - void HandleRequest (const HTTPReq & request); + void HandleRequest (const std::string& uri); void HandlePage (std::stringstream& s, const std::string& request); void HandleCommand (std::stringstream& s, const std::string& request); From 48b3959cfb9b71d5765c70439ab7a7b94a93dae6 Mon Sep 17 00:00:00 2001 From: hagen Date: Wed, 27 Apr 2016 00:00:00 +0000 Subject: [PATCH 13/29] * HTTPServer.{cpp,h}: cleanup --- HTTPServer.cpp | 18 ++++++++---------- HTTPServer.h | 4 ---- 2 files changed, 8 insertions(+), 14 deletions(-) diff --git a/HTTPServer.cpp b/HTTPServer.cpp index 80022897..accca463 100644 --- a/HTTPServer.cpp +++ b/HTTPServer.cpp @@ -836,11 +836,10 @@ namespace http { { m_Acceptor.close(); m_Service.stop (); - if (m_Thread) - { - m_Thread->join (); - m_Thread = nullptr; - } + if (m_Thread) { + m_Thread->join (); + m_Thread = nullptr; + } } void HTTPServer::Run () @@ -858,11 +857,10 @@ namespace http { void HTTPServer::HandleAccept(const boost::system::error_code& ecode, std::shared_ptr newSocket) { - if (!ecode) - { - CreateConnection(newSocket); - Accept (); - } + if (ecode) + return; + CreateConnection(newSocket); + Accept (); } void HTTPServer::CreateConnection(std::shared_ptr newSocket) diff --git a/HTTPServer.h b/HTTPServer.h index 28962dde..a6ef52cc 100644 --- a/HTTPServer.h +++ b/HTTPServer.h @@ -6,7 +6,6 @@ namespace http { extern const char *itoopieImage; extern const char *itoopieFavicon; 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 { @@ -59,9 +58,6 @@ namespace http { protected: virtual void RunRequest (); - - public: - }; class HTTPServer From 4fa4ba6301d4aadd19b5155218a9efc48832b745 Mon Sep 17 00:00:00 2001 From: hagen Date: Wed, 27 Apr 2016 00:00:00 +0000 Subject: [PATCH 14/29] * HTTPServer.cpp: move known jump services to std::map --- HTTPServer.cpp | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/HTTPServer.cpp b/HTTPServer.cpp index accca463..73c9c791 100644 --- a/HTTPServer.cpp +++ b/HTTPServer.cpp @@ -226,7 +226,12 @@ namespace http { const char HTTP_PARAM_BASE32_ADDRESS[] = "b32"; const char HTTP_PARAM_SAM_SESSION_ID[] = "id"; const char HTTP_PARAM_ADDRESS[] = "address"; - + + std::map jumpservices = { + { "inr.i2p", "http://joajgazyztfssty4w2on5oaqksz6tqoxbduy553y34mf4byv6gpq.b32.i2p/search/?q=" }, + { "stats.i2p", "http://7tbay5p4kzeekxvyvbf6v7eauazemsnnl2aoyqhg5jzpr5eke7tq.b32.i2p/cgi-bin/jump.cgi?a=" }, + }; + void HTTPConnection::Terminate () { if (!m_Stream) return; @@ -468,12 +473,16 @@ namespace http { void HTTPConnection::ShowJumpServices (std::stringstream& s, const std::string& address) { - s << "
"; - s << ""; - s << "

\r\n"; - s << "Jump services for " << address << ""; - s << ""; + s << "
"; + s << ""; + s << ""; + s << ""; + s << "

\r\n"; + s << "Jump services for " << address << "\r\n\r\n"; } void HTTPConnection::ShowLocalDestinations (std::stringstream& s) From 2a1fe99a2981dbfe6966d60379155346b1c723c2 Mon Sep 17 00:00:00 2001 From: hagen Date: Wed, 27 Apr 2016 00:00:00 +0000 Subject: [PATCH 15/29] * HTTPServer.{cpp,h}: drop rest of streaming support --- HTTPServer.cpp | 52 +++----------------------------------------------- HTTPServer.h | 9 +++------ 2 files changed, 6 insertions(+), 55 deletions(-) diff --git a/HTTPServer.cpp b/HTTPServer.cpp index 73c9c791..5f195792 100644 --- a/HTTPServer.cpp +++ b/HTTPServer.cpp @@ -17,8 +17,6 @@ #include "NetDb.h" #include "HTTP.h" #include "LeaseSet.h" -#include "I2PEndian.h" -#include "Streaming.h" #include "Destination.h" #include "RouterContext.h" #include "ClientContext.h" @@ -234,9 +232,6 @@ namespace http { void HTTPConnection::Terminate () { - if (!m_Stream) return; - m_Stream->Close (); - m_Stream = nullptr; m_Socket->close (); } @@ -251,14 +246,9 @@ namespace http { { if (!ecode) { - if (!m_Stream) // new request - { - m_Buffer[bytes_transferred] = '\0'; - m_BufferLen = bytes_transferred; - RunRequest(); - } - else // follow-on - m_Stream->Send ((uint8_t *)m_Buffer, bytes_transferred); + m_Buffer[bytes_transferred] = '\0'; + m_BufferLen = bytes_transferred; + RunRequest(); Receive (); } else if (ecode != boost::asio::error::operation_aborted) @@ -289,17 +279,6 @@ namespace http { } } - void HTTPConnection::HandleWrite (const boost::system::error_code& ecode) - { - if (ecode || (m_Stream && !m_Stream->IsOpen ())) - { - if (ecode != boost::asio::error::operation_aborted) - Terminate (); - } - else // data keeps coming - AsyncStreamReceive (); - } - void HTTPConnection::HandleRequest (const std::string &uri) { std::stringstream s; @@ -769,31 +748,6 @@ namespace http { s << "Peer test is running" << std::endl; } - void HTTPConnection::AsyncStreamReceive () - { - if (m_Stream) - m_Stream->AsyncReceive (boost::asio::buffer (m_StreamBuffer, 8192), - std::bind (&HTTPConnection::HandleStreamReceive, shared_from_this (), - std::placeholders::_1, std::placeholders::_2), - 45); // 45 seconds timeout - } - - void HTTPConnection::HandleStreamReceive (const boost::system::error_code& ecode, std::size_t bytes_transferred) - { - if (!ecode) - { - boost::asio::async_write (*m_Socket, boost::asio::buffer (m_StreamBuffer, bytes_transferred), - std::bind (&HTTPConnection::HandleWrite, shared_from_this (), std::placeholders::_1)); - } - else - { - if (ecode == boost::asio::error::timed_out) - SendError ("Host not responding"); - else if (ecode != boost::asio::error::operation_aborted) - Terminate (); - } - } - void HTTPConnection::SendReply (const std::string& content, int code) { std::time_t time_now = std::time(nullptr); diff --git a/HTTPServer.h b/HTTPServer.h index a6ef52cc..cafa9b46 100644 --- a/HTTPServer.h +++ b/HTTPServer.h @@ -13,17 +13,15 @@ namespace http { HTTPConnection (std::shared_ptr socket): m_Socket (socket), m_Timer (socket->get_io_service ()), - m_Stream (nullptr), m_BufferLen (0) {}; + m_BufferLen (0) {}; void Receive (); private: void Terminate (); void HandleReceive (const boost::system::error_code& ecode, std::size_t bytes_transferred); - void AsyncStreamReceive (); - void HandleStreamReceive (const boost::system::error_code& ecode, std::size_t bytes_transferred); void HandleWriteReply(const boost::system::error_code& ecode); - void HandleWrite (const boost::system::error_code& ecode); + void SendReply (const std::string& content, int code = 200); void SendError (const std::string& message); @@ -51,8 +49,7 @@ namespace http { std::shared_ptr m_Socket; boost::asio::deadline_timer m_Timer; - std::shared_ptr m_Stream; - char m_Buffer[HTTP_CONNECTION_BUFFER_SIZE + 1], m_StreamBuffer[HTTP_CONNECTION_BUFFER_SIZE + 1]; + char m_Buffer[HTTP_CONNECTION_BUFFER_SIZE + 1]; size_t m_BufferLen; protected: From fd928e8d12167c87ff63f540d7a2d0c9ff9cd78f Mon Sep 17 00:00:00 2001 From: hagen Date: Wed, 27 Apr 2016 00:00:00 +0000 Subject: [PATCH 16/29] * HTTPServer.h: not virtual: not inherited anywhere --- HTTPServer.h | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/HTTPServer.h b/HTTPServer.h index cafa9b46..18c6bed8 100644 --- a/HTTPServer.h +++ b/HTTPServer.h @@ -25,6 +25,7 @@ namespace http { void SendReply (const std::string& content, int code = 200); void SendError (const std::string& message); + void RunRequest (); void HandleRequest (const std::string& uri); void HandlePage (std::stringstream& s, const std::string& request); void HandleCommand (std::stringstream& s, const std::string& request); @@ -45,16 +46,12 @@ namespace http { void StopAcceptingTunnels (std::stringstream& s); void RunPeerTest (std::stringstream& s); - protected: + private: std::shared_ptr m_Socket; boost::asio::deadline_timer m_Timer; char m_Buffer[HTTP_CONNECTION_BUFFER_SIZE + 1]; size_t m_BufferLen; - - protected: - - virtual void RunRequest (); }; class HTTPServer @@ -62,7 +59,7 @@ namespace http { public: HTTPServer (const std::string& address, int port); - virtual ~HTTPServer (); + ~HTTPServer (); void Start (); void Stop (); @@ -73,6 +70,7 @@ namespace http { void Accept (); void HandleAccept(const boost::system::error_code& ecode, std::shared_ptr newSocket); + void CreateConnection(std::shared_ptr newSocket); private: @@ -80,9 +78,6 @@ namespace http { boost::asio::io_service m_Service; boost::asio::io_service::work m_Work; boost::asio::ip::tcp::acceptor m_Acceptor; - - protected: - virtual void CreateConnection(std::shared_ptr newSocket); }; } // http } // i2p From 0c8fdfca7d9670a692891cebb25ef8848411a794 Mon Sep 17 00:00:00 2001 From: hagen Date: Wed, 27 Apr 2016 00:00:00 +0000 Subject: [PATCH 17/29] * HTTPServer.{cpp,h}: merge HandleWriteReply & Terminate : the same purpose --- HTTPServer.cpp | 36 +++++++++++++++--------------------- HTTPServer.h | 3 +-- 2 files changed, 16 insertions(+), 23 deletions(-) diff --git a/HTTPServer.cpp b/HTTPServer.cpp index 5f195792..c7b91fd0 100644 --- a/HTTPServer.cpp +++ b/HTTPServer.cpp @@ -230,11 +230,6 @@ namespace http { { "stats.i2p", "http://7tbay5p4kzeekxvyvbf6v7eauazemsnnl2aoyqhg5jzpr5eke7tq.b32.i2p/cgi-bin/jump.cgi?a=" }, }; - void HTTPConnection::Terminate () - { - m_Socket->close (); - } - void HTTPConnection::Receive () { m_Socket->async_read_some (boost::asio::buffer (m_Buffer, HTTP_CONNECTION_BUFFER_SIZE), @@ -244,15 +239,15 @@ namespace http { void HTTPConnection::HandleReceive (const boost::system::error_code& ecode, std::size_t bytes_transferred) { - if (!ecode) - { - m_Buffer[bytes_transferred] = '\0'; - m_BufferLen = bytes_transferred; - RunRequest(); - Receive (); + if (ecode) { + if (ecode != boost::asio::error::operation_aborted) + Terminate (ecode); + return; } - else if (ecode != boost::asio::error::operation_aborted) - Terminate (); + m_Buffer[bytes_transferred] = '\0'; + m_BufferLen = bytes_transferred; + RunRequest(); + Receive (); } void HTTPConnection::RunRequest () @@ -269,14 +264,13 @@ namespace http { HandleRequest (request.uri); } - void HTTPConnection::HandleWriteReply (const boost::system::error_code& ecode) + void HTTPConnection::Terminate (const boost::system::error_code& ecode) { - if (ecode != boost::asio::error::operation_aborted) - { - boost::system::error_code ignored_ec; - m_Socket->shutdown(boost::asio::ip::tcp::socket::shutdown_both, ignored_ec); - Terminate (); - } + if (ecode == boost::asio::error::operation_aborted) + return; + boost::system::error_code ignored_ec; + m_Socket->shutdown(boost::asio::ip::tcp::socket::shutdown_both, ignored_ec); + m_Socket->close (); } void HTTPConnection::HandleRequest (const std::string &uri) @@ -767,7 +761,7 @@ namespace http { buffers.push_back(boost::asio::buffer(content)); boost::asio::async_write (*m_Socket, buffers, - std::bind (&HTTPConnection::HandleWriteReply, shared_from_this (), std::placeholders::_1)); + std::bind (&HTTPConnection::Terminate, shared_from_this (), std::placeholders::_1)); } void HTTPConnection::SendError(const std::string& content) diff --git a/HTTPServer.h b/HTTPServer.h index 18c6bed8..f3070502 100644 --- a/HTTPServer.h +++ b/HTTPServer.h @@ -18,9 +18,8 @@ namespace http { 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 Terminate (const boost::system::error_code& ecode); void SendReply (const std::string& content, int code = 200); void SendError (const std::string& message); From 4d98a64000bf3ccce04f5165a59c3deb3f29beac Mon Sep 17 00:00:00 2001 From: hagen Date: Wed, 27 Apr 2016 00:00:00 +0000 Subject: [PATCH 18/29] * HTTPServer.{cpp,h}: extract html-rendering methods from class --- HTTPServer.cpp | 316 ++++++++++++++++++++++++------------------------- HTTPServer.h | 16 --- 2 files changed, 158 insertions(+), 174 deletions(-) diff --git a/HTTPServer.cpp b/HTTPServer.cpp index c7b91fd0..98080808 100644 --- a/HTTPServer.cpp +++ b/HTTPServer.cpp @@ -230,100 +230,7 @@ namespace http { { "stats.i2p", "http://7tbay5p4kzeekxvyvbf6v7eauazemsnnl2aoyqhg5jzpr5eke7tq.b32.i2p/cgi-bin/jump.cgi?a=" }, }; - void HTTPConnection::Receive () - { - m_Socket->async_read_some (boost::asio::buffer (m_Buffer, HTTP_CONNECTION_BUFFER_SIZE), - std::bind(&HTTPConnection::HandleReceive, shared_from_this (), - std::placeholders::_1, std::placeholders::_2)); - } - - void HTTPConnection::HandleReceive (const boost::system::error_code& ecode, std::size_t bytes_transferred) - { - if (ecode) { - if (ecode != boost::asio::error::operation_aborted) - Terminate (ecode); - return; - } - m_Buffer[bytes_transferred] = '\0'; - m_BufferLen = bytes_transferred; - RunRequest(); - Receive (); - } - - void HTTPConnection::RunRequest () - { - HTTPReq request; - int ret = request.parse(m_Buffer); - if (ret < 0) { - m_Buffer[0] = '\0'; - m_BufferLen = 0; - return; /* error */ - } - if (ret == 0) - return; /* need more data */ - HandleRequest (request.uri); - } - - void HTTPConnection::Terminate (const boost::system::error_code& ecode) - { - if (ecode == boost::asio::error::operation_aborted) - return; - boost::system::error_code ignored_ec; - m_Socket->shutdown(boost::asio::ip::tcp::socket::shutdown_both, ignored_ec); - m_Socket->close (); - } - - void HTTPConnection::HandleRequest (const std::string &uri) - { - std::stringstream s; - // Html5 head start - s << - "\r\n" - "\r\n" /* TODO: Add support for locale */ - " \r\n" - " \r\n" /* TODO: Find something to parse html/template system. This is horrible. */ - " \r\n" - " Purple I2P " VERSION " Webconsole\r\n" - << cssStyles << - "\r\n"; - s << - "\r\n" - "
i2pd webconsole
\r\n" - "
\r\n" - "
\r\n" - " Main page
\r\n
\r\n" - " Local destinations
\r\n" - " Tunnels
\r\n" - " Transit tunnels
\r\n" - " Transports
\r\n" - " I2P tunnels
\r\n" - " Jump services
\r\n" - ; - if (i2p::client::context.GetSAMBridge ()) - s << " SAM sessions
\r\n"; - /* commands */ - s << "
\r\n"; - s << " Run peer test
\r\n"; - if (i2p::context.AcceptsTunnels ()) - s << " Stop accepting tunnels
\r\n"; - else - s << " Start accepting tunnels
\r\n"; - s << "
\r\n"; - s << "
"; - if (uri.find("page=") != std::string::npos) - HandlePage (s, uri); - else if (uri.find("cmd=") != std::string::npos) - HandleCommand (s, uri); - else - ShowStatus (s); - s << - "
\r\n" - "\r\n" - "\r\n"; - SendReply (s.str ()); - } - - void HTTPConnection::ShowStatus (std::stringstream& s) + void ShowStatus (std::stringstream& s) { s << "Uptime: " << boost::posix_time::to_simple_string ( boost::posix_time::time_duration (boost::posix_time::seconds ( @@ -392,59 +299,7 @@ namespace http { s << "Transit Tunnels: " << std::to_string(transitTunnelCount) << "
\r\n"; } - void HTTPConnection::HandlePage (std::stringstream& s, const std::string & uri) - { - std::map params; - std::string page(""); - URL url; - - url.parse(uri); - url.parse_query(params); - page = params["page"]; - - if (page == HTTP_PAGE_TRANSPORTS) - ShowTransports (s); - else if (page == HTTP_PAGE_TUNNELS) - ShowTunnels (s); - else if (page == HTTP_PAGE_JUMPSERVICES) - ShowJumpServices (s, params["address"]); - else if (page == HTTP_PAGE_TRANSIT_TUNNELS) - ShowTransitTunnels (s); - else if (page == HTTP_PAGE_LOCAL_DESTINATIONS) - ShowLocalDestinations (s); - else if (page == HTTP_PAGE_LOCAL_DESTINATION) - ShowLocalDestination (s, params["b32"]); - else if (page == HTTP_PAGE_SAM_SESSIONS) - ShowSAMSessions (s); - else if (page == HTTP_PAGE_SAM_SESSION) - ShowSAMSession (s, params["sam_id"]); - else if (page == HTTP_PAGE_I2P_TUNNELS) - ShowI2PTunnels (s); - else - SendError("Unknown page: " + page); - } - - void HTTPConnection::HandleCommand (std::stringstream& s, const std::string & uri) - { - std::map params; - std::string cmd(""); - URL url; - - url.parse(uri); - url.parse_query(params); - cmd = params["cmd"]; - - if (cmd == HTTP_COMMAND_START_ACCEPTING_TUNNELS) - StartAcceptingTunnels (s); - else if (cmd == HTTP_COMMAND_STOP_ACCEPTING_TUNNELS) - StopAcceptingTunnels (s); - else if (cmd == HTTP_COMMAND_RUN_PEER_TEST) - RunPeerTest (s); - else - SendError("Unknown command: " + cmd); - } - - void HTTPConnection::ShowJumpServices (std::stringstream& s, const std::string& address) + void ShowJumpServices (std::stringstream& s, const std::string& address) { s << "
"; s << ""; @@ -458,7 +313,7 @@ namespace http { s << "\r\n"; } - void HTTPConnection::ShowLocalDestinations (std::stringstream& s) + void ShowLocalDestinations (std::stringstream& s) { s << "Local Destinations:
\r\n
\r\n"; for (auto& it: i2p::client::context.GetDestinations ()) @@ -469,7 +324,7 @@ namespace http { } } - void HTTPConnection::ShowLocalDestination (std::stringstream& s, const std::string& b32) + void ShowLocalDestination (std::stringstream& s, const std::string& b32) { s << "Local Destination:
\r\n
\r\n"; i2p::data::IdentHash ident; @@ -555,7 +410,7 @@ namespace http { } } - void HTTPConnection::ShowTunnels (std::stringstream& s) + void ShowTunnels (std::stringstream& s) { s << "Tunnels:
\r\n
\r\n"; s << "Queue size: " << i2p::tunnel::tunnels.GetQueueSize () << "
\r\n"; @@ -584,7 +439,7 @@ namespace http { } } - void HTTPConnection::ShowTransitTunnels (std::stringstream& s) + void ShowTransitTunnels (std::stringstream& s) { s << "Transit tunnels:
\r\n
\r\n"; for (auto it: i2p::tunnel::tunnels.GetTransitTunnels ()) @@ -599,7 +454,7 @@ namespace http { } } - void HTTPConnection::ShowTransports (std::stringstream& s) + void ShowTransports (std::stringstream& s) { s << "Transports:
\r\n
\r\n"; auto ntcpServer = i2p::transport::transports.GetNTCPServer (); @@ -648,7 +503,7 @@ namespace http { } } - void HTTPConnection::ShowSAMSessions (std::stringstream& s) + void ShowSAMSessions (std::stringstream& s) { s << "SAM Sessions:
\r\n
\r\n"; auto sam = i2p::client::context.GetSAMBridge (); @@ -662,7 +517,7 @@ namespace http { } } - void HTTPConnection::ShowSAMSession (std::stringstream& s, const std::string& id) + void ShowSAMSession (std::stringstream& s, const std::string& id) { s << "SAM Session:
\r\n
\r\n"; auto sam = i2p::client::context.GetSAMBridge (); @@ -698,7 +553,7 @@ namespace http { } } - void HTTPConnection::ShowI2PTunnels (std::stringstream& s) + void ShowI2PTunnels (std::stringstream& s) { s << "Client Tunnels:
\r\n
\r\n"; for (auto& it: i2p::client::context.GetClientTunnels ()) @@ -721,27 +576,172 @@ namespace http { } } - void HTTPConnection::StopAcceptingTunnels (std::stringstream& s) + void StopAcceptingTunnels (std::stringstream& s) { s << "Stop Accepting Tunnels:
\r\n
\r\n"; i2p::context.SetAcceptsTunnels (false); s << "Accepting tunnels stopped" << std::endl; } - void HTTPConnection::StartAcceptingTunnels (std::stringstream& s) + void StartAcceptingTunnels (std::stringstream& s) { s << "Start Accepting Tunnels:
\r\n
\r\n"; i2p::context.SetAcceptsTunnels (true); s << "Accepting tunnels started" << std::endl; } - void HTTPConnection::RunPeerTest (std::stringstream& s) + void RunPeerTest (std::stringstream& s) { s << "Run Peer Test:
\r\n
\r\n"; i2p::transport::transports.PeerTest (); s << "Peer test is running" << std::endl; } + void HTTPConnection::Receive () + { + m_Socket->async_read_some (boost::asio::buffer (m_Buffer, HTTP_CONNECTION_BUFFER_SIZE), + std::bind(&HTTPConnection::HandleReceive, shared_from_this (), + std::placeholders::_1, std::placeholders::_2)); + } + + void HTTPConnection::HandleReceive (const boost::system::error_code& ecode, std::size_t bytes_transferred) + { + if (ecode) { + if (ecode != boost::asio::error::operation_aborted) + Terminate (ecode); + return; + } + m_Buffer[bytes_transferred] = '\0'; + m_BufferLen = bytes_transferred; + RunRequest(); + Receive (); + } + + void HTTPConnection::RunRequest () + { + HTTPReq request; + int ret = request.parse(m_Buffer); + if (ret < 0) { + m_Buffer[0] = '\0'; + m_BufferLen = 0; + return; /* error */ + } + if (ret == 0) + return; /* need more data */ + HandleRequest (request.uri); + } + + void HTTPConnection::Terminate (const boost::system::error_code& ecode) + { + if (ecode == boost::asio::error::operation_aborted) + return; + boost::system::error_code ignored_ec; + m_Socket->shutdown(boost::asio::ip::tcp::socket::shutdown_both, ignored_ec); + m_Socket->close (); + } + + void HTTPConnection::HandleRequest (const std::string &uri) + { + std::stringstream s; + // Html5 head start + s << + "\r\n" + "\r\n" /* TODO: Add support for locale */ + " \r\n" + " \r\n" /* TODO: Find something to parse html/template system. This is horrible. */ + " \r\n" + " Purple I2P " VERSION " Webconsole\r\n" + << cssStyles << + "\r\n"; + s << + "\r\n" + "
i2pd webconsole
\r\n" + "
\r\n" + "
\r\n" + " Main page
\r\n
\r\n" + " Local destinations
\r\n" + " Tunnels
\r\n" + " Transit tunnels
\r\n" + " Transports
\r\n" + " I2P tunnels
\r\n" + " Jump services
\r\n" + ; + if (i2p::client::context.GetSAMBridge ()) + s << " SAM sessions
\r\n"; + /* commands */ + s << "
\r\n"; + s << " Run peer test
\r\n"; + if (i2p::context.AcceptsTunnels ()) + s << " Stop accepting tunnels
\r\n"; + else + s << " Start accepting tunnels
\r\n"; + s << "
\r\n"; + s << "
"; + if (uri.find("page=") != std::string::npos) + HandlePage (s, uri); + else if (uri.find("cmd=") != std::string::npos) + HandleCommand (s, uri); + else + ShowStatus (s); + s << + "
\r\n" + "\r\n" + "\r\n"; + SendReply (s.str ()); + } + + void HTTPConnection::HandlePage (std::stringstream& s, const std::string & uri) + { + std::map params; + std::string page(""); + URL url; + + url.parse(uri); + url.parse_query(params); + page = params["page"]; + + if (page == HTTP_PAGE_TRANSPORTS) + ShowTransports (s); + else if (page == HTTP_PAGE_TUNNELS) + ShowTunnels (s); + else if (page == HTTP_PAGE_JUMPSERVICES) + ShowJumpServices (s, params["address"]); + else if (page == HTTP_PAGE_TRANSIT_TUNNELS) + ShowTransitTunnels (s); + else if (page == HTTP_PAGE_LOCAL_DESTINATIONS) + ShowLocalDestinations (s); + else if (page == HTTP_PAGE_LOCAL_DESTINATION) + ShowLocalDestination (s, params["b32"]); + else if (page == HTTP_PAGE_SAM_SESSIONS) + ShowSAMSessions (s); + else if (page == HTTP_PAGE_SAM_SESSION) + ShowSAMSession (s, params["sam_id"]); + else if (page == HTTP_PAGE_I2P_TUNNELS) + ShowI2PTunnels (s); + else + SendError("Unknown page: " + page); + } + + void HTTPConnection::HandleCommand (std::stringstream& s, const std::string & uri) + { + std::map params; + std::string cmd(""); + URL url; + + url.parse(uri); + url.parse_query(params); + cmd = params["cmd"]; + + if (cmd == HTTP_COMMAND_START_ACCEPTING_TUNNELS) + StartAcceptingTunnels (s); + else if (cmd == HTTP_COMMAND_STOP_ACCEPTING_TUNNELS) + StopAcceptingTunnels (s); + else if (cmd == HTTP_COMMAND_RUN_PEER_TEST) + RunPeerTest (s); + else + SendError("Unknown command: " + cmd); + } + void HTTPConnection::SendReply (const std::string& content, int code) { std::time_t time_now = std::time(nullptr); diff --git a/HTTPServer.h b/HTTPServer.h index f3070502..06fa4457 100644 --- a/HTTPServer.h +++ b/HTTPServer.h @@ -29,22 +29,6 @@ namespace http { void HandlePage (std::stringstream& s, const std::string& request); void HandleCommand (std::stringstream& s, const std::string& request); - /* pages */ - void ShowJumpServices (std::stringstream& s, const std::string& address); - void ShowTransports (std::stringstream& s); - void ShowTunnels (std::stringstream& s); - void ShowStatus (std::stringstream& s); - void ShowTransitTunnels (std::stringstream& s); - void ShowLocalDestinations (std::stringstream& s); - void ShowLocalDestination (std::stringstream& s, const std::string& b32); - void ShowSAMSessions (std::stringstream& s); - void ShowSAMSession (std::stringstream& s, const std::string& id); - void ShowI2PTunnels (std::stringstream& s); - /* commands */ - void StartAcceptingTunnels (std::stringstream& s); - void StopAcceptingTunnels (std::stringstream& s); - void RunPeerTest (std::stringstream& s); - private: std::shared_ptr m_Socket; From 849308e28d3f0852bf86873399bea809d16719fe Mon Sep 17 00:00:00 2001 From: hagen Date: Wed, 27 Apr 2016 00:00:00 +0000 Subject: [PATCH 19/29] * HTTPServer.cpp: drop boost::date_time dep --- HTTPServer.cpp | 25 +++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/HTTPServer.cpp b/HTTPServer.cpp index 98080808..d5a4622e 100644 --- a/HTTPServer.cpp +++ b/HTTPServer.cpp @@ -6,7 +6,6 @@ #include #include -#include #include "Base.h" #include "FS.h" @@ -230,11 +229,29 @@ namespace http { { "stats.i2p", "http://7tbay5p4kzeekxvyvbf6v7eauazemsnnl2aoyqhg5jzpr5eke7tq.b32.i2p/cgi-bin/jump.cgi?a=" }, }; + void ShowUptime (std::stringstream& s, int seconds) { + int num; + + if ((num = seconds / 86400) > 0) { + s << num << " days, "; + seconds -= num; + } + if ((num = seconds / 3600) > 0) { + s << num << " hours, "; + seconds -= num; + } + if ((num = seconds / 60) > 0) { + s << num << " min, "; + seconds -= num; + } + s << seconds << " seconds"; + } + void ShowStatus (std::stringstream& s) { - s << "Uptime: " << boost::posix_time::to_simple_string ( - boost::posix_time::time_duration (boost::posix_time::seconds ( - i2p::context.GetUptime ()))) << "
\r\n"; + s << "Uptime: "; + ShowUptime(s, i2p::context.GetUptime ()); + s << "
\r\n"; s << "Status: "; switch (i2p::context.GetStatus ()) { From 65395516b0b087d09fc28ae3df9dd012f38160e0 Mon Sep 17 00:00:00 2001 From: hagen Date: Wed, 27 Apr 2016 00:00:00 +0000 Subject: [PATCH 20/29] * HTTPServer.cpp: drop separate function handlers for commands --- HTTPServer.cpp | 36 +++++++++--------------------------- 1 file changed, 9 insertions(+), 27 deletions(-) diff --git a/HTTPServer.cpp b/HTTPServer.cpp index d5a4622e..d3a57b50 100644 --- a/HTTPServer.cpp +++ b/HTTPServer.cpp @@ -593,27 +593,6 @@ namespace http { } } - void StopAcceptingTunnels (std::stringstream& s) - { - s << "Stop Accepting Tunnels:
\r\n
\r\n"; - i2p::context.SetAcceptsTunnels (false); - s << "Accepting tunnels stopped" << std::endl; - } - - void StartAcceptingTunnels (std::stringstream& s) - { - s << "Start Accepting Tunnels:
\r\n
\r\n"; - i2p::context.SetAcceptsTunnels (true); - s << "Accepting tunnels started" << std::endl; - } - - void RunPeerTest (std::stringstream& s) - { - s << "Run Peer Test:
\r\n
\r\n"; - i2p::transport::transports.PeerTest (); - s << "Peer test is running" << std::endl; - } - void HTTPConnection::Receive () { m_Socket->async_read_some (boost::asio::buffer (m_Buffer, HTTP_CONNECTION_BUFFER_SIZE), @@ -749,14 +728,17 @@ namespace http { url.parse_query(params); cmd = params["cmd"]; - if (cmd == HTTP_COMMAND_START_ACCEPTING_TUNNELS) - StartAcceptingTunnels (s); + if (cmd == HTTP_COMMAND_RUN_PEER_TEST) + i2p::transport::transports.PeerTest (); + else if (cmd == HTTP_COMMAND_START_ACCEPTING_TUNNELS) + i2p::context.SetAcceptsTunnels (true); else if (cmd == HTTP_COMMAND_STOP_ACCEPTING_TUNNELS) - StopAcceptingTunnels (s); - else if (cmd == HTTP_COMMAND_RUN_PEER_TEST) - RunPeerTest (s); - else + i2p::context.SetAcceptsTunnels (false); + else { SendError("Unknown command: " + cmd); + return; + } + s << "Command accepted"; } void HTTPConnection::SendReply (const std::string& content, int code) From 23b8df1c36a420f367b12bfa5e897bb163813e2a Mon Sep 17 00:00:00 2001 From: hagen Date: Wed, 27 Apr 2016 00:00:00 +0000 Subject: [PATCH 21/29] * HTTPServer.cpp: move commands to separate page --- HTTPServer.cpp | 28 ++++++++++++++++++---------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/HTTPServer.cpp b/HTTPServer.cpp index d3a57b50..44841a91 100644 --- a/HTTPServer.cpp +++ b/HTTPServer.cpp @@ -217,6 +217,7 @@ namespace http { const char HTTP_PAGE_SAM_SESSION[] = "sam_session"; const char HTTP_PAGE_I2P_TUNNELS[] = "i2p_tunnels"; const char HTTP_PAGE_JUMPSERVICES[] = "jumpservices"; + const char HTTP_PAGE_COMMANDS[] = "commands"; const char HTTP_COMMAND_START_ACCEPTING_TUNNELS[] = "start_accepting_tunnels"; const char HTTP_COMMAND_STOP_ACCEPTING_TUNNELS[] = "stop_accepting_tunnels"; const char HTTP_COMMAND_RUN_PEER_TEST[] = "run_peer_test"; @@ -452,10 +453,20 @@ namespace http { else if (state == i2p::tunnel::eTunnelStateExpiring) s << " " << "Expiring"; s << " " << (int)it->GetNumReceivedBytes () << "
\r\n"; - s << std::endl; } } + void ShowCommands (std::stringstream& s) + { + /* commands */ + s << "Router Commands
\r\n"; + s << " Run peer test
\r\n"; + if (i2p::context.AcceptsTunnels ()) + s << " Stop accepting tunnels
\r\n"; + else + s << " Start accepting tunnels
\r\n"; + } + void ShowTransitTunnels (std::stringstream& s) { s << "Transit tunnels:
\r\n
\r\n"; @@ -655,22 +666,16 @@ namespace http { "
\r\n" "
\r\n" " Main page
\r\n
\r\n" + " Router commands
\r\n" " Local destinations
\r\n" " Tunnels
\r\n" " Transit tunnels
\r\n" " Transports
\r\n" " I2P tunnels
\r\n" - " Jump services
\r\n" + " Jump services
\r\n" ; if (i2p::client::context.GetSAMBridge ()) s << " SAM sessions
\r\n"; - /* commands */ - s << "
\r\n"; - s << " Run peer test
\r\n"; - if (i2p::context.AcceptsTunnels ()) - s << " Stop accepting tunnels
\r\n"; - else - s << " Start accepting tunnels
\r\n"; s << "
\r\n"; s << "
"; if (uri.find("page=") != std::string::npos) @@ -700,6 +705,8 @@ namespace http { ShowTransports (s); else if (page == HTTP_PAGE_TUNNELS) ShowTunnels (s); + else if (page == HTTP_PAGE_COMMANDS) + ShowCommands (s); else if (page == HTTP_PAGE_JUMPSERVICES) ShowJumpServices (s, params["address"]); else if (page == HTTP_PAGE_TRANSIT_TUNNELS) @@ -738,7 +745,8 @@ namespace http { SendError("Unknown command: " + cmd); return; } - s << "Command accepted"; + s << "Command accepted

\r\n"; + s << "Back to commands list"; } void HTTPConnection::SendReply (const std::string& content, int code) From 54078087e5713da4b692563b55a1b3420462a0cd Mon Sep 17 00:00:00 2001 From: hagen Date: Wed, 27 Apr 2016 00:00:00 +0000 Subject: [PATCH 22/29] * HTTPServer.cpp: move common code to function --- HTTPServer.cpp | 78 ++++++++++++++++++++++++-------------------------- 1 file changed, 38 insertions(+), 40 deletions(-) diff --git a/HTTPServer.cpp b/HTTPServer.cpp index 44841a91..142c392b 100644 --- a/HTTPServer.cpp +++ b/HTTPServer.cpp @@ -248,6 +248,23 @@ namespace http { s << seconds << " seconds"; } + void ShowTunnelDetails (std::stringstream& s, enum i2p::tunnel::TunnelState eState, int bytes) + { + std::string state; + switch (eState) { + case i2p::tunnel::eTunnelStateBuildReplyReceived : + case i2p::tunnel::eTunnelStatePending : state = "building"; break; + case i2p::tunnel::eTunnelStateBuildFailed : + case i2p::tunnel::eTunnelStateTestFailed : + case i2p::tunnel::eTunnelStateFailed : state = "failed"; break; + case i2p::tunnel::eTunnelStateExpiring : state = "expiring"; break; + case i2p::tunnel::eTunnelStateEstablished : state = "established"; break; + default: state = "unknown"; break; + } + s << " " << state << ", "; + s << " " << (int) (bytes / 1024) << " KiB
\r\n"; + } + void ShowStatus (std::stringstream& s) { s << "Uptime: "; @@ -356,28 +373,19 @@ namespace http { auto pool = dest->GetTunnelPool (); if (pool) { - s << "Tunnels:
\r\n"; - for (auto it: pool->GetOutboundTunnels ()) - { - it->Print (s); - auto state = it->GetState (); - if (state == i2p::tunnel::eTunnelStateFailed) - s << " " << "Failed"; - else if (state == i2p::tunnel::eTunnelStateExpiring) - s << " " << "Exp"; - s << "
\r\n" << std::endl; + s << "Inbound tunnels:
\r\n"; + for (auto & it : pool->GetInboundTunnels ()) { + it->Print(s); + ShowTunnelDetails(s, it->GetState (), it->GetNumReceivedBytes ()); } - for (auto it: pool->GetInboundTunnels ()) - { - it->Print (s); - auto state = it->GetState (); - if (state == i2p::tunnel::eTunnelStateFailed) - s << " " << "Failed"; - else if (state == i2p::tunnel::eTunnelStateExpiring) - s << " " << "Exp"; - s << "
\r\n" << std::endl; + s << "
\r\n"; + s << "Outbound tunnels:
\r\n"; + for (auto & it : pool->GetOutboundTunnels ()) { + it->Print(s); + ShowTunnelDetails(s, it->GetState (), it->GetNumSentBytes ()); } } + s << "
\r\n"; s << "Tags
Incoming: " << dest->GetNumIncomingTags () << "
Outgoing:
" << std::endl; for (auto it: dest->GetSessions ()) { @@ -430,30 +438,20 @@ namespace http { void ShowTunnels (std::stringstream& s) { - s << "Tunnels:
\r\n
\r\n"; s << "Queue size: " << i2p::tunnel::tunnels.GetQueueSize () << "
\r\n"; - for (auto it: i2p::tunnel::tunnels.GetOutboundTunnels ()) - { - it->Print (s); - auto state = it->GetState (); - if (state == i2p::tunnel::eTunnelStateFailed) - s << " " << "Failed"; - else if (state == i2p::tunnel::eTunnelStateExpiring) - s << " " << "Expiring"; - s << " " << (int)it->GetNumSentBytes () << "
\r\n"; - s << std::endl; - } - for (auto it: i2p::tunnel::tunnels.GetInboundTunnels ()) - { - it->Print (s); - auto state = it->GetState (); - if (state == i2p::tunnel::eTunnelStateFailed) - s << " " << "Failed"; - else if (state == i2p::tunnel::eTunnelStateExpiring) - s << " " << "Expiring"; - s << " " << (int)it->GetNumReceivedBytes () << "
\r\n"; + s << "Inbound tunnels:
\r\n"; + for (auto & it : i2p::tunnel::tunnels.GetInboundTunnels ()) { + it->Print(s); + ShowTunnelDetails(s, it->GetState (), it->GetNumReceivedBytes ()); } + s << "
\r\n"; + s << "Outbound tunnels:
\r\n"; + for (auto & it : i2p::tunnel::tunnels.GetOutboundTunnels ()) { + it->Print(s); + ShowTunnelDetails(s, it->GetState (), it->GetNumSentBytes ()); + } + s << "
\r\n"; } void ShowCommands (std::stringstream& s) From 1f404bb62291542b7923bb3656b7e23c8e4d0bb0 Mon Sep 17 00:00:00 2001 From: hagen Date: Wed, 27 Apr 2016 00:00:00 +0000 Subject: [PATCH 23/29] * HTTPServer.cpp: move html parts outside HTTPConnection class --- HTTPServer.cpp | 70 ++++++++++++++++++++++++++++---------------------- 1 file changed, 39 insertions(+), 31 deletions(-) diff --git a/HTTPServer.cpp b/HTTPServer.cpp index 142c392b..864c9fd3 100644 --- a/HTTPServer.cpp +++ b/HTTPServer.cpp @@ -265,6 +265,43 @@ namespace http { s << " " << (int) (bytes / 1024) << " KiB
\r\n"; } + void ShowPageHead (std::stringstream& s) + { + s << + "\r\n" + "\r\n" /* TODO: Add support for locale */ + " \r\n" + " \r\n" /* TODO: Find something to parse html/template system. This is horrible. */ + " \r\n" + " Purple I2P " VERSION " Webconsole\r\n" + << cssStyles << + "\r\n"; + s << + "\r\n" + "
i2pd webconsole
\r\n" + "
\r\n" + "
\r\n" + " Main page
\r\n
\r\n" + " Router commands
\r\n" + " Local destinations
\r\n" + " Tunnels
\r\n" + " Transit tunnels
\r\n" + " Transports
\r\n" + " I2P tunnels
\r\n" + " Jump services
\r\n" + " SAM sessions
\r\n" + "
\r\n" + "
"; + } + + void ShowPageTail (std::stringstream& s) + { + s << + "
\r\n" + "\r\n" + "\r\n"; + } + void ShowStatus (std::stringstream& s) { s << "Uptime: "; @@ -649,43 +686,14 @@ namespace http { { std::stringstream s; // Html5 head start - s << - "\r\n" - "\r\n" /* TODO: Add support for locale */ - " \r\n" - " \r\n" /* TODO: Find something to parse html/template system. This is horrible. */ - " \r\n" - " Purple I2P " VERSION " Webconsole\r\n" - << cssStyles << - "\r\n"; - s << - "\r\n" - "
i2pd webconsole
\r\n" - "
\r\n" - "
\r\n" - " Main page
\r\n
\r\n" - " Router commands
\r\n" - " Local destinations
\r\n" - " Tunnels
\r\n" - " Transit tunnels
\r\n" - " Transports
\r\n" - " I2P tunnels
\r\n" - " Jump services
\r\n" - ; - if (i2p::client::context.GetSAMBridge ()) - s << " SAM sessions
\r\n"; - s << "
\r\n"; - s << "
"; + ShowPageHead (s); if (uri.find("page=") != std::string::npos) HandlePage (s, uri); else if (uri.find("cmd=") != std::string::npos) HandleCommand (s, uri); else ShowStatus (s); - s << - "
\r\n" - "\r\n" - "\r\n"; + ShowPageTail (s); SendReply (s.str ()); } From 80e37df0123067aedc784321ff2c7eb2f0074030 Mon Sep 17 00:00:00 2001 From: hagen Date: Wed, 27 Apr 2016 00:00:00 +0000 Subject: [PATCH 24/29] * HTTPServer.{cpp,h}: change page/cmd processing flow --- Daemon.cpp | 1 + HTTPServer.cpp | 55 ++++++++++++++++++++++++++------------------------ HTTPServer.h | 10 ++++----- 3 files changed, 34 insertions(+), 32 deletions(-) diff --git a/Daemon.cpp b/Daemon.cpp index fdb9bf3f..c98bce05 100644 --- a/Daemon.cpp +++ b/Daemon.cpp @@ -13,6 +13,7 @@ #include "RouterInfo.h" #include "RouterContext.h" #include "Tunnel.h" +#include "HTTP.h" #include "NetDb.h" #include "Garlic.h" #include "Streaming.h" diff --git a/HTTPServer.cpp b/HTTPServer.cpp index 864c9fd3..e5093bba 100644 --- a/HTTPServer.cpp +++ b/HTTPServer.cpp @@ -302,6 +302,11 @@ namespace http { "\r\n"; } + void ShowError(std::stringstream& s, const std::string& string) + { + s << "ERROR: " << string << "
\r\n"; + } + void ShowStatus (std::stringstream& s) { s << "Uptime: "; @@ -670,7 +675,7 @@ namespace http { } if (ret == 0) return; /* need more data */ - HandleRequest (request.uri); + HandleRequest (request); } void HTTPConnection::Terminate (const boost::system::error_code& ecode) @@ -682,28 +687,31 @@ namespace http { m_Socket->close (); } - void HTTPConnection::HandleRequest (const std::string &uri) + void HTTPConnection::HandleRequest (const HTTPReq & req) { std::stringstream s; + std::string content; + HTTPRes res; // Html5 head start ShowPageHead (s); - if (uri.find("page=") != std::string::npos) - HandlePage (s, uri); - else if (uri.find("cmd=") != std::string::npos) - HandleCommand (s, uri); + if (req.uri.find("page=") != std::string::npos) + HandlePage (req, res, s); + else if (req.uri.find("cmd=") != std::string::npos) + HandleCommand (req, res, s); else ShowStatus (s); ShowPageTail (s); - SendReply (s.str ()); + content = s.str (); + SendReply (res, content); } - void HTTPConnection::HandlePage (std::stringstream& s, const std::string & uri) + void HTTPConnection::HandlePage (const HTTPReq& req, HTTPRes& res, std::stringstream& s) { std::map params; std::string page(""); URL url; - url.parse(uri); + url.parse(req.uri); url.parse_query(params); page = params["page"]; @@ -727,17 +735,20 @@ namespace http { ShowSAMSession (s, params["sam_id"]); else if (page == HTTP_PAGE_I2P_TUNNELS) ShowI2PTunnels (s); - else - SendError("Unknown page: " + page); + else { + res.code = 400; + ShowError(s, "Unknown page: " + page); + return; + } } - void HTTPConnection::HandleCommand (std::stringstream& s, const std::string & uri) + void HTTPConnection::HandleCommand (const HTTPReq& req, HTTPRes& res, std::stringstream& s) { std::map params; std::string cmd(""); URL url; - url.parse(uri); + url.parse(req.uri); url.parse_query(params); cmd = params["cmd"]; @@ -748,21 +759,20 @@ namespace http { else if (cmd == HTTP_COMMAND_STOP_ACCEPTING_TUNNELS) i2p::context.SetAcceptsTunnels (false); else { - SendError("Unknown command: " + cmd); + res.code = 400; + ShowError(s, "Unknown command: " + cmd); return; } - s << "Command accepted

\r\n"; + s << "SUCCESS: Command accepted

\r\n"; s << "Back to commands list"; } - void HTTPConnection::SendReply (const std::string& content, int code) + void HTTPConnection::SendReply (HTTPRes& reply, std::string& content) { std::time_t time_now = std::time(nullptr); char time_buff[128]; std::strftime(time_buff, sizeof(time_buff), "%a, %d %b %Y %H:%M:%S GMT", std::gmtime(&time_now)); - HTTPRes reply; - reply.code = code; - reply.status = HTTPCodeToStatus(code); + reply.status = HTTPCodeToStatus(reply.code); reply.headers.insert(std::pair("Date", time_buff)); reply.headers.insert(std::pair("Content-Type", "text/html")); reply.headers.insert(std::pair("Content-Length", std::to_string(content.size()))); @@ -777,13 +787,6 @@ namespace http { std::bind (&HTTPConnection::Terminate, shared_from_this (), std::placeholders::_1)); } - void HTTPConnection::SendError(const std::string& content) - { - std::stringstream ss; - ss << "" << itoopieImage << "
\r\n" << content << ""; - SendReply (ss.str(), 504); - } - HTTPServer::HTTPServer (const std::string& address, int port): m_Thread (nullptr), m_Work (m_Service), m_Acceptor (m_Service, boost::asio::ip::tcp::endpoint (boost::asio::ip::address::from_string(address), port)) diff --git a/HTTPServer.h b/HTTPServer.h index 06fa4457..72a0c383 100644 --- a/HTTPServer.h +++ b/HTTPServer.h @@ -21,13 +21,11 @@ namespace http { void HandleReceive (const boost::system::error_code& ecode, std::size_t bytes_transferred); void Terminate (const boost::system::error_code& ecode); - void SendReply (const std::string& content, int code = 200); - void SendError (const std::string& message); - void RunRequest (); - void HandleRequest (const std::string& uri); - void HandlePage (std::stringstream& s, const std::string& request); - void HandleCommand (std::stringstream& s, const std::string& request); + void HandleRequest (const HTTPReq & req); + void HandlePage (const HTTPReq & req, HTTPRes & res, std::stringstream& data); + void HandleCommand (const HTTPReq & req, HTTPRes & res, std::stringstream& data); + void SendReply (HTTPRes & res, std::string & content); private: From 75db2867dcdd77452414e4cbfec6c19ef3c44619 Mon Sep 17 00:00:00 2001 From: hagen Date: Wed, 27 Apr 2016 00:00:00 +0000 Subject: [PATCH 25/29] * HTTPServer.cpp: protect SAM pages if disabled --- HTTPServer.cpp | 65 ++++++++++++++++++++++++-------------------------- 1 file changed, 31 insertions(+), 34 deletions(-) diff --git a/HTTPServer.cpp b/HTTPServer.cpp index e5093bba..7dc8d910 100644 --- a/HTTPServer.cpp +++ b/HTTPServer.cpp @@ -573,15 +573,16 @@ namespace http { void ShowSAMSessions (std::stringstream& s) { - s << "SAM Sessions:
\r\n
\r\n"; auto sam = i2p::client::context.GetSAMBridge (); - if (sam) - { - for (auto& it: sam->GetSessions ()) - { - s << ""; - s << it.first << "
\r\n" << std::endl; - } + if (!sam) { + ShowError(s, "SAM disabled"); + return; + } + s << "SAM Sessions:
\r\n
\r\n"; + for (auto& it: sam->GetSessions ()) + { + s << ""; + s << it.first << "
\r\n" << std::endl; } } @@ -589,35 +590,31 @@ namespace http { { s << "SAM Session:
\r\n
\r\n"; auto sam = i2p::client::context.GetSAMBridge (); - if (sam) + if (!sam) { + ShowError(s, "SAM disabled"); + return; + } + auto session = sam->FindSession (id); + if (!session) { + ShowError(s, "SAM session not found"); + return; + } + auto& ident = session->localDestination->GetIdentHash(); + s << ""; + s << i2p::client::context.GetAddressBook ().ToAddress(ident) << "
\r\n"; + s << "
\r\n"; + s << "Streams:
\r\n"; + for (auto it: session->ListSockets()) { - auto session = sam->FindSession (id); - if (session) + switch (it->GetSocketType ()) { - auto& ident = session->localDestination->GetIdentHash(); - s << ""; - s << i2p::client::context.GetAddressBook ().ToAddress(ident) << "
\r\n" << std::endl; - s << "Streams:
\r\n"; - for (auto it: session->ListSockets()) - { - switch (it->GetSocketType ()) - { - case i2p::client::eSAMSocketTypeSession: - s << "session"; - break; - case i2p::client::eSAMSocketTypeStream: - s << "stream"; - break; - case i2p::client::eSAMSocketTypeAcceptor: - s << "acceptor"; - break; - default: - s << "unknown"; - } - s << " [" << it->GetSocket ().remote_endpoint() << "]"; - s << "
\r\n" << std::endl; - } + case i2p::client::eSAMSocketTypeSession : s << "session"; break; + case i2p::client::eSAMSocketTypeStream : s << "stream"; break; + case i2p::client::eSAMSocketTypeAcceptor : s << "acceptor"; break; + default: s << "unknown"; break; } + s << " [" << it->GetSocket ().remote_endpoint() << "]"; + s << "
\r\n"; } } From e09386be445fde1a9e7fe63bbbabb6cff39ebff4 Mon Sep 17 00:00:00 2001 From: hagen Date: Wed, 27 Apr 2016 00:00:00 +0000 Subject: [PATCH 26/29] * add http.auth, http.user & http.pass options --- Config.cpp | 3 +++ docs/configuration.md | 3 +++ 2 files changed, 6 insertions(+) diff --git a/Config.cpp b/Config.cpp index d7cef879..44dec286 100644 --- a/Config.cpp +++ b/Config.cpp @@ -141,6 +141,9 @@ namespace config { ("http.enabled", value()->default_value(true), "Enable or disable webconsole") ("http.address", value()->default_value("127.0.0.1"), "Webconsole listen address") ("http.port", value()->default_value(7070), "Webconsole listen port") + ("http.auth", value()->default_value(false), "Enable Basic HTTP auth for webconsole") + ("http.user", value()->default_value("i2pd"), "Username for basic auth") + ("http.pass", value()->default_value(""), "Password for basic auth (default: random, see logs)") ; options_description httpproxy("HTTP Proxy options"); diff --git a/docs/configuration.md b/docs/configuration.md index 2a639be3..11e8b4a8 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -36,6 +36,9 @@ All options below still possible in cmdline, but better write it in config file: * --http.address= - The address to listen on (HTTP server) * --http.port= - The port to listen on (HTTP server) +* --http.auth - Enable basic HTTP auth for webconsole +* --http.user= - Username for basic auth (default: i2pd) +* --http.pass= - Password for basic auth (default: random, see logs) * --httpproxy.address= - The address to listen on (HTTP Proxy) * --httpproxy.port= - The port to listen on (HTTP Proxy) 4446 by default From 678650beaff02b59491233b43aee2ffc5e660e6d Mon Sep 17 00:00:00 2001 From: hagen Date: Wed, 27 Apr 2016 00:00:00 +0000 Subject: [PATCH 27/29] * HTTPServer.{cpp,h}: basic auth --- HTTPServer.cpp | 61 +++++++++++++++++++++++++++++++++++++++++++++++++- HTTPServer.h | 8 ++++--- 2 files changed, 65 insertions(+), 4 deletions(-) diff --git a/HTTPServer.cpp b/HTTPServer.cpp index 7dc8d910..8d9be41f 100644 --- a/HTTPServer.cpp +++ b/HTTPServer.cpp @@ -10,6 +10,7 @@ #include "Base.h" #include "FS.h" #include "Log.h" +#include "Config.h" #include "Tunnel.h" #include "TransitTunnel.h" #include "Transports.h" @@ -640,7 +641,16 @@ namespace http { s << "
\r\n"<< std::endl; } } - + + HTTPConnection::HTTPConnection (std::shared_ptr socket): + m_Socket (socket), m_Timer (socket->get_io_service ()), m_BufferLen (0) + { + /* cache options */ + i2p::config::GetOption("http.auth", needAuth); + i2p::config::GetOption("http.user", user); + i2p::config::GetOption("http.pass", pass); + }; + void HTTPConnection::Receive () { m_Socket->async_read_some (boost::asio::buffer (m_Buffer, HTTP_CONNECTION_BUFFER_SIZE), @@ -672,6 +682,7 @@ namespace http { } if (ret == 0) return; /* need more data */ + HandleRequest (request); } @@ -684,11 +695,44 @@ namespace http { m_Socket->close (); } + bool HTTPConnection::CheckAuth (const HTTPReq & req) { + /* method #1: http://user:pass@127.0.0.1:7070/ */ + if (req.uri.find('@') != std::string::npos) { + URL url; + if (url.parse(req.uri) && url.user == user && url.pass == pass) + return true; + } + /* method #2: 'Authorization' header sent */ + if (req.headers.count("Authorization") > 0) { + std::string provided = req.headers.find("Authorization")->second; + std::string expected = user + ":" + pass; + char b64_creds[64]; + std::size_t len = 0; + len = i2p::data::ByteStreamToBase64((unsigned char *)expected.c_str(), expected.length(), b64_creds, sizeof(b64_creds)); + b64_creds[len] = '\0'; + expected = "Basic "; + expected += b64_creds; + if (provided == expected) + return true; + } + + LogPrint(eLogWarning, "HTTPServer: auth failure from ", m_Socket->remote_endpoint().address ()); + return false; + } + void HTTPConnection::HandleRequest (const HTTPReq & req) { std::stringstream s; std::string content; HTTPRes res; + + if (needAuth && !CheckAuth(req)) { + res.code = 401; + res.headers.insert(std::pair("WWW-Authenticate", "Basic realm=\"WebAdmin\"")); + SendReply(res, content); + return; + } + // Html5 head start ShowPageHead (s); if (req.uri.find("page=") != std::string::npos) @@ -797,6 +841,21 @@ namespace http { void HTTPServer::Start () { + bool needAuth; i2p::config::GetOption("http.auth", needAuth); + std::string user; i2p::config::GetOption("http.user", user); + std::string pass; i2p::config::GetOption("http.pass", pass); + /* generate pass if needed */ + if (needAuth && pass == "") { + char alnum[] = "0123456789" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "abcdefghijklmnopqrstuvwxyz"; + pass.resize(16); + for (size_t i = 0; i < pass.size(); i++) { + pass[i] = alnum[rand() % (sizeof(alnum) - 1)]; + } + i2p::config::SetOption("http.pass", pass); + LogPrint(eLogInfo, "HTTPServer: password set to ", pass); + } m_Thread = std::unique_ptr(new std::thread (std::bind (&HTTPServer::Run, this))); m_Acceptor.listen (); Accept (); diff --git a/HTTPServer.h b/HTTPServer.h index 72a0c383..2635c3be 100644 --- a/HTTPServer.h +++ b/HTTPServer.h @@ -11,9 +11,7 @@ namespace http { { public: - HTTPConnection (std::shared_ptr socket): - m_Socket (socket), m_Timer (socket->get_io_service ()), - m_BufferLen (0) {}; + HTTPConnection (std::shared_ptr socket); void Receive (); private: @@ -22,6 +20,7 @@ namespace http { void Terminate (const boost::system::error_code& ecode); void RunRequest (); + bool CheckAuth (const HTTPReq & req); void HandleRequest (const HTTPReq & req); void HandlePage (const HTTPReq & req, HTTPRes & res, std::stringstream& data); void HandleCommand (const HTTPReq & req, HTTPRes & res, std::stringstream& data); @@ -33,6 +32,9 @@ namespace http { boost::asio::deadline_timer m_Timer; char m_Buffer[HTTP_CONNECTION_BUFFER_SIZE + 1]; size_t m_BufferLen; + bool needAuth; + std::string user; + std::string pass; }; class HTTPServer From 8fd55a210a7613acc01f4467c1a91186028b0ab5 Mon Sep 17 00:00:00 2001 From: hagen Date: Wed, 27 Apr 2016 00:00:00 +0000 Subject: [PATCH 28/29] * HTTPServer.cpp: add 'Shutdown' commands --- HTTPServer.cpp | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/HTTPServer.cpp b/HTTPServer.cpp index 8d9be41f..36ff2a37 100644 --- a/HTTPServer.cpp +++ b/HTTPServer.cpp @@ -21,6 +21,7 @@ #include "RouterContext.h" #include "ClientContext.h" #include "HTTPServer.h" +#include "Daemon.h" // For image and info #include "version.h" @@ -221,6 +222,9 @@ namespace http { const char HTTP_PAGE_COMMANDS[] = "commands"; const char HTTP_COMMAND_START_ACCEPTING_TUNNELS[] = "start_accepting_tunnels"; const char HTTP_COMMAND_STOP_ACCEPTING_TUNNELS[] = "stop_accepting_tunnels"; + const char HTTP_COMMAND_SHUTDOWN_START[] = "shutdown_start"; + const char HTTP_COMMAND_SHUTDOWN_CANCEL[] = "shutdown_cancel"; + const char HTTP_COMMAND_SHUTDOWN_NOW[] = "terminate"; const char HTTP_COMMAND_RUN_PEER_TEST[] = "run_peer_test"; const char HTTP_PARAM_BASE32_ADDRESS[] = "b32"; const char HTTP_PARAM_SAM_SESSION_ID[] = "id"; @@ -506,6 +510,14 @@ namespace http { s << " Stop accepting tunnels
\r\n"; else s << " Start accepting tunnels
\r\n"; + if (Daemon.gracefullShutdownInterval) { + s << " Cancel gracefull shutdown ("; + s << Daemon.gracefullShutdownInterval; + s << " seconds remains)
\r\n"; + } else { + s << " Start gracefull shutdown
\r\n"; + } + s << " Force shutdown
\r\n"; } void ShowTransitTunnels (std::stringstream& s) @@ -799,7 +811,15 @@ namespace http { i2p::context.SetAcceptsTunnels (true); else if (cmd == HTTP_COMMAND_STOP_ACCEPTING_TUNNELS) i2p::context.SetAcceptsTunnels (false); - else { + else if (cmd == HTTP_COMMAND_SHUTDOWN_START) { + i2p::context.SetAcceptsTunnels (false); + Daemon.gracefullShutdownInterval = 10*60; + } else if (cmd == HTTP_COMMAND_SHUTDOWN_CANCEL) { + i2p::context.SetAcceptsTunnels (true); + Daemon.gracefullShutdownInterval = 0; + } else if (cmd == HTTP_COMMAND_SHUTDOWN_NOW) { + Daemon.running = false; + } else { res.code = 400; ShowError(s, "Unknown command: " + cmd); return; From f131e319496739cd3983964cf7e048bec8663423 Mon Sep 17 00:00:00 2001 From: hagen Date: Wed, 27 Apr 2016 00:00:00 +0000 Subject: [PATCH 29/29] * HTTPServer.cpp: add request logging --- HTTPServer.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/HTTPServer.cpp b/HTTPServer.cpp index 36ff2a37..b3efc57d 100644 --- a/HTTPServer.cpp +++ b/HTTPServer.cpp @@ -738,6 +738,8 @@ namespace http { std::string content; HTTPRes res; + LogPrint(eLogDebug, "HTTPServer: request: ", req.uri); + if (needAuth && !CheckAuth(req)) { res.code = 401; res.headers.insert(std::pair("WWW-Authenticate", "Basic realm=\"WebAdmin\""));