2017-09-19 04:34:08 -04:00
2013-09-27 12:14:26 -04:00
// HTTPServer.cpp
// Implements the cHTTPServer class representing a HTTP webserver that uses cListenThread and cSocketThreads for processing
# include "Globals.h"
# include "HTTPServer.h"
2016-02-20 05:50:52 -05:00
# include "HTTPMessageParser.h"
2015-12-25 13:42:50 -05:00
# include "HTTPServerConnection.h"
2013-09-28 13:30:25 -04:00
# include "HTTPFormParser.h"
2015-12-25 13:42:50 -05:00
# include "SslHTTPServerConnection.h"
2018-08-28 20:51:25 -04:00
# include "../mbedTLS++/SslConfig.h"
2013-09-27 12:14:26 -04:00
// Disable MSVC warnings:
# if defined(_MSC_VER)
# pragma warning(push)
# pragma warning(disable:4355) // 'this' : used in base member initializer list
# endif
2015-01-24 04:11:34 -05:00
////////////////////////////////////////////////////////////////////////////////
// cHTTPServerListenCallbacks:
class cHTTPServerListenCallbacks :
public cNetwork : : cListenCallbacks
{
public :
cHTTPServerListenCallbacks ( cHTTPServer & a_HTTPServer , UInt16 a_Port ) :
m_HTTPServer ( a_HTTPServer ) ,
m_Port ( a_Port )
{
}
protected :
/** The HTTP server instance that we're attached to. */
cHTTPServer & m_HTTPServer ;
/** The port for which this instance is responsible. */
UInt16 m_Port ;
// cNetwork::cListenCallbacks overrides:
virtual cTCPLink : : cCallbacksPtr OnIncomingConnection ( const AString & a_RemoteIPAddress , UInt16 a_RemotePort ) override
{
return m_HTTPServer . OnIncomingConnection ( a_RemoteIPAddress , a_RemotePort ) ;
}
virtual void OnAccepted ( cTCPLink & a_Link ) override { }
virtual void OnError ( int a_ErrorCode , const AString & a_ErrorMsg ) override
{
LOGWARNING ( " HTTP server error on port %d: %d (%s) " , m_Port , a_ErrorCode , a_ErrorMsg . c_str ( ) ) ;
}
} ;
2014-07-17 16:15:34 -04:00
////////////////////////////////////////////////////////////////////////////////
2013-09-27 15:28:41 -04:00
// cHTTPServer:
2013-09-27 12:14:26 -04:00
cHTTPServer : : cHTTPServer ( void ) :
2014-10-20 16:55:07 -04:00
m_Callbacks ( nullptr )
2013-09-27 12:14:26 -04:00
{
2014-05-02 17:46:06 -04:00
}
cHTTPServer : : ~ cHTTPServer ( )
{
Stop ( ) ;
}
2015-01-24 04:11:34 -05:00
bool cHTTPServer : : Initialize ( void )
2014-05-02 17:46:06 -04:00
{
// Read the HTTPS cert + key:
2014-05-01 05:48:03 -04:00
AString CertFile = cFile : : ReadWholeFile ( " webadmin/httpscert.crt " ) ;
AString KeyFile = cFile : : ReadWholeFile ( " webadmin/httpskey.pem " ) ;
if ( ! CertFile . empty ( ) & & ! KeyFile . empty ( ) )
{
2017-08-30 10:00:06 -04:00
auto Cert = std : : make_shared < cX509Cert > ( ) ;
int res = Cert - > Parse ( CertFile . data ( ) , CertFile . size ( ) ) ;
2014-05-06 15:43:31 -04:00
if ( res = = 0 )
2014-05-01 05:48:03 -04:00
{
2017-08-30 10:00:06 -04:00
auto CertPrivKey = std : : make_shared < cCryptoKey > ( ) ;
res = CertPrivKey - > ParsePrivate ( KeyFile . data ( ) , KeyFile . size ( ) , " " ) ;
if ( res = = 0 )
{
// Modifyable locally but otherwise must be const
auto Config = cSslConfig : : MakeDefaultConfig ( false ) ;
Config - > SetOwnCert ( Cert , CertPrivKey ) ;
m_SslConfig = std : : move ( Config ) ;
}
else
2014-05-01 05:48:03 -04:00
{
// Reading the private key failed, reset the cert:
2017-08-30 10:00:06 -04:00
LOGWARNING ( " WebServer: Cannot read HTTPS certificate private key: -0x%x " , - res ) ;
2014-05-01 05:48:03 -04:00
}
}
else
{
2014-05-02 17:46:06 -04:00
LOGWARNING ( " WebServer: Cannot read HTTPS certificate: -0x%x " , - res ) ;
2014-05-01 05:48:03 -04:00
}
}
2013-09-27 12:14:26 -04:00
2014-05-02 17:46:06 -04:00
// Notify the admin about the HTTPS / HTTP status
2017-08-30 10:00:06 -04:00
if ( m_SslConfig = = nullptr )
2014-05-02 17:46:06 -04:00
{
2016-08-21 05:03:26 -04:00
LOGWARNING ( " WebServer: The server will run in unsecured HTTP mode. " ) ;
2014-09-10 13:47:59 -04:00
LOGINFO ( " Put a valid HTTPS certificate in file 'webadmin/httpscert.crt' and its corresponding private key to 'webadmin/httpskey.pem' (without any password) to enable HTTPS support " ) ;
2014-05-02 17:46:06 -04:00
}
else
{
2016-08-21 05:03:26 -04:00
LOGINFO ( " WebServer: The server will run in secure HTTPS mode. " ) ;
2014-05-02 17:46:06 -04:00
}
2013-09-27 15:28:41 -04:00
return true ;
}
2015-01-24 04:11:34 -05:00
bool cHTTPServer : : Start ( cCallbacks & a_Callbacks , const AStringVector & a_Ports )
2013-09-27 15:28:41 -04:00
{
m_Callbacks = & a_Callbacks ;
2015-01-24 04:11:34 -05:00
// Open up requested ports:
2016-08-21 05:03:26 -04:00
AStringVector ports ;
2020-05-14 18:15:35 -04:00
for ( const auto & port : a_Ports )
2013-09-27 12:14:26 -04:00
{
2015-01-25 10:25:15 -05:00
UInt16 PortNum ;
if ( ! StringToInteger ( port , PortNum ) )
2015-01-24 04:11:34 -05:00
{
LOGWARNING ( " WebServer: Invalid port value: \" %s \" . Ignoring. " , port . c_str ( ) ) ;
continue ;
}
auto Handle = cNetwork : : Listen ( PortNum , std : : make_shared < cHTTPServerListenCallbacks > ( * this , PortNum ) ) ;
if ( Handle - > IsListening ( ) )
{
m_ServerHandles . push_back ( Handle ) ;
2016-08-21 05:03:26 -04:00
ports . push_back ( port ) ;
2015-01-24 04:11:34 -05:00
}
} // for port - a_Ports[]
2016-02-05 16:45:45 -05:00
2016-08-21 05:03:26 -04:00
// Inform the admin about the ports opened:
AString reportPorts ;
for ( const auto & port : ports )
{
if ( ! reportPorts . empty ( ) )
{
reportPorts . append ( " , " ) ;
}
reportPorts . append ( port ) ;
}
LOGINFO ( " WebAdmin is running on port(s) %s " , reportPorts . c_str ( ) ) ;
2015-01-24 04:11:34 -05:00
// Report success if at least one port opened successfully:
return ! m_ServerHandles . empty ( ) ;
2013-09-27 12:14:26 -04:00
}
2013-09-27 15:28:41 -04:00
void cHTTPServer : : Stop ( void )
{
2020-05-14 18:15:35 -04:00
for ( const auto & handle : m_ServerHandles )
2013-09-27 15:28:41 -04:00
{
2015-01-24 04:11:34 -05:00
handle - > Close ( ) ;
}
m_ServerHandles . clear ( ) ;
2013-09-27 15:28:41 -04:00
}
2015-01-24 04:11:34 -05:00
cTCPLink : : cCallbacksPtr cHTTPServer : : OnIncomingConnection ( const AString & a_RemoteIPAddress , UInt16 a_RemotePort )
2013-09-27 12:14:26 -04:00
{
2015-01-24 04:11:34 -05:00
UNUSED ( a_RemoteIPAddress ) ;
UNUSED ( a_RemotePort ) ;
2017-08-30 10:00:06 -04:00
if ( m_SslConfig ! = nullptr )
2014-05-01 05:48:03 -04:00
{
2017-08-30 10:00:06 -04:00
return std : : make_shared < cSslHTTPServerConnection > ( * this , m_SslConfig ) ;
2014-05-01 05:48:03 -04:00
}
else
{
2015-12-25 13:42:50 -05:00
return std : : make_shared < cHTTPServerConnection > ( * this ) ;
2014-05-01 05:48:03 -04:00
}
2013-09-27 14:33:18 -04:00
}
2016-02-20 05:50:52 -05:00
void cHTTPServer : : NewRequest ( cHTTPServerConnection & a_Connection , cHTTPIncomingRequest & a_Request )
2013-09-27 12:14:26 -04:00
{
2013-09-27 15:28:41 -04:00
m_Callbacks - > OnRequestBegun ( a_Connection , a_Request ) ;
2013-09-27 12:14:26 -04:00
}
2016-02-20 05:50:52 -05:00
void cHTTPServer : : RequestBody ( cHTTPServerConnection & a_Connection , cHTTPIncomingRequest & a_Request , const void * a_Data , size_t a_Size )
2013-09-27 12:14:26 -04:00
{
2018-05-02 03:50:36 -04:00
m_Callbacks - > OnRequestBody ( a_Connection , a_Request , static_cast < const char * > ( a_Data ) , a_Size ) ;
2013-09-27 12:14:26 -04:00
}
2016-02-20 05:50:52 -05:00
void cHTTPServer : : RequestFinished ( cHTTPServerConnection & a_Connection , cHTTPIncomingRequest & a_Request )
2013-09-27 12:14:26 -04:00
{
2013-09-27 15:28:41 -04:00
m_Callbacks - > OnRequestFinished ( a_Connection , a_Request ) ;
2013-09-27 12:14:26 -04:00
}