diff options
Diffstat (limited to 'src/HTTPServer')
-rw-r--r-- | src/HTTPServer/CMakeLists.txt | 27 | ||||
-rw-r--r-- | src/HTTPServer/HTTPConnection.cpp | 18 | ||||
-rw-r--r-- | src/HTTPServer/HTTPConnection.h | 12 | ||||
-rw-r--r-- | src/HTTPServer/HTTPMessage.cpp | 10 | ||||
-rw-r--r-- | src/HTTPServer/HTTPMessage.h | 2 | ||||
-rw-r--r-- | src/HTTPServer/HTTPServer.cpp | 54 | ||||
-rw-r--r-- | src/HTTPServer/HTTPServer.h | 10 | ||||
-rw-r--r-- | src/HTTPServer/MultipartParser.cpp | 4 | ||||
-rw-r--r-- | src/HTTPServer/NameValueParser.cpp | 4 | ||||
-rw-r--r-- | src/HTTPServer/SslHTTPConnection.cpp | 107 | ||||
-rw-r--r-- | src/HTTPServer/SslHTTPConnection.h | 45 |
11 files changed, 263 insertions, 30 deletions
diff --git a/src/HTTPServer/CMakeLists.txt b/src/HTTPServer/CMakeLists.txt index dc894368d..b0efc810d 100644 --- a/src/HTTPServer/CMakeLists.txt +++ b/src/HTTPServer/CMakeLists.txt @@ -4,9 +4,26 @@ project (MCServer) include_directories ("${PROJECT_SOURCE_DIR}/../") -file(GLOB SOURCE - "*.cpp" - "*.h" -) +SET (SRCS + EnvelopeParser.cpp + HTTPConnection.cpp + HTTPFormParser.cpp + HTTPMessage.cpp + HTTPServer.cpp + MultipartParser.cpp + NameValueParser.cpp + SslHTTPConnection.cpp) -add_library(HTTPServer ${SOURCE}) +SET (HDRS + EnvelopeParser.h + HTTPConnection.h + HTTPFormParser.h + HTTPMessage.h + HTTPServer.h + MultipartParser.h + NameValueParser.h + SslHTTPConnection.h) + +if(NOT MSVC) + add_library(HTTPServer ${SRCS} ${HDRS}) +endif() diff --git a/src/HTTPServer/HTTPConnection.cpp b/src/HTTPServer/HTTPConnection.cpp index da4df0e34..b9c762e7c 100644 --- a/src/HTTPServer/HTTPConnection.cpp +++ b/src/HTTPServer/HTTPConnection.cpp @@ -26,7 +26,9 @@ cHTTPConnection::cHTTPConnection(cHTTPServer & a_HTTPServer) : cHTTPConnection::~cHTTPConnection() { + // LOGD("HTTP: Connection deleting: %p", this); delete m_CurrentRequest; + m_CurrentRequest = NULL; } @@ -98,7 +100,7 @@ void cHTTPConnection::AwaitNextRequest(void) { case wcsRecvHeaders: { - // Nothing has been received yet, or a special response was given (SendStatusAndReason() or SendNeedAuth() ) + // Nothing has been received yet, or a special response was given (SendStatusAndReason() or SendNeedAuth()) break; } @@ -144,7 +146,7 @@ void cHTTPConnection::Terminate(void) -void cHTTPConnection::DataReceived(const char * a_Data, size_t a_Size) +bool cHTTPConnection::DataReceived(const char * a_Data, size_t a_Size) { switch (m_State) { @@ -162,12 +164,12 @@ void cHTTPConnection::DataReceived(const char * a_Data, size_t a_Size) m_CurrentRequest = NULL; m_State = wcsInvalid; m_HTTPServer.CloseConnection(*this); - return; + return true; } if (m_CurrentRequest->IsInHeaders()) { // The request headers are not yet complete - return; + return false; } // The request has finished parsing its headers successfully, notify of it: @@ -183,13 +185,12 @@ void cHTTPConnection::DataReceived(const char * a_Data, size_t a_Size) // Process the rest of the incoming data into the request body: if (a_Size > BytesConsumed) { - DataReceived(a_Data + BytesConsumed, a_Size - BytesConsumed); + return cHTTPConnection::DataReceived(a_Data + BytesConsumed, a_Size - BytesConsumed); } else { - DataReceived("", 0); // If the request has zero body length, let it be processed right-away + return cHTTPConnection::DataReceived("", 0); // If the request has zero body length, let it be processed right-away } - break; } case wcsRecvBody: @@ -209,7 +210,7 @@ void cHTTPConnection::DataReceived(const char * a_Data, size_t a_Size) { m_State = wcsInvalid; m_HTTPServer.CloseConnection(*this); - return; + return true; } delete m_CurrentRequest; m_CurrentRequest = NULL; @@ -223,6 +224,7 @@ void cHTTPConnection::DataReceived(const char * a_Data, size_t a_Size) break; } } + return false; } diff --git a/src/HTTPServer/HTTPConnection.h b/src/HTTPServer/HTTPConnection.h index fc11f1ba6..6ea8a1ae8 100644 --- a/src/HTTPServer/HTTPConnection.h +++ b/src/HTTPServer/HTTPConnection.h @@ -91,9 +91,15 @@ protected: // cSocketThreads::cCallback overrides: - virtual void DataReceived (const char * a_Data, size_t a_Size) override; // Data is received from the client - virtual void GetOutgoingData(AString & a_Data) override; // Data can be sent to client - virtual void SocketClosed (void) override; // The socket has been closed for any reason + /** Data is received from the client. + Returns true if the connection has been closed as the result of parsing the data. */ + virtual bool DataReceived(const char * a_Data, size_t a_Size) override; + + /** Data can be sent to client */ + virtual void GetOutgoingData(AString & a_Data) override; + + /** The socket has been closed for any reason */ + virtual void SocketClosed(void) override; } ; typedef std::vector<cHTTPConnection *> cHTTPConnections; diff --git a/src/HTTPServer/HTTPMessage.cpp b/src/HTTPServer/HTTPMessage.cpp index 4a3611050..4226352e9 100644 --- a/src/HTTPServer/HTTPMessage.cpp +++ b/src/HTTPServer/HTTPMessage.cpp @@ -20,7 +20,7 @@ -/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// // cHTTPMessage: cHTTPMessage::cHTTPMessage(eKind a_Kind) : @@ -64,7 +64,7 @@ void cHTTPMessage::AddHeader(const AString & a_Key, const AString & a_Value) -/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// // cHTTPRequest: cHTTPRequest::cHTTPRequest(void) : @@ -139,7 +139,7 @@ AString cHTTPRequest::GetBareURL(void) const size_t cHTTPRequest::ParseRequestLine(const char * a_Data, size_t a_Size) -{ +{ m_IncomingHeaderData.append(a_Data, a_Size); size_t IdxEnd = m_IncomingHeaderData.size(); @@ -201,7 +201,7 @@ size_t cHTTPRequest::ParseRequestLine(const char * a_Data, size_t a_Size) return AString::npos; } // Check that there's HTTP/version at the end - if (strncmp(a_Data + URLEnd + 1, "HTTP/1.", 7) != 0) + if (strncmp(m_IncomingHeaderData.c_str() + URLEnd + 1, "HTTP/1.", 7) != 0) { m_IsValid = false; return AString::npos; @@ -248,7 +248,7 @@ void cHTTPRequest::OnHeaderLine(const AString & a_Key, const AString & a_Value) -/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// // cHTTPResponse: cHTTPResponse::cHTTPResponse(void) : diff --git a/src/HTTPServer/HTTPMessage.h b/src/HTTPServer/HTTPMessage.h index dab942136..e402c8ad6 100644 --- a/src/HTTPServer/HTTPMessage.h +++ b/src/HTTPServer/HTTPMessage.h @@ -33,7 +33,7 @@ public: cHTTPMessage(eKind a_Kind); // Force a virtual destructor in all descendants - virtual ~cHTTPMessage() {}; + virtual ~cHTTPMessage() {} /** Adds a header into the internal map of headers. Recognizes special headers: Content-Type and Content-Length */ void AddHeader(const AString & a_Key, const AString & a_Value); diff --git a/src/HTTPServer/HTTPServer.cpp b/src/HTTPServer/HTTPServer.cpp index eaf8405a3..8eabe5cb2 100644 --- a/src/HTTPServer/HTTPServer.cpp +++ b/src/HTTPServer/HTTPServer.cpp @@ -8,6 +8,7 @@ #include "HTTPMessage.h" #include "HTTPConnection.h" #include "HTTPFormParser.h" +#include "SslHTTPConnection.h" @@ -117,12 +118,12 @@ class cDebugCallbacks : -/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// // cHTTPServer: cHTTPServer::cHTTPServer(void) : - m_ListenThreadIPv4(*this, cSocket::IPv4, "WebServer IPv4"), - m_ListenThreadIPv6(*this, cSocket::IPv6, "WebServer IPv6"), + m_ListenThreadIPv4(*this, cSocket::IPv4, "WebServer"), + m_ListenThreadIPv6(*this, cSocket::IPv6, "WebServer"), m_Callbacks(NULL) { } @@ -142,7 +143,44 @@ cHTTPServer::~cHTTPServer() bool cHTTPServer::Initialize(const AString & a_PortsIPv4, const AString & a_PortsIPv6) { + // Read the HTTPS cert + key: + AString CertFile = cFile::ReadWholeFile("webadmin/httpscert.crt"); + AString KeyFile = cFile::ReadWholeFile("webadmin/httpskey.pem"); + if (!CertFile.empty() && !KeyFile.empty()) + { + m_Cert.reset(new cX509Cert); + int res = m_Cert->Parse(CertFile.data(), CertFile.size()); + if (res == 0) + { + m_CertPrivKey.reset(new cCryptoKey); + int res2 = m_CertPrivKey->ParsePrivate(KeyFile.data(), KeyFile.size(), ""); + if (res2 != 0) + { + // Reading the private key failed, reset the cert: + LOGWARNING("WebServer: Cannot read HTTPS certificate private key: -0x%x", -res2); + m_Cert.reset(); + } + } + else + { + LOGWARNING("WebServer: Cannot read HTTPS certificate: -0x%x", -res); + } + } + + // Notify the admin about the HTTPS / HTTP status + if (m_Cert.get() == NULL) + { + LOGWARNING("WebServer: The server is running in unsecure HTTP mode."); + } + else + { + LOGINFO("WebServer: The server is running in secure HTTPS mode."); + } + + // Open up requested ports: bool HasAnyPort; + m_ListenThreadIPv4.SetReuseAddr(true); + m_ListenThreadIPv6.SetReuseAddr(true); HasAnyPort = m_ListenThreadIPv4.Initialize(a_PortsIPv4); HasAnyPort = m_ListenThreadIPv6.Initialize(a_PortsIPv6) || HasAnyPort; if (!HasAnyPort) @@ -195,7 +233,15 @@ void cHTTPServer::Stop(void) void cHTTPServer::OnConnectionAccepted(cSocket & a_Socket) { - cHTTPConnection * Connection = new cHTTPConnection(*this); + cHTTPConnection * Connection; + if (m_Cert.get() != NULL) + { + Connection = new cSslHTTPConnection(*this, m_Cert, m_CertPrivKey); + } + else + { + Connection = new cHTTPConnection(*this); + } m_SocketThreads.AddClient(a_Socket, Connection); cCSLock Lock(m_CSConnections); m_Connections.push_back(Connection); diff --git a/src/HTTPServer/HTTPServer.h b/src/HTTPServer/HTTPServer.h index 8eff7d879..522b7da62 100644 --- a/src/HTTPServer/HTTPServer.h +++ b/src/HTTPServer/HTTPServer.h @@ -12,6 +12,9 @@ #include "../OSSupport/ListenThread.h" #include "../OSSupport/SocketThreads.h" #include "inifile/iniFile.h" +#include "PolarSSL++/RsaPrivateKey.h" +#include "PolarSSL++/CryptoKey.h" +#include "PolarSSL++/X509Cert.h" @@ -66,6 +69,7 @@ public: protected: friend class cHTTPConnection; + friend class cSslHTTPConnection; cListenThread m_ListenThreadIPv4; cListenThread m_ListenThreadIPv6; @@ -78,6 +82,12 @@ protected: /// The callbacks to call for various events cCallbacks * m_Callbacks; + /** The server certificate to use for the SSL connections */ + cX509CertPtr m_Cert; + + /** The private key for m_Cert. */ + cCryptoKeyPtr m_CertPrivKey; + // cListenThread::cCallback overrides: virtual void OnConnectionAccepted(cSocket & a_Socket) override; diff --git a/src/HTTPServer/MultipartParser.cpp b/src/HTTPServer/MultipartParser.cpp index 309495dd7..09732c5f7 100644 --- a/src/HTTPServer/MultipartParser.cpp +++ b/src/HTTPServer/MultipartParser.cpp @@ -21,7 +21,7 @@ -/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// // self-test: #if 0 @@ -87,7 +87,7 @@ ThisIsIgnoredEpilogue"; -/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// // cMultipartParser: diff --git a/src/HTTPServer/NameValueParser.cpp b/src/HTTPServer/NameValueParser.cpp index 3f6c17dda..b345fef88 100644 --- a/src/HTTPServer/NameValueParser.cpp +++ b/src/HTTPServer/NameValueParser.cpp @@ -69,7 +69,7 @@ public: -/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// // cNameValueParser: cNameValueParser::cNameValueParser(bool a_AllowsKeyOnly) : @@ -97,7 +97,7 @@ void cNameValueParser::Parse(const char * a_Data, size_t a_Size) { ASSERT(m_State != psFinished); // Calling Parse() after Finish() is wrong! - int Last = 0; + size_t Last = 0; for (size_t i = 0; i < a_Size;) { switch (m_State) diff --git a/src/HTTPServer/SslHTTPConnection.cpp b/src/HTTPServer/SslHTTPConnection.cpp new file mode 100644 index 000000000..d237089d9 --- /dev/null +++ b/src/HTTPServer/SslHTTPConnection.cpp @@ -0,0 +1,107 @@ + +// SslHTTPConnection.cpp + +// Implements the cSslHTTPConnection class representing a HTTP connection made over a SSL link + +#include "Globals.h" +#include "SslHTTPConnection.h" +#include "HTTPServer.h" + + + + + +cSslHTTPConnection::cSslHTTPConnection(cHTTPServer & a_HTTPServer, const cX509CertPtr & a_Cert, const cCryptoKeyPtr & a_PrivateKey) : + super(a_HTTPServer), + m_Ssl(64000), + m_Cert(a_Cert), + m_PrivateKey(a_PrivateKey) +{ + m_Ssl.Initialize(false); + m_Ssl.SetOwnCert(a_Cert, a_PrivateKey); +} + + + + + +bool cSslHTTPConnection::DataReceived(const char * a_Data, size_t a_Size) +{ + // If there is outgoing data in the queue, notify the server that it should write it out: + if (!m_OutgoingData.empty()) + { + m_HTTPServer.NotifyConnectionWrite(*this); + } + + // Process the received data: + const char * Data = a_Data; + size_t Size = a_Size; + for (;;) + { + // Try to write as many bytes into Ssl's "incoming" buffer as possible: + size_t BytesWritten = 0; + if (Size > 0) + { + BytesWritten = m_Ssl.WriteIncoming(Data, Size); + Data += BytesWritten; + Size -= BytesWritten; + } + + // Try to read as many bytes from SSL's decryption as possible: + char Buffer[32000]; + int NumRead = m_Ssl.ReadPlain(Buffer, sizeof(Buffer)); + if (NumRead > 0) + { + if (super::DataReceived(Buffer, (size_t)NumRead)) + { + // The socket has been closed, and the object is already deleted. Bail out. + return true; + } + } + + // If both failed, bail out: + if ((BytesWritten == 0) && (NumRead <= 0)) + { + return false; + } + } +} + + + + + +void cSslHTTPConnection::GetOutgoingData(AString & a_Data) +{ + for (;;) + { + // Write as many bytes from our buffer to SSL's encryption as possible: + int NumWritten = 0; + if (!m_OutgoingData.empty()) + { + NumWritten = m_Ssl.WritePlain(m_OutgoingData.data(), m_OutgoingData.size()); + if (NumWritten > 0) + { + m_OutgoingData.erase(0, (size_t)NumWritten); + } + } + + // Read as many bytes from SSL's "outgoing" buffer as possible: + char Buffer[32000]; + size_t NumBytes = m_Ssl.ReadOutgoing(Buffer, sizeof(Buffer)); + if (NumBytes > 0) + { + a_Data.append(Buffer, NumBytes); + } + + // If both failed, bail out: + if ((NumWritten <= 0) && (NumBytes == 0)) + { + return; + } + } +} + + + + diff --git a/src/HTTPServer/SslHTTPConnection.h b/src/HTTPServer/SslHTTPConnection.h new file mode 100644 index 000000000..c2c1585cd --- /dev/null +++ b/src/HTTPServer/SslHTTPConnection.h @@ -0,0 +1,45 @@ + +// SslHTTPConnection.h + +// Declared the cSslHTTPConnection class representing a HTTP connection made over a SSL link + + + + + +#pragma once + +#include "HTTPConnection.h" +#include "PolarSSL++/BufferedSslContext.h" + + + + + +class cSslHTTPConnection : + public cHTTPConnection +{ + typedef cHTTPConnection super; + +public: + /** Creates a new connection on the specified server. + Sends the specified cert as the server certificate, uses the private key for decryption. */ + cSslHTTPConnection(cHTTPServer & a_HTTPServer, const cX509CertPtr & a_Cert, const cCryptoKeyPtr & a_PrivateKey); + +protected: + cBufferedSslContext m_Ssl; + + /** The certificate to send to the client */ + cX509CertPtr m_Cert; + + /** The private key used for the certificate */ + cCryptoKeyPtr m_PrivateKey; + + // cHTTPConnection overrides: + virtual bool DataReceived (const char * a_Data, size_t a_Size) override; // Data is received from the client + virtual void GetOutgoingData(AString & a_Data) override; // Data can be sent to client +} ; + + + + |