parent
eeb3a42da8
commit
622643fabf
@ -0,0 +1,85 @@
|
|||||||
|
|
||||||
|
#ifndef _UDPTCPNETWORK_WEBUTILS_H_
|
||||||
|
#define _UDPTCPNETWORK_WEBUTILS_H_
|
||||||
|
|
||||||
|
#include "UDPTCPNetwork.h"
|
||||||
|
#include <string>
|
||||||
|
#include <list>
|
||||||
|
|
||||||
|
/*********************************************************************************/
|
||||||
|
#define WEB_READ_BUFFER_SIZE 0x10000
|
||||||
|
|
||||||
|
enum { // request types
|
||||||
|
WEB_REQEST_UNSUPPORTED,
|
||||||
|
WEB_REQEST_GET,
|
||||||
|
WEB_REQEST_POST,
|
||||||
|
WEB_REQEST_MAX // not set
|
||||||
|
};
|
||||||
|
|
||||||
|
/***************************************************************************************
|
||||||
|
* WebHeaderLine
|
||||||
|
*/
|
||||||
|
|
||||||
|
class WebHeaderLine {
|
||||||
|
public:
|
||||||
|
WebHeaderLine() { Clear(); };
|
||||||
|
~WebHeaderLine() {};
|
||||||
|
void Clear () { parameter = ""; value = ""; };
|
||||||
|
std::string parameter;
|
||||||
|
std::string value;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/***************************************************************************************
|
||||||
|
* WebRequestBuffer
|
||||||
|
*/
|
||||||
|
|
||||||
|
class WebRequestBuffer {
|
||||||
|
private:
|
||||||
|
char *buffer_ptr;
|
||||||
|
int buffer_size; // allocated size
|
||||||
|
int buffer_len; // current len
|
||||||
|
|
||||||
|
int request_type;
|
||||||
|
std::string request;
|
||||||
|
std::string protocol_version;
|
||||||
|
std::list<WebHeaderLine> headerlines;
|
||||||
|
int buffer_pos_data;
|
||||||
|
|
||||||
|
public:
|
||||||
|
WebRequestBuffer();
|
||||||
|
~WebRequestBuffer();
|
||||||
|
|
||||||
|
int AddBuffer (char *b, int len);
|
||||||
|
int GetBuffer (char **dstptr, int *max);
|
||||||
|
bool RequestComplete();
|
||||||
|
void Clear() { buffer_len = 0; };
|
||||||
|
int GetType() { return request_type; };
|
||||||
|
std::string GetRequestRaw() { return request; };
|
||||||
|
std::string GetRequest();
|
||||||
|
std::string GetProtocolVersion() { return protocol_version; };
|
||||||
|
int GetRequestCmdObj(std::string *cmd, std::string *obj, JSONParse *jp);
|
||||||
|
std::string GetCookie(std::string name);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class WebServerClient {
|
||||||
|
private:
|
||||||
|
std::string ssl_key;
|
||||||
|
std::string ssl_cert;
|
||||||
|
TCP *tcp;
|
||||||
|
SSLSocket *ssl; // only set if SSL is used
|
||||||
|
char buffer[WEB_READ_BUFFER_SIZE];
|
||||||
|
public:
|
||||||
|
WebServerClient();
|
||||||
|
~WebServerClient();
|
||||||
|
|
||||||
|
// 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);
|
||||||
|
virtual int HandleRequest (WebRequestBuffer *req) { return 0; };
|
||||||
|
virtual int Loop();
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
@ -0,0 +1,97 @@
|
|||||||
|
#include <unistd.h>
|
||||||
|
#include "UDPTCPNetwork.h"
|
||||||
|
|
||||||
|
#define DEFAULT_HTTP_PORT 2222
|
||||||
|
#define DEFAULT_HTTPS_PORT 2223
|
||||||
|
#define DEFAULT_CERT "./cert.pem"
|
||||||
|
#define DEFAULT_KEY "./privkey.pem"
|
||||||
|
#define MAX_CLIENTS 10
|
||||||
|
|
||||||
|
int running = 1;
|
||||||
|
|
||||||
|
class SimpleWebSrvClient: public WebServerClient {
|
||||||
|
public:
|
||||||
|
SimpleWebSrvClient () {};
|
||||||
|
~SimpleWebSrvClient () {};
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
int main (int argc, char **argv) {
|
||||||
|
list<SimpleWebSrvClient*> webclients;
|
||||||
|
|
||||||
|
TCP http;
|
||||||
|
TCP https;
|
||||||
|
|
||||||
|
std::string ssl_cert = DEFAULT_CERT;
|
||||||
|
std::string ssl_key = DEFAULT_KEY;
|
||||||
|
|
||||||
|
if (http.Listen(DEFAULT_HTTP_PORT) != 1) {
|
||||||
|
printf ("error on listen\n");
|
||||||
|
exit (1);
|
||||||
|
}
|
||||||
|
printf ("test server is running on http://localhost:%d\n", DEFAULT_HTTP_PORT);
|
||||||
|
|
||||||
|
if (https.Listen(DEFAULT_HTTPS_PORT) != 1) {
|
||||||
|
printf ("error on listen\n");
|
||||||
|
exit (1);
|
||||||
|
}
|
||||||
|
printf ("test server is running on https://localhost:%d\n", DEFAULT_HTTPS_PORT);
|
||||||
|
|
||||||
|
while (running == 1) {
|
||||||
|
SimpleWebSrvClient *webclient = NULL;
|
||||||
|
list<SimpleWebSrvClient*>::iterator wci;
|
||||||
|
TCP *tcpclient = NULL;
|
||||||
|
int ssl_enabled = 1;
|
||||||
|
int res;
|
||||||
|
|
||||||
|
//
|
||||||
|
// any new connection?
|
||||||
|
if ((tcpclient = https.Accept()) == NULL) {
|
||||||
|
ssl_enabled = 0;
|
||||||
|
tcpclient = http.Accept();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tcpclient) {
|
||||||
|
printf ("new %s connection from %s\n", ssl_enabled ? "HTTPS" : "HTTP", tcpclient->GetRemoteAddr().c_str());
|
||||||
|
|
||||||
|
if (webclients.size() > MAX_CLIENTS) {
|
||||||
|
printf ("max connections reached. closing connection.\n");
|
||||||
|
tcpclient->Close();
|
||||||
|
delete tcpclient;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
webclient = new SimpleWebSrvClient();
|
||||||
|
if (ssl_enabled) res = webclient->Accept(tcpclient, ssl_key, ssl_cert);
|
||||||
|
else res = webclient->Accept(tcpclient);
|
||||||
|
|
||||||
|
if (res == 0) {
|
||||||
|
printf ("webclient could not connect. closing connection\n");
|
||||||
|
delete webclient;
|
||||||
|
delete tcpclient;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
webclients.push_back(webclient);
|
||||||
|
printf ("add new connection to client list\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// go through all the clients and check for new requests
|
||||||
|
for (wci = webclients.begin(); wci != webclients.end(); wci++) {
|
||||||
|
webclient = *wci;
|
||||||
|
if (webclient->Loop() == 0) {
|
||||||
|
// error on loop, remove and delete webclient.
|
||||||
|
printf ("remove connection\n");
|
||||||
|
webclients.remove(webclient);
|
||||||
|
delete webclient;
|
||||||
|
wci = webclients.begin();
|
||||||
|
if (wci == webclients.end()) continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
usleep (1000);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
@ -0,0 +1,74 @@
|
|||||||
|
|
||||||
|
#include "UDPTCPNetwork.h"
|
||||||
|
|
||||||
|
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;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
};
|
||||||
|
|
||||||
@ -0,0 +1,209 @@
|
|||||||
|
|
||||||
|
#include "UDPTCPNetwork.h"
|
||||||
|
|
||||||
|
#include <pthread.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <time.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <list>
|
||||||
|
|
||||||
|
|
||||||
|
WebRequestBuffer::WebRequestBuffer () {
|
||||||
|
buffer_pos_data = -1;
|
||||||
|
buffer_size = 0;
|
||||||
|
buffer_ptr = NULL;
|
||||||
|
buffer_len = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
WebRequestBuffer::~WebRequestBuffer () {
|
||||||
|
if (buffer_ptr) {
|
||||||
|
free (buffer_ptr);
|
||||||
|
buffer_ptr = NULL;
|
||||||
|
buffer_size = 0;
|
||||||
|
buffer_len = 0;
|
||||||
|
buffer_pos_data = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// @brief add text to buffer
|
||||||
|
/// @param buffer
|
||||||
|
/// @param len
|
||||||
|
/// @return 0 on error, 1 on success
|
||||||
|
int WebRequestBuffer::AddBuffer (char *buffer, int len) {
|
||||||
|
//
|
||||||
|
// if needed allocate enought buffer, to the next kB
|
||||||
|
if (buffer_ptr == NULL || buffer_size <= buffer_len+len) {
|
||||||
|
buffer_size = 1024 * (1 + ((buffer_len + len) / 1024));
|
||||||
|
if (buffer_ptr == NULL) buffer_ptr = (char*) malloc (buffer_size);
|
||||||
|
else buffer_ptr = (char*) realloc (buffer_ptr, buffer_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (buffer_ptr == NULL || buffer_size < buffer_len+len) {
|
||||||
|
fprintf (stderr, "%s:%d could not allocate enought memory. buffer_size:%d buffer_len+len:%d \n",
|
||||||
|
__FILE__, __LINE__, buffer_size, buffer_len + len);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy (buffer_ptr + buffer_len, buffer, len);
|
||||||
|
buffer_len += len;
|
||||||
|
buffer_ptr[buffer_len] = 0;
|
||||||
|
|
||||||
|
debug("buffer:'%s'\n", buffer_ptr);
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/// @brief copy the curren buffer to the dstination, 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
|
||||||
|
int WebRequestBuffer::GetBuffer (char **dstptr, int *max) {
|
||||||
|
// check: valid pointers
|
||||||
|
if (dstptr == NULL || max == NULL) {
|
||||||
|
fprintf (stderr, "%s:%d not pointer to buffer or not pointer to a lenght set\n",
|
||||||
|
__FILE__, __LINE__);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// check: size and reallocate
|
||||||
|
if (*max < buffer_len || *max < 0) {
|
||||||
|
char *tb = (char*) realloc (*dstptr, buffer_len);
|
||||||
|
*dstptr = tb;
|
||||||
|
*max = buffer_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
// check: could alloc memory
|
||||||
|
if (*dstptr == NULL) {
|
||||||
|
fprintf (stderr, "%s:%d no destination pointer set\n",
|
||||||
|
__FILE__, __LINE__);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy (*dstptr, buffer_ptr, buffer_len);
|
||||||
|
return buffer_len;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/// @brief Check if the Request is Complete. In this case the request_type and the request can
|
||||||
|
/// @brief be read with GetRequest and GetType(). For a new request Clear() must be called.
|
||||||
|
/// @return 0 . not complete, 1 . request complete
|
||||||
|
bool WebRequestBuffer::RequestComplete() {
|
||||||
|
int i = 0;
|
||||||
|
int element = 0; // 0. Parameter 1. Value 2. Value n
|
||||||
|
int line = 0;
|
||||||
|
WebHeaderLine hl;
|
||||||
|
|
||||||
|
request = "";
|
||||||
|
protocol_version = "HTTP/1.0";
|
||||||
|
request_type = WEB_REQEST_UNSUPPORTED;
|
||||||
|
buffer_pos_data = -1;
|
||||||
|
|
||||||
|
if (buffer_ptr == NULL) return false;
|
||||||
|
|
||||||
|
hl.Clear();
|
||||||
|
for (i = 0, element = 0; i < buffer_len; i++) {
|
||||||
|
//
|
||||||
|
// check if line is complete
|
||||||
|
if (buffer_ptr[i] == '\n') {
|
||||||
|
if (hl.value.length() == 0 && hl.parameter.length() == 0) {
|
||||||
|
buffer_pos_data = i+1; // save position of first data byte
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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;
|
||||||
|
request = string_to_lower(hl.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
headerlines.push_back(hl);
|
||||||
|
hl.Clear();
|
||||||
|
element = 0;
|
||||||
|
line++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ignore some elements -> maybe it is not needed
|
||||||
|
else if (strchr ("\t ", buffer_ptr[i]) != NULL) {
|
||||||
|
element++;
|
||||||
|
if (element > 1) hl.value += buffer_ptr[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
// ignore last CR
|
||||||
|
else if (buffer_ptr[i] != '\r') {
|
||||||
|
if (element == 0) hl.parameter += buffer_ptr[i];
|
||||||
|
// first line ignore protocol version
|
||||||
|
else if (line > 0 || element == 1) hl.value += buffer_ptr[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// @brief get some information about the complete request
|
||||||
|
/// @param cmd propably get or set command
|
||||||
|
/// @param obj object related with this command
|
||||||
|
/// @param jp some json data
|
||||||
|
/// @return
|
||||||
|
int WebRequestBuffer::GetRequestCmdObj(std::string *cmd, std::string *obj, JSONParse *jp) {
|
||||||
|
std::string rq = GetRequest();
|
||||||
|
int secslash = 0;
|
||||||
|
|
||||||
|
if (cmd == NULL || obj == NULL || jp == NULL)
|
||||||
|
errorexit ("Fatal Error cmd:%p obj:%p jp:%p none of these should be NULL\n",
|
||||||
|
cmd, obj, jp);
|
||||||
|
|
||||||
|
secslash = rq.find ('/', 1);
|
||||||
|
*cmd = rq.substr(1, secslash-1);
|
||||||
|
*obj = rq.substr(secslash+1, std::string::npos);
|
||||||
|
if (buffer_pos_data > 0) (*jp).Set(buffer_ptr+buffer_pos_data);
|
||||||
|
else (*jp).Clear();
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
std::string WebRequestBuffer::GetRequest() {
|
||||||
|
std::string rq = "";
|
||||||
|
char lastc = 0;
|
||||||
|
char c = 0;
|
||||||
|
|
||||||
|
//
|
||||||
|
// filter out /. .. ./
|
||||||
|
for (int i = 0; i < request.length(); i++) {
|
||||||
|
c = request[i];
|
||||||
|
if (((c >= '0' && c <= '9') || (c >= 'a' && c <= 'z') ||
|
||||||
|
(c >= 'A' && c <= 'Z') || c == '/' || c == '.' || c == '-' ) &&
|
||||||
|
(!((c == '.' || c == '/' ) && (lastc == '/' || lastc == '.')))) {
|
||||||
|
rq += c;
|
||||||
|
lastc = c;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return rq;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
std::string WebRequestBuffer::GetCookie(std::string name) {
|
||||||
|
std::list<WebHeaderLine>::iterator il;
|
||||||
|
std::size_t i;
|
||||||
|
|
||||||
|
for (il = headerlines.begin(); il != headerlines.end(); il++) {
|
||||||
|
if (string_to_lower(il->parameter).compare("cookie:") == 0) {
|
||||||
|
i = il->value.find('=');
|
||||||
|
if (i == std::string::npos) continue;
|
||||||
|
if (il->value.substr(0, i).compare(name) == 0)
|
||||||
|
return il->value.substr(i+1, std::string::npos);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return "";
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
Loading…
Reference in new issue