mirror of
				https://github.com/PurpleI2P/i2pd.git
				synced 2025-11-04 08:30:46 +00:00 
			
		
		
		
	webconsole: add stream closing
Signed-off-by: R4SAS <r4sas@i2pmail.org>
This commit is contained in:
		
							parent
							
								
									5eec580727
								
							
						
					
					
						commit
						51d018acc6
					
				
					 2 changed files with 121 additions and 60 deletions
				
			
		| 
						 | 
				
			
			@ -54,6 +54,7 @@ namespace http {
 | 
			
		|||
		"  body { font: 100%/1.5em sans-serif; margin: 0; padding: 1.5em; background: #FAFAFA; color: #103456; }\r\n"
 | 
			
		||||
		"  a, .slide label { text-decoration: none; color: #894C84; }\r\n"
 | 
			
		||||
		"  a:hover, .slide label:hover { color: #FAFAFA; background: #894C84; }\r\n"
 | 
			
		||||
		"  a.button { -webkit-appearance: button; -moz-appearance: button; appearance: button; text-decoration: none; color: initial;}\r\n"
 | 
			
		||||
		"  .header { font-size: 2.5em; text-align: center; margin: 1.5em 0; color: #894C84; }\r\n"
 | 
			
		||||
		"  .wrapper { margin: 0 auto; padding: 1em; max-width: 60em; }\r\n"
 | 
			
		||||
		"  .left  { float: left; position: absolute; }\r\n"
 | 
			
		||||
| 
						 | 
				
			
			@ -64,10 +65,11 @@ namespace http {
 | 
			
		|||
		"  .tunnel.building    { color: #434343; }\r\n"
 | 
			
		||||
		"  caption { font-size: 1.5em; text-align: center; color: #894C84; }\r\n"
 | 
			
		||||
		"  table { width: 100%; border-collapse: collapse; text-align: center; }\r\n"
 | 
			
		||||
		"  .slide p, .slide [type='checkbox']{ display:none; }\r\n"
 | 
			
		||||
		"  .slide [type='checkbox']:checked ~ p { display:block; margin-top: 0; padding: 0; }\r\n"
 | 
			
		||||
		"  .slide p, .slide [type='checkbox'] { display: none; }\r\n"
 | 
			
		||||
		"  .slide [type='checkbox']:checked ~ p { display: block; margin-top: 0; padding: 0; }\r\n"
 | 
			
		||||
		"  .disabled:after { color: #D33F3F; content: \"Disabled\" }\r\n"
 | 
			
		||||
		"  .enabled:after  { color: #56B734; content: \"Enabled\"  }\r\n"
 | 
			
		||||
		"  .streamdest { width: 120px; max-width: 240px; overflow: hidden; text-overflow: ellipsis;}\r\n"
 | 
			
		||||
		"</style>\r\n";
 | 
			
		||||
 | 
			
		||||
	const char HTTP_PAGE_TUNNELS[] = "tunnels";
 | 
			
		||||
| 
						 | 
				
			
			@ -89,10 +91,12 @@ namespace http {
 | 
			
		|||
	const char HTTP_COMMAND_RUN_PEER_TEST[] = "run_peer_test";
 | 
			
		||||
	const char HTTP_COMMAND_RELOAD_CONFIG[] = "reload_config";
 | 
			
		||||
	const char HTTP_COMMAND_LOGLEVEL[] = "set_loglevel";
 | 
			
		||||
	const char HTTP_COMMAND_KILLSTREAM[] = "closestream";
 | 
			
		||||
	const char HTTP_PARAM_SAM_SESSION_ID[] = "id";
 | 
			
		||||
	const char HTTP_PARAM_ADDRESS[] = "address";
 | 
			
		||||
 | 
			
		||||
	static std::string ConvertTime (uint64_t time);
 | 
			
		||||
	std::map<uint32_t, uint32_t> HTTPConnection::m_Tokens;
 | 
			
		||||
 | 
			
		||||
	static void ShowUptime (std::stringstream& s, int seconds)
 | 
			
		||||
	{
 | 
			
		||||
| 
						 | 
				
			
			@ -203,10 +207,7 @@ namespace http {
 | 
			
		|||
		s << "<b>ERROR:</b> " << string << "<br>\r\n";
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
    void ShowStatus (
 | 
			
		||||
            std::stringstream& s,
 | 
			
		||||
            bool includeHiddenContent,
 | 
			
		||||
            i2p::http::OutputFormatEnum outputFormat)
 | 
			
		||||
	void ShowStatus (std::stringstream& s, bool includeHiddenContent, i2p::http::OutputFormatEnum outputFormat)
 | 
			
		||||
	{
 | 
			
		||||
		s << "<b>Uptime:</b> ";
 | 
			
		||||
		ShowUptime(s, i2p::context.GetUptime ());
 | 
			
		||||
| 
						 | 
				
			
			@ -253,12 +254,12 @@ namespace http {
 | 
			
		|||
		ShowTraffic (s, i2p::transport::transports.GetTotalTransitTransmittedBytes ());
 | 
			
		||||
		s << " (" << (double) i2p::transport::transports.GetTransitBandwidth () / 1024 << " KiB/s)<br>\r\n";
 | 
			
		||||
		s << "<b>Data path:</b> " << i2p::fs::GetDataDir() << "<br>\r\n";
 | 
			
		||||
        s << "<div class='slide'>";
 | 
			
		||||
        if((outputFormat==OutputFormatEnum::forWebConsole)||!includeHiddenContent) {
 | 
			
		||||
            s << "<label for='slide-info'>Hidden content. Press on text to see.</label>\r\n<input type='checkbox' id='slide-info'/>\r\n<p class='content'>\r\n";
 | 
			
		||||
        }
 | 
			
		||||
        if(includeHiddenContent) {
 | 
			
		||||
            s << "<b>Router Ident:</b> " << i2p::context.GetRouterInfo().GetIdentHashBase64() << "<br>\r\n";
 | 
			
		||||
		s << "<div class='slide'>";
 | 
			
		||||
		if((outputFormat==OutputFormatEnum::forWebConsole)||!includeHiddenContent) {
 | 
			
		||||
			s << "<label for='slide-info'>Hidden content. Press on text to see.</label>\r\n<input type='checkbox' id='slide-info'/>\r\n<p class='content'>\r\n";
 | 
			
		||||
		}
 | 
			
		||||
		if(includeHiddenContent) {
 | 
			
		||||
			s << "<b>Router Ident:</b> " << i2p::context.GetRouterInfo().GetIdentHashBase64() << "<br>\r\n";
 | 
			
		||||
			s << "<b>Router Family:</b> " << i2p::context.GetRouterInfo().GetProperty("family") << "<br>\r\n";
 | 
			
		||||
			s << "<b>Router Caps:</b> " << i2p::context.GetRouterInfo().GetProperty("caps") << "<br>\r\n";
 | 
			
		||||
			s << "<b>Our external address:</b>" << "<br>\r\n" ;
 | 
			
		||||
| 
						 | 
				
			
			@ -292,12 +293,12 @@ namespace http {
 | 
			
		|||
				}
 | 
			
		||||
				s << address->host.to_string() << ":" << address->port << "<br>\r\n";
 | 
			
		||||
			}
 | 
			
		||||
        }
 | 
			
		||||
		}
 | 
			
		||||
		s << "</p>\r\n</div>\r\n";
 | 
			
		||||
        if(outputFormat==OutputFormatEnum::forQtUi) {
 | 
			
		||||
            s << "<br>";
 | 
			
		||||
        }
 | 
			
		||||
        s << "<b>Routers:</b> " << i2p::data::netdb.GetNumRouters () << " ";
 | 
			
		||||
		if(outputFormat==OutputFormatEnum::forQtUi) {
 | 
			
		||||
			s << "<br>";
 | 
			
		||||
		}
 | 
			
		||||
		s << "<b>Routers:</b> " << i2p::data::netdb.GetNumRouters () << " ";
 | 
			
		||||
		s << "<b>Floodfills:</b> " << i2p::data::netdb.GetNumFloodfills () << " ";
 | 
			
		||||
		s << "<b>LeaseSets:</b> " << i2p::data::netdb.GetNumLeaseSets () << "<br>\r\n";
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -308,17 +309,17 @@ namespace http {
 | 
			
		|||
		s << "<b>Client Tunnels:</b> " << std::to_string(clientTunnelCount) << " ";
 | 
			
		||||
		s << "<b>Transit Tunnels:</b> " << std::to_string(transitTunnelCount) << "<br>\r\n<br>\r\n";
 | 
			
		||||
 | 
			
		||||
        if(outputFormat==OutputFormatEnum::forWebConsole) {
 | 
			
		||||
            s << "<table><caption>Services</caption><tr><th>Service</th><th>State</th></tr>\r\n";
 | 
			
		||||
            s << "<tr><td>" << "HTTP Proxy"		<< "</td><td><div class='" << ((i2p::client::context.GetHttpProxy ())			? "enabled" : "disabled") << "'></div></td></tr>\r\n";
 | 
			
		||||
            s << "<tr><td>" << "SOCKS Proxy"	<< "</td><td><div class='" << ((i2p::client::context.GetSocksProxy ())			? "enabled" : "disabled") << "'></div></td></tr>\r\n";
 | 
			
		||||
            s << "<tr><td>" << "BOB"			<< "</td><td><div class='" << ((i2p::client::context.GetBOBCommandChannel ())	? "enabled" : "disabled") << "'></div></td></tr>\r\n";
 | 
			
		||||
            s << "<tr><td>" << "SAM"			<< "</td><td><div class='" << ((i2p::client::context.GetSAMBridge ())			? "enabled" : "disabled") << "'></div></td></tr>\r\n";
 | 
			
		||||
            s << "<tr><td>" << "I2CP"			<< "</td><td><div class='" << ((i2p::client::context.GetI2CPServer ())			? "enabled" : "disabled") << "'></div></td></tr>\r\n";
 | 
			
		||||
            bool i2pcontrol; i2p::config::GetOption("i2pcontrol.enabled", i2pcontrol);
 | 
			
		||||
            s << "<tr><td>" << "I2PControl"		<< "</td><td><div class='" << ((i2pcontrol) 									? "enabled" : "disabled") << "'></div></td></tr>\r\n";
 | 
			
		||||
            s << "</table>\r\n";
 | 
			
		||||
        }
 | 
			
		||||
		if(outputFormat==OutputFormatEnum::forWebConsole) {
 | 
			
		||||
			s << "<table><caption>Services</caption><tr><th>Service</th><th>State</th></tr>\r\n";
 | 
			
		||||
			s << "<tr><td>" << "HTTP Proxy"		<< "</td><td><div class='" << ((i2p::client::context.GetHttpProxy ())			? "enabled" : "disabled") << "'></div></td></tr>\r\n";
 | 
			
		||||
			s << "<tr><td>" << "SOCKS Proxy"	<< "</td><td><div class='" << ((i2p::client::context.GetSocksProxy ())			? "enabled" : "disabled") << "'></div></td></tr>\r\n";
 | 
			
		||||
			s << "<tr><td>" << "BOB"			<< "</td><td><div class='" << ((i2p::client::context.GetBOBCommandChannel ())	? "enabled" : "disabled") << "'></div></td></tr>\r\n";
 | 
			
		||||
			s << "<tr><td>" << "SAM"			<< "</td><td><div class='" << ((i2p::client::context.GetSAMBridge ())			? "enabled" : "disabled") << "'></div></td></tr>\r\n";
 | 
			
		||||
			s << "<tr><td>" << "I2CP"			<< "</td><td><div class='" << ((i2p::client::context.GetI2CPServer ())			? "enabled" : "disabled") << "'></div></td></tr>\r\n";
 | 
			
		||||
			bool i2pcontrol; i2p::config::GetOption("i2pcontrol.enabled", i2pcontrol);
 | 
			
		||||
			s << "<tr><td>" << "I2PControl"		<< "</td><td><div class='" << ((i2pcontrol) 									? "enabled" : "disabled") << "'></div></td></tr>\r\n";
 | 
			
		||||
			s << "</table>\r\n";
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void ShowLocalDestinations (std::stringstream& s)
 | 
			
		||||
| 
						 | 
				
			
			@ -352,7 +353,7 @@ namespace http {
 | 
			
		|||
 | 
			
		||||
	static void ShowLeaseSetDestination (std::stringstream& s, std::shared_ptr<const i2p::client::LeaseSetDestination> dest)
 | 
			
		||||
	{
 | 
			
		||||
		s << "<b>Base64:</b><br>\r\n<textarea readonly=\"readonly\" cols=\"64\" rows=\"11\" wrap=\"on\">";
 | 
			
		||||
		s << "<b>Base64:</b><br>\r\n<textarea readonly cols=\"80\" rows=\"11\" wrap=\"on\">";
 | 
			
		||||
		s << dest->GetIdentity ()->ToBase64 () << "</textarea><br>\r\n<br>\r\n";
 | 
			
		||||
		if (dest->IsEncryptedLeaseSet ())
 | 
			
		||||
		{
 | 
			
		||||
| 
						 | 
				
			
			@ -403,19 +404,21 @@ namespace http {
 | 
			
		|||
		s << "<br>\r\n";
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void ShowLocalDestination (std::stringstream& s, const std::string& b32)
 | 
			
		||||
	void ShowLocalDestination (std::stringstream& s, const std::string& b32, uint32_t token)
 | 
			
		||||
	{
 | 
			
		||||
		s << "<b>Local Destination:</b><br>\r\n<br>\r\n";
 | 
			
		||||
		i2p::data::IdentHash ident;
 | 
			
		||||
		ident.FromBase32 (b32);
 | 
			
		||||
		auto dest = i2p::client::context.FindLocalDestination (ident);
 | 
			
		||||
 | 
			
		||||
		if (dest)
 | 
			
		||||
		{
 | 
			
		||||
			ShowLeaseSetDestination (s, dest);
 | 
			
		||||
			// show streams
 | 
			
		||||
			s << "<table><caption>Streams</caption>\r\n<tr>";
 | 
			
		||||
			s << "<th>StreamID</th>";
 | 
			
		||||
			s << "<th>Destination</th>";
 | 
			
		||||
			s << "<table>\r\n<caption>Streams</caption>\r\n<thead>\r\n<tr>";
 | 
			
		||||
			s << "<th style=\"width:25px;\">StreamID</th>";
 | 
			
		||||
			s << "<th style=\"width:5px;\" \\>"; // Stream closing button column
 | 
			
		||||
			s << "<th class=\"streamdest\">Destination</th>";
 | 
			
		||||
			s << "<th>Sent</th>";
 | 
			
		||||
			s << "<th>Received</th>";
 | 
			
		||||
			s << "<th>Out</th>";
 | 
			
		||||
| 
						 | 
				
			
			@ -424,13 +427,20 @@ namespace http {
 | 
			
		|||
			s << "<th>RTT</th>";
 | 
			
		||||
			s << "<th>Window</th>";
 | 
			
		||||
			s << "<th>Status</th>";
 | 
			
		||||
			s << "</tr>\r\n";
 | 
			
		||||
			s << "</tr>\r\n</thead>\r\n<tbody>\r\n";
 | 
			
		||||
 | 
			
		||||
			for (const auto& it: dest->GetAllStreams ())
 | 
			
		||||
			{
 | 
			
		||||
				auto streamDest = i2p::client::context.GetAddressBook ().ToAddress(it->GetRemoteIdentity ());
 | 
			
		||||
				s << "<tr>";
 | 
			
		||||
				s << "<td>" << it->GetSendStreamID () << "</td>";
 | 
			
		||||
				s << "<td>" << i2p::client::context.GetAddressBook ().ToAddress(it->GetRemoteIdentity ()) << "</td>";
 | 
			
		||||
				s << "<td>" << it->GetRecvStreamID () << "</td>";
 | 
			
		||||
				if (it->GetRecvStreamID ()) {
 | 
			
		||||
					s << "<td><a class=\"button\" href=\"/?cmd=" << HTTP_COMMAND_KILLSTREAM << "&b32=" << b32 << "&streamID="
 | 
			
		||||
					  << it->GetRecvStreamID () << "&token=" << token << "\" title=\"Close stream\"> ✘ </a></td>";
 | 
			
		||||
				} else {
 | 
			
		||||
					s << "<td \\>";
 | 
			
		||||
				}
 | 
			
		||||
				s << "<td class=\"streamdest\" title=\"" << streamDest << "\">" << streamDest << "</td>";
 | 
			
		||||
				s << "<td>" << it->GetNumSentBytes () << "</td>";
 | 
			
		||||
				s << "<td>" << it->GetNumReceivedBytes () << "</td>";
 | 
			
		||||
				s << "<td>" << it->GetSendQueueSize () << "</td>";
 | 
			
		||||
| 
						 | 
				
			
			@ -441,7 +451,7 @@ namespace http {
 | 
			
		|||
				s << "<td>" << (int)it->GetStatus () << "</td>";
 | 
			
		||||
				s << "</tr>\r\n";
 | 
			
		||||
			}
 | 
			
		||||
			s << "</table>";
 | 
			
		||||
			s << "</tbody>\r\n</table>";
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -858,7 +868,8 @@ namespace http {
 | 
			
		|||
		m_Socket->close ();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	bool HTTPConnection::CheckAuth (const HTTPReq & req) {
 | 
			
		||||
	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;
 | 
			
		||||
| 
						 | 
				
			
			@ -920,7 +931,7 @@ namespace http {
 | 
			
		|||
		} else if (req.uri.find("cmd=") != std::string::npos) {
 | 
			
		||||
			HandleCommand (req, res, s);
 | 
			
		||||
		} else {
 | 
			
		||||
            ShowStatus (s, true, i2p::http::OutputFormatEnum::forWebConsole);
 | 
			
		||||
			ShowStatus (s, true, i2p::http::OutputFormatEnum::forWebConsole);
 | 
			
		||||
			res.add_header("Refresh", "10");
 | 
			
		||||
		}
 | 
			
		||||
		ShowPageTail (s);
 | 
			
		||||
| 
						 | 
				
			
			@ -930,7 +941,23 @@ namespace http {
 | 
			
		|||
		SendReply (res, content);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	std::map<uint32_t, uint32_t> HTTPConnection::m_Tokens;
 | 
			
		||||
	uint32_t HTTPConnection::CreateToken ()
 | 
			
		||||
	{
 | 
			
		||||
		uint32_t token;
 | 
			
		||||
		RAND_bytes ((uint8_t *)&token, 4);
 | 
			
		||||
		token &= 0x7FFFFFFF; // clear first bit
 | 
			
		||||
		auto ts = i2p::util::GetSecondsSinceEpoch ();
 | 
			
		||||
		for (auto it = m_Tokens.begin (); it != m_Tokens.end (); )
 | 
			
		||||
		{
 | 
			
		||||
			if (ts > it->second + TOKEN_EXPIRATION_TIMEOUT)
 | 
			
		||||
				it = m_Tokens.erase (it);
 | 
			
		||||
			else
 | 
			
		||||
				++it;
 | 
			
		||||
		}
 | 
			
		||||
		m_Tokens[token] = ts;
 | 
			
		||||
		return token;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void HTTPConnection::HandlePage (const HTTPReq& req, HTTPRes& res, std::stringstream& s)
 | 
			
		||||
	{
 | 
			
		||||
		std::map<std::string, std::string> params;
 | 
			
		||||
| 
						 | 
				
			
			@ -947,18 +974,7 @@ namespace http {
 | 
			
		|||
			ShowTunnels (s);
 | 
			
		||||
		else if (page == HTTP_PAGE_COMMANDS)
 | 
			
		||||
		{
 | 
			
		||||
			uint32_t token;
 | 
			
		||||
			RAND_bytes ((uint8_t *)&token, 4);
 | 
			
		||||
			token &= 0x7FFFFFFF; // clear first bit
 | 
			
		||||
			auto ts = i2p::util::GetSecondsSinceEpoch ();
 | 
			
		||||
			for (auto it = m_Tokens.begin (); it != m_Tokens.end (); )
 | 
			
		||||
			{
 | 
			
		||||
				if (ts > it->second + TOKEN_EXPIRATION_TIMEOUT)
 | 
			
		||||
					it = m_Tokens.erase (it);
 | 
			
		||||
				else
 | 
			
		||||
					++it;
 | 
			
		||||
			}
 | 
			
		||||
			m_Tokens[token] = ts;
 | 
			
		||||
			uint32_t token = CreateToken ();
 | 
			
		||||
			ShowCommands (s, token);
 | 
			
		||||
		}
 | 
			
		||||
		else if (page == HTTP_PAGE_TRANSIT_TUNNELS)
 | 
			
		||||
| 
						 | 
				
			
			@ -966,7 +982,10 @@ namespace http {
 | 
			
		|||
		else if (page == HTTP_PAGE_LOCAL_DESTINATIONS)
 | 
			
		||||
			ShowLocalDestinations (s);
 | 
			
		||||
		else if (page == HTTP_PAGE_LOCAL_DESTINATION)
 | 
			
		||||
			ShowLocalDestination (s, params["b32"]);
 | 
			
		||||
		{
 | 
			
		||||
			uint32_t token = CreateToken ();
 | 
			
		||||
			ShowLocalDestination (s, params["b32"], token);
 | 
			
		||||
		}
 | 
			
		||||
		else if (page == HTTP_PAGE_I2CP_LOCAL_DESTINATION)
 | 
			
		||||
			ShowI2CPLocalDestination (s, params["i2cp_id"]);
 | 
			
		||||
		else if (page == HTTP_PAGE_SAM_SESSIONS)
 | 
			
		||||
| 
						 | 
				
			
			@ -992,7 +1011,10 @@ namespace http {
 | 
			
		|||
		url.parse(req.uri);
 | 
			
		||||
		url.parse_query(params);
 | 
			
		||||
 | 
			
		||||
		std::string webroot; i2p::config::GetOption("http.webroot", webroot);
 | 
			
		||||
		std::string redirect = "5; url=" + webroot + "?page=commands";
 | 
			
		||||
		std::string token = params["token"];
 | 
			
		||||
 | 
			
		||||
		if (token.empty () || m_Tokens.find (std::stoi (token)) == m_Tokens.end ())
 | 
			
		||||
		{
 | 
			
		||||
			ShowError(s, "Invalid token");
 | 
			
		||||
| 
						 | 
				
			
			@ -1008,36 +1030,74 @@ namespace http {
 | 
			
		|||
			i2p::context.SetAcceptsTunnels (true);
 | 
			
		||||
		else if (cmd == HTTP_COMMAND_DISABLE_TRANSIT)
 | 
			
		||||
			i2p::context.SetAcceptsTunnels (false);
 | 
			
		||||
		else if (cmd == HTTP_COMMAND_SHUTDOWN_START) {
 | 
			
		||||
		else if (cmd == HTTP_COMMAND_SHUTDOWN_START)
 | 
			
		||||
		{
 | 
			
		||||
			i2p::context.SetAcceptsTunnels (false);
 | 
			
		||||
#if ((!defined(WIN32) && !defined(QT_GUI_LIB) && !defined(ANDROID)) || defined(ANDROID_BINARY))
 | 
			
		||||
			Daemon.gracefulShutdownInterval = 10*60;
 | 
			
		||||
#elif defined(WIN32_APP)
 | 
			
		||||
			i2p::win32::GracefulShutdown ();
 | 
			
		||||
#endif
 | 
			
		||||
		} else if (cmd == HTTP_COMMAND_SHUTDOWN_CANCEL) {
 | 
			
		||||
		}
 | 
			
		||||
		else if (cmd == HTTP_COMMAND_SHUTDOWN_CANCEL)
 | 
			
		||||
		{
 | 
			
		||||
			i2p::context.SetAcceptsTunnels (true);
 | 
			
		||||
#if ((!defined(WIN32) && !defined(QT_GUI_LIB) && !defined(ANDROID))  || defined(ANDROID_BINARY))
 | 
			
		||||
			Daemon.gracefulShutdownInterval = 0;
 | 
			
		||||
#elif defined(WIN32_APP)
 | 
			
		||||
			i2p::win32::StopGracefulShutdown ();
 | 
			
		||||
#endif
 | 
			
		||||
		} else if (cmd == HTTP_COMMAND_SHUTDOWN_NOW) {
 | 
			
		||||
		}
 | 
			
		||||
		else if (cmd == HTTP_COMMAND_SHUTDOWN_NOW)
 | 
			
		||||
		{
 | 
			
		||||
#ifndef WIN32_APP
 | 
			
		||||
			Daemon.running = false;
 | 
			
		||||
#else
 | 
			
		||||
			i2p::win32::StopWin32App ();
 | 
			
		||||
#endif
 | 
			
		||||
		} else if (cmd == HTTP_COMMAND_LOGLEVEL){
 | 
			
		||||
		}
 | 
			
		||||
		else if (cmd == HTTP_COMMAND_LOGLEVEL)
 | 
			
		||||
		{
 | 
			
		||||
			std::string level = params["level"];
 | 
			
		||||
			SetLogLevel (level);
 | 
			
		||||
		} else {
 | 
			
		||||
		}
 | 
			
		||||
		else if (cmd == HTTP_COMMAND_KILLSTREAM)
 | 
			
		||||
		{
 | 
			
		||||
			std::string b32 = params["b32"];
 | 
			
		||||
			uint32_t streamID = std::stoul(params["streamID"], nullptr);
 | 
			
		||||
 | 
			
		||||
			i2p::data::IdentHash ident;
 | 
			
		||||
			ident.FromBase32 (b32);
 | 
			
		||||
			auto dest = i2p::client::context.FindLocalDestination (ident);
 | 
			
		||||
 | 
			
		||||
			if (streamID)
 | 
			
		||||
			{
 | 
			
		||||
				if (dest)
 | 
			
		||||
				{
 | 
			
		||||
					if(dest->DeleteStream (streamID))
 | 
			
		||||
						s << "<b>SUCCESS</b>: Stream closed<br><br>\r\n";
 | 
			
		||||
					else
 | 
			
		||||
						s << "<b>ERROR</b>: Stream not found or already was closed<br><br>\r\n";
 | 
			
		||||
				}
 | 
			
		||||
				else
 | 
			
		||||
					s << "<b>ERROR</b>: Destination not found<br><br>\r\n";
 | 
			
		||||
			}
 | 
			
		||||
			else
 | 
			
		||||
				s << "<b>ERROR</b>: StreamID can be null<br><br>\r\n";
 | 
			
		||||
 | 
			
		||||
			s << "<a href=\"" << webroot << "?page=local_destination&b32=" << b32 << "\">Return to destination page</a><br>\r\n";
 | 
			
		||||
			s << "<p>You will be redirected back in 5 seconds</b>";
 | 
			
		||||
			redirect = "5; url=" + webroot + "?page=local_destination&b32=" + b32;
 | 
			
		||||
			res.add_header("Refresh", redirect.c_str());
 | 
			
		||||
			return;
 | 
			
		||||
		}
 | 
			
		||||
		else
 | 
			
		||||
		{
 | 
			
		||||
			res.code = 400;
 | 
			
		||||
			ShowError(s, "Unknown command: " + cmd);
 | 
			
		||||
			return;
 | 
			
		||||
		}
 | 
			
		||||
		std::string webroot; i2p::config::GetOption("http.webroot", webroot);
 | 
			
		||||
		std::string redirect = "5; url=" + webroot + "?page=commands";
 | 
			
		||||
 | 
			
		||||
		s << "<b>SUCCESS</b>: Command accepted<br><br>\r\n";
 | 
			
		||||
		s << "<a href=\"" << webroot << "?page=commands\">Back to commands list</a><br>\r\n";
 | 
			
		||||
		s << "<p>You will be redirected in 5 seconds</b>";
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -35,6 +35,7 @@ namespace http
 | 
			
		|||
			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);
 | 
			
		||||
			uint32_t CreateToken ();
 | 
			
		||||
 | 
			
		||||
		private:
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue