@ -1,5 +1,11 @@
# include "UDPTCPNetwork.h"
# include <pthread.h>
# include <unistd.h>
# include <time.h>
# include <sys/stat.h>
# include <fcntl.h>
# include <list>
WebServerClient : : WebServerClient ( ) {
tcp = NULL ;
@ -55,20 +61,244 @@ int WebServerClient::Accept (TCP *socket) {
} ;
/// @brief Read data from the network and check if the request is complete
/// @return -1 on error, 0 no data , 1 request complete
int WebServerClient : : Loop ( ) {
int len ;
//
// read data
if ( ssl ) {
len = ssl - > Read ( buffer , WEB_READ_BUFFER_SIZE ) ;
}
else {
len = tcp - > ReadTimeout ( buffer , WEB_READ_BUFFER_SIZE , 20 ) ;
}
if ( len < 0 ) return 0 ;
if ( len > 0 ) printf ( " %s \n " , buffer ) ;
if ( len < 0 ) return - 1 ;
if ( len == 0 ) return 0 ;
ReqBuffer . AddBuffer ( buffer , len ) ;
if ( ReqBuffer . RequestComplete ( ) ) {
HandleRequest ( ) ;
return 1 ;
}
return 0 ;
} ;
int WebServerClient : : HandleRequest ( ) {
std : : string request = ReqBuffer . GetRequest ( ) ;
printf ( " WebServerClient::HandleRequest() Request:%s \n " , request . c_str ( ) ) ;
if ( request . compare ( " / " ) = = 0 ) request = " /index.html " ;
SendResponseFile ( & ReqBuffer , request , " " ) ;
ReqBuffer . Clear ( ) ;
return 1 ;
} ;
# define TIME_TEXT_SIZE 128
std : : string WebServerClient : : CreateHeader ( WebRequestBuffer * request , int errcode ,
std : : string doc_type , int doc_size , std : : string addheader ) {
long int l ;
long bytes ;
std : : string errortext ;
std : : string response ;
char timebuf [ TIME_TEXT_SIZE ] ;
struct tm tm ;
time_t t = time ( NULL ) ;
// debug ("errcode:%d cont_type:%s doc_size:%d\n", errcode, doc_type.c_str(), doc_size);
//
// read the current time int the timebuf
if ( localtime_r ( & t , & tm ) ! = & tm ) {
fprintf ( stderr , " %s:%d %s could not get localtime. Error:%s \n " ,
__FILE__ , __LINE__ , __FUNCTION__ , strerror ( errno ) ) ;
return " " ;
}
if ( asctime_r ( & tm , timebuf ) ! = timebuf ) {
fprintf ( stderr , " %s:%d %s could not get asctime. Error:%s \n " ,
__FILE__ , __LINE__ , __FUNCTION__ , strerror ( errno ) ) ;
return " " ;
}
timebuf [ strlen ( timebuf ) - 3 ] = 0 ;
switch ( errcode ) {
case ( 200 ) :
errortext = " 200 OK " ;
break ;
default :
errortext = " 501 NOT IMPLEMENTED " ;
break ;
}
response = request - > GetProtocolVersion ( ) + " " + errortext + " \r \n " ;
response + = " Accept-Ranges: bytes \r \n " ;
response + = " Content-Type: " + doc_type + " \r \n " ;
response + = " Content-Length: " + std : : to_string ( doc_size ) + " \r \n " ;
response + = " Date: " + ( std : : string ) timebuf + " \r \n " ;
response + = " Server: SyslogCollect \r \n " ;
if ( addheader . length ( ) > 0 )
response + = addheader ;
response + = " \r \n " ;
return response ;
}
/// @brief send some data as response
/// @param request the orginal request this response is for
/// @param data json type data to send
/// @param addheader add header lines if set
/// @return 0 on error, 1 on success
int WebServerClient : : SendResponseData ( WebRequestBuffer * request , std : : string data , std : : string addheader ) {
char * outbuffer = NULL ;
int outbufferpos = 0 ;
int error = 200 ;
long int l ;
std : : string datatype = " application/x-www-form-urlencoded; charset=UTF-8 " ;
std : : string header ;
ssize_t databytes ;
//
// send header and file
header = CreateHeader ( request , error , datatype , data . length ( ) , addheader ) ;
outbufferpos = header . length ( ) ;
outbuffer = ( char * ) malloc ( outbufferpos + data . length ( ) + 16 ) ;
memcpy ( outbuffer , header . c_str ( ) , outbufferpos ) ;
memcpy ( outbuffer + outbufferpos , data . c_str ( ) , data . length ( ) ) ;
databytes = outbufferpos + data . length ( ) ;
outbuffer [ databytes ] = 0 ;
if ( ssl ) l = ssl - > Write ( outbuffer , databytes ) ;
else l = tcp - > Write ( outbuffer , databytes ) ;
if ( l ! = databytes ) {
debug ( " could not send all data. Error:%s \n " , strerror ( errno ) ) ;
free ( outbuffer ) ;
return 0 ;
}
free ( outbuffer ) ;
return 1 ;
}
std : : string WebServerClient : : GetFileType ( std : : string fname ) {
std : : string res = " text/html;charset=utf-8 " ;
std : : size_t pos = fname . find_last_of ( ' . ' , std : : string : : npos ) ;
if ( pos = = std : : string : : npos ) return res ;
std : : string suffix = string_to_lower ( fname . substr ( pos ) ) ;
if ( suffix . compare ( " .html " ) = = 0 ) return res ;
if ( suffix . compare ( " .htm " ) = = 0 ) return res ;
if ( suffix . compare ( " .js " ) = = 0 ) return res ;
if ( suffix . compare ( " .json " ) = = 0 ) return " application/json; charset=utf-8 " ;
if ( suffix . compare ( " .svg " ) = = 0 ) return " image/svg+xml " ;
if ( suffix . compare ( " .png " ) = = 0 ) return " image/png " ;
if ( suffix . compare ( " .jpg " ) = = 0 ) return " image/jpeg " ;
if ( suffix . compare ( " .jpeg " ) = = 0 ) return " image/jpeg " ;
return res ;
}
/// @brief send a file as response
/// @param request requested file
/// @param fname file relative to the DOCUMENT_ROOT
/// @param addheader add header if set -> must contain "\n\r" at each line
/// @return 0 on error, 1 on success
int WebServerClient : : SendResponseFile ( WebRequestBuffer * request , std : : string fname , std : : string addheader ) {
char * outbuffer = NULL ;
int outbufferpos = 0 ;
int error = 200 ;
long int l ;
std : : string fullfname = Get_WebFile_FullPath ( fname ) ;
std : : string filetype = " text/html;charset=utf-8 " ;
std : : string header ;
struct stat filestat ;
int filefd ;
ssize_t filereadbytes ;
//
// open file and determine file type and size
filetype = GetFileType ( fname ) ;
filefd = open ( fullfname . c_str ( ) , O_RDONLY ) ;
if ( filefd < 0 ) {
debug ( " could not open file '%s' for reading. Error:%s \n " ,
fullfname . c_str ( ) , strerror ( errno ) ) ;
//
// set errorcode and reopen error file
error = 404 ;
fullfname = Get_WebFile_FullPath ( " error404.html " ) ;
filefd = open ( fullfname . c_str ( ) , O_RDONLY ) ;
if ( filefd < 0 ) errorexit ( " could not open file '%s' for reading. Error:%s \n " ,
fullfname . c_str ( ) , strerror ( errno ) ) ;
}
if ( fstat ( filefd , & filestat ) ! = 0 ) {
debug ( " could not get stats on file '%s'. Error:%s \n " ,
fullfname . c_str ( ) , strerror ( errno ) ) ;
error = 500 ;
fullfname = Get_WebFile_FullPath ( " error500.html " ) ;
filefd = open ( fullfname . c_str ( ) , O_RDONLY ) ;
if ( filefd < 0 )
errorexit ( " could not open file '%s' for reading. Error:%s \n " ,
fullfname . c_str ( ) , strerror ( errno ) ) ;
if ( fstat ( filefd , & filestat ) ! = 0 )
errorexit ( " could not get stats on file '%s'. Error:%s \n " ,
fullfname . c_str ( ) , strerror ( errno ) ) ;
}
//
// send header and file
header = CreateHeader ( request , error , filetype , filestat . st_size , addheader ) ;
outbufferpos = header . length ( ) ;
outbuffer = ( char * ) malloc ( outbufferpos + filestat . st_size + 16 ) ;
memcpy ( outbuffer , header . c_str ( ) , outbufferpos ) ;
filereadbytes = read ( filefd , outbuffer + outbufferpos , filestat . st_size ) ;
close ( filefd ) ;
if ( filereadbytes < = 0 ) {
debug ( " could not read all data from file '%s'. Error:%s \n " ,
fullfname . c_str ( ) , strerror ( errno ) ) ;
free ( outbuffer ) ;
return 0 ;
}
filereadbytes + = outbufferpos ;
if ( ssl ) l = ssl - > Write ( outbuffer , filereadbytes ) ;
else l = tcp - > Write ( outbuffer , filereadbytes ) ;
// debug ("send file %s with %ld bytes\n", fname.c_str(), filereadbytes);
if ( l ! = filereadbytes ) {
debug ( " could not send all data. Error:%s \n " , strerror ( errno ) ) ;
free ( outbuffer ) ;
return 0 ;
}
free ( outbuffer ) ;
return 1 ;
}
std : : string WebServerClient : : Get_WebFile_FullPath ( std : : string file ) {
std : : string ret = file ;
if ( DocumentRoot . length ( ) > 0 ) {
if ( DocumentRoot [ DocumentRoot . length ( ) - 1 ] = = ' / ' ) {
if ( file [ 0 ] = = ' / ' ) ret = DocumentRoot + file . substr ( 1 , std : : string : : npos ) ;
else ret = DocumentRoot + file ;
}
else {
if ( file [ 0 ] = = ' / ' ) ret = DocumentRoot + file ;
else ret = DocumentRoot + " / " + file ;
}
}
return ret ;
} ;