summaryrefslogtreecommitdiffstats
path: root/src/HTTPServer
diff options
context:
space:
mode:
Diffstat (limited to 'src/HTTPServer')
-rw-r--r--src/HTTPServer/CMakeLists.txt1
-rw-r--r--src/HTTPServer/EnvelopeParser.cpp4
-rw-r--r--src/HTTPServer/EnvelopeParser.h30
-rw-r--r--src/HTTPServer/HTTPConnection.cpp27
-rw-r--r--src/HTTPServer/HTTPConnection.h16
-rw-r--r--src/HTTPServer/HTTPFormParser.cpp6
-rw-r--r--src/HTTPServer/HTTPFormParser.h11
-rw-r--r--src/HTTPServer/HTTPMessage.cpp30
-rw-r--r--src/HTTPServer/HTTPMessage.h18
-rw-r--r--src/HTTPServer/HTTPServer.cpp52
-rw-r--r--src/HTTPServer/HTTPServer.h20
-rw-r--r--src/HTTPServer/MultipartParser.cpp8
-rw-r--r--src/HTTPServer/MultipartParser.h39
-rw-r--r--src/HTTPServer/NameValueParser.cpp10
-rw-r--r--src/HTTPServer/NameValueParser.h4
-rw-r--r--src/HTTPServer/SslHTTPConnection.cpp107
-rw-r--r--src/HTTPServer/SslHTTPConnection.h45
17 files changed, 327 insertions, 101 deletions
diff --git a/src/HTTPServer/CMakeLists.txt b/src/HTTPServer/CMakeLists.txt
index 3badc669f..dc894368d 100644
--- a/src/HTTPServer/CMakeLists.txt
+++ b/src/HTTPServer/CMakeLists.txt
@@ -6,6 +6,7 @@ include_directories ("${PROJECT_SOURCE_DIR}/../")
file(GLOB SOURCE
"*.cpp"
+ "*.h"
)
add_library(HTTPServer ${SOURCE})
diff --git a/src/HTTPServer/EnvelopeParser.cpp b/src/HTTPServer/EnvelopeParser.cpp
index 8dbe05f14..fd4f3836d 100644
--- a/src/HTTPServer/EnvelopeParser.cpp
+++ b/src/HTTPServer/EnvelopeParser.cpp
@@ -20,7 +20,7 @@ cEnvelopeParser::cEnvelopeParser(cCallbacks & a_Callbacks) :
-int cEnvelopeParser::Parse(const char * a_Data, int a_Size)
+size_t cEnvelopeParser::Parse(const char * a_Data, size_t a_Size)
{
if (!m_IsInHeaders)
{
@@ -55,7 +55,7 @@ int cEnvelopeParser::Parse(const char * a_Data, int a_Size)
{
// An error has occurred
m_IsInHeaders = false;
- return -1;
+ return AString::npos;
}
Last = idxCRLF + 2;
idxCRLF = m_IncomingData.find("\r\n", idxCRLF + 2);
diff --git a/src/HTTPServer/EnvelopeParser.h b/src/HTTPServer/EnvelopeParser.h
index 6430fbebf..e96d80abe 100644
--- a/src/HTTPServer/EnvelopeParser.h
+++ b/src/HTTPServer/EnvelopeParser.h
@@ -19,7 +19,10 @@ public:
class cCallbacks
{
public:
- /// Called when a full header line is parsed
+ // Force a virtual destructor in descendants:
+ virtual ~cCallbacks() {}
+
+ /** Called when a full header line is parsed */
virtual void OnHeaderLine(const AString & a_Key, const AString & a_Value) = 0;
} ;
@@ -27,40 +30,41 @@ public:
cEnvelopeParser(cCallbacks & a_Callbacks);
/** Parses the incoming data.
- Returns the number of bytes consumed from the input. The bytes not consumed are not part of the envelope header
+ Returns the number of bytes consumed from the input. The bytes not consumed are not part of the envelope header.
+ Returns AString::npos on error
*/
- int Parse(const char * a_Data, int a_Size);
+ size_t Parse(const char * a_Data, size_t a_Size);
- /// Makes the parser forget everything parsed so far, so that it can be reused for parsing another datastream
+ /** Makes the parser forget everything parsed so far, so that it can be reused for parsing another datastream */
void Reset(void);
- /// Returns true if more input is expected for the envelope header
+ /** Returns true if more input is expected for the envelope header */
bool IsInHeaders(void) const { return m_IsInHeaders; }
- /// Sets the IsInHeaders flag; used by cMultipartParser to simplify the parser initial conditions
+ /** Sets the IsInHeaders flag; used by cMultipartParser to simplify the parser initial conditions */
void SetIsInHeaders(bool a_IsInHeaders) { m_IsInHeaders = a_IsInHeaders; }
public:
- /// Callbacks to call for the various events
+ /** Callbacks to call for the various events */
cCallbacks & m_Callbacks;
- /// Set to true while the parser is still parsing the envelope headers. Once set to true, the parser will not consume any more data.
+ /** Set to true while the parser is still parsing the envelope headers. Once set to true, the parser will not consume any more data. */
bool m_IsInHeaders;
- /// Buffer for the incoming data until it is parsed
+ /** Buffer for the incoming data until it is parsed */
AString m_IncomingData;
- /// Holds the last parsed key; used for line-wrapped values
+ /** Holds the last parsed key; used for line-wrapped values */
AString m_LastKey;
- /// Holds the last parsed value; used for line-wrapped values
+ /** Holds the last parsed value; used for line-wrapped values */
AString m_LastValue;
- /// Notifies the callback of the key/value stored in m_LastKey/m_LastValue, then erases them
+ /** Notifies the callback of the key/value stored in m_LastKey/m_LastValue, then erases them */
void NotifyLast(void);
- /// Parses one line of header data. Returns true if successful
+ /** Parses one line of header data. Returns true if successful */
bool ParseLine(const char * a_Data, size_t a_Size);
} ;
diff --git a/src/HTTPServer/HTTPConnection.cpp b/src/HTTPServer/HTTPConnection.cpp
index 78b7ce4d9..b127e7091 100644
--- a/src/HTTPServer/HTTPConnection.cpp
+++ b/src/HTTPServer/HTTPConnection.cpp
@@ -26,6 +26,7 @@ cHTTPConnection::cHTTPConnection(cHTTPServer & a_HTTPServer) :
cHTTPConnection::~cHTTPConnection()
{
+ // LOGD("HTTP: Connection deleting: %p", this);
delete m_CurrentRequest;
}
@@ -67,10 +68,10 @@ void cHTTPConnection::Send(const cHTTPResponse & a_Response)
-void cHTTPConnection::Send(const void * a_Data, int a_Size)
+void cHTTPConnection::Send(const void * a_Data, size_t a_Size)
{
ASSERT(m_State == wcsSendingResp);
- AppendPrintf(m_OutgoingData, "%x\r\n", a_Size);
+ AppendPrintf(m_OutgoingData, SIZE_T_FMT_HEX "\r\n", a_Size);
m_OutgoingData.append((const char *)a_Data, a_Size);
m_OutgoingData.append("\r\n");
m_HTTPServer.NotifyConnectionWrite(*this);
@@ -144,7 +145,7 @@ void cHTTPConnection::Terminate(void)
-void cHTTPConnection::DataReceived(const char * a_Data, int a_Size)
+bool cHTTPConnection::DataReceived(const char * a_Data, size_t a_Size)
{
switch (m_State)
{
@@ -155,26 +156,26 @@ void cHTTPConnection::DataReceived(const char * a_Data, int a_Size)
m_CurrentRequest = new cHTTPRequest;
}
- int BytesConsumed = m_CurrentRequest->ParseHeaders(a_Data, a_Size);
- if (BytesConsumed < 0)
+ size_t BytesConsumed = m_CurrentRequest->ParseHeaders(a_Data, a_Size);
+ if (BytesConsumed == AString::npos)
{
delete m_CurrentRequest;
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:
m_State = wcsRecvBody;
m_HTTPServer.NewRequest(*this, *m_CurrentRequest);
m_CurrentRequestBodyRemaining = m_CurrentRequest->GetContentLength();
- if (m_CurrentRequestBodyRemaining < 0)
+ if (m_CurrentRequestBodyRemaining == AString::npos)
{
// The body length was not specified in the request, assume zero
m_CurrentRequestBodyRemaining = 0;
@@ -183,13 +184,12 @@ void cHTTPConnection::DataReceived(const char * a_Data, int 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:
@@ -197,7 +197,7 @@ void cHTTPConnection::DataReceived(const char * a_Data, int a_Size)
ASSERT(m_CurrentRequest != NULL);
if (m_CurrentRequestBodyRemaining > 0)
{
- int BytesToConsume = std::min(m_CurrentRequestBodyRemaining, a_Size);
+ size_t BytesToConsume = std::min(m_CurrentRequestBodyRemaining, (size_t)a_Size);
m_HTTPServer.RequestBody(*this, *m_CurrentRequest, a_Data, BytesToConsume);
m_CurrentRequestBodyRemaining -= BytesToConsume;
}
@@ -209,7 +209,7 @@ void cHTTPConnection::DataReceived(const char * a_Data, int a_Size)
{
m_State = wcsInvalid;
m_HTTPServer.CloseConnection(*this);
- return;
+ return true;
}
delete m_CurrentRequest;
m_CurrentRequest = NULL;
@@ -223,6 +223,7 @@ void cHTTPConnection::DataReceived(const char * a_Data, int a_Size)
break;
}
}
+ return false;
}
diff --git a/src/HTTPServer/HTTPConnection.h b/src/HTTPServer/HTTPConnection.h
index 5b8103554..6ea8a1ae8 100644
--- a/src/HTTPServer/HTTPConnection.h
+++ b/src/HTTPServer/HTTPConnection.h
@@ -51,7 +51,7 @@ public:
void Send(const cHTTPResponse & a_Response);
/** Sends the data as the response (may be called multiple times) */
- void Send(const void * a_Data, int a_Size);
+ void Send(const void * a_Data, size_t a_Size);
/** Sends the data as the response (may be called multiple times) */
void Send(const AString & a_Data) { Send(a_Data.data(), a_Data.size()); }
@@ -87,13 +87,19 @@ protected:
/** Number of bytes that remain to read for the complete body of the message to be received.
Valid only in wcsRecvBody */
- int m_CurrentRequestBodyRemaining;
+ size_t m_CurrentRequestBodyRemaining;
// cSocketThreads::cCallback overrides:
- virtual void DataReceived (const char * a_Data, int 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/HTTPFormParser.cpp b/src/HTTPServer/HTTPFormParser.cpp
index e661ea6f9..9ddfb82f1 100644
--- a/src/HTTPServer/HTTPFormParser.cpp
+++ b/src/HTTPServer/HTTPFormParser.cpp
@@ -52,7 +52,7 @@ cHTTPFormParser::cHTTPFormParser(cHTTPRequest & a_Request, cCallbacks & a_Callba
-cHTTPFormParser::cHTTPFormParser(eKind a_Kind, const char * a_Data, int a_Size, cCallbacks & a_Callbacks) :
+cHTTPFormParser::cHTTPFormParser(eKind a_Kind, const char * a_Data, size_t a_Size, cCallbacks & a_Callbacks) :
m_Callbacks(a_Callbacks),
m_Kind(a_Kind),
m_IsValid(true)
@@ -64,7 +64,7 @@ cHTTPFormParser::cHTTPFormParser(eKind a_Kind, const char * a_Data, int a_Size,
-void cHTTPFormParser::Parse(const char * a_Data, int a_Size)
+void cHTTPFormParser::Parse(const char * a_Data, size_t a_Size)
{
if (!m_IsValid)
{
@@ -243,7 +243,7 @@ void cHTTPFormParser::OnPartHeader(const AString & a_Key, const AString & a_Valu
-void cHTTPFormParser::OnPartData(const char * a_Data, int a_Size)
+void cHTTPFormParser::OnPartData(const char * a_Data, size_t a_Size)
{
if (m_CurrentPartName.empty())
{
diff --git a/src/HTTPServer/HTTPFormParser.h b/src/HTTPServer/HTTPFormParser.h
index a554ca5a4..edc6d2471 100644
--- a/src/HTTPServer/HTTPFormParser.h
+++ b/src/HTTPServer/HTTPFormParser.h
@@ -36,11 +36,14 @@ public:
class cCallbacks
{
public:
+ // Force a virtual destructor in descendants:
+ virtual ~cCallbacks() {}
+
/// Called when a new file part is encountered in the form data
virtual void OnFileStart(cHTTPFormParser & a_Parser, const AString & a_FileName) = 0;
/// Called when more file data has come for the current file in the form data
- virtual void OnFileData(cHTTPFormParser & a_Parser, const char * a_Data, int a_Size) = 0;
+ virtual void OnFileData(cHTTPFormParser & a_Parser, const char * a_Data, size_t a_Size) = 0;
/// Called when the current file part has ended in the form data
virtual void OnFileEnd(cHTTPFormParser & a_Parser) = 0;
@@ -51,10 +54,10 @@ public:
cHTTPFormParser(cHTTPRequest & a_Request, cCallbacks & a_Callbacks);
/// Creates a parser with the specified content type that reads data from a string
- cHTTPFormParser(eKind a_Kind, const char * a_Data, int a_Size, cCallbacks & a_Callbacks);
+ cHTTPFormParser(eKind a_Kind, const char * a_Data, size_t a_Size, cCallbacks & a_Callbacks);
/// Adds more data into the parser, as the request body is received
- void Parse(const char * a_Data, int a_Size);
+ void Parse(const char * a_Data, size_t a_Size);
/** Notifies that there's no more data incoming and the parser should finish its parsing.
Returns true if parsing successful
@@ -103,7 +106,7 @@ protected:
// cMultipartParser::cCallbacks overrides:
virtual void OnPartStart (void) override;
virtual void OnPartHeader(const AString & a_Key, const AString & a_Value) override;
- virtual void OnPartData (const char * a_Data, int a_Size) override;
+ virtual void OnPartData (const char * a_Data, size_t a_Size) override;
virtual void OnPartEnd (void) override;
} ;
diff --git a/src/HTTPServer/HTTPMessage.cpp b/src/HTTPServer/HTTPMessage.cpp
index 98627eb8e..44feda469 100644
--- a/src/HTTPServer/HTTPMessage.cpp
+++ b/src/HTTPServer/HTTPMessage.cpp
@@ -25,7 +25,7 @@
cHTTPMessage::cHTTPMessage(eKind a_Kind) :
m_Kind(a_Kind),
- m_ContentLength(-1)
+ m_ContentLength(AString::npos)
{
}
@@ -81,23 +81,23 @@ cHTTPRequest::cHTTPRequest(void) :
-int cHTTPRequest::ParseHeaders(const char * a_Data, int a_Size)
+size_t cHTTPRequest::ParseHeaders(const char * a_Data, size_t a_Size)
{
if (!m_IsValid)
{
- return -1;
+ return AString::npos;
}
if (m_Method.empty())
{
// The first line hasn't been processed yet
- int res = ParseRequestLine(a_Data, a_Size);
- if ((res < 0) || (res == a_Size))
+ size_t res = ParseRequestLine(a_Data, a_Size);
+ if ((res == AString::npos) || (res == a_Size))
{
return res;
}
- int res2 = m_EnvelopeParser.Parse(a_Data + res, a_Size - res);
- if (res2 < 0)
+ size_t res2 = m_EnvelopeParser.Parse(a_Data + res, a_Size - res);
+ if (res2 == AString::npos)
{
m_IsValid = false;
return res2;
@@ -107,8 +107,8 @@ int cHTTPRequest::ParseHeaders(const char * a_Data, int a_Size)
if (m_EnvelopeParser.IsInHeaders())
{
- int res = m_EnvelopeParser.Parse(a_Data, a_Size);
- if (res < 0)
+ size_t res = m_EnvelopeParser.Parse(a_Data, a_Size);
+ if (res == AString::npos)
{
m_IsValid = false;
}
@@ -138,7 +138,7 @@ AString cHTTPRequest::GetBareURL(void) const
-int cHTTPRequest::ParseRequestLine(const char * a_Data, int a_Size)
+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();
@@ -158,7 +158,7 @@ int cHTTPRequest::ParseRequestLine(const char * a_Data, int a_Size)
if (LineStart >= IdxEnd)
{
m_IsValid = false;
- return -1;
+ return AString::npos;
}
int NumSpaces = 0;
@@ -186,7 +186,7 @@ int cHTTPRequest::ParseRequestLine(const char * a_Data, int a_Size)
{
// Too many spaces in the request
m_IsValid = false;
- return -1;
+ return AString::npos;
}
}
NumSpaces += 1;
@@ -198,13 +198,13 @@ int cHTTPRequest::ParseRequestLine(const char * a_Data, int a_Size)
{
// LF too early, without a CR, without two preceeding spaces or too soon after the second space
m_IsValid = false;
- return -1;
+ 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 -1;
+ return AString::npos;
}
m_Method = m_IncomingHeaderData.substr(LineStart, MethodEnd - LineStart);
m_URL = m_IncomingHeaderData.substr(MethodEnd + 1, URLEnd - MethodEnd - 1);
diff --git a/src/HTTPServer/HTTPMessage.h b/src/HTTPServer/HTTPMessage.h
index ab3338db7..dab942136 100644
--- a/src/HTTPServer/HTTPMessage.h
+++ b/src/HTTPServer/HTTPMessage.h
@@ -39,10 +39,10 @@ public:
void AddHeader(const AString & a_Key, const AString & a_Value);
void SetContentType (const AString & a_ContentType) { m_ContentType = a_ContentType; }
- void SetContentLength(int a_ContentLength) { m_ContentLength = a_ContentLength; }
+ void SetContentLength(size_t a_ContentLength) { m_ContentLength = a_ContentLength; }
const AString & GetContentType (void) const { return m_ContentType; }
- int GetContentLength(void) const { return m_ContentLength; }
+ size_t GetContentLength(void) const { return m_ContentLength; }
protected:
typedef std::map<AString, AString> cNameValueMap;
@@ -54,8 +54,10 @@ protected:
/** Type of the content; parsed by AddHeader(), set directly by SetContentLength() */
AString m_ContentType;
- /** Length of the content that is to be received. -1 when the object is created, parsed by AddHeader() or set directly by SetContentLength() */
- int m_ContentLength;
+ /** Length of the content that is to be received.
+ AString::npos when the object is created.
+ Parsed by AddHeader() or set directly by SetContentLength() */
+ size_t m_ContentLength;
} ;
@@ -72,12 +74,12 @@ public:
cHTTPRequest(void);
/** Parses the request line and then headers from the received data.
- Returns the number of bytes consumed or a negative number for error
+ Returns the number of bytes consumed or AString::npos number for error
*/
- int ParseHeaders(const char * a_Data, int a_Size);
+ size_t ParseHeaders(const char * a_Data, size_t a_Size);
/** Returns true if the request did contain a Content-Length header */
- bool HasReceivedContentLength(void) const { return (m_ContentLength >= 0); }
+ bool HasReceivedContentLength(void) const { return (m_ContentLength != AString::npos); }
/** Returns the method used in the request */
const AString & GetMethod(void) const { return m_Method; }
@@ -145,7 +147,7 @@ protected:
/** Parses the incoming data for the first line (RequestLine)
Returns the number of bytes consumed, or -1 for an error
*/
- int ParseRequestLine(const char * a_Data, int a_Size);
+ size_t ParseRequestLine(const char * a_Data, size_t a_Size);
// cEnvelopeParser::cCallbacks overrides:
virtual void OnHeaderLine(const AString & a_Key, const AString & a_Value) override;
diff --git a/src/HTTPServer/HTTPServer.cpp b/src/HTTPServer/HTTPServer.cpp
index 4e9195a00..d288c83c9 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"
@@ -38,7 +39,7 @@ class cDebugCallbacks :
}
- virtual void OnRequestBody(cHTTPConnection & a_Connection, cHTTPRequest & a_Request, const char * a_Data, int a_Size) override
+ virtual void OnRequestBody(cHTTPConnection & a_Connection, cHTTPRequest & a_Request, const char * a_Data, size_t a_Size) override
{
UNUSED(a_Connection);
@@ -100,7 +101,7 @@ class cDebugCallbacks :
}
- virtual void OnFileData(cHTTPFormParser & a_Parser, const char * a_Data, int a_Size) override
+ virtual void OnFileData(cHTTPFormParser & a_Parser, const char * a_Data, size_t a_Size) override
{
// TODO
}
@@ -142,6 +143,41 @@ 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;
HasAnyPort = m_ListenThreadIPv4.Initialize(a_PortsIPv4);
HasAnyPort = m_ListenThreadIPv6.Initialize(a_PortsIPv6) || HasAnyPort;
@@ -195,7 +231,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);
@@ -242,7 +286,7 @@ void cHTTPServer::NewRequest(cHTTPConnection & a_Connection, cHTTPRequest & a_Re
-void cHTTPServer::RequestBody(cHTTPConnection & a_Connection, cHTTPRequest & a_Request, const char * a_Data, int a_Size)
+void cHTTPServer::RequestBody(cHTTPConnection & a_Connection, cHTTPRequest & a_Request, const char * a_Data, size_t a_Size)
{
m_Callbacks->OnRequestBody(a_Connection, a_Request, a_Data, a_Size);
}
diff --git a/src/HTTPServer/HTTPServer.h b/src/HTTPServer/HTTPServer.h
index 383abb4b6..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"
@@ -44,8 +47,9 @@ public:
*/
virtual void OnRequestBegun(cHTTPConnection & a_Connection, cHTTPRequest & a_Request) = 0;
- /// Called when another part of request body has arrived.
- virtual void OnRequestBody(cHTTPConnection & a_Connection, cHTTPRequest & a_Request, const char * a_Data, int a_Size) = 0;
+ /** Called when another part of request body has arrived.
+ May be called multiple times for a single request. */
+ virtual void OnRequestBody(cHTTPConnection & a_Connection, cHTTPRequest & a_Request, const char * a_Data, size_t a_Size) = 0;
/// Called when the request body has been fully received in previous calls to OnRequestBody()
virtual void OnRequestFinished(cHTTPConnection & a_Connection, cHTTPRequest & a_Request) = 0;
@@ -65,6 +69,7 @@ public:
protected:
friend class cHTTPConnection;
+ friend class cSslHTTPConnection;
cListenThread m_ListenThreadIPv4;
cListenThread m_ListenThreadIPv6;
@@ -77,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;
@@ -90,8 +101,9 @@ protected:
/// Called by cHTTPConnection when it finishes parsing the request header
void NewRequest(cHTTPConnection & a_Connection, cHTTPRequest & a_Request);
- /// Called by cHTTPConenction when it receives more data for the request body
- void RequestBody(cHTTPConnection & a_Connection, cHTTPRequest & a_Request, const char * a_Data, int a_Size);
+ /** Called by cHTTPConenction when it receives more data for the request body.
+ May be called multiple times for a single request. */
+ void RequestBody(cHTTPConnection & a_Connection, cHTTPRequest & a_Request, const char * a_Data, size_t a_Size);
/// Called by cHTTPConnection when it detects that the request has finished (all of its body has been received)
void RequestFinished(cHTTPConnection & a_Connection, cHTTPRequest & a_Request);
diff --git a/src/HTTPServer/MultipartParser.cpp b/src/HTTPServer/MultipartParser.cpp
index 14c2c00fa..309495dd7 100644
--- a/src/HTTPServer/MultipartParser.cpp
+++ b/src/HTTPServer/MultipartParser.cpp
@@ -97,8 +97,6 @@ cMultipartParser::cMultipartParser(const AString & a_ContentType, cCallbacks & a
m_EnvelopeParser(*this),
m_HasHadData(false)
{
- static AString s_Multipart = "multipart/";
-
// Check that the content type is multipart:
AString ContentType(a_ContentType);
if (strncmp(ContentType.c_str(), "multipart/", 10) != 0)
@@ -146,7 +144,7 @@ cMultipartParser::cMultipartParser(const AString & a_ContentType, cCallbacks & a
-void cMultipartParser::Parse(const char * a_Data, int a_Size)
+void cMultipartParser::Parse(const char * a_Data, size_t a_Size)
{
// Skip parsing if invalid
if (!m_IsValid)
@@ -160,8 +158,8 @@ void cMultipartParser::Parse(const char * a_Data, int a_Size)
{
if (m_EnvelopeParser.IsInHeaders())
{
- int BytesConsumed = m_EnvelopeParser.Parse(m_IncomingData.data(), m_IncomingData.size());
- if (BytesConsumed < 0)
+ size_t BytesConsumed = m_EnvelopeParser.Parse(m_IncomingData.data(), m_IncomingData.size());
+ if (BytesConsumed == AString::npos)
{
m_IsValid = false;
return;
diff --git a/src/HTTPServer/MultipartParser.h b/src/HTTPServer/MultipartParser.h
index d853929ed..ad76ad650 100644
--- a/src/HTTPServer/MultipartParser.h
+++ b/src/HTTPServer/MultipartParser.h
@@ -22,50 +22,53 @@ public:
class cCallbacks
{
public:
- /// Called when a new part starts
+ // Force a virtual destructor in descendants:
+ virtual ~cCallbacks() {}
+
+ /** Called when a new part starts */
virtual void OnPartStart(void) = 0;
- /// Called when a complete header line is received for a part
+ /** Called when a complete header line is received for a part */
virtual void OnPartHeader(const AString & a_Key, const AString & a_Value) = 0;
- /// Called when body for a part is received
- virtual void OnPartData(const char * a_Data, int a_Size) = 0;
+ /** Called when body for a part is received */
+ virtual void OnPartData(const char * a_Data, size_t a_Size) = 0;
- /// Called when the current part ends
+ /** Called when the current part ends */
virtual void OnPartEnd(void) = 0;
} ;
- /// Creates the parser, expects to find the boundary in a_ContentType
+ /** Creates the parser, expects to find the boundary in a_ContentType */
cMultipartParser(const AString & a_ContentType, cCallbacks & a_Callbacks);
- /// Parses more incoming data
- void Parse(const char * a_Data, int a_Size);
+ /** Parses more incoming data */
+ void Parse(const char * a_Data, size_t a_Size);
protected:
- /// The callbacks to call for various parsing events
+ /** The callbacks to call for various parsing events */
cCallbacks & m_Callbacks;
- /// True if the data parsed so far is valid; if false, further parsing is skipped
+ /** True if the data parsed so far is valid; if false, further parsing is skipped */
bool m_IsValid;
- /// Parser for each part's envelope
+ /** Parser for each part's envelope */
cEnvelopeParser m_EnvelopeParser;
- /// Buffer for the incoming data until it is parsed
+ /** Buffer for the incoming data until it is parsed */
AString m_IncomingData;
- /// The boundary, excluding both the initial "--" and the terminating CRLF
+ /** The boundary, excluding both the initial "--" and the terminating CRLF */
AString m_Boundary;
- /// Set to true if some data for the current part has already been signalized to m_Callbacks. Used for proper CRLF inserting.
+ /** Set to true if some data for the current part has already been signalized to m_Callbacks. Used for proper CRLF inserting. */
bool m_HasHadData;
- /// Parse one line of incoming data. The CRLF has already been stripped from a_Data / a_Size
- void ParseLine(const char * a_Data, int a_Size);
+ /** Parse one line of incoming data. The CRLF has already been stripped from a_Data / a_Size */
+ void ParseLine(const char * a_Data, size_t a_Size);
- /// Parse one line of incoming data in the headers section of a part. The CRLF has already been stripped from a_Data / a_Size
- void ParseHeaderLine(const char * a_Data, int a_Size);
+ /** Parse one line of incoming data in the headers section of a part. The CRLF has already been stripped from a_Data / a_Size */
+ void ParseHeaderLine(const char * a_Data, size_t a_Size);
// cEnvelopeParser overrides:
virtual void OnHeaderLine(const AString & a_Key, const AString & a_Value) override;
diff --git a/src/HTTPServer/NameValueParser.cpp b/src/HTTPServer/NameValueParser.cpp
index 9ea8594ae..f16ea1915 100644
--- a/src/HTTPServer/NameValueParser.cpp
+++ b/src/HTTPServer/NameValueParser.cpp
@@ -24,7 +24,7 @@ public:
// Now try parsing char-by-char, to debug transitions across datachunk boundaries:
cNameValueParser Parser2;
- for (int i = 0; i < sizeof(Data) - 1; i++)
+ for (size_t i = 0; i < sizeof(Data) - 1; i++)
{
Parser2.Parse(Data + i, 1);
}
@@ -82,7 +82,7 @@ cNameValueParser::cNameValueParser(bool a_AllowsKeyOnly) :
-cNameValueParser::cNameValueParser(const char * a_Data, int a_Size, bool a_AllowsKeyOnly) :
+cNameValueParser::cNameValueParser(const char * a_Data, size_t a_Size, bool a_AllowsKeyOnly) :
m_State(psKeySpace),
m_AllowsKeyOnly(a_AllowsKeyOnly)
{
@@ -93,12 +93,12 @@ cNameValueParser::cNameValueParser(const char * a_Data, int a_Size, bool a_Allow
-void cNameValueParser::Parse(const char * a_Data, int a_Size)
+void cNameValueParser::Parse(const char * a_Data, size_t a_Size)
{
ASSERT(m_State != psFinished); // Calling Parse() after Finish() is wrong!
- int Last = 0;
- for (int i = 0; i < a_Size;)
+ size_t Last = 0;
+ for (size_t i = 0; i < a_Size;)
{
switch (m_State)
{
diff --git a/src/HTTPServer/NameValueParser.h b/src/HTTPServer/NameValueParser.h
index 07dc0b942..9794614fa 100644
--- a/src/HTTPServer/NameValueParser.h
+++ b/src/HTTPServer/NameValueParser.h
@@ -21,10 +21,10 @@ public:
cNameValueParser(bool a_AllowsKeyOnly = true);
/// Creates an empty parser, then parses the data given. Doesn't call Finish(), so more data can be parsed later
- cNameValueParser(const char * a_Data, int a_Size, bool a_AllowsKeyOnly = true);
+ cNameValueParser(const char * a_Data, size_t a_Size, bool a_AllowsKeyOnly = true);
/// Parses the data given
- void Parse(const char * a_Data, int a_Size);
+ void Parse(const char * a_Data, size_t a_Size);
/// Notifies the parser that no more data will be coming. Returns true if the parser state is valid
bool Finish(void);
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
+} ;
+
+
+
+