From df0e235de2b2fcd8e49a01f2961f61fe08f4c453 Mon Sep 17 00:00:00 2001 From: chertov Date: Sun, 30 Mar 2014 02:16:23 +0400 Subject: [PATCH] use HTTPConnection as the base class for proxy --- HTTPProxy.cpp | 283 +++++++++++-------------------------------------- HTTPProxy.h | 87 +++------------ HTTPServer.cpp | 55 ++++++---- HTTPServer.h | 60 ++++++----- 4 files changed, 144 insertions(+), 341 deletions(-) diff --git a/HTTPProxy.cpp b/HTTPProxy.cpp index 61264db2..fbda9d7c 100644 --- a/HTTPProxy.cpp +++ b/HTTPProxy.cpp @@ -1,80 +1,13 @@ -#include #include -#include #include -#include "base64.h" -#include "Log.h" -#include "Tunnel.h" -#include "TransitTunnel.h" -#include "Transports.h" -#include "NetDb.h" -#include "Streaming.h" #include "HTTPProxy.h" namespace i2p { namespace proxy { - namespace misc_strings - { - - const char name_value_separator[] = { ':', ' ' }; - const char crlf[] = { '\r', '\n' }; - - } // namespace misc_strings - - std::vector HTTPConnection::reply::to_buffers() - { - std::vector buffers; - if (headers.size () > 0) - { - buffers.push_back (boost::asio::buffer ("HTTP/1.0 200 OK\r\n")); // always OK - 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; - } - - void HTTPConnection::Terminate () - { - m_Socket->close (); - delete this; - } - - void HTTPConnection::Receive () - { - m_Socket->async_read_some (boost::asio::buffer (m_Buffer, 8192), - boost::bind(&HTTPConnection::HandleReceive, this, - boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred)); - } - - void HTTPConnection::HandleReceive (const boost::system::error_code& ecode, std::size_t bytes_transferred) - { - if (!ecode) - { - m_Buffer[bytes_transferred] = 0; - - request m_Request; - ExtractRequest (m_Request); - parseHeaders (m_Buffer, m_Request.headers); - - LogPrint("Requesting ", m_Request.host, " with path ", m_Request.uri, " and method ", m_Request.method); - HandleDestinationRequest (m_Request.host, m_Request.uri); - } - else if (ecode != boost::asio::error::operation_aborted) - Terminate (); - } - - void HTTPConnection::parseHeaders(const std::string& h, std::vector
& hm) { + void HTTPProxyConnection::parseHeaders(const std::string& h, std::vector
& hm) { std::string str (h); std::string::size_type idx; std::string t; @@ -97,7 +30,7 @@ namespace proxy } } - void HTTPConnection::ExtractRequest (request &m_Request) + void HTTPProxyConnection::ExtractRequest(request &m_Request) { std::string requestString = m_Buffer; int idx=requestString.find(" "); @@ -123,162 +56,68 @@ namespace proxy m_Request.method = method; m_Request.host = server; } - - void HTTPConnection::HandleWriteReply (const boost::system::error_code& ecode) - { - Terminate (); - } - void HTTPConnection::HandleWrite (const boost::system::error_code& ecode) - { - if (ecode || (m_Stream && !m_Stream->IsOpen ())) - Terminate (); - else // data keeps coming - AsyncStreamReceive (); - } - void HTTPConnection::HandleDestinationRequest (const std::string& address, const std::string& uri) - { - i2p::data::IdentHash destination; - std::string fullAddress; - if (address.find (".b32.i2p") != std::string::npos) - { - int li = address.find_first_of ("."); - std::string newaddress = address.substr (0, li); - if (i2p::data::Base32ToByteStream (newaddress.c_str (), newaddress.length (), (uint8_t *)destination, 32) != 32) - { - LogPrint ("Invalid Base32 address ", newaddress); - return; - } - fullAddress = newaddress + ".b32.i2p"; - } - else - { - auto addr = i2p::data::netdb.FindAddress (address); - if (!addr) - { - LogPrint ("Unknown address ", address); - SendReply(""+ i2p::proxy::itoopieImage +"
Unknown address " + address + ""); - return; - } - destination = *addr; - fullAddress = address; - } - - auto leaseSet = i2p::data::netdb.FindLeaseSet (destination); - if (!leaseSet || !leaseSet->HasNonExpiredLeases ()) - { - i2p::data::netdb.Subscribe(destination); - std::this_thread::sleep_for (std::chrono::seconds(10)); // wait for 10 seconds - leaseSet = i2p::data::netdb.FindLeaseSet (destination); - if (!leaseSet || !leaseSet->HasNonExpiredLeases ()) // still no LeaseSet - { - SendReply(leaseSet ? ""+ i2p::proxy::itoopieImage +"
Leases expired" : ""+ i2p::proxy::itoopieImage +"LeaseSet not found"); - return; - } - } - if (!m_Stream) - m_Stream = i2p::stream::CreateStream (*leaseSet); - if (m_Stream) - { - std::string request = "GET " + uri + " HTTP/1.1\n Host:" + fullAddress + "\n"; - m_Stream->Send ((uint8_t *)request.c_str (), request.length (), 10); - AsyncStreamReceive (); - } - } - - void HTTPConnection::AsyncStreamReceive () - { - if (m_Stream) - m_Stream->AsyncReceive (boost::asio::buffer (m_StreamBuffer, 8192), - boost::protect (boost::bind (&HTTPConnection::HandleStreamReceive, this, - boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred)), - 45); // 45 seconds timeout - } - - void HTTPConnection::HandleStreamReceive (const boost::system::error_code& ecode, std::size_t bytes_transferred) - { - if (bytes_transferred) - { - boost::asio::async_write (*m_Socket, boost::asio::buffer (m_StreamBuffer, bytes_transferred), - boost::bind (&HTTPConnection::HandleWrite, this, boost::asio::placeholders::error)); - } - else - { - if (m_Stream && m_Stream->IsOpen ()) - SendReply (""+ i2p::proxy::itoopieImage +"
Not responding"); - else - Terminate (); - } - } - - void HTTPConnection::SendReply (const std::string& content) - { - m_Reply.content = content; - m_Reply.headers.resize(2); - m_Reply.headers[0].name = "Content-Length"; - m_Reply.headers[0].value = boost::lexical_cast(m_Reply.content.size()); - m_Reply.headers[1].name = "Content-Type"; - m_Reply.headers[1].value = "text/html"; - - boost::asio::async_write (*m_Socket, m_Reply.to_buffers(), - boost::bind (&HTTPConnection::HandleWriteReply, this, - boost::asio::placeholders::error)); - } - - - HTTPProxy::HTTPProxy (int port): - m_Thread (nullptr), m_Work (m_Service), - m_Acceptor (m_Service, boost::asio::ip::tcp::endpoint (boost::asio::ip::tcp::v4(), port)), - m_NewSocket (nullptr) - { - - } - - HTTPProxy::~HTTPProxy () - { - Stop (); - } - - void HTTPProxy::Start () - { - m_Thread = new std::thread (std::bind (&HTTPProxy::Run, this)); - m_Acceptor.listen (); - Accept (); - } - - void HTTPProxy::Stop () - { - m_Acceptor.close(); - m_Service.stop (); - if (m_Thread) - { - m_Thread->join (); - delete m_Thread; - m_Thread = nullptr; - } - } + void HTTPProxyConnection::RunRequest() + { + request m_Request; + ExtractRequest(m_Request); + parseHeaders(m_Buffer, m_Request.headers); + + LogPrint("Requesting ", m_Request.host, " with path ", m_Request.uri, " and method ", m_Request.method); + HandleDestinationRequest(m_Request.host, m_Request.uri); + } + + //void HTTPConnection::HandleDestinationRequest (const std::string& address, const std::string& uri) + //{ + // i2p::data::IdentHash destination; + // std::string fullAddress; + // if (address.find (".b32.i2p") != std::string::npos) + // { + // int li = address.find_first_of ("."); + // std::string newaddress = address.substr (0, li); + // if (i2p::data::Base32ToByteStream (newaddress.c_str (), newaddress.length (), (uint8_t *)destination, 32) != 32) + // { + // LogPrint ("Invalid Base32 address ", newaddress); + // return; + // } + // fullAddress = newaddress + ".b32.i2p"; + // } + // else + // { + // auto addr = i2p::data::netdb.FindAddress (address); + // if (!addr) + // { + // LogPrint ("Unknown address ", address); + // SendReply(""+ i2p::proxy::itoopieImage +"
Unknown address " + address + ""); + // return; + // } + // destination = *addr; + // fullAddress = address; + // } + // + // auto leaseSet = i2p::data::netdb.FindLeaseSet (destination); + // if (!leaseSet || !leaseSet->HasNonExpiredLeases ()) + // { + // i2p::data::netdb.Subscribe(destination); + // std::this_thread::sleep_for (std::chrono::seconds(10)); // wait for 10 seconds + // leaseSet = i2p::data::netdb.FindLeaseSet (destination); + // if (!leaseSet || !leaseSet->HasNonExpiredLeases ()) // still no LeaseSet + // { + // SendReply(leaseSet ? ""+ i2p::proxy::itoopieImage +"
Leases expired" : ""+ i2p::proxy::itoopieImage +"LeaseSet not found"); + // return; + // } + // } + // if (!m_Stream) + // m_Stream = i2p::stream::CreateStream (*leaseSet); + // if (m_Stream) + // { + // std::string request = "GET " + uri + " HTTP/1.1\n Host:" + fullAddress + "\n"; + // m_Stream->Send ((uint8_t *)request.c_str (), request.length (), 10); + // AsyncStreamReceive (); + // } + //} - void HTTPProxy::Run () - { - m_Service.run (); - } - - void HTTPProxy::Accept () - { - m_NewSocket = new boost::asio::ip::tcp::socket (m_Service); - m_Acceptor.async_accept (*m_NewSocket, boost::bind (&HTTPProxy::HandleAccept, this, - boost::asio::placeholders::error)); - } - - void HTTPProxy::HandleAccept(const boost::system::error_code& ecode) - { - if (!ecode) - { - new HTTPConnection (m_NewSocket); - Accept (); - } - } } } diff --git a/HTTPProxy.h b/HTTPProxy.h index f0e04a23..497e90af 100644 --- a/HTTPProxy.h +++ b/HTTPProxy.h @@ -6,91 +6,34 @@ #include #include +#include "HTTPServer.h" + namespace i2p { namespace proxy { - const std::string itoopieImage = "\"\""; - - class HTTPConnection + class HTTPProxyConnection : public i2p::util::HTTPConnection { - struct header - { - std::string name; - std::string value; - }; - - struct request - { - std::string method; - std::string uri; - std::string host; - int http_version_major; - int http_version_minor; - std::vector
headers; - }; - - struct reply - { - std::vector
headers; - std::string content; - - std::vector to_buffers(); - }; - public: + HTTPProxyConnection (boost::asio::ip::tcp::socket * socket): HTTPConnection(socket) { }; - HTTPConnection (boost::asio::ip::tcp::socket * socket): m_Socket (socket), m_Stream (nullptr) { Receive (); }; - ~HTTPConnection () { delete m_Socket; } - - private: - - void Terminate (); - void Receive (); - 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); - - void HandleDestinationRequest (const std::string& address, const std::string& uri); - void ExtractRequest (request& m_Request); + protected: + void RunRequest(); void parseHeaders(const std::string& h, std::vector
& hm); - - private: - - boost::asio::ip::tcp::socket * m_Socket; - i2p::stream::Stream * m_Stream; - char m_Buffer[8192], m_StreamBuffer[8192]; - request m_Request; - reply m_Reply; - }; + void ExtractRequest(request &m_Request); + }; - class HTTPProxy + class HTTPProxy : public i2p::util::HTTPServer { public: - - HTTPProxy (int port); - ~HTTPProxy (); - - void Start (); - void Stop (); + HTTPProxy (int port): HTTPServer(port) {}; 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; - }; + void CreateConnection(boost::asio::ip::tcp::socket * m_NewSocket) + { + new HTTPProxyConnection(m_NewSocket); + } + }; } } diff --git a/HTTPServer.cpp b/HTTPServer.cpp index d2061164..b7a2989a 100644 --- a/HTTPServer.cpp +++ b/HTTPServer.cpp @@ -64,28 +64,33 @@ namespace util if (!ecode) { m_Buffer[bytes_transferred] = 0; - auto address = ExtractAddress (); - if (address.length () > 1) // not just '/' - { - std::string uri ("/"), b32; - size_t pos = address.find ('/', 1); - if (pos == std::string::npos) - b32 = address.substr (1); // excluding leading '/' to end of line - else - { - b32 = address.substr (1, pos - 1); // excluding leading '/' to next '/' - uri = address.substr (pos); // rest of line - } - - HandleDestinationRequest (b32, uri); - } - else - HandleRequest (); + RunRequest(); } else if (ecode != boost::asio::error::operation_aborted) Terminate (); } + void HTTPConnection::RunRequest () + { + auto address = ExtractAddress (); + if (address.length () > 1) // not just '/' + { + std::string uri ("/"), b32; + size_t pos = address.find ('/', 1); + if (pos == std::string::npos) + b32 = address.substr (1); // excluding leading '/' to end of line + else + { + b32 = address.substr (1, pos - 1); // excluding leading '/' to next '/' + uri = address.substr (pos); // rest of line + } + + HandleDestinationRequest (b32, uri); + } + else + HandleRequest (); + } + std::string HTTPConnection::ExtractAddress () { char * get = strstr (m_Buffer, "GET"); @@ -215,7 +220,7 @@ namespace util if (!addr) { LogPrint ("Unknown address ", address); - SendReply ("Unknown address"); + SendReply ("" + itoopieImage + "
Unknown address " + address + ""); return; } destination = *addr; @@ -226,7 +231,7 @@ namespace util if (i2p::data::Base32ToByteStream (address.c_str (), address.length (), (uint8_t *)destination, 32) != 32) { LogPrint ("Invalid Base32 address ", address); - SendReply ("Invalid Base32 address"); + SendReply ("" + itoopieImage + "
Invalid Base32 address"); return; } fullAddress = address + ".b32.i2p"; @@ -240,7 +245,7 @@ namespace util leaseSet = i2p::data::netdb.FindLeaseSet (destination); if (!leaseSet || !leaseSet->HasNonExpiredLeases ()) // still no LeaseSet { - SendReply (leaseSet ? "Leases expired" : "LeaseSet not found"); + SendReply (leaseSet ? "" + itoopieImage + "
Leases expired" : "" + itoopieImage + "LeaseSet not found"); return; } } @@ -273,7 +278,7 @@ namespace util else { if (m_Stream && m_Stream->IsOpen ()) - SendReply ("Not responding"); + SendReply ("" + itoopieImage + "
Not responding"); else Terminate (); } @@ -341,10 +346,16 @@ namespace util { if (!ecode) { - new HTTPConnection (m_NewSocket); + CreateConnection(m_NewSocket); // new HTTPConnection(m_NewSocket); Accept (); } } + + void HTTPServer::CreateConnection(boost::asio::ip::tcp::socket * m_NewSocket) + { + new HTTPConnection (m_NewSocket); + } + } } diff --git a/HTTPServer.h b/HTTPServer.h index 3fed5bd0..dca004b0 100644 --- a/HTTPServer.h +++ b/HTTPServer.h @@ -13,33 +13,37 @@ namespace util { class HTTPConnection { - struct header - { - std::string name; - std::string value; - }; + const std::string itoopieImage = "\"\""; + + protected: + struct header + { + std::string name; + std::string value; + }; - struct request - { - std::string method; - std::string uri; - int http_version_major; - int http_version_minor; - std::vector
headers; - }; - - struct reply - { - std::vector
headers; - std::string content; - - std::vector to_buffers(); - }; + struct request + { + std::string method; + std::string uri; + std::string host; + int http_version_major; + int http_version_minor; + std::vector
headers; + }; + + struct reply + { + std::vector
headers; + std::string content; + + std::vector to_buffers(); + }; public: HTTPConnection (boost::asio::ip::tcp::socket * socket): m_Socket (socket), m_Stream (nullptr) { Receive (); }; - ~HTTPConnection () { delete m_Socket; } + virtual ~HTTPConnection() { delete m_Socket; } private: @@ -53,17 +57,20 @@ namespace util void SendReply (const std::string& content); void HandleRequest (); - void HandleDestinationRequest (const std::string& address, const std::string& uri); void FillContent (std::stringstream& s); std::string ExtractAddress (); - private: + protected: boost::asio::ip::tcp::socket * m_Socket; i2p::stream::Stream * m_Stream; char m_Buffer[8192], m_StreamBuffer[8192]; request m_Request; reply m_Reply; + + protected: + virtual void HandleDestinationRequest(const std::string& address, const std::string& uri); + virtual void RunRequest (); }; class HTTPServer @@ -71,7 +78,7 @@ namespace util public: HTTPServer (int port); - ~HTTPServer (); + virtual ~HTTPServer (); void Start (); void Stop (); @@ -89,6 +96,9 @@ namespace util 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); }; } }