#include "UDPTCPNetwork.h" #include #include #include #include #include #include WebServerClient::WebServerClient () { tcp = NULL; ssl = NULL; ssl_key = ""; ssl_cert = ""; }; WebServerClient::~WebServerClient () { if (ssl) delete ssl; ssl = NULL; if (tcp) delete tcp; tcp = NULL; }; /// @brief /// @param socket /// @param _ssl_key /// @param _ssl_cert /// @return int WebServerClient::Accept (TCP *socket, std::string _ssl_key, std::string _ssl_cert) { if (ssl) delete ssl; ssl = NULL; if (tcp) delete tcp; tcp = NULL; tcp = socket; ssl_key = _ssl_key; ssl_cert = _ssl_cert; ssl = new SSLSocket; ssl->SetCertificat(ssl_cert, ssl_key); ssl->Accept(tcp->GetSocket(),200); return 1; }; /// @brief /// @param socket /// @return int WebServerClient::Accept (TCP *socket) { if (ssl) delete ssl; ssl = NULL; if (tcp) delete tcp; tcp = NULL; tcp = socket; return 1; }; /// @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; if (ssl) { len = ssl->Read(buffer, WEB_READ_BUFFER_SIZE); } else { len = tcp->ReadTimeout(buffer, WEB_READ_BUFFER_SIZE, 20); } 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; };