basic webserver seem to work

master
Steffen Pohle 6 days ago
parent 622643fabf
commit 985f2c490a

@ -10,10 +10,10 @@
#define WEB_READ_BUFFER_SIZE 0x10000
enum { // request types
WEB_REQEST_UNSUPPORTED,
WEB_REQEST_GET,
WEB_REQEST_POST,
WEB_REQEST_MAX // not set
WEB_REQUEST_UNSUPPORTED,
WEB_REQUEST_GET,
WEB_REQUEST_POST,
WEB_REQUEST_MAX // not set
};
/***************************************************************************************
@ -70,16 +70,32 @@ class WebServerClient {
TCP *tcp;
SSLSocket *ssl; // only set if SSL is used
char buffer[WEB_READ_BUFFER_SIZE];
std::string DocumentRoot;
protected:
WebRequestBuffer ReqBuffer;
public:
WebServerClient();
~WebServerClient();
void SetDecoumentRoot(std::string path) { DocumentRoot = path; };
// will handle the request and send the response
// on error reply with ERROR 500
int Accept (TCP *socket, std::string _ssl_key, std::string _ssl_cert);
int Accept (TCP *socket);
std::string CreateHeader(WebRequestBuffer *request, int errcode,
std::string doc_type, int doc_size, std::string addheader);
int SendResponseData (WebRequestBuffer *request, std::string data,
std::string addheader);
std::string GetFileType (std::string fname);
std::string Get_WebFile_FullPath(std::string file);
int SendResponseFile (WebRequestBuffer *request, std::string fname, std::string addheader);
virtual int HandleRequest (WebRequestBuffer *req) { return 0; };
virtual int Loop();
virtual int HandleRequest ();
};
#endif

@ -72,7 +72,7 @@ int main (int argc, char **argv) {
delete tcpclient;
continue;
}
webclient->SetDecoumentRoot("./www");
webclients.push_back(webclient);
printf ("add new connection to client list\n");
}
@ -80,8 +80,11 @@ int main (int argc, char **argv) {
//
// go through all the clients and check for new requests
for (wci = webclients.begin(); wci != webclients.end(); wci++) {
int res = 0;
webclient = *wci;
if (webclient->Loop() == 0) {
res = webclient->Loop();
if (res == -1) {
// error on loop, remove and delete webclient.
printf ("remove connection\n");
webclients.remove(webclient);

@ -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;
};

@ -51,13 +51,13 @@ int WebRequestBuffer::AddBuffer (char *buffer, int len) {
buffer_len += len;
buffer_ptr[buffer_len] = 0;
debug("buffer:'%s'\n", buffer_ptr);
// debug("buffer:'%s'\n", buffer_ptr);
return 1;
};
/// @brief copy the curren buffer to the dstination, resize destination if needed
/// @brief copy the current buffer to the destination, resize destination if needed
/// @param dstptr pointer to the destination pointer, in case of a reallocation
/// @param max pointer to current allocated size of the pointer
/// @return > 0 - len in bytes of the buffer, = -1 error occured
@ -99,7 +99,7 @@ bool WebRequestBuffer::RequestComplete() {
request = "";
protocol_version = "HTTP/1.0";
request_type = WEB_REQEST_UNSUPPORTED;
request_type = WEB_REQUEST_UNSUPPORTED;
buffer_pos_data = -1;
if (buffer_ptr == NULL) return false;
@ -117,8 +117,8 @@ bool WebRequestBuffer::RequestComplete() {
// the first line holds the request type and the location/path.
if (line == 0) {
hl.parameter = string_to_upper(hl.parameter);
if (hl.parameter.compare("GET") == 0) request_type = WEB_REQEST_GET;
if (hl.parameter.compare("POST") == 0) request_type = WEB_REQEST_POST;
if (hl.parameter.compare("GET") == 0) request_type = WEB_REQUEST_GET;
if (hl.parameter.compare("POST") == 0) request_type = WEB_REQUEST_POST;
request = string_to_lower(hl.value);
}

@ -0,0 +1,13 @@
<html>
<head>
<title>TestWebserver</title>
</head>
<body>
<h1>Testpage</h1>
<p>
This is only a test for more detail see at <a href="https://steffen.gulpe.de/gitea/steffen/libUDPTCPNetwork">https://steffen.gulpe.de/gitea/steffen/libUDPTCPNetwork</a>
</p>
</body>
</html>
Loading…
Cancel
Save