diff --git a/src/network/Address.cpp b/src/network/Address.cpp
new file mode 100644
index 0000000..d283ea1
--- /dev/null
+++ b/src/network/Address.cpp
@@ -0,0 +1,68 @@
+
+
+#include <iostream>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <cstring>
+#include "Address.h"
+
+using namespace std;
+
+
+Address::Address() {
+
+}
+
+Address::Address(string addr) {
+	// TODO
+}
+
+Address::Address(struct sockaddr_in *addr) {
+	address = ntohl(addr->sin_addr.s_addr);
+}
+
+
+struct sockaddr_in Address::toStruct(unsigned short port)const {
+	struct sockaddr_in addr;
+	addr.sin_family = AF_INET;
+	addr.sin_addr.s_addr = htonl(address);
+	addr.sin_port = htons(port);
+	return addr;
+}
+
+
+
+string Address::toString() const {
+	struct sockaddr_in addr = toStruct(0);
+	struct in_addr ipAddr = addr.sin_addr;
+	return inet_ntoa(ipAddr);
+}
+
+bool Address::isLocal() {
+	string a = toString();
+	return a.find("127.0.0.") == 0;
+}
+
+
+ostream& operator<<(ostream &str, const Address &addr) {
+	return str << addr.toString();
+}
+
+string operator+(string &str, const Address &addr) {
+	return str + addr.toString();
+}
+
+string operator+(string &str, const Address *addr) {
+	return str + addr->toString();
+}
+
+string operator+(const Address &addr, string &str) {
+	return addr.toString() + str;
+}
+
+string operator+(const Address *addr, string &str) {
+	return addr->toString() + str;
+}
+
+
+
diff --git a/src/network/Address.h b/src/network/Address.h
new file mode 100644
index 0000000..4583b5c
--- /dev/null
+++ b/src/network/Address.h
@@ -0,0 +1,31 @@
+/**
+ * Necronda Web Server 3.0
+ * HttpHeader.h - HttpHeader Class definition
+ * Lorenz Stechauner, 2018-05-09
+ */
+
+#ifndef NECRONDA_ADDRESS
+#define NECRONDA_ADDRESS
+
+using namespace std;
+
+class Address {
+private:
+	unsigned int address;
+
+public:
+	Address();
+
+	explicit Address(string address);
+
+	explicit Address(struct sockaddr_in *address);
+
+	struct sockaddr_in toStruct(unsigned short port) const;
+
+	string toString() const;
+
+	bool isLocal();
+
+};
+
+#endif
diff --git a/src/network/Socket.cpp b/src/network/Socket.cpp
new file mode 100644
index 0000000..be0a4ce
--- /dev/null
+++ b/src/network/Socket.cpp
@@ -0,0 +1,628 @@
+/**
+ * Necronda Web Server 3.0
+ * Socket.cpp - Socket Class methods
+ * Lorenz Stechauner, 2018-05-09
+ */
+
+
+#include <iostream>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <cstring>
+#include <utility>
+#include <unistd.h>
+#include <sstream>
+#include <ctime>
+#include <poll.h>
+#include <openssl/ssl.h>
+#include <openssl/bio.h>
+#include <openssl/err.h>
+#include <openssl/x509.h>
+#include <list>
+
+#include "Address.h"
+#include "Socket.h"
+#include "../necronda-server.h"
+
+
+using namespace std;
+
+
+static void multi_ssl_init() {
+	SSL_load_error_strings();
+	SSL_library_init();
+	ERR_load_crypto_strings();
+	OpenSSL_add_all_algorithms();
+}
+
+
+char *multi_ssl_get_error(SSL *ssl, int ret) {
+	if (ret > 0) {
+		return NULL;
+	}
+
+	unsigned long ret2 = ERR_get_error();
+	const char *err2 = strerror(errno);
+	const char *err1 = ERR_reason_error_string(ret2);
+
+	switch (SSL_get_error(ssl, ret)) {
+		case SSL_ERROR_NONE:
+			return (char *) "none";
+		case SSL_ERROR_ZERO_RETURN:
+			return (char *) "closed";
+		case SSL_ERROR_WANT_READ:
+			return (char *) "want_read";
+		case SSL_ERROR_WANT_WRITE:
+			return (char *) "want_write";
+		case SSL_ERROR_WANT_CONNECT:
+			return (char *) "want_connect";
+		case SSL_ERROR_WANT_ACCEPT:
+			return (char *) "want_accept";
+		case SSL_ERROR_WANT_X509_LOOKUP:
+			return (char *) "want_x509_lookup";
+		case SSL_ERROR_SYSCALL:
+			return (char *) ((ret2 == 0) ? (ret == 0) ? "protocol violation" : err2 : err1);
+		case SSL_ERROR_SSL:
+			return (char *) err1;
+		default:
+			return (char *) "unknown error";
+	}
+}
+
+char *strerror_socket(int nr) {
+	if (nr == EAGAIN || nr == EWOULDBLOCK) {
+		return (char *) "timeout";
+	} else if (nr == ECONNRESET) {
+		return (char *) "closed";
+	} else {
+		return strerror(nr);
+	}
+}
+
+
+Socket::Socket(int fd) {
+	this->fd = fd;
+	microsStart = getMicros();
+	microsLast = microsStart;
+	bytesSent = 0;
+	bytesReceived = 0;
+	enc = false;
+	ssl = nullptr;
+	ctx = nullptr;
+	clients = false;
+	servers = false;
+}
+
+Socket::Socket() {
+	fd = ::socket(AF_INET, SOCK_STREAM, 0);
+	if (fd == 0) {
+		throw strerror(errno);
+	}
+	enc = false;
+	microsStart = getMicros();
+	microsLast = microsStart;
+	bytesSent = 0;
+	bytesReceived = 0;
+	ssl = nullptr;
+	ctx = nullptr;
+	clients = false;
+	servers = false;
+}
+
+void Socket::setSocketOption(int option, bool value = true) {
+	int val = value ? 1 : 0;
+
+	if (::setsockopt(fd, SOL_SOCKET, option, &val, sizeof(val)) != 0) {
+		throw strerror(errno);
+	}
+}
+
+void Socket::bind(Address *address, unsigned short port) {
+	struct sockaddr_in addr;
+	addr.sin_family = AF_INET;
+	addr.sin_addr.s_addr = INADDR_ANY; // address.
+	addr.sin_port = htons(port);
+
+	if (::bind(fd, (struct sockaddr *) &addr, sizeof(addr)) != 0) {
+		throw strerror(errno);
+	}
+}
+
+void Socket::bind(unsigned short port) {
+	struct sockaddr_in addr;
+	addr.sin_family = AF_INET;
+	addr.sin_addr.s_addr = INADDR_ANY;
+	addr.sin_port = htons(port);
+
+	if (::bind(fd, (struct sockaddr *) &addr, sizeof(addr)) != 0) {
+		throw strerror(errno);
+	}
+}
+
+void Socket::listen(int num) {
+	if (::listen(fd, num) != 0) {
+		throw strerror(errno);
+	}
+}
+
+void Socket::connect(Address, unsigned short) {
+
+}
+
+Socket* Socket::accept() {
+	int newfd = ::accept(fd, nullptr, nullptr);
+	if (newfd < 0) {
+		throw strerror(errno);
+	}
+	Socket *socket = new Socket(newfd);
+	socket->servers = true;
+	return socket;
+}
+
+void Socket::close() {
+	if (isSecured()) {
+		//SSL_shutdown(ssl);
+		SSL_free(ssl);
+		SSL_CTX_free(ctx);
+	}
+
+	if (::close(fd) != 0) {
+		throw strerror(errno);
+	}
+}
+
+Address *Socket::getPeerAddress() const {
+	struct sockaddr_storage addr;
+	socklen_t len = sizeof(addr);
+	getpeername(fd, (struct sockaddr *) &addr, &len);
+	struct sockaddr_in *s = (struct sockaddr_in *) &addr;
+	return new Address(s);
+}
+
+unsigned short Socket::getPeerPort() const {
+	struct sockaddr_storage addr;
+	socklen_t len = sizeof(addr);
+	getpeername(fd, (struct sockaddr *) &addr, &len);
+	return ntohs(((struct sockaddr_in *) &addr)->sin_port);
+}
+
+Address *Socket::getSocketAddress() const {
+	struct sockaddr_storage addr;
+	socklen_t len = sizeof(addr);
+	getsockname(fd, (struct sockaddr *) &addr, &len);
+	struct sockaddr_in *s = (struct sockaddr_in *) &addr;
+	return new Address(s);
+}
+
+unsigned short Socket::getSocketPort() const {
+	struct sockaddr_storage addr;
+	socklen_t len = sizeof(addr);
+	getsockname(fd, (struct sockaddr *) &addr, &len);
+	return ntohs(((struct sockaddr_in *) &addr)->sin_port);
+}
+
+
+void Socket::setReuseAddress(bool value) {
+	setSocketOption(SO_REUSEADDR, value);
+}
+
+void Socket::setReusePort(bool value) {
+	setSocketOption(SO_REUSEPORT, value);
+}
+
+
+string Socket::toString() const {
+	return "{[Socket]" + getSocketAddress()->toString() + ":" + to_string(getSocketPort()) + "<->" +
+		   getPeerAddress()->toString() + ":" + to_string(getPeerPort()) + "}";
+}
+
+long Socket::send(string *str) {
+	return send(str->c_str(), str->length());
+}
+
+long Socket::send(string str) {
+	return send(str.c_str(), str.length());
+}
+
+long Socket::send(const char *str, long length) {
+	return send((void*) str, length);
+}
+
+long Socket::send(const char *str) {
+	return send(str, strlen(str));
+}
+
+Socket::~Socket() {
+
+}
+
+long Socket::receive(void *buffer, int size) {
+	long len;
+	if (isSecured()) {
+		len = SSL_read(ssl, buffer,  size);
+		if (len < 0) {
+			throw multi_ssl_get_error(ssl, (int) len);
+		}
+	} else {
+		len = recv(fd, buffer, (size_t) size, 0);
+		if (len < 0) {
+			throw strerror_socket(errno);
+		}
+	}
+	bytesReceived += len;
+	return len;
+}
+
+long Socket::peek(void *buffer, int size) {
+	long len;
+	if (isSecured()) {
+		len = SSL_peek(ssl, buffer, size);
+		if (len < 0) {
+			throw multi_ssl_get_error(ssl, (int) len);
+		}
+	} else {
+		len = recv(fd, buffer, (size_t) size, MSG_PEEK);
+		if (len < 0) {
+			throw strerror_socket(errno);
+		}
+	}
+	return len;
+}
+
+long Socket::send(void *buffer, int size) {
+	long len;
+	if (isSecured()) {
+		if (size != 0) {
+			len = SSL_write(ssl, buffer, size);
+			if (len <= 0) {
+				throw multi_ssl_get_error(ssl, (int) len);
+			}
+		} else {
+			len = 0;
+		}
+	} else {
+		len = ::send(fd, buffer, (size_t) size, 0);
+		if (len < 0) {
+			throw strerror_socket(errno);
+		}
+	}
+	bytesSent += len;
+	return len;
+}
+
+
+string Socket::receive() {
+	string *str = new string();
+
+	char buffer[CHUNK];
+	long len = 0;
+	do {
+		len = receive((void*) buffer, CHUNK);
+		str->append(buffer, (unsigned) len);
+	} while (len > 0 && len == CHUNK);
+
+	return *str;
+}
+
+string Socket::receive(long length) {
+	string *str = new string();
+
+	char buffer[CHUNK];
+	long len = 0;
+	long reclen = 0;
+	do {
+		len = receive((void*) buffer, CHUNK);
+		reclen += len;
+		str->append(buffer, (unsigned) len);
+	} while (reclen < length);
+
+	return *str;
+}
+
+string Socket::receive(string until) {
+	string *str = new string();
+
+	struct pollfd ufds[1];
+	ufds[0].fd = fd;
+	ufds[0].events = POLLIN | POLLOUT;
+
+	char buffer[CHUNK];
+	long len = 0;
+	do {
+		len = peek((void*) buffer, CHUNK);
+		if (len != 0) {
+			string s = string(buffer, (size_t) len);
+			size_t found = s.find(until);
+			long l = (found != string::npos) ? found + 1 : len;
+			long l2 = (found != string::npos) ? found : len;
+			str->append(buffer, (unsigned) l2);
+			receive((void *) buffer, (int) l);
+			if (found != string::npos) {
+				break;
+			}
+		}
+		if (poll(ufds, 1, 0) < 0) {
+			throw strerror_socket(errno);
+		} else if ((ufds[0].revents & POLLIN) == 0) {
+			if ((ufds[0].revents & POLLOUT) != 0) {
+				throw (char *) "error";
+			} else {
+				throw (char *) "want_write";
+			}
+		} else if ((ufds[0].revents & POLLERR) != 0) {
+			throw (char *) "error";
+		} else if (ufds[0].revents & (POLLRDHUP | POLLHUP | POLLNVAL) != 0) {
+			throw (char *) "closed";
+		}
+	} while (true);
+
+	return *str;
+}
+
+string Socket::receive(const char *until) {
+	return receive(until, (int) (strlen(until)));
+}
+
+string Socket::receive(const char *until, unsigned long strlen) {
+	return receive(string(until, strlen));
+}
+
+void Socket::receive(FILE *file) {
+	char buffer[CHUNK];
+	long len = 0;
+	do {
+		len = receive((void*) buffer, CHUNK);
+		fwrite(buffer, 1, CHUNK, file);
+	} while (len > 0 && len == CHUNK);
+}
+
+string Socket::receiveLine() {
+	string str = receive("\n");
+	if (str.length() > 0 && str.at(str.length() - 1) == '\r') {
+		str = str.substr(0, str.length() - 1);
+	}
+	return str;
+}
+
+
+long Socket::getDuration() {
+	return getMicros() - microsStart;
+}
+
+
+void Socket::setReceiveTimeout(unsigned long ms) {
+	struct timeval timeout;
+	if (ms == 0) {
+		timeout.tv_sec = 0;
+		timeout.tv_usec = 1;
+	} else {
+		timeout.tv_sec = ms / 1000;
+		timeout.tv_usec = (ms % 1000) * 1000;
+	}
+	if (setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, (char *) &timeout, sizeof(timeout)) < 0) {
+		throw strerror(errno);
+	}
+}
+
+void Socket::setSendTimeout(unsigned long ms) {
+	struct timeval timeout;
+	if (ms == 0) {
+		timeout.tv_sec = 0;
+		timeout.tv_usec = 1;
+	} else {
+		timeout.tv_sec = ms / 1000;
+		timeout.tv_usec = (ms % 1000) * 1000;
+	}
+	if (setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, (char *) &timeout, sizeof(timeout)) < 0) {
+		throw strerror(errno);
+	}
+}
+
+bool Socket::isServerSide() {
+	return servers;
+}
+
+bool Socket::isSecured() {
+	return enc;
+}
+
+bool Socket::isClientSide() {
+	return clients;
+}
+
+void Socket::sslHandshake(map<string, KeyPair> sni) {
+	/*if (isSecured()) {
+		throw (char *) "Socket already secured";
+	}
+
+	const SSL_METHOD *method;
+	if (isServerSide()) {
+		method = TLSv1_2_server_method();
+	} else if (isClientSide()) {
+		method = TLSv1_2_client_method();
+	} else {
+		method = TLSv1_2_method();
+	}
+
+	SSL_CTX *ctx = SSL_CTX_new(method);
+	SSL_CTX_set_options(ctx, SSL_OP_SINGLE_DH_USE | SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3);
+	SSL_CTX_set_mode(ctx, SSL_MODE_ENABLE_PARTIAL_WRITE);
+	SSL_CTX_set_cipher_list(ctx, "HIGH:!aNULL:!kRSA:!PSK:!SRP:!MD5:!RC4");
+	SSL_CTX_set_ecdh_auto(ctx, 1);
+
+	const char *certfile = keypair.fullchain.c_str();
+	const char *keyfile = keypair.privkey.c_str();
+
+	if (isServerSide()) {
+		if (SSL_CTX_use_certificate_file(ctx, certfile, SSL_FILETYPE_PEM) != 1) {
+			throw (char *) ERR_reason_error_string(ERR_get_error());
+		}
+
+		if (SSL_CTX_use_PrivateKey_file(ctx, keyfile, SSL_FILETYPE_PEM) != 1) {
+			throw (char *) ERR_reason_error_string(ERR_get_error());
+		}
+	}
+
+	SSL_CTX_set_tlsext_servername_callback
+
+	this->ctx = ctx;
+	this->ssl = SSL_new(ctx);
+	SSL_set_fd(ssl, fd);
+	enc = true;
+
+	while (true) {
+		int ret = 0;
+		if (isServerSide()) {
+			ret = SSL_accept(ssl);
+		} else if (isClientSide()) {
+			ret = SSL_connect(ssl);
+		} else {
+			ret = SSL_do_handshake(ssl);
+		}
+
+		if (ret <= 0 && ((isServerSide() && SSL_get_error(ssl, ret) != SSL_ERROR_WANT_READ) ||
+						 (isClientSide() && SSL_get_error(ssl, ret) != SSL_ERROR_WANT_WRITE))) {
+			throw multi_ssl_get_error(ssl, ret);
+		} else if (ret == 1) {
+			break;
+		}
+	}*/
+
+}
+
+void Socket::sslHandshake() {
+	sslHandshake(KeyPair{"", ""});
+}
+
+void Socket::sslHandshake(KeyPair keypair) {
+	if (isSecured()) {
+		throw (char *) "Socket already secured";
+	}
+
+	const SSL_METHOD *method;
+	if (isServerSide()) {
+		method = TLSv1_2_server_method();
+	} else if (isClientSide()) {
+		method = TLSv1_2_client_method();
+	} else {
+		method = TLSv1_2_method();
+	}
+
+	SSL_CTX *ctx = SSL_CTX_new(method);
+	SSL_CTX_set_options(ctx, SSL_OP_SINGLE_DH_USE | SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3);
+	SSL_CTX_set_mode(ctx, SSL_MODE_ENABLE_PARTIAL_WRITE);
+	SSL_CTX_set_cipher_list(ctx, "HIGH:!aNULL:!kRSA:!PSK:!SRP:!MD5:!RC4");
+	SSL_CTX_set_ecdh_auto(ctx, 1);
+
+	const char *certfile = keypair.fullchain.c_str();
+	const char *keyfile = keypair.privkey.c_str();
+
+	if (isServerSide()) {
+		if (SSL_CTX_use_certificate_file(ctx, certfile, SSL_FILETYPE_PEM) != 1) {
+			throw (char *) ERR_reason_error_string(ERR_get_error());
+		}
+
+		if (SSL_CTX_use_PrivateKey_file(ctx, keyfile, SSL_FILETYPE_PEM) != 1) {
+			throw (char *) ERR_reason_error_string(ERR_get_error());
+		}
+	}
+
+	this->ctx = ctx;
+	this->ssl = SSL_new(ctx);
+	SSL_set_fd(ssl, fd);
+	enc = true;
+
+	while (true) {
+		int ret = 0;
+		if (isServerSide()) {
+			ret = SSL_accept(ssl);
+		} else if (isClientSide()) {
+			ret = SSL_connect(ssl);
+		} else {
+			ret = SSL_do_handshake(ssl);
+		}
+
+		if (ret <= 0 && ((isServerSide() && SSL_get_error(ssl, ret) != SSL_ERROR_WANT_READ) ||
+						 (isClientSide() && SSL_get_error(ssl, ret) != SSL_ERROR_WANT_WRITE))) {
+			throw multi_ssl_get_error(ssl, ret);
+		} else if (ret == 1) {
+			break;
+		}
+	}
+
+}
+
+void Socket::sslHandshake(string privkey, string fullchain) {
+	sslHandshake(KeyPair{std::move(privkey), std::move(fullchain)});
+}
+
+long Socket::select(list<Socket> read, list<Socket> write, long millis) {
+	fd_set readfd, writefd;
+	int maxfd = 0;
+	FD_ZERO(&readfd);
+	FD_ZERO(&writefd);
+
+	for (Socket s : read) {
+		if (s.fd > maxfd) {
+			maxfd = s.fd;
+		}
+		FD_SET(s.fd, &readfd);
+	}
+
+	for (Socket s : write) {
+		if (s.fd > maxfd) {
+			maxfd = s.fd;
+		}
+		FD_SET(s.fd, &writefd);
+	}
+
+	struct timeval *tv;
+	if (millis < 0) {
+		tv = nullptr;
+	} else if (millis == 0) {
+		tv->tv_sec = 0;
+		tv->tv_usec = 1;
+	} else {
+		tv->tv_sec = millis / 1000;
+		tv->tv_usec = (millis % 1000) * 1000;
+	}
+
+	int ret = ::select(maxfd + 1, &readfd, &writefd, nullptr, tv);
+	if (ret < 0) {
+		throw (char *) strerror(errno);
+	}
+	return ret;
+}
+
+long Socket::select(list<Socket> read, list<Socket> write) {
+	Socket::select(std::move(read), std::move(write), -1);
+}
+
+unsigned long Socket::getBytesSent() {
+	return bytesSent;
+}
+
+unsigned long Socket::getBytesReceived() {
+	return bytesReceived;
+}
+
+
+ostream &operator<<(ostream &str, const Socket &socket) {
+	return str << socket.toString();
+}
+
+ostream &operator<<(ostream &str, const Socket *socket) {
+	return str << socket->toString();
+}
+
+string operator+(string &str, const Socket &socket) {
+	return str + socket.toString();
+}
+
+string operator+(const Socket &socket, string &str) {
+	return socket.toString() + str;
+}
+
+
+
+
diff --git a/src/network/Socket.h b/src/network/Socket.h
new file mode 100644
index 0000000..e0669c8
--- /dev/null
+++ b/src/network/Socket.h
@@ -0,0 +1,166 @@
+/**
+ * Necronda Web Server 3.0
+ * Socket.h - Socket Class definition
+ * Lorenz Stechauner, 2018-05-09
+ */
+
+#ifndef NECRONDA_SOCKET
+#define NECRONDA_SOCKET
+
+#include <map>
+
+typedef struct {
+	string privkey;
+	string fullchain;
+} KeyPair;
+
+using namespace std;
+
+class Socket {
+private:
+	int fd;
+	SSL *ssl;
+	SSL_CTX *ctx;
+	bool enc;
+	bool servers;
+	bool clients;
+	unsigned long bytesSent;
+	unsigned long bytesReceived;
+	long microsStart;
+	long microsLast;
+
+	void setSocketOption(int, bool);
+
+	long send(void *buffer, int size);
+
+	long receive(void *buffer, int size);
+
+	long peek(void *buffer, int size);
+
+public:
+	Socket();
+
+	explicit Socket(int filedescriptor);
+
+	~Socket();
+
+	void bind(Address *address, unsigned short port);
+
+	void bind(unsigned short port);
+
+	void listen(int count = 1);
+
+	void connect(Address address, unsigned short port);
+
+	Socket* accept();
+
+	void sslHandshake();
+
+	void sslHandshake(map<string, KeyPair> sni);
+
+	void sslHandshake(KeyPair keypair);
+
+	void sslHandshake(string privkey, string fullchain);
+
+	long send(string *str);
+
+	long send(string str);
+
+	long send(const char *str);
+
+	long send(const char *str, long length);
+
+	string receive();
+
+	string receive(long length);
+
+	string receive(string until);
+
+	string receive(const char *until, unsigned long strlen);
+
+	string receive(const char *until);
+
+	void receive(FILE *file);
+
+	string receiveLine();
+
+	void shutdown();
+
+	void close();
+
+	long getDuration();
+
+	Address *getSocketAddress() const;
+
+	unsigned short getSocketPort() const;
+
+	Address *getPeerAddress() const;
+
+	unsigned short getPeerPort() const;
+
+	string toString() const;
+
+
+	bool isServerSide();
+
+	bool isClientSide();
+
+	bool isSecured();
+
+
+	void setReuseAddress(bool value = true);
+
+	void setReusePort(bool value = true);
+
+	void setSendBufferSize(int value);
+
+	void setReceiveBufferSize(int value);
+
+	void setMinReceiveBytes(int value);
+
+	void setMinSendBytes(int value);
+
+	void setSendTimeout(unsigned long ms);
+
+	void setReceiveTimeout(unsigned long ms);
+
+
+	bool getReuseAddress();
+
+	bool getReusePort();
+
+	int getSendBufferSize();
+
+	int getReceiveBufferSize();
+
+	int getMinReceiveBytes();
+
+	int getMinSendBytes();
+
+	long getSendTimeout();
+
+	long getReceiveTimeout();
+
+	unsigned long getBytesSent();
+
+	unsigned long getBytesReceived();
+
+	static long select(list<Socket> read, list<Socket> write, long millis);
+
+	static long select(list<Socket> read, list<Socket> write);
+
+};
+
+Socket operator<<(Socket sock, const char *str);
+
+Socket operator<<(Socket sock, string str);
+
+ostream &operator<<(ostream &str, const Socket &socket);
+
+ostream &operator<<(ostream &str, const Socket *socket);
+
+string operator+(string &str, const Socket &socket);
+
+string operator+(const Socket &socket, string &str);
+
+#endif
diff --git a/src/network/http/HttpConnection.cpp b/src/network/http/HttpConnection.cpp
new file mode 100644
index 0000000..7b17604
--- /dev/null
+++ b/src/network/http/HttpConnection.cpp
@@ -0,0 +1,190 @@
+
+
+#include <zlib.h>
+#include <cassert>
+#include <iostream>
+#include <utility>
+#include "HttpConnection.h"
+#include "../../necronda-server.h"
+#include "HttpStatusCode.h"
+
+HttpConnection::HttpConnection(Socket *socket) {
+	this->socket = socket;
+	this->request = new HttpRequest(socket);
+	this->response = new HttpResponse();
+	microsStart = getMicros();
+	response->setVersion("1.1");
+	response->setField("Server", "Necronda/3.0");
+}
+
+void HttpConnection::respond(int statuscode) {
+	if (statuscode >= 400 && statuscode < 600) {
+		respond(statuscode,
+				"<!DOCTYPE html><html><head><title>" + to_string(statuscode) + " " +
+				::getStatusCode(statuscode).message +
+				"</title></head><body><center><h1>" + to_string(statuscode) + " " +
+				::getStatusCode(statuscode).message +
+				"</h1>" +
+				((request->isExistingField("Host")) ? "<p>Go back to the home page of <a href=\"//" +
+													 request->getField("Host") + "/\">" +
+													 request->getField("Host") +
+													 "</a></p>" : "") + "</center></body></html>\r\n"
+		);
+	} else {
+		respond(statuscode, "");
+	}
+}
+
+void HttpConnection::respond(int statuscode, string payload) {
+	response->setStatusCode(statuscode);
+	response->setField("Date", getHttpDate());
+	response->setField("Content-Length", to_string(payload.length()));
+	response->sendHeader(socket);
+	socket->send(std::move(payload));
+}
+
+void HttpConnection::respond(int statuscode, FILE *file, bool compress, long start, long end) {
+	response->setStatusCode(statuscode);
+	response->setField("Transfer-Encoding", "chunked");
+	response->setField("Date", getHttpDate());
+
+	long shouldTransfer;
+	long transfered = 0;
+
+	fseek(file, 0, SEEK_END);
+	long len = ftell(file);
+
+	if (start != -1 && end != -1) {
+		fseek(file, start, SEEK_SET);
+		response->setField("Content-Length", to_string(end - start + 1));
+		shouldTransfer = end - start + 1;
+		compress = false;
+	} else {
+		fseek(file, 0, SEEK_SET);
+		shouldTransfer = len;
+		if (len >= 0) {
+			response->setField("Content-Length", to_string(len));
+		}
+	}
+
+	if (compress) {
+		response->setField("Content-Encoding", "deflate");
+	}
+
+	response->sendHeader(socket);
+
+	if (compress) {
+		int level = 1;
+		int ret, flush;
+		unsigned have;
+		z_stream strm;
+		unsigned char in[CHUNK];
+		unsigned char out[CHUNK];
+
+		strm.zalloc = Z_NULL;
+		strm.zfree = Z_NULL;
+		strm.opaque = Z_NULL;
+		ret = deflateInit(&strm, level);
+		if (ret != Z_OK) {
+			throw (char *) "Unable to open file";
+		}
+
+		do {
+			strm.avail_in = (uInt) fread(in, 1, CHUNK, file);
+
+			if (ferror(file)) {
+				(void) deflateEnd(&strm);
+				throw (char *) strerror(errno);
+			}
+			flush = feof(file) ? Z_FINISH : Z_NO_FLUSH;
+			strm.next_in = in;
+			do {
+				strm.avail_out = CHUNK;
+				strm.next_out = out;
+				ret = deflate(&strm, flush);
+				assert(ret != Z_STREAM_ERROR);
+				have = CHUNK - strm.avail_out;
+
+				if (have != 0) {
+					char buffer[64];
+					sprintf(buffer, "%X\r\n", have);
+					socket->send(buffer);
+					socket->send((const char *) out, have);
+					socket->send("\r\n");
+				}
+			} while (strm.avail_out == 0);
+			assert(strm.avail_in == 0);
+		} while (flush != Z_FINISH);
+		assert(ret == Z_STREAM_END);
+		socket->send("0\r\n\r\n");
+		deflateEnd(&strm);
+	} else {
+		char buffer[CHUNK];
+		char buff[64];
+		while (true) {
+			unsigned long size = fread(buffer, 1,
+									   (CHUNK > (shouldTransfer - transfered)) ? (shouldTransfer - transfered) : CHUNK,
+									   file);
+			transfered += size;
+			sprintf(buff, "%lX\r\n", size);
+			socket->send(buff);
+			socket->send((const char *) buffer, size);
+			socket->send("\r\n");
+			if (size == 0) {
+				break;
+			}
+		}
+	}
+}
+
+string HttpConnection::getField(string index) {
+	return request->getField(std::move(index));
+}
+
+string HttpConnection::getPath() {
+	return request->getPath();
+}
+
+void HttpConnection::setField(string index, string data) {
+	response->setField(std::move(index), std::move(data));
+}
+
+bool HttpConnection::isExistingField(string index) {
+	return request->isExistingField(std::move(index));
+}
+
+string HttpConnection::getMethod() {
+	return request->getMethod();
+}
+
+long HttpConnection::getDuration() {
+	return getMicros() - microsStart;
+}
+
+HttpStatusCode HttpConnection::getStatusCode() {
+	return response->getStatusCode();
+}
+
+void HttpConnection::redirect(int statuscode, string location) {
+	setField("Location", std::move(location));
+	respond(statuscode, "");
+}
+
+string HttpConnection::getResponseField(string index) {
+	return response->getField(std::move(index));
+}
+
+bool HttpConnection::isExistingResponseField(string index) {
+	return response->isExistingField(std::move(index));
+}
+
+string HttpConnection::cgiExport() {
+	return request->cgiExport();
+}
+
+void HttpConnection::removeField(string index) {
+	response->removeField(std::move(index));
+}
+
+
+
diff --git a/src/network/http/HttpConnection.h b/src/network/http/HttpConnection.h
new file mode 100644
index 0000000..464ea98
--- /dev/null
+++ b/src/network/http/HttpConnection.h
@@ -0,0 +1,54 @@
+
+
+#ifndef NECRONDA_HTTP_CONNECTION
+#define NECRONDA_HTTP_CONNECTION
+
+
+#include "../Socket.h"
+#include "HttpResponse.h"
+#include "HttpRequest.h"
+#include "../../necronda-server.h"
+
+
+class HttpConnection {
+private:
+	Socket *socket;
+	HttpRequest *request;
+	HttpResponse *response;
+	long microsStart;
+
+public:
+	explicit HttpConnection(Socket *socket);
+
+	void respond(int statuscode);
+
+	void respond(int statuscode, string payload);
+
+	void respond(int statuscode, FILE *file, bool compress = false, long start = -1, long end = -1);
+
+	void redirect(int statuscode, string location);
+
+	bool isExistingField(string index);
+
+	bool isExistingResponseField(string index);
+
+	string getField(string index);
+
+	string getResponseField(string index);
+
+	string getPath();
+
+	string getMethod();
+
+	void setField(string index, string data);
+
+	long getDuration();
+
+	HttpStatusCode getStatusCode();
+
+	string cgiExport();
+
+	void removeField(string index);
+};
+
+#endif
diff --git a/src/network/http/HttpHeader.cpp b/src/network/http/HttpHeader.cpp
new file mode 100644
index 0000000..d6db7b7
--- /dev/null
+++ b/src/network/http/HttpHeader.cpp
@@ -0,0 +1,123 @@
+/**
+ * Necronda Web Server 3.0
+ * HttpHeader.cpp - HttpHeader Class methods
+ * Lorenz Stechauner, 2018-05-09
+ */
+
+
+#include <map>
+#include <iostream>
+#include "../Socket.h"
+
+#include "HttpHeader.h"
+#include "../../necronda-server.h"
+
+
+using namespace std;
+
+string to_cgi(string text) {
+	for (auto & c: text) c = (char) toupper(c);
+	long pos = 0;
+	while ((pos = text.find('-', pos + 1)) != string::npos) {
+		text.replace(pos, 1, 1, '_');
+	}
+	return text;
+}
+
+
+/**
+ * Default Constructor
+ */
+HttpHeader::HttpHeader() {
+	fields = fields;
+}
+
+HttpHeader::HttpHeader(Socket *socket) : HttpHeader::HttpHeader() {
+	parse(socket);
+}
+
+
+void HttpHeader::parse(Socket *socket) {
+	while (true) {
+		string line = socket->receiveLine();
+		if (line.length() == 0) {
+			break;
+		} else {
+			unsigned long pos = line.find(':');
+			if (pos == string::npos) {
+				throw (char *) "Malformed header";
+			}
+			string index = line.substr(0, pos);
+			string data = line.substr(pos + 1, line.length() - pos);
+			while (index[0] == ' ') index.erase(index.begin() + 0);
+			while (index[index.length() - 1] == ' ') index.erase(index.end() - 1);
+			while (data[0] == ' ') data.erase(data.begin() + 0);
+			while (data[data.length() - 1] == ' ') data.erase(data.end() - 1);
+			setField(index, data);
+		}
+	}
+}
+
+
+/**
+ * Default Destructor
+ */
+HttpHeader::~HttpHeader() {
+	fields.clear();
+}
+
+
+/**
+ * Sets a field in the HTTP header
+ * e.g. Content-Length: 42
+ * @param index The field index
+ * @param data The field data
+ */
+void HttpHeader::setField(string index, string data) {
+	removeField(index);
+	fields.insert(make_pair(index, data));
+}
+
+void HttpHeader::removeField(string index) {
+	fields.erase(index);
+}
+
+/**
+ * Gets a field from the HTTP header
+ * e.g. Content-Length: 42
+ * @param index The field index
+ * @return The field data
+ */
+string HttpHeader::getField(string index) {
+	auto i = fields.find(index);
+	if (i != fields.end()) {
+		return fields.at(index);
+	} else {
+		return nullptr;
+	}
+}
+
+
+bool HttpHeader::isExistingField(string index) {
+	auto i = fields.find(index);
+	return i != fields.end();
+}
+
+string HttpHeader::toString() {
+	string header = "";
+	for (auto it = fields.begin(); it != fields.end(); it++ ) {
+		header += it->first + ": " + it->second + "\r\n";
+	}
+	return header;
+}
+
+string HttpHeader::cgiExport() {
+	string header = "";
+	for (auto it = fields.begin(); it != fields.end(); it++ ) {
+		header += "HTTP_" + to_cgi(it->first) + "=" + cli_encode(it->second) + " ";
+	}
+	return header;
+}
+
+
+
diff --git a/src/network/http/HttpHeader.h b/src/network/http/HttpHeader.h
new file mode 100644
index 0000000..291f434
--- /dev/null
+++ b/src/network/http/HttpHeader.h
@@ -0,0 +1,53 @@
+/**
+ * Necronda Web Server 3.0
+ * HttpHeader.h - HttpHeader Class definition
+ * Lorenz Stechauner, 2018-05-09
+ */
+
+#ifndef NECRONDA_HTTP_HEADER
+#define NECRONDA_HTTP_HEADER
+
+#include <cstring>
+
+using namespace std;
+
+struct comp {
+	bool operator()(const std::string& lhs, const std::string& rhs) const {
+		return strcasecmp(lhs.c_str(), rhs.c_str()) < 0;
+	}
+};
+
+/**
+ * Stores Key-Value Pairs for a HTTP header
+ * e.g.
+ * Content-Length: 64
+ * Host: example.org
+ */
+class HttpHeader {
+private:
+	map<string, string, comp> fields;
+
+public:
+	HttpHeader();
+
+	explicit HttpHeader(Socket *socket);
+
+	~HttpHeader();
+
+	void setField(string index, string data);
+
+	string getField(string index);
+
+	void removeField(string index);
+
+	bool isExistingField(string index);
+
+	void parse(Socket *socket);
+
+	string toString();
+
+	string cgiExport();
+
+};
+
+#endif
diff --git a/src/network/http/HttpRequest.cpp b/src/network/http/HttpRequest.cpp
new file mode 100644
index 0000000..c323a01
--- /dev/null
+++ b/src/network/http/HttpRequest.cpp
@@ -0,0 +1,107 @@
+
+
+#include <string>
+#include <utility>
+#include <iostream>
+#include "../Socket.h"
+#include "HttpHeader.h"
+#include "HttpRequest.h"
+
+
+HttpRequest::HttpRequest() {
+	this->header = HttpHeader();
+}
+
+HttpRequest::HttpRequest(Socket *socket) : HttpRequest::HttpRequest() {
+	parseHeader(socket);
+}
+
+HttpRequest::HttpRequest(string method, string path, string version) : HttpRequest::HttpRequest() {
+	this->method = std::move(method);
+	this->path = std::move(path);
+	this->version = std::move(version);
+}
+
+void HttpRequest::parseHeader(Socket *socket) {
+	string line = socket->receiveLine();
+
+	unsigned long pos1 = line.find(' ');
+	unsigned long pos2;
+
+	bool invalid = false;
+
+	if (pos1 != string::npos) {
+		pos2 = line.find(' ', pos1 + 1);
+		if (pos2 != string::npos) {
+			method = line.substr(0, pos1);
+			for (auto &c: method) c = (char) toupper(c);
+			path = line.substr(pos1 + 1, pos2 - pos1 - 1);
+			version = line.substr(pos2 + 6, 3);
+		} else {
+			invalid = true;
+		}
+	} else {
+		pos2 = string::npos;
+		invalid = true;
+	}
+
+
+	if (!invalid && (line.substr(pos2 + 1, 5) != "HTTP/" || version[1] != '.' || path[0] != '/' || !(version[0] >= '0' && version[0] <= '9') || !(version[2] >= '0' && version[2] <= '9'))) {
+		invalid = true;
+	}
+
+	if (invalid) {
+		method = "";
+		path = "";
+		version = "";
+		throw (char *) "Malformed header";
+	}
+
+	header.parse(socket);
+}
+
+string HttpRequest::getMethod() {
+	return method;
+}
+
+string HttpRequest::getPath() {
+	return path;
+}
+
+string HttpRequest::getVersion() {
+	return version;
+}
+
+void HttpRequest::setMethod(string method) {
+	this->method = std::move(method);
+}
+
+void HttpRequest::setPath(string path) {
+	this->path = std::move(path);
+}
+
+void HttpRequest::setVersion(string version) {
+	this->version = std::move(version);
+}
+
+string HttpRequest::getField(string index) {
+	return header.getField(std::move(index));
+}
+
+void HttpRequest::setField(string index, string data) {
+	header.setField(std::move(index), std::move(data));
+}
+
+bool HttpRequest::isExistingField(string index) {
+	return header.isExistingField(std::move(index));
+}
+
+string HttpRequest::cgiExport() {
+	return header.cgiExport();
+}
+
+
+
+
+
+
diff --git a/src/network/http/HttpRequest.h b/src/network/http/HttpRequest.h
new file mode 100644
index 0000000..1432719
--- /dev/null
+++ b/src/network/http/HttpRequest.h
@@ -0,0 +1,52 @@
+/**
+ * Necronda Web Server 3.0
+ * HttpHeader.h - HttpHeader Class definition
+ * Lorenz Stechauner, 2018-05-09
+ */
+
+#ifndef NECRONDA_HTTP_REQUEST
+#define NECRONDA_HTTP_REQUEST
+
+using namespace std;
+
+class HttpRequest {
+private:
+	HttpHeader header;
+	string method;
+	string path;
+	string version;
+
+public:
+	HttpRequest();
+
+	explicit HttpRequest(Socket *socket);
+
+	HttpRequest(string method, string path, string version = "1.1");
+
+	void parseHeader(Socket *socket);
+
+	void sendHeader(Socket *socket);
+
+	string getField(string index);
+
+	void setField(string index, string data);
+
+	bool isExistingField(string index);
+
+	string getMethod();
+
+	string getPath();
+
+	string getVersion();
+
+	void setMethod(string method);
+
+	void setPath(string path);
+
+	void setVersion(string version);
+
+	string cgiExport();
+
+};
+
+#endif
diff --git a/src/network/http/HttpResponse.cpp b/src/network/http/HttpResponse.cpp
new file mode 100644
index 0000000..83df59e
--- /dev/null
+++ b/src/network/http/HttpResponse.cpp
@@ -0,0 +1,70 @@
+//
+// Created by lorenz on 5/17/18.
+//
+
+#include "HttpResponse.h"
+#include <utility>
+#include <iostream>
+#include "HttpStatusCode.h"
+
+
+HttpResponse::HttpResponse() {
+	this->header = HttpHeader();
+}
+
+HttpResponse::HttpResponse(Socket *socket) : HttpResponse::HttpResponse() {
+	this->parseHeader(socket);
+}
+
+HttpResponse::HttpResponse(int statuscode, string version) : HttpResponse::HttpResponse(::getStatusCode(statuscode), std::move(version)) {
+}
+
+HttpResponse::HttpResponse(HttpStatusCode statuscode, string version) : HttpResponse::HttpResponse() {
+	this->statuscode = statuscode;
+	this->version = std::move(version);
+}
+
+void HttpResponse::sendHeader(Socket *socket) {
+	socket->send("HTTP/" + version + " " + to_string(statuscode.code) + " " + statuscode.message + "\r\n" +
+			header.toString() + "\r\n");
+}
+
+string HttpResponse::getField(string index) {
+	return header.getField(std::move(index));
+}
+
+void HttpResponse::setField(string index, string data) {
+	header.setField(std::move(index), std::move(data));
+}
+
+bool HttpResponse::isExistingField(string index) {
+	return header.isExistingField(std::move(index));
+}
+
+HttpStatusCode HttpResponse::getStatusCode() {
+	return statuscode;
+}
+
+string HttpResponse::getVersion() {
+	return version;
+}
+
+void HttpResponse::setStatusCode(HttpStatusCode statuscode) {
+	this->statuscode = statuscode;
+}
+
+void HttpResponse::setStatusCode(int statuscode) {
+	this->statuscode = ::getStatusCode(statuscode);
+}
+
+void HttpResponse::setVersion(string version) {
+	this->version = std::move(version);
+}
+
+void HttpResponse::parseHeader(Socket *socket) {
+
+}
+
+void HttpResponse::removeField(string index) {
+	header.removeField(std::move(index));
+}
diff --git a/src/network/http/HttpResponse.h b/src/network/http/HttpResponse.h
new file mode 100644
index 0000000..f664e71
--- /dev/null
+++ b/src/network/http/HttpResponse.h
@@ -0,0 +1,50 @@
+
+
+#ifndef NECRONDA_HTTP_RESPONSE
+#define NECRONDA_HTTP_RESPONSE
+
+
+#include <string>
+#include "HttpHeader.h"
+#include "HttpStatusCode.h"
+#include "../Socket.h"
+
+class HttpResponse {
+private:
+	HttpHeader header;
+	HttpStatusCode statuscode;
+	string version;
+
+public:
+	HttpResponse();
+
+	explicit HttpResponse(Socket *socket);
+
+	explicit HttpResponse(int statuscode, string version = "1.1");
+
+	explicit HttpResponse(HttpStatusCode statuscode, string version = "1.1");
+
+	void parseHeader(Socket *socket);
+
+	void sendHeader(Socket *socket);
+
+	string getField(string index);
+
+	void setField(string index, string data);
+
+	bool isExistingField(string index);
+
+	HttpStatusCode getStatusCode();
+
+	string getVersion();
+
+	void setStatusCode(HttpStatusCode statuscode);
+
+	void setStatusCode(int statuscode);
+
+	void setVersion(string version);
+
+	void removeField(string index);
+};
+
+#endif
diff --git a/src/network/http/HttpStatusCode.cpp b/src/network/http/HttpStatusCode.cpp
new file mode 100644
index 0000000..bffeafb
--- /dev/null
+++ b/src/network/http/HttpStatusCode.cpp
@@ -0,0 +1,65 @@
+#include "HttpStatusCode.h"
+
+/**
+ * Necronda Web Server 3.0
+ * HttpStatusCode.cpp - HTTP Status Code definition
+ * Lorenz Stechauner, 2018-05-16
+ * Reference: https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html
+ */
+
+
+HttpStatusCode httpStatusCodes[] = {
+		HttpStatusCode{100, "Informational", 	"Continue", ""},
+		HttpStatusCode{101, "Informational", 	"Switching Protocols", ""},
+
+		HttpStatusCode{200, "Success", 			"OK", ""},
+		HttpStatusCode{201, "Success", 			"Created", ""},
+		HttpStatusCode{202, "Success",			"Accepted", ""},
+		HttpStatusCode{203, "Success", 			"Non-Authoritative Information", ""},
+		HttpStatusCode{204, "Success", 			"No Centent", ""},
+		HttpStatusCode{205, "Success", 			"Reset Content", ""},
+		HttpStatusCode{206, "Success", 			"Partial Content", ""},
+
+		HttpStatusCode{300, "Redirection", 		"Multiple Choices", ""},
+		HttpStatusCode{301, "Redirection", 		"Moved Permanently", ""},
+		HttpStatusCode{302, "Redirection", 		"Found", ""},
+		HttpStatusCode{303, "Redirection", 		"See Other", ""},
+		HttpStatusCode{304, "Redirection", 		"Not Modified", ""},
+		HttpStatusCode{305, "Redirection", 		"Use Proxy", ""},
+		HttpStatusCode{307, "Redirection", 		"Temporary Redirect", ""},
+
+		HttpStatusCode{400, "Client Error", 	"Bad Request", ""},
+		HttpStatusCode{401, "Client Error", 	"Unauthorized", ""},
+		HttpStatusCode{402, "Client Error", 	"Payment Required", ""},
+		HttpStatusCode{403, "Client Error", 	"Forbidden", ""},
+		HttpStatusCode{404, "Client Error", 	"Not Found", ""},
+		HttpStatusCode{405, "Client Error", 	"Method Not Allowed", ""},
+		HttpStatusCode{406, "Client Error", 	"Not Acceptable", ""},
+		HttpStatusCode{407, "Client Error", 	"Proxy Authentication Required", ""},
+		HttpStatusCode{408, "Client Error", 	"Request Timeout", ""},
+		HttpStatusCode{409, "Client Error", 	"Conflict", ""},
+		HttpStatusCode{410, "Client Error", 	"Gone", ""},
+		HttpStatusCode{411, "Client Error", 	"Length Required", ""},
+		HttpStatusCode{412, "Client Error", 	"Precondition Failed", ""},
+		HttpStatusCode{413, "Client Error", 	"Request Entity Too Large", ""},
+		HttpStatusCode{414, "Client Error", 	"Request-URI Too Long", ""},
+		HttpStatusCode{415, "Client Error", 	"Unsupported Media Type", ""},
+		HttpStatusCode{416, "Client Error", 	"Requested Range Not Satisfiable", ""},
+		HttpStatusCode{417, "Client Error", 	"Expectation Failed", ""},
+
+		HttpStatusCode{500, "Server Error", 	"Internal Server Error", ""},
+		HttpStatusCode{501, "Server Error", 	"Not Implemented", ""},
+		HttpStatusCode{502, "Server Error", 	"Bad Gateway", ""},
+		HttpStatusCode{503, "Server Error", 	"Service Unavailable", ""},
+		HttpStatusCode{504, "Server Error", 	"Gateway Timeout", ""},
+		HttpStatusCode{505, "Server Error", 	"HTTP Version Not Supported", ""},
+};
+
+HttpStatusCode getStatusCode(int statuscode) {
+	for (HttpStatusCode sc : httpStatusCodes) {
+		if (sc.code == statuscode) {
+			return sc;
+		}
+	}
+	throw (char *) "Invalid status code";
+}
diff --git a/src/network/http/HttpStatusCode.h b/src/network/http/HttpStatusCode.h
new file mode 100644
index 0000000..7773af9
--- /dev/null
+++ b/src/network/http/HttpStatusCode.h
@@ -0,0 +1,15 @@
+
+
+#ifndef NECRONDA_HTTP_STATUSCODE
+#define NECRONDA_HTTP_STATUSCODE
+
+typedef struct {
+	short code;					// The status code (e.g. 200)
+	const char *type; 			// The status type type (e.g Success)
+	const char *message;		// The status code message (e.g. OK)
+	const char *description;	// The status code description (currently not used)
+} HttpStatusCode;
+
+HttpStatusCode getStatusCode(int statuscode);
+
+#endif
\ No newline at end of file