summaryrefslogtreecommitdiffstats
path: root/src/HTTPServer
diff options
context:
space:
mode:
Diffstat (limited to 'src/HTTPServer')
-rw-r--r--src/HTTPServer/CMakeLists.txt27
-rw-r--r--src/HTTPServer/HTTPConnection.cpp18
-rw-r--r--src/HTTPServer/HTTPConnection.h12
-rw-r--r--src/HTTPServer/HTTPMessage.cpp10
-rw-r--r--src/HTTPServer/HTTPMessage.h2
-rw-r--r--src/HTTPServer/HTTPServer.cpp54
-rw-r--r--src/HTTPServer/HTTPServer.h10
-rw-r--r--src/HTTPServer/MultipartParser.cpp4
-rw-r--r--src/HTTPServer/NameValueParser.cpp4
-rw-r--r--src/HTTPServer/SslHTTPConnection.cpp107
-rw-r--r--src/HTTPServer/SslHTTPConnection.h45
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
+} ;
+
+
+
+