Replaced tabs with spaces
This commit is contained in:
246
src/URI.cpp
246
src/URI.cpp
@ -7,188 +7,188 @@
|
|||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
string getExtension(string path) {
|
string getExtension(string path) {
|
||||||
long pos = path.find_last_of('.');
|
long pos = path.find_last_of('.');
|
||||||
if (pos == string::npos) {
|
if (pos == string::npos) {
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
return path.substr(pos + 1, path.length() - pos);
|
return path.substr(pos + 1, path.length() - pos);
|
||||||
}
|
}
|
||||||
|
|
||||||
string getFilename(string path) {
|
string getFilename(string path) {
|
||||||
long pos = path.find_last_of('/');
|
long pos = path.find_last_of('/');
|
||||||
if (pos == string::npos) {
|
if (pos == string::npos) {
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
return path.substr(pos + 1, path.length() - pos);
|
return path.substr(pos + 1, path.length() - pos);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isDirectory(string path) {
|
bool isDirectory(string path) {
|
||||||
struct stat statbuf;
|
struct stat statbuf;
|
||||||
return stat(path.c_str(), &statbuf) == 0 && S_ISDIR(statbuf.st_mode) != 0;
|
return stat(path.c_str(), &statbuf) == 0 && S_ISDIR(statbuf.st_mode) != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isFile(string path) {
|
bool isFile(string path) {
|
||||||
struct stat statbuf;
|
struct stat statbuf;
|
||||||
return stat(path.c_str(), &statbuf) == 0 && S_ISDIR(statbuf.st_mode) == 0;
|
return stat(path.c_str(), &statbuf) == 0 && S_ISDIR(statbuf.st_mode) == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool fileExists(string path) {
|
bool fileExists(string path) {
|
||||||
struct stat statbuf;
|
struct stat statbuf;
|
||||||
return stat(path.c_str(), &statbuf) == 0;
|
return stat(path.c_str(), &statbuf) == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
URI::URI(string webroot, string reqpath) {
|
URI::URI(string webroot, string reqpath) {
|
||||||
unsigned long pos = reqpath.find('?');
|
unsigned long pos = reqpath.find('?');
|
||||||
if (pos != string::npos) {
|
if (pos != string::npos) {
|
||||||
queryinit = true;
|
queryinit = true;
|
||||||
query = reqpath.substr(pos + 1, reqpath.length() - pos);
|
query = reqpath.substr(pos + 1, reqpath.length() - pos);
|
||||||
reqpath.erase(pos, reqpath.length() - pos);
|
reqpath.erase(pos, reqpath.length() - pos);
|
||||||
} else {
|
} else {
|
||||||
query = "";
|
query = "";
|
||||||
queryinit = false;
|
queryinit = false;
|
||||||
}
|
}
|
||||||
if (webroot.length() >= 1 && webroot[webroot.length() - 1] == '/') {
|
if (webroot.length() >= 1 && webroot[webroot.length() - 1] == '/') {
|
||||||
webroot.erase(webroot.length() - 1);
|
webroot.erase(webroot.length() - 1);
|
||||||
}
|
}
|
||||||
reqpath = url_decode(reqpath);
|
reqpath = url_decode(reqpath);
|
||||||
if (reqpath.find("/../") != string::npos) {
|
if (reqpath.find("/../") != string::npos) {
|
||||||
throw (char *) "Invalid path";
|
throw (char *) "Invalid path";
|
||||||
}
|
}
|
||||||
if (reqpath[0] != '/') {
|
if (reqpath[0] != '/') {
|
||||||
reqpath = '/' + reqpath;
|
reqpath = '/' + reqpath;
|
||||||
}
|
}
|
||||||
this->webroot = webroot;
|
this->webroot = webroot;
|
||||||
this->reqpath = reqpath;
|
this->reqpath = reqpath;
|
||||||
|
|
||||||
info = "";
|
info = "";
|
||||||
relpath = reqpath;
|
relpath = reqpath;
|
||||||
|
|
||||||
while ((!fileExists(webroot + relpath) || (isDirectory(webroot + relpath) && !fileExists(webroot + relpath + "/index.php")))
|
while ((!fileExists(webroot + relpath) || (isDirectory(webroot + relpath) && !fileExists(webroot + relpath + "/index.php")))
|
||||||
&& (!fileExists(webroot + relpath + ".php") || (isDirectory(webroot + relpath + ".php") && !fileExists(webroot + relpath + ".php/index.php")))
|
&& (!fileExists(webroot + relpath + ".php") || (isDirectory(webroot + relpath + ".php") && !fileExists(webroot + relpath + ".php/index.php")))
|
||||||
&& (!fileExists(webroot + relpath + ".html") || (isDirectory(webroot + relpath + ".html") && !fileExists(webroot + relpath + ".html/index.php")))) {
|
&& (!fileExists(webroot + relpath + ".html") || (isDirectory(webroot + relpath + ".html") && !fileExists(webroot + relpath + ".html/index.php")))) {
|
||||||
long slash = relpath.find_last_of('/');
|
long slash = relpath.find_last_of('/');
|
||||||
if (slash == string::npos || relpath == "/") {
|
if (slash == string::npos || relpath == "/") {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
info = relpath.substr(slash) + info;
|
info = relpath.substr(slash) + info;
|
||||||
relpath.erase(slash);
|
relpath.erase(slash);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!info.empty() && isDirectory(webroot + relpath)) {
|
if (!info.empty() && isDirectory(webroot + relpath)) {
|
||||||
relpath.append("/");
|
relpath.append("/");
|
||||||
}
|
}
|
||||||
|
|
||||||
string abs = relpath;
|
string abs = relpath;
|
||||||
if (fileExists(webroot + abs)) {
|
if (fileExists(webroot + abs)) {
|
||||||
string ext = getExtension(abs);
|
string ext = getExtension(abs);
|
||||||
if (ext == "php" || ext == "html") {
|
if (ext == "php" || ext == "html") {
|
||||||
abs.erase(abs.length() - ext.length() - 1, abs.length());
|
abs.erase(abs.length() - ext.length() - 1, abs.length());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
string fname = getFilename(abs);
|
string fname = getFilename(abs);
|
||||||
if (fname == "index") {
|
if (fname == "index") {
|
||||||
abs.erase(abs.length() - fname.length() - 1, abs.length());
|
abs.erase(abs.length() - fname.length() - 1, abs.length());
|
||||||
}
|
}
|
||||||
|
|
||||||
this->filepath = webroot + relpath;
|
this->filepath = webroot + relpath;
|
||||||
|
|
||||||
if (isDirectory(webroot + abs)) {
|
if (isDirectory(webroot + abs)) {
|
||||||
if (abs[abs.length() - 1] != '/') {
|
if (abs[abs.length() - 1] != '/') {
|
||||||
abs += "/";
|
abs += "/";
|
||||||
}
|
}
|
||||||
this->relpath = abs;
|
this->relpath = abs;
|
||||||
abs += "index";
|
abs += "index";
|
||||||
if (fileExists(webroot + abs + ".php")) {
|
if (fileExists(webroot + abs + ".php")) {
|
||||||
this->filepath = webroot + abs + ".php";
|
this->filepath = webroot + abs + ".php";
|
||||||
} else if (fileExists(webroot + abs + ".html")) {
|
} else if (fileExists(webroot + abs + ".html")) {
|
||||||
this->filepath = webroot + abs + ".html";
|
this->filepath = webroot + abs + ".html";
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (abs[abs.length() - 1] == '/') {
|
if (abs[abs.length() - 1] == '/') {
|
||||||
abs.erase(abs.length() - 1, abs.length() - 1);
|
abs.erase(abs.length() - 1, abs.length() - 1);
|
||||||
}
|
}
|
||||||
this->relpath = abs;
|
this->relpath = abs;
|
||||||
if (fileExists(webroot + abs + ".php")) {
|
if (fileExists(webroot + abs + ".php")) {
|
||||||
this->filepath = webroot + abs + ".php";
|
this->filepath = webroot + abs + ".php";
|
||||||
} else if (fileExists(webroot + abs + ".html")) {
|
} else if (fileExists(webroot + abs + ".html")) {
|
||||||
this->filepath = webroot + abs + ".html";
|
this->filepath = webroot + abs + ".html";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isStatic() && !info.empty()) {
|
if (isStatic() && !info.empty()) {
|
||||||
if (relpath[relpath.length() - 1] == '/') {
|
if (relpath[relpath.length() - 1] == '/') {
|
||||||
relpath.erase(relpath.length() - 1);
|
relpath.erase(relpath.length() - 1);
|
||||||
}
|
}
|
||||||
newpath = relpath + info;
|
newpath = relpath + info;
|
||||||
filepath = "";
|
filepath = "";
|
||||||
} else if (relpath != reqpath) {
|
} else if (relpath != reqpath) {
|
||||||
if (!info.empty() && relpath[relpath.length() - 1] == '/') {
|
if (!info.empty() && relpath[relpath.length() - 1] == '/') {
|
||||||
info.erase(0,1);
|
info.erase(0,1);
|
||||||
}
|
}
|
||||||
newpath = relpath + info;
|
newpath = relpath + info;
|
||||||
} else {
|
} else {
|
||||||
newpath = "";
|
newpath = "";
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
string URI::getWebRoot() {
|
string URI::getWebRoot() {
|
||||||
return webroot;
|
return webroot;
|
||||||
}
|
}
|
||||||
|
|
||||||
string URI::getRelativePath() {
|
string URI::getRelativePath() {
|
||||||
return relpath;
|
return relpath;
|
||||||
}
|
}
|
||||||
|
|
||||||
string URI::getAbsolutePath() {
|
string URI::getAbsolutePath() {
|
||||||
return webroot + relpath;
|
return webroot + relpath;
|
||||||
}
|
}
|
||||||
|
|
||||||
string URI::getFilePath() {
|
string URI::getFilePath() {
|
||||||
return filepath;
|
return filepath;
|
||||||
}
|
}
|
||||||
|
|
||||||
string URI::getRelativeFilePath() {
|
string URI::getRelativeFilePath() {
|
||||||
string str = getFilePath();
|
string str = getFilePath();
|
||||||
long len = getWebRoot().length();
|
long len = getWebRoot().length();
|
||||||
return str.substr(len, str.length() - len);
|
return str.substr(len, str.length() - len);
|
||||||
}
|
}
|
||||||
|
|
||||||
string URI::getNewPath() {
|
string URI::getNewPath() {
|
||||||
if (isStatic()) {
|
if (isStatic()) {
|
||||||
if (hasQuery()) {
|
if (hasQuery()) {
|
||||||
return getRelativePath();
|
return getRelativePath();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!newpath.empty() && newpath != reqpath) {
|
if (!newpath.empty() && newpath != reqpath) {
|
||||||
return url_encode(newpath) + (queryinit? "?" + query : "");
|
return url_encode(newpath) + (queryinit? "?" + query : "");
|
||||||
} else {
|
} else {
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
FILE *URI::openFile() {
|
FILE *URI::openFile() {
|
||||||
return fopen64(getFilePath().c_str(), "rb");
|
return fopen64(getFilePath().c_str(), "rb");
|
||||||
}
|
}
|
||||||
|
|
||||||
string URI::getFilePathInfo() {
|
string URI::getFilePathInfo() {
|
||||||
return info; //getAbsolutePath().erase(getFilePath().length(), getAbsolutePath().length());
|
return info; //getAbsolutePath().erase(getFilePath().length(), getAbsolutePath().length());
|
||||||
}
|
}
|
||||||
|
|
||||||
string URI::getFileType() {
|
string URI::getFileType() {
|
||||||
return getMimeType(getFilePath());
|
return getMimeType(getFilePath());
|
||||||
}
|
}
|
||||||
|
|
||||||
bool URI::isStatic() {
|
bool URI::isStatic() {
|
||||||
return getExtension(filepath) != "php";
|
return getExtension(filepath) != "php";
|
||||||
}
|
}
|
||||||
|
|
||||||
string URI::getQuery() {
|
string URI::getQuery() {
|
||||||
return query;
|
return query;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool URI::hasQuery() {
|
bool URI::hasQuery() {
|
||||||
return queryinit;
|
return queryinit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
42
src/URI.h
42
src/URI.h
@ -8,41 +8,41 @@ using namespace std;
|
|||||||
|
|
||||||
class URI {
|
class URI {
|
||||||
private:
|
private:
|
||||||
string webroot;
|
string webroot;
|
||||||
string reqpath;
|
string reqpath;
|
||||||
string relpath;
|
string relpath;
|
||||||
string query;
|
string query;
|
||||||
string info;
|
string info;
|
||||||
string filepath;
|
string filepath;
|
||||||
string newpath;
|
string newpath;
|
||||||
bool queryinit;
|
bool queryinit;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
URI(string webroot, string reqpath);
|
URI(string webroot, string reqpath);
|
||||||
|
|
||||||
string getWebRoot();
|
string getWebRoot();
|
||||||
|
|
||||||
string getRelativePath();
|
string getRelativePath();
|
||||||
|
|
||||||
string getAbsolutePath();
|
string getAbsolutePath();
|
||||||
|
|
||||||
string getFilePath();
|
string getFilePath();
|
||||||
|
|
||||||
string getRelativeFilePath();
|
string getRelativeFilePath();
|
||||||
|
|
||||||
string getNewPath();
|
string getNewPath();
|
||||||
|
|
||||||
FILE *openFile();
|
FILE *openFile();
|
||||||
|
|
||||||
string getFilePathInfo();
|
string getFilePathInfo();
|
||||||
|
|
||||||
string getFileType();
|
string getFileType();
|
||||||
|
|
||||||
bool isStatic();
|
bool isStatic();
|
||||||
|
|
||||||
string getQuery();
|
string getQuery();
|
||||||
|
|
||||||
bool hasQuery();
|
bool hasQuery();
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
836
src/client.cpp
836
src/client.cpp
@ -58,20 +58,20 @@ void log_error_to_file(const char *prefix, const string &str, string host) {
|
|||||||
* @param str The string to be written
|
* @param str The string to be written
|
||||||
*/
|
*/
|
||||||
void log(const char *prefix, const string &str) {
|
void log(const char *prefix, const string &str) {
|
||||||
printf("%s%s\r\n", prefix, str.c_str());
|
printf("%s%s\r\n", prefix, str.c_str());
|
||||||
flush(cout);
|
flush(cout);
|
||||||
}
|
}
|
||||||
|
|
||||||
void log_error(const char *prefix, const string &str) {
|
void log_error(const char *prefix, const string &str) {
|
||||||
log(prefix, "\x1B[1;31m" + str + "\x1B[0m");
|
log(prefix, "\x1B[1;31m" + str + "\x1B[0m");
|
||||||
}
|
}
|
||||||
|
|
||||||
void php_error_handler(const char *prefix, FILE *stderr) {
|
void php_error_handler(const char *prefix, FILE *stderr) {
|
||||||
string line;
|
string line;
|
||||||
while (!(line = read_line(stderr)).empty()) {
|
while (!(line = read_line(stderr)).empty()) {
|
||||||
log_error(prefix, line);
|
log_error(prefix, line);
|
||||||
}
|
}
|
||||||
fclose(stderr);
|
fclose(stderr);
|
||||||
}
|
}
|
||||||
|
|
||||||
IpAddressInfo get_ip_address_info(Address* addr) {
|
IpAddressInfo get_ip_address_info(Address* addr) {
|
||||||
@ -101,78 +101,78 @@ IpAddressInfo get_ip_address_info(Address* addr) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
string getETag(string filename) {
|
string getETag(string filename) {
|
||||||
ifstream etags = ifstream("/var/necronda/ETags");
|
ifstream etags = ifstream("/var/necronda/ETags");
|
||||||
|
|
||||||
ifstream a = ifstream();
|
ifstream a = ifstream();
|
||||||
string line;
|
string line;
|
||||||
int index = 0;
|
int index = 0;
|
||||||
int i = 0;
|
int i = 0;
|
||||||
string timestamp = getTimestamp(filename);
|
string timestamp = getTimestamp(filename);
|
||||||
long size = getFileSize(filename);
|
long size = getFileSize(filename);
|
||||||
while (getline(etags, line)) {
|
while (getline(etags, line)) {
|
||||||
i++;
|
i++;
|
||||||
if (line == filename) {
|
if (line == filename) {
|
||||||
index = i;
|
index = i;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
long p1 = line.find(':');
|
long p1 = line.find(':');
|
||||||
if (p1 == string::npos) continue;
|
if (p1 == string::npos) continue;
|
||||||
long p2 = line.find(':', (unsigned) p1 + 1);
|
long p2 = line.find(':', (unsigned) p1 + 1);
|
||||||
if (p2 == string::npos) continue;
|
if (p2 == string::npos) continue;
|
||||||
long p3 = line.find(':', (unsigned) p2 + 1);
|
long p3 = line.find(':', (unsigned) p2 + 1);
|
||||||
if (p3 == string::npos) continue;
|
if (p3 == string::npos) continue;
|
||||||
string FILENAME = line.substr(0, (unsigned) p1);
|
string FILENAME = line.substr(0, (unsigned) p1);
|
||||||
string HASH = line.substr((unsigned) p1 + 1, (unsigned) (p2 - p1));
|
string HASH = line.substr((unsigned) p1 + 1, (unsigned) (p2 - p1));
|
||||||
string TIMESTAMP = line.substr((unsigned) p2 + 1, (unsigned) (p3 - p2));
|
string TIMESTAMP = line.substr((unsigned) p2 + 1, (unsigned) (p3 - p2));
|
||||||
long SIZE = strtol(line.substr((unsigned) p3 + 1, line.length() - p3).c_str(), nullptr, 10);
|
long SIZE = strtol(line.substr((unsigned) p3 + 1, line.length() - p3).c_str(), nullptr, 10);
|
||||||
if (FILENAME == filename) {
|
if (FILENAME == filename) {
|
||||||
index = i;
|
index = i;
|
||||||
if (timestamp != TIMESTAMP || size != SIZE) {
|
if (timestamp != TIMESTAMP || size != SIZE) {
|
||||||
break;
|
break;
|
||||||
} else {
|
} else {
|
||||||
etags.close();
|
etags.close();
|
||||||
return HASH;
|
return HASH;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
etags.close();
|
etags.close();
|
||||||
|
|
||||||
MD5_CTX mdContext;
|
MD5_CTX mdContext;
|
||||||
MD5_Init(&mdContext);
|
MD5_Init(&mdContext);
|
||||||
size_t bytes;
|
size_t bytes;
|
||||||
char buffer[4096];
|
char buffer[4096];
|
||||||
FILE *file = fopen(filename.c_str(), "rb");
|
FILE *file = fopen(filename.c_str(), "rb");
|
||||||
if (file == nullptr) {
|
if (file == nullptr) {
|
||||||
throw (char *) "Invalid file";
|
throw (char *) "Invalid file";
|
||||||
}
|
}
|
||||||
while ((bytes = fread(buffer, 1, 4096, file)) != 0) {
|
while ((bytes = fread(buffer, 1, 4096, file)) != 0) {
|
||||||
MD5_Update(&mdContext, buffer, bytes);
|
MD5_Update(&mdContext, buffer, bytes);
|
||||||
}
|
}
|
||||||
fclose(file);
|
fclose(file);
|
||||||
unsigned char md[16];
|
unsigned char md[16];
|
||||||
MD5_Final(md, &mdContext);
|
MD5_Final(md, &mdContext);
|
||||||
char md5buff[32];
|
char md5buff[32];
|
||||||
for (int i = 0; i < 16; i++) {
|
for (int i = 0; i < 16; i++) {
|
||||||
sprintf(md5buff + i * 2, "%02x", md[i]);
|
sprintf(md5buff + i * 2, "%02x", md[i]);
|
||||||
}
|
}
|
||||||
string md5 = string(md5buff);
|
string md5 = string(md5buff);
|
||||||
|
|
||||||
if (index == 0) {
|
if (index == 0) {
|
||||||
char buff[256];
|
char buff[256];
|
||||||
sprintf(buff, "%s:%s:%s:%ld\n", filename.c_str(), md5.c_str(), timestamp.c_str(), size);
|
sprintf(buff, "%s:%s:%s:%ld\n", filename.c_str(), md5.c_str(), timestamp.c_str(), size);
|
||||||
FILE *f = fopen("/var/necronda/ETags", "a");
|
FILE *f = fopen("/var/necronda/ETags", "a");
|
||||||
if (f == nullptr) {
|
if (f == nullptr) {
|
||||||
throw (char *) strerror(errno);
|
throw (char *) strerror(errno);
|
||||||
}
|
}
|
||||||
fseek(f, 0, SEEK_END);
|
fseek(f, 0, SEEK_END);
|
||||||
fwrite(buff, 1, strlen(buff), f);
|
fwrite(buff, 1, strlen(buff), f);
|
||||||
fflush(f);
|
fflush(f);
|
||||||
fclose(f);
|
fclose(f);
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return md5;
|
return md5;
|
||||||
}
|
}
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
@ -181,18 +181,18 @@ string getETag(string filename) {
|
|||||||
|
|
||||||
|
|
||||||
long getPosition(std::string str, char c, int occurence) {
|
long getPosition(std::string str, char c, int occurence) {
|
||||||
int tempOccur = 0;
|
int tempOccur = 0;
|
||||||
int num = 0;
|
int num = 0;
|
||||||
for (auto it : str) {
|
for (auto it : str) {
|
||||||
num++;
|
num++;
|
||||||
if (it == c) {
|
if (it == c) {
|
||||||
if (++tempOccur == occurence) {
|
if (++tempOccur == occurence) {
|
||||||
return num;
|
return num;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -204,314 +204,314 @@ long getPosition(std::string str, char c, int occurence) {
|
|||||||
* @return Should the server wait for another header?
|
* @return Should the server wait for another header?
|
||||||
*/
|
*/
|
||||||
bool connection_handler(const char *preprefix, const char *col1, const char *col2, Socket *socket, long id, long num, IpAddressInfo *info) {
|
bool connection_handler(const char *preprefix, const char *col1, const char *col2, Socket *socket, long id, long num, IpAddressInfo *info) {
|
||||||
bool error = false;
|
bool error = false;
|
||||||
char buffer[1024];
|
char buffer[1024];
|
||||||
char *prefix = (char *) preprefix;
|
char *prefix = (char *) preprefix;
|
||||||
try {
|
try {
|
||||||
HttpConnection req(socket);
|
HttpConnection req(socket);
|
||||||
try {
|
try {
|
||||||
if (req.isExistingField("Connection") && req.getField("Connection") == "keep-alive") {
|
if (req.isExistingField("Connection") && req.getField("Connection") == "keep-alive") {
|
||||||
req.setField("Connection", "keep-alive");
|
req.setField("Connection", "keep-alive");
|
||||||
req.setField("Keep-Alive", "timeout=60, max=100");
|
req.setField("Keep-Alive", "timeout=60, max=100");
|
||||||
} else {
|
} else {
|
||||||
req.setField("Connection", "close");
|
req.setField("Connection", "close");
|
||||||
error = true;
|
error = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
string host = "";
|
string host = "";
|
||||||
|
|
||||||
if (!req.isExistingField("Host")) {
|
if (!req.isExistingField("Host")) {
|
||||||
req.respond(400);
|
req.respond(400);
|
||||||
} else {
|
} else {
|
||||||
host = req.getField("Host");
|
host = req.getField("Host");
|
||||||
long pos = host.find(':');
|
long pos = host.find(':');
|
||||||
if (pos != string::npos) {
|
if (pos != string::npos) {
|
||||||
host.erase(pos, host.length() - pos);
|
host.erase(pos, host.length() - pos);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*FILE *name = popen(("dig @8.8.8.8 +time=1 -x " + socket->getPeerAddress()->toString() +
|
/*FILE *name = popen(("dig @8.8.8.8 +time=1 -x " + socket->getPeerAddress()->toString() +
|
||||||
" | grep -oP \"^[^;].*\\t\\K([^ ]*)\\w\"").c_str(), "r");
|
" | grep -oP \"^[^;].*\\t\\K([^ ]*)\\w\"").c_str(), "r");
|
||||||
char hostbuffer[1024];
|
char hostbuffer[1024];
|
||||||
memset(hostbuffer, 0, 1024);
|
memset(hostbuffer, 0, 1024);
|
||||||
size_t size = fread(hostbuffer, 1, 1024, name);
|
size_t size = fread(hostbuffer, 1, 1024, name);
|
||||||
hostbuffer[size - 1] = 0; // remove \n
|
hostbuffer[size - 1] = 0; // remove \n
|
||||||
if (size <= 1) {
|
if (size <= 1) {
|
||||||
sprintf(hostbuffer, "%s", socket->getPeerAddress()->toString().c_str());
|
sprintf(hostbuffer, "%s", socket->getPeerAddress()->toString().c_str());
|
||||||
}*/
|
}*/
|
||||||
|
|
||||||
sprintf(buffer, "[\x1B[1m%s\x1B[0m][%i]%s[%s][%i]%s ", host.c_str(), socket->getSocketPort(), col1,
|
sprintf(buffer, "[\x1B[1m%s\x1B[0m][%i]%s[%s][%i]%s ", host.c_str(), socket->getSocketPort(), col1,
|
||||||
info->host.c_str(), socket->getPeerPort(), col2);
|
info->host.c_str(), socket->getPeerPort(), col2);
|
||||||
prefix = buffer;
|
prefix = buffer;
|
||||||
|
|
||||||
log(prefix, "\x1B[1m" + req.getMethod() + " " + req.getPath() + "\x1B[0m");
|
log(prefix, "\x1B[1m" + req.getMethod() + " " + req.getPath() + "\x1B[0m");
|
||||||
log_to_file(prefix, "\x1B[1m" + req.getMethod() + " " + req.getPath() + "\x1B[0m", host);
|
log_to_file(prefix, "\x1B[1m" + req.getMethod() + " " + req.getPath() + "\x1B[0m", host);
|
||||||
|
|
||||||
bool noRedirect = req.getPath().find("/.well-known/") == 0 || (req.getPath().find("/files/") == 0);
|
bool noRedirect = req.getPath().find("/.well-known/") == 0 || (req.getPath().find("/files/") == 0);
|
||||||
|
|
||||||
bool redir = true;
|
bool redir = true;
|
||||||
if (!noRedirect) {
|
if (!noRedirect) {
|
||||||
if (getWebRoot(host).empty()) {
|
if (getWebRoot(host).empty()) {
|
||||||
req.redirect(303, "https://www.necronda.net" + req.getPath());
|
req.redirect(303, "https://www.necronda.net" + req.getPath());
|
||||||
} else if (socket->getSocketPort() != 443) {
|
} else if (socket->getSocketPort() != 443) {
|
||||||
req.redirect(302, "https://" + host + req.getPath());
|
req.redirect(302, "https://" + host + req.getPath());
|
||||||
} else {
|
} else {
|
||||||
redir = false;
|
redir = false;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
redir = false;
|
redir = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
URI path = URI(getWebRoot(host), req.getPath());
|
URI path = URI(getWebRoot(host), req.getPath());
|
||||||
pid_t childpid = 0;
|
pid_t childpid = 0;
|
||||||
|
|
||||||
if (redir) {
|
if (redir) {
|
||||||
|
|
||||||
} else if (!path.getNewPath().empty() && req.getMethod() != "POST") {
|
} else if (!path.getNewPath().empty() && req.getMethod() != "POST") {
|
||||||
req.redirect(303, path.getNewPath());
|
req.redirect(303, path.getNewPath());
|
||||||
} else {
|
} else {
|
||||||
FILE *file = path.openFile();
|
FILE *file = path.openFile();
|
||||||
if (file == nullptr) {
|
if (file == nullptr) {
|
||||||
req.setField("Cache-Control", "public, max-age=60");
|
req.setField("Cache-Control", "public, max-age=60");
|
||||||
req.respond(404);
|
req.respond(404);
|
||||||
} else {
|
} else {
|
||||||
string type = path.getFileType();
|
string type = path.getFileType();
|
||||||
|
|
||||||
if (type.find("inode/") == 0) {
|
if (type.find("inode/") == 0) {
|
||||||
req.respond(403);
|
req.respond(403);
|
||||||
} else if (path.getRelativeFilePath().find("/.") != string::npos && !noRedirect) {
|
} else if (path.getRelativeFilePath().find("/.") != string::npos && !noRedirect) {
|
||||||
req.respond(403);
|
req.respond(403);
|
||||||
} else {
|
} else {
|
||||||
req.setField("Content-Type", type);
|
req.setField("Content-Type", type);
|
||||||
req.setField("Last-Modified", getHttpDate(path.getFilePath()));
|
req.setField("Last-Modified", getHttpDate(path.getFilePath()));
|
||||||
|
|
||||||
bool invalidMethod = false;
|
bool invalidMethod = false;
|
||||||
bool etag = false;
|
bool etag = false;
|
||||||
|
|
||||||
if (path.isStatic()) {
|
if (path.isStatic()) {
|
||||||
string hash = getETag(path.getFilePath());
|
string hash = getETag(path.getFilePath());
|
||||||
req.setField("ETag", hash);
|
req.setField("ETag", hash);
|
||||||
req.setField("Accept-Ranges", "bytes");
|
req.setField("Accept-Ranges", "bytes");
|
||||||
if (type.find("text/") == 0) {
|
if (type.find("text/") == 0) {
|
||||||
req.setField("Cache-Control", "public, max-age=3600");
|
req.setField("Cache-Control", "public, max-age=3600");
|
||||||
} else {
|
} else {
|
||||||
req.setField("Cache-Control", "public, max-age=86400");
|
req.setField("Cache-Control", "public, max-age=86400");
|
||||||
}
|
}
|
||||||
req.setField("Allow", "GET");
|
req.setField("Allow", "GET");
|
||||||
if (req.getMethod() != "GET") {
|
if (req.getMethod() != "GET") {
|
||||||
invalidMethod = true;
|
invalidMethod = true;
|
||||||
}
|
}
|
||||||
if (req.isExistingField("If-None-Match") && req.getField("If-None-Match") == hash) {
|
if (req.isExistingField("If-None-Match") && req.getField("If-None-Match") == hash) {
|
||||||
etag = true;
|
etag = true;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
req.setField("Accept-Ranges", "none");
|
req.setField("Accept-Ranges", "none");
|
||||||
req.setField("Cache-Control", "private, no-cache");
|
req.setField("Cache-Control", "private, no-cache");
|
||||||
req.setField("Allow", "GET, POST, PUT");
|
req.setField("Allow", "GET, POST, PUT");
|
||||||
if (req.getMethod() != "GET" && req.getMethod() != "POST" && req.getMethod() != "PUT") {
|
if (req.getMethod() != "GET" && req.getMethod() != "POST" && req.getMethod() != "PUT") {
|
||||||
invalidMethod = true;
|
invalidMethod = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (invalidMethod) {
|
if (invalidMethod) {
|
||||||
req.respond(405);
|
req.respond(405);
|
||||||
} else if (etag) {
|
} else if (etag) {
|
||||||
req.respond(304);
|
req.respond(304);
|
||||||
} else {
|
} else {
|
||||||
int statuscode = 0;
|
int statuscode = 0;
|
||||||
if (!path.isStatic()) {
|
if (!path.isStatic()) {
|
||||||
string cmd = (string) "env -i" +
|
string cmd = (string) "env -i" +
|
||||||
" REDIRECT_STATUS=" + cli_encode("CGI") +
|
" REDIRECT_STATUS=" + cli_encode("CGI") +
|
||||||
" DOCUMENT_ROOT=" + cli_encode(getWebRoot(host)) +
|
" DOCUMENT_ROOT=" + cli_encode(getWebRoot(host)) +
|
||||||
" " + req.cgiExport() +
|
" " + req.cgiExport() +
|
||||||
(req.isExistingField("Content-Length") ? " CONTENT_LENGTH=" +
|
(req.isExistingField("Content-Length") ? " CONTENT_LENGTH=" +
|
||||||
cli_encode(req.getField(
|
cli_encode(req.getField(
|
||||||
"Content-Length"))
|
"Content-Length"))
|
||||||
: "") +
|
: "") +
|
||||||
(req.isExistingField("Content-Type") ? " CONTENT_TYPE=" + cli_encode(
|
(req.isExistingField("Content-Type") ? " CONTENT_TYPE=" + cli_encode(
|
||||||
req.getField("Content-Type")) : "") +
|
req.getField("Content-Type")) : "") +
|
||||||
((socket->isSecured()) ? " HTTPS=on" : "") +
|
((socket->isSecured()) ? " HTTPS=on" : "") +
|
||||||
" PATH_INFO=" + cli_encode(path.getFilePathInfo()) +
|
" PATH_INFO=" + cli_encode(path.getFilePathInfo()) +
|
||||||
" PATH_TRANSLATED=" + cli_encode(path.getAbsolutePath()) +
|
" PATH_TRANSLATED=" + cli_encode(path.getAbsolutePath()) +
|
||||||
" QUERY_STRING=" + cli_encode(path.getQuery()) +
|
" QUERY_STRING=" + cli_encode(path.getQuery()) +
|
||||||
" REMOTE_ADDR=" + cli_encode(socket->getPeerAddress()->toString()) +
|
" REMOTE_ADDR=" + cli_encode(socket->getPeerAddress()->toString()) +
|
||||||
" REMOTE_HOST=" + cli_encode(info->host) +
|
" REMOTE_HOST=" + cli_encode(info->host) +
|
||||||
" REMOTE_PORT=" + cli_encode(to_string(socket->getPeerPort())) +
|
" REMOTE_PORT=" + cli_encode(to_string(socket->getPeerPort())) +
|
||||||
" REQUEST_METHOD=" + cli_encode(req.getMethod()) +
|
" REQUEST_METHOD=" + cli_encode(req.getMethod()) +
|
||||||
" REQUEST_URI=" + cli_encode(req.getPath()) +
|
" REQUEST_URI=" + cli_encode(req.getPath()) +
|
||||||
" SCRIPT_FILENAME=" + cli_encode(path.getFilePath()) +
|
" SCRIPT_FILENAME=" + cli_encode(path.getFilePath()) +
|
||||||
" SCRIPT_NAME=" + cli_encode(path.getRelativePath()) +
|
" SCRIPT_NAME=" + cli_encode(path.getRelativePath()) +
|
||||||
" SERVER_ADMIN=" + cli_encode("lorenz.stechauner@gmail.com") +
|
" SERVER_ADMIN=" + cli_encode("lorenz.stechauner@gmail.com") +
|
||||||
" SERVER_NAME=" + cli_encode(host) +
|
" SERVER_NAME=" + cli_encode(host) +
|
||||||
" SERVER_PORT=" + cli_encode(to_string(socket->getSocketPort())) +
|
" SERVER_PORT=" + cli_encode(to_string(socket->getSocketPort())) +
|
||||||
" SERVER_SOFTWARE=" + cli_encode("Necronda 3.0") +
|
" SERVER_SOFTWARE=" + cli_encode("Necronda 3.0") +
|
||||||
" SERVER_PROTOCOL=" + cli_encode("HTTP/1.1") +
|
" SERVER_PROTOCOL=" + cli_encode("HTTP/1.1") +
|
||||||
" GATEWAY_INTERFACE=" + cli_encode("CGI/1.1") +
|
" GATEWAY_INTERFACE=" + cli_encode("CGI/1.1") +
|
||||||
" /usr/bin/php-cgi";
|
" /usr/bin/php-cgi";
|
||||||
|
|
||||||
stds pipes = procopen(cmd.c_str());
|
stds pipes = procopen(cmd.c_str());
|
||||||
childpid = pipes.pid;
|
childpid = pipes.pid;
|
||||||
|
|
||||||
long len = req.isExistingField("Content-Length") ? strtol(req.getField("Content-Length").c_str(), nullptr, 10) : (req.getMethod() == "POST" || req.getMethod() == "PUT")?-1:0;
|
long len = req.isExistingField("Content-Length") ? strtol(req.getField("Content-Length").c_str(), nullptr, 10) : (req.getMethod() == "POST" || req.getMethod() == "PUT")?-1:0;
|
||||||
socket->receive(pipes.stdin, len);
|
socket->receive(pipes.stdin, len);
|
||||||
fclose(pipes.stdin);
|
fclose(pipes.stdin);
|
||||||
|
|
||||||
thread *t = new thread(php_error_handler, prefix, pipes.stderr);
|
thread *t = new thread(php_error_handler, prefix, pipes.stderr);
|
||||||
|
|
||||||
string line;
|
string line;
|
||||||
while (!(line = read_line(pipes.stdout)).empty()) {
|
while (!(line = read_line(pipes.stdout)).empty()) {
|
||||||
long pos = line.find(':');
|
long pos = line.find(':');
|
||||||
string index = line.substr(0, pos);
|
string index = line.substr(0, pos);
|
||||||
string data = line.substr(pos + 1, line.length() - pos);
|
string data = line.substr(pos + 1, line.length() - pos);
|
||||||
|
|
||||||
while (index[0] == ' ') index.erase(index.begin() + 0);
|
while (index[0] == ' ') index.erase(index.begin() + 0);
|
||||||
while (index[index.length() - 1] == ' ') index.erase(index.end() - 1);
|
while (index[index.length() - 1] == ' ') index.erase(index.end() - 1);
|
||||||
while (data[0] == ' ') data.erase(data.begin() + 0);
|
while (data[0] == ' ') data.erase(data.begin() + 0);
|
||||||
while (data[data.length() - 1] == ' ') data.erase(data.end() - 1);
|
while (data[data.length() - 1] == ' ') data.erase(data.end() - 1);
|
||||||
|
|
||||||
if (index == "Status") {
|
if (index == "Status") {
|
||||||
statuscode = (int) strtol(data.substr(0, 3).c_str(), nullptr, 10);
|
statuscode = (int) strtol(data.substr(0, 3).c_str(), nullptr, 10);
|
||||||
} else {
|
} else {
|
||||||
if (index == "Location" && statuscode == 0) {
|
if (index == "Location" && statuscode == 0) {
|
||||||
statuscode = 303;
|
statuscode = 303;
|
||||||
}
|
}
|
||||||
req.setField(index, data);
|
req.setField(index, data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fclose(file);
|
fclose(file);
|
||||||
int c = fgetc(pipes.stdout);
|
int c = fgetc(pipes.stdout);
|
||||||
if (c == -1) {
|
if (c == -1) {
|
||||||
// No Data -> Error
|
// No Data -> Error
|
||||||
req.respond((statuscode == 0) ? 500 : statuscode);
|
req.respond((statuscode == 0) ? 500 : statuscode);
|
||||||
statuscode = -1;
|
statuscode = -1;
|
||||||
} else {
|
} else {
|
||||||
ungetc(c, pipes.stdout);
|
ungetc(c, pipes.stdout);
|
||||||
}
|
}
|
||||||
file = pipes.stdout;
|
file = pipes.stdout;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (statuscode != -1) {
|
if (statuscode != -1) {
|
||||||
statuscode = (statuscode == 0) ? 200 : statuscode;
|
statuscode = (statuscode == 0) ? 200 : statuscode;
|
||||||
|
|
||||||
bool compress = /*path.isStatic() &&*/ type.find("text/") == 0 &&
|
bool compress = /*path.isStatic() &&*/ type.find("text/") == 0 &&
|
||||||
req.isExistingField("Accept-Encoding") &&
|
req.isExistingField("Accept-Encoding") &&
|
||||||
req.getField("Accept-Encoding").find(
|
req.getField("Accept-Encoding").find(
|
||||||
"deflate") != string::npos;
|
"deflate") != string::npos;
|
||||||
|
|
||||||
if (compress) {
|
if (compress) {
|
||||||
req.setField("Accept-Ranges", "none");
|
req.setField("Accept-Ranges", "none");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (compress && req.isExistingField("Range")) {
|
if (compress && req.isExistingField("Range")) {
|
||||||
req.respond(416);
|
req.respond(416);
|
||||||
} else if (req.isExistingField("Range")) {
|
} else if (req.isExistingField("Range")) {
|
||||||
string range = req.getField("Range");
|
string range = req.getField("Range");
|
||||||
if (range.find("bytes=") != 0 || !path.isStatic()) {
|
if (range.find("bytes=") != 0 || !path.isStatic()) {
|
||||||
req.respond(416);
|
req.respond(416);
|
||||||
} else {
|
} else {
|
||||||
fseek(file, 0L, SEEK_END);
|
fseek(file, 0L, SEEK_END);
|
||||||
long len = ftell(file);
|
long len = ftell(file);
|
||||||
fseek(file, 0L, SEEK_SET);
|
fseek(file, 0L, SEEK_SET);
|
||||||
long p = range.find('-');
|
long p = range.find('-');
|
||||||
if (p == string::npos) {
|
if (p == string::npos) {
|
||||||
req.respond(416);
|
req.respond(416);
|
||||||
} else {
|
} else {
|
||||||
string part1 = range.substr(6, (unsigned long) (p - 6));
|
string part1 = range.substr(6, (unsigned long) (p - 6));
|
||||||
string part2 = range.substr((unsigned long) (p + 1),
|
string part2 = range.substr((unsigned long) (p + 1),
|
||||||
range.length() - p - 1);
|
range.length() - p - 1);
|
||||||
long num1 = stol(part1, nullptr, 10);
|
long num1 = stol(part1, nullptr, 10);
|
||||||
long num2 = len - 1;
|
long num2 = len - 1;
|
||||||
if (!part2.empty()) {
|
if (!part2.empty()) {
|
||||||
num2 = stol(part2, nullptr, 10);
|
num2 = stol(part2, nullptr, 10);
|
||||||
}
|
}
|
||||||
if (num1 < 0 || num1 >= len || num2 < 0 || num2 >= len) {
|
if (num1 < 0 || num1 >= len || num2 < 0 || num2 >= len) {
|
||||||
req.respond(416);
|
req.respond(416);
|
||||||
} else {
|
} else {
|
||||||
req.setField("Content-Range",
|
req.setField("Content-Range",
|
||||||
(string) "bytes " + to_string(num1) + "-" +
|
(string) "bytes " + to_string(num1) + "-" +
|
||||||
to_string(num2) +
|
to_string(num2) +
|
||||||
"/" + to_string(len));
|
"/" + to_string(len));
|
||||||
req.respond(206, file, compress, num1, num2);
|
req.respond(206, file, compress, num1, num2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
req.respond(statuscode, file, compress);
|
req.respond(statuscode, file, compress);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fclose(file);
|
fclose(file);
|
||||||
if (childpid > 0) {
|
if (childpid > 0) {
|
||||||
waitpid(childpid, nullptr, 0);
|
waitpid(childpid, nullptr, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
HttpStatusCode status = req.getStatusCode();
|
HttpStatusCode status = req.getStatusCode();
|
||||||
int code = status.code;
|
int code = status.code;
|
||||||
string color = "";
|
string color = "";
|
||||||
string comment = "";
|
string comment = "";
|
||||||
if ((code >= 200 && code < 300) || code == 304) {
|
if ((code >= 200 && code < 300) || code == 304) {
|
||||||
color = "\x1B[1;32m"; // Success (Cached): Green
|
color = "\x1B[1;32m"; // Success (Cached): Green
|
||||||
} else if (code >= 100 && code < 200) {
|
} else if (code >= 100 && code < 200) {
|
||||||
color = "\x1B[1;93m"; // Continue: Yellow
|
color = "\x1B[1;93m"; // Continue: Yellow
|
||||||
} else if (code >= 300 && code < 400) {
|
} else if (code >= 300 && code < 400) {
|
||||||
color = "\x1B[1;93m"; // Redirect: Yellow
|
color = "\x1B[1;93m"; // Redirect: Yellow
|
||||||
comment = " -> " +
|
comment = " -> " +
|
||||||
(req.isExistingResponseField("Location") ? req.getResponseField("Location") : "<invalid>");
|
(req.isExistingResponseField("Location") ? req.getResponseField("Location") : "<invalid>");
|
||||||
} else if (code >= 400 && code < 500) {
|
} else if (code >= 400 && code < 500) {
|
||||||
color = "\x1B[1;31m"; // Client Error: Red
|
color = "\x1B[1;31m"; // Client Error: Red
|
||||||
//comment = " -> " + req.getPath();
|
//comment = " -> " + req.getPath();
|
||||||
} else if (code >= 500 & code < 600) {
|
} else if (code >= 500 & code < 600) {
|
||||||
color = "\x1B[1;31m"; // Server Error: Red
|
color = "\x1B[1;31m"; // Server Error: Red
|
||||||
//comment = " -> " + req.getPath();
|
//comment = " -> " + req.getPath();
|
||||||
}
|
}
|
||||||
string msg = color + to_string(status.code) + " " + status.message + comment + " (" + formatTime(req.getDuration()) + ")\x1B[0m";
|
string msg = color + to_string(status.code) + " " + status.message + comment + " (" + formatTime(req.getDuration()) + ")\x1B[0m";
|
||||||
log(prefix, msg);
|
log(prefix, msg);
|
||||||
if (!host.empty()) {
|
if (!host.empty()) {
|
||||||
log_to_file(prefix, msg, host);
|
log_to_file(prefix, msg, host);
|
||||||
}
|
}
|
||||||
} catch (char *msg) {
|
} catch (char *msg) {
|
||||||
HttpStatusCode status = req.getStatusCode();
|
HttpStatusCode status = req.getStatusCode();
|
||||||
log(prefix, to_string(status.code) + " " + status.message + " (" + formatTime(req.getDuration()) + ")");
|
log(prefix, to_string(status.code) + " " + status.message + " (" + formatTime(req.getDuration()) + ")");
|
||||||
try {
|
try {
|
||||||
if (strncmp(msg, "timeout", strlen(msg)) == 0) {
|
if (strncmp(msg, "timeout", strlen(msg)) == 0) {
|
||||||
log(prefix, "Timeout!");
|
log(prefix, "Timeout!");
|
||||||
req.setField("Connection", "close");
|
req.setField("Connection", "close");
|
||||||
req.respond(408);
|
req.respond(408);
|
||||||
error = true;
|
error = true;
|
||||||
} else if (strncmp(msg, "Invalid path", strlen(msg)) == 0) {
|
} else if (strncmp(msg, "Invalid path", strlen(msg)) == 0) {
|
||||||
log(prefix, "Timeout!");
|
log(prefix, "Timeout!");
|
||||||
req.setField("Connection", "close");
|
req.setField("Connection", "close");
|
||||||
req.respond(400);
|
req.respond(400);
|
||||||
} else {
|
} else {
|
||||||
log(prefix, (string) "Unable to receive from socket: " + msg);
|
log(prefix, (string) "Unable to receive from socket: " + msg);
|
||||||
error = true;
|
error = true;
|
||||||
}
|
}
|
||||||
} catch (char *msg2) {
|
} catch (char *msg2) {
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (char *msg) {
|
} catch (char *msg) {
|
||||||
try {
|
try {
|
||||||
if (msg == "Malformed header") {
|
if (msg == "Malformed header") {
|
||||||
log(prefix, "Unable to parse header: Malformed header");
|
log(prefix, "Unable to parse header: Malformed header");
|
||||||
socket->send("HTTP/1.1 400 Bad Request\r\nConnection: close\r\n\r\n");
|
socket->send("HTTP/1.1 400 Bad Request\r\nConnection: close\r\n\r\n");
|
||||||
error = true;
|
error = true;
|
||||||
} else if (msg == "timeout") {
|
} else if (msg == "timeout") {
|
||||||
log(prefix, "Timeout!");
|
log(prefix, "Timeout!");
|
||||||
socket->send("HTTP/1.1 408 Request Timeout\r\nConnection: close\r\n\r\n");
|
socket->send("HTTP/1.1 408 Request Timeout\r\nConnection: close\r\n\r\n");
|
||||||
error = true;
|
error = true;
|
||||||
} else {
|
} else {
|
||||||
log(prefix, (string) "Unable to receive from socket: " + msg);
|
log(prefix, (string) "Unable to receive from socket: " + msg);
|
||||||
error = true;
|
error = true;
|
||||||
}
|
}
|
||||||
} catch (char *msg2) {
|
} catch (char *msg2) {
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return !error;
|
return !error;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -520,70 +520,70 @@ bool connection_handler(const char *preprefix, const char *col1, const char *col
|
|||||||
* @param id The client ID
|
* @param id The client ID
|
||||||
*/
|
*/
|
||||||
void client_handler(Socket *socket, long id, bool ssl) {
|
void client_handler(Socket *socket, long id, bool ssl) {
|
||||||
const char *prefix;
|
const char *prefix;
|
||||||
char const *col1;
|
char const *col1;
|
||||||
char const *col2 = "\x1B[0m";
|
char const *col2 = "\x1B[0m";
|
||||||
IpAddressInfo info = get_ip_address_info(socket->getPeerAddress());
|
IpAddressInfo info = get_ip_address_info(socket->getPeerAddress());
|
||||||
{
|
{
|
||||||
auto group = (int) (id % 6);
|
auto group = (int) (id % 6);
|
||||||
if (group == 0) {
|
if (group == 0) {
|
||||||
col1 = "\x1B[0;31m"; // Red
|
col1 = "\x1B[0;31m"; // Red
|
||||||
} else if (group == 1) {
|
} else if (group == 1) {
|
||||||
col1 = "\x1B[0;32m"; // Green
|
col1 = "\x1B[0;32m"; // Green
|
||||||
} else if (group == 2) {
|
} else if (group == 2) {
|
||||||
col1 = "\x1B[0;34m"; // Blue
|
col1 = "\x1B[0;34m"; // Blue
|
||||||
} else if (group == 3) {
|
} else if (group == 3) {
|
||||||
col1 = "\x1B[0;33m"; // Yellow
|
col1 = "\x1B[0;33m"; // Yellow
|
||||||
} else if (group == 4) {
|
} else if (group == 4) {
|
||||||
col1 = "\x1B[0;35m"; // Magenta
|
col1 = "\x1B[0;35m"; // Magenta
|
||||||
} else {
|
} else {
|
||||||
col1 = "\x1B[0;36m"; // Cyan
|
col1 = "\x1B[0;36m"; // Cyan
|
||||||
}
|
}
|
||||||
|
|
||||||
string *a = new string("[" + socket->getSocketAddress()->toString() + "][" +
|
string *a = new string("[" + socket->getSocketAddress()->toString() + "][" +
|
||||||
to_string(socket->getSocketPort()) + "]" + col1 +
|
to_string(socket->getSocketPort()) + "]" + col1 +
|
||||||
"[" + info.host + "][" + to_string(socket->getPeerPort()) +
|
"[" + info.host + "][" + to_string(socket->getPeerPort()) +
|
||||||
"]" + col2 + " ");
|
"]" + col2 + " ");
|
||||||
prefix = a->c_str();
|
prefix = a->c_str();
|
||||||
}
|
}
|
||||||
|
|
||||||
log(prefix, "Connection established");
|
log(prefix, "Connection established");
|
||||||
log(prefix, string("Host: ") + info.host + " (" + socket->getPeerAddress()->toString() + ")");
|
log(prefix, string("Host: ") + info.host + " (" + socket->getPeerAddress()->toString() + ")");
|
||||||
log(prefix, string("Location: ") + info.cc + "/" + info.country + ", " + info.prov + "/" + info.provname + ", " + info.city);
|
log(prefix, string("Location: ") + info.cc + "/" + info.country + ", " + info.prov + "/" + info.provname + ", " + info.city);
|
||||||
log(prefix, string("Local Date: ") + info.localdate + " (" + info.timezone + ")");
|
log(prefix, string("Local Date: ") + info.localdate + " (" + info.timezone + ")");
|
||||||
|
|
||||||
|
|
||||||
bool err = false;
|
bool err = false;
|
||||||
try {
|
try {
|
||||||
socket->setReceiveTimeout(60000);
|
socket->setReceiveTimeout(60000);
|
||||||
socket->setSendTimeout(60000);
|
socket->setSendTimeout(60000);
|
||||||
} catch (char *msg) {
|
} catch (char *msg) {
|
||||||
log(prefix, (string) "Unable to set timeout on socket: " + msg);
|
log(prefix, (string) "Unable to set timeout on socket: " + msg);
|
||||||
err = true;
|
err = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (ssl) {
|
if (ssl) {
|
||||||
//socket->sslHandshake("/home/lorenz/Documents/Projects/Necronda-Server/necronda-server-3.0/privkey.pem",
|
//socket->sslHandshake("/home/lorenz/Documents/Projects/Necronda-Server/necronda-server-3.0/privkey.pem",
|
||||||
// "/home/lorenz/Documents/Projects/Necronda-Server/necronda-server-3.0/fullchain.pem");
|
// "/home/lorenz/Documents/Projects/Necronda-Server/necronda-server-3.0/fullchain.pem");
|
||||||
socket->sslHandshake("/cert/necronda.net/privkey.pem",
|
socket->sslHandshake("/cert/necronda.net/privkey.pem",
|
||||||
"/cert/necronda.net/fullchain.pem");
|
"/cert/necronda.net/fullchain.pem");
|
||||||
}
|
}
|
||||||
} catch (char *msg) {
|
} catch (char *msg) {
|
||||||
log(prefix, (string) "Unable to perform handshake: " + msg);
|
log(prefix, (string) "Unable to perform handshake: " + msg);
|
||||||
err = true;
|
err = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
long reqnum = 0;
|
long reqnum = 0;
|
||||||
if (!err) {
|
if (!err) {
|
||||||
while (connection_handler(prefix, col1, col2, socket, id, ++reqnum, &info));
|
while (connection_handler(prefix, col1, col2, socket, id, ++reqnum, &info));
|
||||||
reqnum--;
|
reqnum--;
|
||||||
}
|
}
|
||||||
|
|
||||||
log(prefix,
|
log(prefix,
|
||||||
"Connection terminated (#:" + to_string(reqnum) + ", R: " + formatSize(socket->getBytesReceived()) + ", S: " +
|
"Connection terminated (#:" + to_string(reqnum) + ", R: " + formatSize(socket->getBytesReceived()) + ", S: " +
|
||||||
formatSize(socket->getBytesSent()) + ", T: " + formatTime(socket->getDuration()) + ")");
|
formatSize(socket->getBytesSent()) + ", T: " + formatTime(socket->getDuration()) + ")");
|
||||||
socket->close();
|
socket->close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -22,29 +22,29 @@ const char* webroot = "/srv/necronda/";
|
|||||||
|
|
||||||
string getMimeType(string path) {
|
string getMimeType(string path) {
|
||||||
|
|
||||||
unsigned long pos = path.find_last_of('.');
|
unsigned long pos = path.find_last_of('.');
|
||||||
string ext;
|
string ext;
|
||||||
if (pos != string::npos) {
|
if (pos != string::npos) {
|
||||||
ext = path.substr(pos + 1, path.length() - pos);
|
ext = path.substr(pos + 1, path.length() - pos);
|
||||||
}
|
}
|
||||||
|
|
||||||
magic_t magic = magic_open(MAGIC_MIME_TYPE);
|
magic_t magic = magic_open(MAGIC_MIME_TYPE);
|
||||||
magic_load(magic, "/usr/share/misc/magic.mgc");
|
magic_load(magic, "/usr/share/misc/magic.mgc");
|
||||||
string type = magic_file(magic, path.c_str());
|
string type = magic_file(magic, path.c_str());
|
||||||
magic_setflags(magic, MAGIC_MIME_ENCODING);
|
magic_setflags(magic, MAGIC_MIME_ENCODING);
|
||||||
string charset = magic_file(magic, path.c_str());
|
string charset = magic_file(magic, path.c_str());
|
||||||
|
|
||||||
if (type == "text/plain") {
|
if (type == "text/plain") {
|
||||||
if (ext == "css") {
|
if (ext == "css") {
|
||||||
type = "text/css";
|
type = "text/css";
|
||||||
} else if (ext == "js") {
|
} else if (ext == "js") {
|
||||||
type = "text/javascript";
|
type = "text/javascript";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
magic_close(magic);
|
magic_close(magic);
|
||||||
|
|
||||||
return type + "; charset=" + charset;
|
return type + "; charset=" + charset;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -53,22 +53,22 @@ string getMimeType(string path) {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
std::string getTimestamp(string path) {
|
std::string getTimestamp(string path) {
|
||||||
struct stat attrib;
|
struct stat attrib;
|
||||||
stat(path.c_str(), &attrib);
|
stat(path.c_str(), &attrib);
|
||||||
return getTimestamp(attrib.st_ctime);
|
return getTimestamp(attrib.st_ctime);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string getTimestamp(time_t time) {
|
std::string getTimestamp(time_t time) {
|
||||||
char buffer[64];
|
char buffer[64];
|
||||||
struct tm *timeinfo = gmtime(&time);
|
struct tm *timeinfo = gmtime(&time);
|
||||||
strftime(buffer, sizeof(buffer), "%Y%m%d%H%M%S", timeinfo);
|
strftime(buffer, sizeof(buffer), "%Y%m%d%H%M%S", timeinfo);
|
||||||
return string(buffer);
|
return string(buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
long getFileSize(string filename) {
|
long getFileSize(string filename) {
|
||||||
struct stat stat_buf;
|
struct stat stat_buf;
|
||||||
int rc = stat(filename.c_str(), &stat_buf);
|
int rc = stat(filename.c_str(), &stat_buf);
|
||||||
return rc == 0 ? stat_buf.st_size : -1;
|
return rc == 0 ? stat_buf.st_size : -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -78,104 +78,104 @@ long getFileSize(string filename) {
|
|||||||
* @return A formatted time string
|
* @return A formatted time string
|
||||||
*/
|
*/
|
||||||
std::string formatTime(long micros) {
|
std::string formatTime(long micros) {
|
||||||
char buffer[64];
|
char buffer[64];
|
||||||
if (micros < 1000) {
|
if (micros < 1000) {
|
||||||
sprintf(buffer, "%.3f ms", micros / 1000.0);
|
sprintf(buffer, "%.3f ms", micros / 1000.0);
|
||||||
} else if (micros < 10000) {
|
} else if (micros < 10000) {
|
||||||
sprintf(buffer, "%.2f ms", micros / 1000.0);
|
sprintf(buffer, "%.2f ms", micros / 1000.0);
|
||||||
} else if (micros < 100000) {
|
} else if (micros < 100000) {
|
||||||
sprintf(buffer, "%.1f ms", micros / 1000.0);
|
sprintf(buffer, "%.1f ms", micros / 1000.0);
|
||||||
} else if (micros < 1000000) {
|
} else if (micros < 1000000) {
|
||||||
sprintf(buffer, "%.0f ms", micros / 1000.0);
|
sprintf(buffer, "%.0f ms", micros / 1000.0);
|
||||||
} else {
|
} else {
|
||||||
sprintf(buffer, "%.1f s", micros / 1000000.0);
|
sprintf(buffer, "%.1f s", micros / 1000000.0);
|
||||||
}
|
}
|
||||||
return std::string(buffer);
|
return std::string(buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string formatSize(unsigned long bytes) {
|
std::string formatSize(unsigned long bytes) {
|
||||||
char buffer[64];
|
char buffer[64];
|
||||||
if (bytes > 0x10000000000) {
|
if (bytes > 0x10000000000) {
|
||||||
sprintf(buffer, "%.1f TiB", (double) bytes / 0x10000000000);
|
sprintf(buffer, "%.1f TiB", (double) bytes / 0x10000000000);
|
||||||
} else if (bytes > 0x40000000) {
|
} else if (bytes > 0x40000000) {
|
||||||
sprintf(buffer, "%.1f GiB", (double) bytes / 0x40000000);
|
sprintf(buffer, "%.1f GiB", (double) bytes / 0x40000000);
|
||||||
} else if (bytes > 0x100000) {
|
} else if (bytes > 0x100000) {
|
||||||
sprintf(buffer, "%.1f MiB", (double) bytes / 0x100000);
|
sprintf(buffer, "%.1f MiB", (double) bytes / 0x100000);
|
||||||
} else if (bytes > 0x400) {
|
} else if (bytes > 0x400) {
|
||||||
sprintf(buffer, "%.1f KiB", (double) bytes / 0x400);
|
sprintf(buffer, "%.1f KiB", (double) bytes / 0x400);
|
||||||
} else {
|
} else {
|
||||||
sprintf(buffer, "%ld B", bytes);
|
sprintf(buffer, "%ld B", bytes);
|
||||||
}
|
}
|
||||||
return std::string(buffer);
|
return std::string(buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
string url_decode(string url) {
|
string url_decode(string url) {
|
||||||
long pos = 0;
|
long pos = 0;
|
||||||
while ((pos = url.find('+', pos + 1)) != string::npos) {
|
while ((pos = url.find('+', pos + 1)) != string::npos) {
|
||||||
url.replace(pos, 1, 1, ' ');
|
url.replace(pos, 1, 1, ' ');
|
||||||
}
|
}
|
||||||
pos = 0;
|
pos = 0;
|
||||||
while ((pos = url.find('%', pos + 1)) != string::npos) {
|
while ((pos = url.find('%', pos + 1)) != string::npos) {
|
||||||
const char *num = url.substr(pos + 1, 2).c_str();
|
const char *num = url.substr(pos + 1, 2).c_str();
|
||||||
auto c = (char) strtol(num, nullptr, 16);
|
auto c = (char) strtol(num, nullptr, 16);
|
||||||
url.erase(pos, 3);
|
url.erase(pos, 3);
|
||||||
url.insert(pos, 1, c);
|
url.insert(pos, 1, c);
|
||||||
}
|
}
|
||||||
|
|
||||||
return url;
|
return url;
|
||||||
}
|
}
|
||||||
|
|
||||||
string url_encode(string url) {
|
string url_encode(string url) {
|
||||||
char buff[4];
|
char buff[4];
|
||||||
for (long pos = 0; pos < url.length(); pos++) {
|
for (long pos = 0; pos < url.length(); pos++) {
|
||||||
auto c = (unsigned char) url[pos];
|
auto c = (unsigned char) url[pos];
|
||||||
if (c < ' ' || c > '~' || c == ' ' || c == '#' || c == '?' || c == '&' || c == '=' || c == '\\' || c == '%') {
|
if (c < ' ' || c > '~' || c == ' ' || c == '#' || c == '?' || c == '&' || c == '=' || c == '\\' || c == '%') {
|
||||||
sprintf(buff, "%%%02X", c);
|
sprintf(buff, "%%%02X", c);
|
||||||
url.replace(pos, 1, buff);
|
url.replace(pos, 1, buff);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return url;
|
return url;
|
||||||
}
|
}
|
||||||
|
|
||||||
string html_decode(string text) {
|
string html_decode(string text) {
|
||||||
return text;
|
return text;
|
||||||
}
|
}
|
||||||
|
|
||||||
string html_encode(string text) {
|
string html_encode(string text) {
|
||||||
return text;
|
return text;
|
||||||
}
|
}
|
||||||
|
|
||||||
string cli_encode(string text) {
|
string cli_encode(string text) {
|
||||||
char buff[5];
|
char buff[5];
|
||||||
for (long pos = 0; pos < text.length(); pos++) {
|
for (long pos = 0; pos < text.length(); pos++) {
|
||||||
auto c = (unsigned char) text[pos];
|
auto c = (unsigned char) text[pos];
|
||||||
if (!((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == ',' || c == '.' || c == '_' || c == '+' || c == ':' || c == '@' || c == '%' || c == '/' || c == '-')) {
|
if (!((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == ',' || c == '.' || c == '_' || c == '+' || c == ':' || c == '@' || c == '%' || c == '/' || c == '-')) {
|
||||||
sprintf(buff, "\\%.1s", &c);
|
sprintf(buff, "\\%.1s", &c);
|
||||||
text.replace(pos, 1, buff);
|
text.replace(pos, 1, buff);
|
||||||
pos++;
|
pos++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return text;
|
return text;
|
||||||
}
|
}
|
||||||
|
|
||||||
string read_line(FILE* file) {
|
string read_line(FILE* file) {
|
||||||
char *line;
|
char *line;
|
||||||
size_t len = 0;
|
size_t len = 0;
|
||||||
ssize_t read;
|
ssize_t read;
|
||||||
if ((read = getline(&line, &len, file)) < 0 || line == nullptr) {
|
if ((read = getline(&line, &len, file)) < 0 || line == nullptr) {
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
string l = string(line);
|
string l = string(line);
|
||||||
if (l[l.length()-1] == '\n') {
|
if (l[l.length()-1] == '\n') {
|
||||||
l.erase(l.length()-1);
|
l.erase(l.length()-1);
|
||||||
}
|
}
|
||||||
if (l[l.length()-1] == '\r') {
|
if (l[l.length()-1] == '\r') {
|
||||||
l.erase(l.length()-1);
|
l.erase(l.length()-1);
|
||||||
}
|
}
|
||||||
return l;
|
return l;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -191,12 +191,12 @@ string read_line(FILE* file) {
|
|||||||
#include "network/http/HttpConnection.cpp"
|
#include "network/http/HttpConnection.cpp"
|
||||||
|
|
||||||
string getWebRoot(string host) {
|
string getWebRoot(string host) {
|
||||||
string root = webroot + host;
|
string root = webroot + host;
|
||||||
if (fileExists(root)) {
|
if (fileExists(root)) {
|
||||||
return root;
|
return root;
|
||||||
} else {
|
} else {
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -206,79 +206,79 @@ string getWebRoot(string host) {
|
|||||||
long clientnum = 0;
|
long clientnum = 0;
|
||||||
|
|
||||||
int main() {
|
int main() {
|
||||||
cout << "Necronda Server 3.0" << endl << "by Lorenz Stechauner" << endl << endl;
|
cout << "Necronda Server 3.0" << endl << "by Lorenz Stechauner" << endl << endl;
|
||||||
|
|
||||||
signal(SIGPIPE, SIG_IGN);
|
signal(SIGPIPE, SIG_IGN);
|
||||||
|
|
||||||
SSL_load_error_strings();
|
SSL_load_error_strings();
|
||||||
SSL_library_init();
|
SSL_library_init();
|
||||||
ERR_load_crypto_strings();
|
ERR_load_crypto_strings();
|
||||||
OpenSSL_add_all_algorithms();
|
OpenSSL_add_all_algorithms();
|
||||||
|
|
||||||
int ret = system("mkdir -p /var/necronda /etc/necronda /tmp/necronda; touch /var/necronda/ETags");
|
int ret = system("mkdir -p /var/necronda /etc/necronda /tmp/necronda; touch /var/necronda/ETags");
|
||||||
|
|
||||||
if (ret != 0) {
|
if (ret != 0) {
|
||||||
cout << "Unable to create server files" << endl;
|
cout << "Unable to create server files" << endl;
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
list<unsigned short> ports = {80, 443};
|
list<unsigned short> ports = {80, 443};
|
||||||
|
|
||||||
list<Socket> servers = {};
|
list<Socket> servers = {};
|
||||||
auto it = ports.begin();
|
auto it = ports.begin();
|
||||||
|
|
||||||
for (int i = 0; i < ports.size(); i++) {
|
for (int i = 0; i < ports.size(); i++) {
|
||||||
unsigned short port = *it;
|
unsigned short port = *it;
|
||||||
advance(it, 1);
|
advance(it, 1);
|
||||||
Socket server = Socket();
|
Socket server = Socket();
|
||||||
servers.push_back(server);
|
servers.push_back(server);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
server.setReuseAddress(true);
|
server.setReuseAddress(true);
|
||||||
server.setReceiveTimeout(0);
|
server.setReceiveTimeout(0);
|
||||||
server.setSendTimeout(0);
|
server.setSendTimeout(0);
|
||||||
} catch (char *msg) {
|
} catch (char *msg) {
|
||||||
cout << "Unable to set socket option: " << msg << endl;
|
cout << "Unable to set socket option: " << msg << endl;
|
||||||
exit(2);
|
exit(2);
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
server.bind(port);
|
server.bind(port);
|
||||||
} catch (char *msg) {
|
} catch (char *msg) {
|
||||||
cout << "Unable to bind socket to port " << port << ": " << msg << endl;
|
cout << "Unable to bind socket to port " << port << ": " << msg << endl;
|
||||||
exit(3);
|
exit(3);
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
server.listen(256);
|
server.listen(256);
|
||||||
} catch (char *msg) {
|
} catch (char *msg) {
|
||||||
cout << "Unable to listen on socket: " << msg << endl;
|
cout << "Unable to listen on socket: " << msg << endl;
|
||||||
exit(4);
|
exit(4);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
cout << "Ready for connections" << endl;
|
cout << "Ready for connections" << endl;
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
try {
|
try {
|
||||||
Socket::select(servers, {});
|
Socket::select(servers, {});
|
||||||
for (Socket server : servers) {
|
for (Socket server : servers) {
|
||||||
try {
|
try {
|
||||||
Socket *socket = server.accept();
|
Socket *socket = server.accept();
|
||||||
clientnum++;
|
clientnum++;
|
||||||
thread *t = new thread(client_handler, socket, clientnum, server.getSocketPort() == 443);
|
thread *t = new thread(client_handler, socket, clientnum, server.getSocketPort() == 443);
|
||||||
} catch (char *msg) {
|
} catch (char *msg) {
|
||||||
// Nothing
|
// Nothing
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (char *msg) {
|
} catch (char *msg) {
|
||||||
cout << "Select: " << msg << endl;
|
cout << "Select: " << msg << endl;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -14,54 +14,54 @@ Address::Address() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Address::Address(string addr) {
|
Address::Address(string addr) {
|
||||||
// TODO
|
// TODO
|
||||||
}
|
}
|
||||||
|
|
||||||
Address::Address(struct sockaddr_in *addr) {
|
Address::Address(struct sockaddr_in *addr) {
|
||||||
address = ntohl(addr->sin_addr.s_addr);
|
address = ntohl(addr->sin_addr.s_addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
struct sockaddr_in Address::toStruct(unsigned short port)const {
|
struct sockaddr_in Address::toStruct(unsigned short port)const {
|
||||||
struct sockaddr_in addr;
|
struct sockaddr_in addr;
|
||||||
addr.sin_family = AF_INET;
|
addr.sin_family = AF_INET;
|
||||||
addr.sin_addr.s_addr = htonl(address);
|
addr.sin_addr.s_addr = htonl(address);
|
||||||
addr.sin_port = htons(port);
|
addr.sin_port = htons(port);
|
||||||
return addr;
|
return addr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
string Address::toString() const {
|
string Address::toString() const {
|
||||||
struct sockaddr_in addr = toStruct(0);
|
struct sockaddr_in addr = toStruct(0);
|
||||||
struct in_addr ipAddr = addr.sin_addr;
|
struct in_addr ipAddr = addr.sin_addr;
|
||||||
return inet_ntoa(ipAddr);
|
return inet_ntoa(ipAddr);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Address::isLocal() {
|
bool Address::isLocal() {
|
||||||
string a = toString();
|
string a = toString();
|
||||||
return a.find("127.0.0.") == 0;
|
return a.find("127.0.0.") == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
ostream& operator<<(ostream &str, const Address &addr) {
|
ostream& operator<<(ostream &str, const Address &addr) {
|
||||||
return str << addr.toString();
|
return str << addr.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
string operator+(string &str, const Address &addr) {
|
string operator+(string &str, const Address &addr) {
|
||||||
return str + addr.toString();
|
return str + addr.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
string operator+(string &str, const Address *addr) {
|
string operator+(string &str, const Address *addr) {
|
||||||
return str + addr->toString();
|
return str + addr->toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
string operator+(const Address &addr, string &str) {
|
string operator+(const Address &addr, string &str) {
|
||||||
return addr.toString() + str;
|
return addr.toString() + str;
|
||||||
}
|
}
|
||||||
|
|
||||||
string operator+(const Address *addr, string &str) {
|
string operator+(const Address *addr, string &str) {
|
||||||
return addr->toString() + str;
|
return addr->toString() + str;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -11,20 +11,20 @@ using namespace std;
|
|||||||
|
|
||||||
class Address {
|
class Address {
|
||||||
private:
|
private:
|
||||||
unsigned int address;
|
unsigned int address;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Address();
|
Address();
|
||||||
|
|
||||||
explicit Address(string address);
|
explicit Address(string address);
|
||||||
|
|
||||||
explicit Address(struct sockaddr_in *address);
|
explicit Address(struct sockaddr_in *address);
|
||||||
|
|
||||||
struct sockaddr_in toStruct(unsigned short port) const;
|
struct sockaddr_in toStruct(unsigned short port) const;
|
||||||
|
|
||||||
string toString() const;
|
string toString() const;
|
||||||
|
|
||||||
bool isLocal();
|
bool isLocal();
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -12,8 +12,8 @@
|
|||||||
#define CPPNET_CHUNK 16384
|
#define CPPNET_CHUNK 16384
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
string privkey;
|
string privkey;
|
||||||
string fullchain;
|
string fullchain;
|
||||||
} KeyPair;
|
} KeyPair;
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
@ -21,138 +21,138 @@ using namespace std;
|
|||||||
|
|
||||||
class Socket {
|
class Socket {
|
||||||
private:
|
private:
|
||||||
int fd;
|
int fd;
|
||||||
SSL *ssl;
|
SSL *ssl;
|
||||||
SSL_CTX *ctx;
|
SSL_CTX *ctx;
|
||||||
bool enc;
|
bool enc;
|
||||||
bool servers;
|
bool servers;
|
||||||
bool clients;
|
bool clients;
|
||||||
unsigned long bytesSent;
|
unsigned long bytesSent;
|
||||||
unsigned long bytesReceived;
|
unsigned long bytesReceived;
|
||||||
long microsStart;
|
long microsStart;
|
||||||
long microsLast;
|
long microsLast;
|
||||||
|
|
||||||
void setSocketOption(int, bool);
|
void setSocketOption(int, bool);
|
||||||
|
|
||||||
long send(void *buffer, int size);
|
long send(void *buffer, int size);
|
||||||
|
|
||||||
long receive(void *buffer, int size);
|
long receive(void *buffer, int size);
|
||||||
|
|
||||||
long peek(void *buffer, int size);
|
long peek(void *buffer, int size);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Socket();
|
Socket();
|
||||||
|
|
||||||
explicit Socket(int filedescriptor);
|
explicit Socket(int filedescriptor);
|
||||||
|
|
||||||
~Socket();
|
~Socket();
|
||||||
|
|
||||||
void bind(Address *address, unsigned short port);
|
void bind(Address *address, unsigned short port);
|
||||||
|
|
||||||
void bind(unsigned short port);
|
void bind(unsigned short port);
|
||||||
|
|
||||||
void listen(int count = 1);
|
void listen(int count = 1);
|
||||||
|
|
||||||
void connect(Address address, unsigned short port);
|
void connect(Address address, unsigned short port);
|
||||||
|
|
||||||
Socket* accept();
|
Socket* accept();
|
||||||
|
|
||||||
void sslHandshake();
|
void sslHandshake();
|
||||||
|
|
||||||
void sslHandshake(map<string, KeyPair> sni);
|
void sslHandshake(map<string, KeyPair> sni);
|
||||||
|
|
||||||
void sslHandshake(KeyPair keypair);
|
void sslHandshake(KeyPair keypair);
|
||||||
|
|
||||||
void sslHandshake(string privkey, string fullchain);
|
void sslHandshake(string privkey, string fullchain);
|
||||||
|
|
||||||
long send(string *str);
|
long send(string *str);
|
||||||
|
|
||||||
long send(string str);
|
long send(string str);
|
||||||
|
|
||||||
long send(const char *str);
|
long send(const char *str);
|
||||||
|
|
||||||
long send(const char *str, long length);
|
long send(const char *str, long length);
|
||||||
|
|
||||||
string receive();
|
string receive();
|
||||||
|
|
||||||
string receive(long length);
|
string receive(long length);
|
||||||
|
|
||||||
string receive(string until);
|
string receive(string until);
|
||||||
|
|
||||||
string receive(const char *until, unsigned long strlen);
|
string receive(const char *until, unsigned long strlen);
|
||||||
|
|
||||||
string receive(const char *until);
|
string receive(const char *until);
|
||||||
|
|
||||||
void receive(FILE *file);
|
void receive(FILE *file);
|
||||||
|
|
||||||
string receiveLine();
|
string receiveLine();
|
||||||
|
|
||||||
void shutdown();
|
void shutdown();
|
||||||
|
|
||||||
void close();
|
void close();
|
||||||
|
|
||||||
long getDuration();
|
long getDuration();
|
||||||
|
|
||||||
Address *getSocketAddress() const;
|
Address *getSocketAddress() const;
|
||||||
|
|
||||||
unsigned short getSocketPort() const;
|
unsigned short getSocketPort() const;
|
||||||
|
|
||||||
Address *getPeerAddress() const;
|
Address *getPeerAddress() const;
|
||||||
|
|
||||||
unsigned short getPeerPort() const;
|
unsigned short getPeerPort() const;
|
||||||
|
|
||||||
string toString() const;
|
string toString() const;
|
||||||
|
|
||||||
|
|
||||||
bool isServerSide();
|
bool isServerSide();
|
||||||
|
|
||||||
bool isClientSide();
|
bool isClientSide();
|
||||||
|
|
||||||
bool isSecured();
|
bool isSecured();
|
||||||
|
|
||||||
|
|
||||||
void setReuseAddress(bool value = true);
|
void setReuseAddress(bool value = true);
|
||||||
|
|
||||||
void setReusePort(bool value = true);
|
void setReusePort(bool value = true);
|
||||||
|
|
||||||
void setSendBufferSize(int value);
|
void setSendBufferSize(int value);
|
||||||
|
|
||||||
void setReceiveBufferSize(int value);
|
void setReceiveBufferSize(int value);
|
||||||
|
|
||||||
void setMinReceiveBytes(int value);
|
void setMinReceiveBytes(int value);
|
||||||
|
|
||||||
void setMinSendBytes(int value);
|
void setMinSendBytes(int value);
|
||||||
|
|
||||||
void setSendTimeout(unsigned long ms);
|
void setSendTimeout(unsigned long ms);
|
||||||
|
|
||||||
void setReceiveTimeout(unsigned long ms);
|
void setReceiveTimeout(unsigned long ms);
|
||||||
|
|
||||||
|
|
||||||
bool getReuseAddress();
|
bool getReuseAddress();
|
||||||
|
|
||||||
bool getReusePort();
|
bool getReusePort();
|
||||||
|
|
||||||
int getSendBufferSize();
|
int getSendBufferSize();
|
||||||
|
|
||||||
int getReceiveBufferSize();
|
int getReceiveBufferSize();
|
||||||
|
|
||||||
int getMinReceiveBytes();
|
int getMinReceiveBytes();
|
||||||
|
|
||||||
int getMinSendBytes();
|
int getMinSendBytes();
|
||||||
|
|
||||||
long getSendTimeout();
|
long getSendTimeout();
|
||||||
|
|
||||||
long getReceiveTimeout();
|
long getReceiveTimeout();
|
||||||
|
|
||||||
unsigned long getBytesSent();
|
unsigned long getBytesSent();
|
||||||
|
|
||||||
unsigned long getBytesReceived();
|
unsigned long getBytesReceived();
|
||||||
|
|
||||||
static long select(list<Socket> read, list<Socket> write, long millis);
|
static long select(list<Socket> read, list<Socket> write, long millis);
|
||||||
|
|
||||||
static long select(list<Socket> read, list<Socket> write);
|
static long select(list<Socket> read, list<Socket> write);
|
||||||
|
|
||||||
void receive(FILE *file, long size);
|
void receive(FILE *file, long size);
|
||||||
};
|
};
|
||||||
|
|
||||||
Socket operator<<(Socket sock, const char *str);
|
Socket operator<<(Socket sock, const char *str);
|
||||||
|
@ -7,26 +7,26 @@
|
|||||||
#include "Http.h"
|
#include "Http.h"
|
||||||
|
|
||||||
unsigned long getMicros() {
|
unsigned long getMicros() {
|
||||||
struct timeval tv;
|
struct timeval tv;
|
||||||
gettimeofday(&tv, nullptr);
|
gettimeofday(&tv, nullptr);
|
||||||
return (unsigned long) (1000000 * tv.tv_sec + tv.tv_usec);
|
return (unsigned long) (1000000 * tv.tv_sec + tv.tv_usec);
|
||||||
}
|
}
|
||||||
|
|
||||||
string getHttpDate() {
|
string getHttpDate() {
|
||||||
time_t rawtime;
|
time_t rawtime;
|
||||||
time(&rawtime);
|
time(&rawtime);
|
||||||
return getHttpDate(rawtime);
|
return getHttpDate(rawtime);
|
||||||
}
|
}
|
||||||
|
|
||||||
string getHttpDate(string filename) {
|
string getHttpDate(string filename) {
|
||||||
struct stat attrib;
|
struct stat attrib;
|
||||||
stat(filename.c_str(), &attrib);
|
stat(filename.c_str(), &attrib);
|
||||||
return getHttpDate(attrib.st_ctime);
|
return getHttpDate(attrib.st_ctime);
|
||||||
}
|
}
|
||||||
|
|
||||||
string getHttpDate(time_t time) {
|
string getHttpDate(time_t time) {
|
||||||
char buffer[64];
|
char buffer[64];
|
||||||
struct tm *timeinfo = gmtime(&time);
|
struct tm *timeinfo = gmtime(&time);
|
||||||
strftime(buffer, sizeof(buffer), "%a, %d %b %Y %H:%M:%S GMT", timeinfo);
|
strftime(buffer, sizeof(buffer), "%a, %d %b %Y %H:%M:%S GMT", timeinfo);
|
||||||
return string(buffer);
|
return string(buffer);
|
||||||
}
|
}
|
||||||
|
@ -10,184 +10,184 @@
|
|||||||
#include "Http.h"
|
#include "Http.h"
|
||||||
|
|
||||||
HttpConnection::HttpConnection(Socket *socket) {
|
HttpConnection::HttpConnection(Socket *socket) {
|
||||||
this->socket = socket;
|
this->socket = socket;
|
||||||
this->request = new HttpRequest(socket);
|
this->request = new HttpRequest(socket);
|
||||||
this->response = new HttpResponse();
|
this->response = new HttpResponse();
|
||||||
microsStart = getMicros();
|
microsStart = getMicros();
|
||||||
response->setVersion("1.1");
|
response->setVersion("1.1");
|
||||||
response->setField("Server", "Necronda/3.0");
|
response->setField("Server", "Necronda/3.0");
|
||||||
}
|
}
|
||||||
|
|
||||||
void HttpConnection::respond(int statuscode) {
|
void HttpConnection::respond(int statuscode) {
|
||||||
if (statuscode >= 400 && statuscode < 600) {
|
if (statuscode >= 400 && statuscode < 600) {
|
||||||
respond(statuscode,
|
respond(statuscode,
|
||||||
"<!DOCTYPE html><html><head><title>" + to_string(statuscode) + " " +
|
"<!DOCTYPE html><html><head><title>" + to_string(statuscode) + " " +
|
||||||
::getStatusCode(statuscode).message +
|
::getStatusCode(statuscode).message +
|
||||||
"</title></head><body><center><h1>" + to_string(statuscode) + " " +
|
"</title></head><body><center><h1>" + to_string(statuscode) + " " +
|
||||||
::getStatusCode(statuscode).message +
|
::getStatusCode(statuscode).message +
|
||||||
"</h1>" +
|
"</h1>" +
|
||||||
((request->isExistingField("Host")) ?
|
((request->isExistingField("Host")) ?
|
||||||
(request->isExistingField("Referer") &&
|
(request->isExistingField("Referer") &&
|
||||||
request->getField("Referer").find(request->getField("Host")) != string::npos) ?
|
request->getField("Referer").find(request->getField("Host")) != string::npos) ?
|
||||||
"<p>Go back to the last page you visited: <a href=\"" + request->getField("Referer") + "\">" +
|
"<p>Go back to the last page you visited: <a href=\"" + request->getField("Referer") + "\">" +
|
||||||
request->getField("Referer") + "</a></p>" :
|
request->getField("Referer") + "</a></p>" :
|
||||||
"<p>Go back to the home page of <a href=\"//" +
|
"<p>Go back to the home page of <a href=\"//" +
|
||||||
request->getField("Host") + "/\">" +
|
request->getField("Host") + "/\">" +
|
||||||
request->getField("Host") +
|
request->getField("Host") +
|
||||||
"</a></p>" : "") + "</center></body></html>\r\n"
|
"</a></p>" : "") + "</center></body></html>\r\n"
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
respond(statuscode, "");
|
respond(statuscode, "");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void HttpConnection::respond(int statuscode, string payload) {
|
void HttpConnection::respond(int statuscode, string payload) {
|
||||||
response->setStatusCode(statuscode);
|
response->setStatusCode(statuscode);
|
||||||
response->setField("Date", getHttpDate());
|
response->setField("Date", getHttpDate());
|
||||||
response->setField("Content-Length", to_string(payload.length()));
|
response->setField("Content-Length", to_string(payload.length()));
|
||||||
response->sendHeader(socket);
|
response->sendHeader(socket);
|
||||||
socket->send(std::move(payload));
|
socket->send(std::move(payload));
|
||||||
}
|
}
|
||||||
|
|
||||||
void HttpConnection::respond(int statuscode, FILE *file, bool compress, long start, long end) {
|
void HttpConnection::respond(int statuscode, FILE *file, bool compress, long start, long end) {
|
||||||
response->setStatusCode(statuscode);
|
response->setStatusCode(statuscode);
|
||||||
response->setField("Transfer-Encoding", "chunked");
|
response->setField("Transfer-Encoding", "chunked");
|
||||||
response->setField("Date", getHttpDate());
|
response->setField("Date", getHttpDate());
|
||||||
|
|
||||||
long shouldTransfer;
|
long shouldTransfer;
|
||||||
long transfered = 0;
|
long transfered = 0;
|
||||||
|
|
||||||
fseek(file, 0, SEEK_END);
|
fseek(file, 0, SEEK_END);
|
||||||
long len = ftell(file);
|
long len = ftell(file);
|
||||||
|
|
||||||
if (start != -1 && end != -1) {
|
if (start != -1 && end != -1) {
|
||||||
fseek(file, start, SEEK_SET);
|
fseek(file, start, SEEK_SET);
|
||||||
response->setField("Content-Length", to_string(end - start + 1));
|
response->setField("Content-Length", to_string(end - start + 1));
|
||||||
shouldTransfer = end - start + 1;
|
shouldTransfer = end - start + 1;
|
||||||
compress = false;
|
compress = false;
|
||||||
} else {
|
} else {
|
||||||
fseek(file, 0, SEEK_SET);
|
fseek(file, 0, SEEK_SET);
|
||||||
shouldTransfer = len;
|
shouldTransfer = len;
|
||||||
if (len >= 0 && !compress) {
|
if (len >= 0 && !compress) {
|
||||||
response->setField("Content-Length", to_string(len));
|
response->setField("Content-Length", to_string(len));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (compress) {
|
if (compress) {
|
||||||
response->setField("Content-Encoding", "deflate");
|
response->setField("Content-Encoding", "deflate");
|
||||||
}
|
}
|
||||||
|
|
||||||
response->sendHeader(socket);
|
response->sendHeader(socket);
|
||||||
|
|
||||||
if (compress) {
|
if (compress) {
|
||||||
int level = 1;
|
int level = 1;
|
||||||
int ret, flush;
|
int ret, flush;
|
||||||
unsigned have;
|
unsigned have;
|
||||||
z_stream strm;
|
z_stream strm;
|
||||||
unsigned char in[CPPNET_CHUNK];
|
unsigned char in[CPPNET_CHUNK];
|
||||||
unsigned char out[CPPNET_CHUNK];
|
unsigned char out[CPPNET_CHUNK];
|
||||||
|
|
||||||
strm.zalloc = Z_NULL;
|
strm.zalloc = Z_NULL;
|
||||||
strm.zfree = Z_NULL;
|
strm.zfree = Z_NULL;
|
||||||
strm.opaque = Z_NULL;
|
strm.opaque = Z_NULL;
|
||||||
ret = deflateInit(&strm, level);
|
ret = deflateInit(&strm, level);
|
||||||
if (ret != Z_OK) {
|
if (ret != Z_OK) {
|
||||||
throw (char *) "Unable to open file";
|
throw (char *) "Unable to open file";
|
||||||
}
|
}
|
||||||
|
|
||||||
do {
|
do {
|
||||||
strm.avail_in = (uInt) fread(in, 1, CPPNET_CHUNK, file);
|
strm.avail_in = (uInt) fread(in, 1, CPPNET_CHUNK, file);
|
||||||
|
|
||||||
if (ferror(file)) {
|
if (ferror(file)) {
|
||||||
(void) deflateEnd(&strm);
|
(void) deflateEnd(&strm);
|
||||||
throw (char *) strerror(errno);
|
throw (char *) strerror(errno);
|
||||||
}
|
}
|
||||||
flush = feof(file) ? Z_FINISH : Z_NO_FLUSH;
|
flush = feof(file) ? Z_FINISH : Z_NO_FLUSH;
|
||||||
strm.next_in = in;
|
strm.next_in = in;
|
||||||
do {
|
do {
|
||||||
strm.avail_out = CPPNET_CHUNK;
|
strm.avail_out = CPPNET_CHUNK;
|
||||||
strm.next_out = out;
|
strm.next_out = out;
|
||||||
ret = deflate(&strm, flush);
|
ret = deflate(&strm, flush);
|
||||||
assert(ret != Z_STREAM_ERROR);
|
assert(ret != Z_STREAM_ERROR);
|
||||||
have = CPPNET_CHUNK - strm.avail_out;
|
have = CPPNET_CHUNK - strm.avail_out;
|
||||||
|
|
||||||
if (have != 0) {
|
if (have != 0) {
|
||||||
char buffer[64];
|
char buffer[64];
|
||||||
sprintf(buffer, "%X\r\n", have);
|
sprintf(buffer, "%X\r\n", have);
|
||||||
socket->send(buffer);
|
socket->send(buffer);
|
||||||
socket->send((const char *) out, have);
|
socket->send((const char *) out, have);
|
||||||
socket->send("\r\n");
|
socket->send("\r\n");
|
||||||
}
|
}
|
||||||
} while (strm.avail_out == 0);
|
} while (strm.avail_out == 0);
|
||||||
assert(strm.avail_in == 0);
|
assert(strm.avail_in == 0);
|
||||||
} while (flush != Z_FINISH);
|
} while (flush != Z_FINISH);
|
||||||
assert(ret == Z_STREAM_END);
|
assert(ret == Z_STREAM_END);
|
||||||
socket->send("0\r\n\r\n");
|
socket->send("0\r\n\r\n");
|
||||||
deflateEnd(&strm);
|
deflateEnd(&strm);
|
||||||
} else {
|
} else {
|
||||||
char buffer[CPPNET_CHUNK];
|
char buffer[CPPNET_CHUNK];
|
||||||
char buff[64];
|
char buff[64];
|
||||||
while (true) {
|
while (true) {
|
||||||
unsigned long size = fread(buffer, 1, (size_t) ((CPPNET_CHUNK > (shouldTransfer - transfered) && shouldTransfer > 0) ? (shouldTransfer - transfered) : CPPNET_CHUNK), file);
|
unsigned long size = fread(buffer, 1, (size_t) ((CPPNET_CHUNK > (shouldTransfer - transfered) && shouldTransfer > 0) ? (shouldTransfer - transfered) : CPPNET_CHUNK), file);
|
||||||
transfered += size;
|
transfered += size;
|
||||||
sprintf(buff, "%lX\r\n", size);
|
sprintf(buff, "%lX\r\n", size);
|
||||||
socket->send(buff);
|
socket->send(buff);
|
||||||
socket->send((const char *) buffer, size);
|
socket->send((const char *) buffer, size);
|
||||||
socket->send("\r\n");
|
socket->send("\r\n");
|
||||||
if (size == 0) {
|
if (size == 0) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
string HttpConnection::getField(string index) {
|
string HttpConnection::getField(string index) {
|
||||||
return request->getField(std::move(index));
|
return request->getField(std::move(index));
|
||||||
}
|
}
|
||||||
|
|
||||||
string HttpConnection::getPath() {
|
string HttpConnection::getPath() {
|
||||||
return request->getPath();
|
return request->getPath();
|
||||||
}
|
}
|
||||||
|
|
||||||
void HttpConnection::setField(string index, string data) {
|
void HttpConnection::setField(string index, string data) {
|
||||||
response->setField(std::move(index), std::move(data));
|
response->setField(std::move(index), std::move(data));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool HttpConnection::isExistingField(string index) {
|
bool HttpConnection::isExistingField(string index) {
|
||||||
return request->isExistingField(std::move(index));
|
return request->isExistingField(std::move(index));
|
||||||
}
|
}
|
||||||
|
|
||||||
string HttpConnection::getMethod() {
|
string HttpConnection::getMethod() {
|
||||||
return request->getMethod();
|
return request->getMethod();
|
||||||
}
|
}
|
||||||
|
|
||||||
long HttpConnection::getDuration() {
|
long HttpConnection::getDuration() {
|
||||||
return getMicros() - microsStart;
|
return getMicros() - microsStart;
|
||||||
}
|
}
|
||||||
|
|
||||||
HttpStatusCode HttpConnection::getStatusCode() {
|
HttpStatusCode HttpConnection::getStatusCode() {
|
||||||
return response->getStatusCode();
|
return response->getStatusCode();
|
||||||
}
|
}
|
||||||
|
|
||||||
void HttpConnection::redirect(int statuscode, string location) {
|
void HttpConnection::redirect(int statuscode, string location) {
|
||||||
setField("Location", std::move(location));
|
setField("Location", std::move(location));
|
||||||
respond(statuscode, "");
|
respond(statuscode, "");
|
||||||
}
|
}
|
||||||
|
|
||||||
string HttpConnection::getResponseField(string index) {
|
string HttpConnection::getResponseField(string index) {
|
||||||
return response->getField(std::move(index));
|
return response->getField(std::move(index));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool HttpConnection::isExistingResponseField(string index) {
|
bool HttpConnection::isExistingResponseField(string index) {
|
||||||
return response->isExistingField(std::move(index));
|
return response->isExistingField(std::move(index));
|
||||||
}
|
}
|
||||||
|
|
||||||
string HttpConnection::cgiExport() {
|
string HttpConnection::cgiExport() {
|
||||||
return request->cgiExport();
|
return request->cgiExport();
|
||||||
}
|
}
|
||||||
|
|
||||||
void HttpConnection::removeField(string index) {
|
void HttpConnection::removeField(string index) {
|
||||||
response->removeField(std::move(index));
|
response->removeField(std::move(index));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -11,43 +11,43 @@
|
|||||||
|
|
||||||
class HttpConnection {
|
class HttpConnection {
|
||||||
private:
|
private:
|
||||||
Socket *socket;
|
Socket *socket;
|
||||||
HttpRequest *request;
|
HttpRequest *request;
|
||||||
HttpResponse *response;
|
HttpResponse *response;
|
||||||
long microsStart;
|
long microsStart;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit HttpConnection(Socket *socket);
|
explicit HttpConnection(Socket *socket);
|
||||||
|
|
||||||
void respond(int statuscode);
|
void respond(int statuscode);
|
||||||
|
|
||||||
void respond(int statuscode, string payload);
|
void respond(int statuscode, string payload);
|
||||||
|
|
||||||
void respond(int statuscode, FILE *file, bool compress = false, long start = -1, long end = -1);
|
void respond(int statuscode, FILE *file, bool compress = false, long start = -1, long end = -1);
|
||||||
|
|
||||||
void redirect(int statuscode, string location);
|
void redirect(int statuscode, string location);
|
||||||
|
|
||||||
bool isExistingField(string index);
|
bool isExistingField(string index);
|
||||||
|
|
||||||
bool isExistingResponseField(string index);
|
bool isExistingResponseField(string index);
|
||||||
|
|
||||||
string getField(string index);
|
string getField(string index);
|
||||||
|
|
||||||
string getResponseField(string index);
|
string getResponseField(string index);
|
||||||
|
|
||||||
string getPath();
|
string getPath();
|
||||||
|
|
||||||
string getMethod();
|
string getMethod();
|
||||||
|
|
||||||
void setField(string index, string data);
|
void setField(string index, string data);
|
||||||
|
|
||||||
long getDuration();
|
long getDuration();
|
||||||
|
|
||||||
HttpStatusCode getStatusCode();
|
HttpStatusCode getStatusCode();
|
||||||
|
|
||||||
string cgiExport();
|
string cgiExport();
|
||||||
|
|
||||||
void removeField(string index);
|
void removeField(string index);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -15,12 +15,12 @@
|
|||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
string to_cgi(string text) {
|
string to_cgi(string text) {
|
||||||
for (auto & c: text) c = (char) toupper(c);
|
for (auto & c: text) c = (char) toupper(c);
|
||||||
long pos = 0;
|
long pos = 0;
|
||||||
while ((pos = text.find('-', pos + 1)) != string::npos) {
|
while ((pos = text.find('-', pos + 1)) != string::npos) {
|
||||||
text.replace(pos, 1, 1, '_');
|
text.replace(pos, 1, 1, '_');
|
||||||
}
|
}
|
||||||
return text;
|
return text;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -28,33 +28,33 @@ string to_cgi(string text) {
|
|||||||
* Default Constructor
|
* Default Constructor
|
||||||
*/
|
*/
|
||||||
HttpHeader::HttpHeader() {
|
HttpHeader::HttpHeader() {
|
||||||
fields = fields;
|
fields = fields;
|
||||||
}
|
}
|
||||||
|
|
||||||
HttpHeader::HttpHeader(Socket *socket) : HttpHeader::HttpHeader() {
|
HttpHeader::HttpHeader(Socket *socket) : HttpHeader::HttpHeader() {
|
||||||
parse(socket);
|
parse(socket);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void HttpHeader::parse(Socket *socket) {
|
void HttpHeader::parse(Socket *socket) {
|
||||||
while (true) {
|
while (true) {
|
||||||
string line = socket->receiveLine();
|
string line = socket->receiveLine();
|
||||||
if (line.length() == 0) {
|
if (line.length() == 0) {
|
||||||
break;
|
break;
|
||||||
} else {
|
} else {
|
||||||
unsigned long pos = line.find(':');
|
unsigned long pos = line.find(':');
|
||||||
if (pos == string::npos) {
|
if (pos == string::npos) {
|
||||||
throw (char *) "Malformed header";
|
throw (char *) "Malformed header";
|
||||||
}
|
}
|
||||||
string index = line.substr(0, pos);
|
string index = line.substr(0, pos);
|
||||||
string data = line.substr(pos + 1, line.length() - pos);
|
string data = line.substr(pos + 1, line.length() - pos);
|
||||||
while (index[0] == ' ') index.erase(index.begin() + 0);
|
while (index[0] == ' ') index.erase(index.begin() + 0);
|
||||||
while (index[index.length() - 1] == ' ') index.erase(index.end() - 1);
|
while (index[index.length() - 1] == ' ') index.erase(index.end() - 1);
|
||||||
while (data[0] == ' ') data.erase(data.begin() + 0);
|
while (data[0] == ' ') data.erase(data.begin() + 0);
|
||||||
while (data[data.length() - 1] == ' ') data.erase(data.end() - 1);
|
while (data[data.length() - 1] == ' ') data.erase(data.end() - 1);
|
||||||
setField(index, data);
|
setField(index, data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -62,7 +62,7 @@ void HttpHeader::parse(Socket *socket) {
|
|||||||
* Default Destructor
|
* Default Destructor
|
||||||
*/
|
*/
|
||||||
HttpHeader::~HttpHeader() {
|
HttpHeader::~HttpHeader() {
|
||||||
fields.clear();
|
fields.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -73,12 +73,12 @@ HttpHeader::~HttpHeader() {
|
|||||||
* @param data The field data
|
* @param data The field data
|
||||||
*/
|
*/
|
||||||
void HttpHeader::setField(string index, string data) {
|
void HttpHeader::setField(string index, string data) {
|
||||||
removeField(index);
|
removeField(index);
|
||||||
fields.insert(make_pair(index, data));
|
fields.insert(make_pair(index, data));
|
||||||
}
|
}
|
||||||
|
|
||||||
void HttpHeader::removeField(string index) {
|
void HttpHeader::removeField(string index) {
|
||||||
fields.erase(index);
|
fields.erase(index);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -88,34 +88,34 @@ void HttpHeader::removeField(string index) {
|
|||||||
* @return The field data
|
* @return The field data
|
||||||
*/
|
*/
|
||||||
string HttpHeader::getField(string index) {
|
string HttpHeader::getField(string index) {
|
||||||
auto i = fields.find(index);
|
auto i = fields.find(index);
|
||||||
if (i != fields.end()) {
|
if (i != fields.end()) {
|
||||||
return fields.at(index);
|
return fields.at(index);
|
||||||
} else {
|
} else {
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool HttpHeader::isExistingField(string index) {
|
bool HttpHeader::isExistingField(string index) {
|
||||||
auto i = fields.find(index);
|
auto i = fields.find(index);
|
||||||
return i != fields.end();
|
return i != fields.end();
|
||||||
}
|
}
|
||||||
|
|
||||||
string HttpHeader::toString() {
|
string HttpHeader::toString() {
|
||||||
string header = "";
|
string header = "";
|
||||||
for (auto it = fields.begin(); it != fields.end(); it++ ) {
|
for (auto it = fields.begin(); it != fields.end(); it++ ) {
|
||||||
header += it->first + ": " + it->second + "\r\n";
|
header += it->first + ": " + it->second + "\r\n";
|
||||||
}
|
}
|
||||||
return header;
|
return header;
|
||||||
}
|
}
|
||||||
|
|
||||||
string HttpHeader::cgiExport() {
|
string HttpHeader::cgiExport() {
|
||||||
string header = "";
|
string header = "";
|
||||||
for (auto it = fields.begin(); it != fields.end(); it++ ) {
|
for (auto it = fields.begin(); it != fields.end(); it++ ) {
|
||||||
header += "HTTP_" + to_cgi(it->first) + "=" + cli_encode(it->second) + " ";
|
header += "HTTP_" + to_cgi(it->first) + "=" + cli_encode(it->second) + " ";
|
||||||
}
|
}
|
||||||
return header;
|
return header;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -12,9 +12,9 @@
|
|||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
struct comp {
|
struct comp {
|
||||||
bool operator()(const std::string& lhs, const std::string& rhs) const {
|
bool operator()(const std::string& lhs, const std::string& rhs) const {
|
||||||
return strcasecmp(lhs.c_str(), rhs.c_str()) < 0;
|
return strcasecmp(lhs.c_str(), rhs.c_str()) < 0;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -25,28 +25,28 @@ struct comp {
|
|||||||
*/
|
*/
|
||||||
class HttpHeader {
|
class HttpHeader {
|
||||||
private:
|
private:
|
||||||
map<string, string, comp> fields;
|
map<string, string, comp> fields;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
HttpHeader();
|
HttpHeader();
|
||||||
|
|
||||||
explicit HttpHeader(Socket *socket);
|
explicit HttpHeader(Socket *socket);
|
||||||
|
|
||||||
~HttpHeader();
|
~HttpHeader();
|
||||||
|
|
||||||
void setField(string index, string data);
|
void setField(string index, string data);
|
||||||
|
|
||||||
string getField(string index);
|
string getField(string index);
|
||||||
|
|
||||||
void removeField(string index);
|
void removeField(string index);
|
||||||
|
|
||||||
bool isExistingField(string index);
|
bool isExistingField(string index);
|
||||||
|
|
||||||
void parse(Socket *socket);
|
void parse(Socket *socket);
|
||||||
|
|
||||||
string toString();
|
string toString();
|
||||||
|
|
||||||
string cgiExport();
|
string cgiExport();
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -9,95 +9,95 @@
|
|||||||
|
|
||||||
|
|
||||||
HttpRequest::HttpRequest() {
|
HttpRequest::HttpRequest() {
|
||||||
this->header = HttpHeader();
|
this->header = HttpHeader();
|
||||||
}
|
}
|
||||||
|
|
||||||
HttpRequest::HttpRequest(Socket *socket) : HttpRequest::HttpRequest() {
|
HttpRequest::HttpRequest(Socket *socket) : HttpRequest::HttpRequest() {
|
||||||
parseHeader(socket);
|
parseHeader(socket);
|
||||||
}
|
}
|
||||||
|
|
||||||
HttpRequest::HttpRequest(string method, string path, string version) : HttpRequest::HttpRequest() {
|
HttpRequest::HttpRequest(string method, string path, string version) : HttpRequest::HttpRequest() {
|
||||||
this->method = std::move(method);
|
this->method = std::move(method);
|
||||||
this->path = std::move(path);
|
this->path = std::move(path);
|
||||||
this->version = std::move(version);
|
this->version = std::move(version);
|
||||||
}
|
}
|
||||||
|
|
||||||
void HttpRequest::parseHeader(Socket *socket) {
|
void HttpRequest::parseHeader(Socket *socket) {
|
||||||
string line = socket->receiveLine();
|
string line = socket->receiveLine();
|
||||||
|
|
||||||
unsigned long pos1 = line.find(' ');
|
unsigned long pos1 = line.find(' ');
|
||||||
unsigned long pos2;
|
unsigned long pos2;
|
||||||
|
|
||||||
bool invalid = false;
|
bool invalid = false;
|
||||||
|
|
||||||
if (pos1 != string::npos) {
|
if (pos1 != string::npos) {
|
||||||
pos2 = line.find(' ', pos1 + 1);
|
pos2 = line.find(' ', pos1 + 1);
|
||||||
if (pos2 != string::npos) {
|
if (pos2 != string::npos) {
|
||||||
method = line.substr(0, pos1);
|
method = line.substr(0, pos1);
|
||||||
for (auto &c: method) c = (char) toupper(c);
|
for (auto &c: method) c = (char) toupper(c);
|
||||||
path = line.substr(pos1 + 1, pos2 - pos1 - 1);
|
path = line.substr(pos1 + 1, pos2 - pos1 - 1);
|
||||||
version = line.substr(pos2 + 6, 3);
|
version = line.substr(pos2 + 6, 3);
|
||||||
} else {
|
} else {
|
||||||
invalid = true;
|
invalid = true;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
pos2 = string::npos;
|
pos2 = string::npos;
|
||||||
invalid = true;
|
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'))) {
|
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;
|
invalid = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (invalid) {
|
if (invalid) {
|
||||||
method = "";
|
method = "";
|
||||||
path = "";
|
path = "";
|
||||||
version = "";
|
version = "";
|
||||||
throw (char *) "Malformed header";
|
throw (char *) "Malformed header";
|
||||||
}
|
}
|
||||||
|
|
||||||
header.parse(socket);
|
header.parse(socket);
|
||||||
}
|
}
|
||||||
|
|
||||||
string HttpRequest::getMethod() {
|
string HttpRequest::getMethod() {
|
||||||
return method;
|
return method;
|
||||||
}
|
}
|
||||||
|
|
||||||
string HttpRequest::getPath() {
|
string HttpRequest::getPath() {
|
||||||
return path;
|
return path;
|
||||||
}
|
}
|
||||||
|
|
||||||
string HttpRequest::getVersion() {
|
string HttpRequest::getVersion() {
|
||||||
return version;
|
return version;
|
||||||
}
|
}
|
||||||
|
|
||||||
void HttpRequest::setMethod(string method) {
|
void HttpRequest::setMethod(string method) {
|
||||||
this->method = std::move(method);
|
this->method = std::move(method);
|
||||||
}
|
}
|
||||||
|
|
||||||
void HttpRequest::setPath(string path) {
|
void HttpRequest::setPath(string path) {
|
||||||
this->path = std::move(path);
|
this->path = std::move(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
void HttpRequest::setVersion(string version) {
|
void HttpRequest::setVersion(string version) {
|
||||||
this->version = std::move(version);
|
this->version = std::move(version);
|
||||||
}
|
}
|
||||||
|
|
||||||
string HttpRequest::getField(string index) {
|
string HttpRequest::getField(string index) {
|
||||||
return header.getField(std::move(index));
|
return header.getField(std::move(index));
|
||||||
}
|
}
|
||||||
|
|
||||||
void HttpRequest::setField(string index, string data) {
|
void HttpRequest::setField(string index, string data) {
|
||||||
header.setField(std::move(index), std::move(data));
|
header.setField(std::move(index), std::move(data));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool HttpRequest::isExistingField(string index) {
|
bool HttpRequest::isExistingField(string index) {
|
||||||
return header.isExistingField(std::move(index));
|
return header.isExistingField(std::move(index));
|
||||||
}
|
}
|
||||||
|
|
||||||
string HttpRequest::cgiExport() {
|
string HttpRequest::cgiExport() {
|
||||||
return header.cgiExport();
|
return header.cgiExport();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -11,41 +11,41 @@ using namespace std;
|
|||||||
|
|
||||||
class HttpRequest {
|
class HttpRequest {
|
||||||
private:
|
private:
|
||||||
HttpHeader header;
|
HttpHeader header;
|
||||||
string method;
|
string method;
|
||||||
string path;
|
string path;
|
||||||
string version;
|
string version;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
HttpRequest();
|
HttpRequest();
|
||||||
|
|
||||||
explicit HttpRequest(Socket *socket);
|
explicit HttpRequest(Socket *socket);
|
||||||
|
|
||||||
HttpRequest(string method, string path, string version = "1.1");
|
HttpRequest(string method, string path, string version = "1.1");
|
||||||
|
|
||||||
void parseHeader(Socket *socket);
|
void parseHeader(Socket *socket);
|
||||||
|
|
||||||
void sendHeader(Socket *socket);
|
void sendHeader(Socket *socket);
|
||||||
|
|
||||||
string getField(string index);
|
string getField(string index);
|
||||||
|
|
||||||
void setField(string index, string data);
|
void setField(string index, string data);
|
||||||
|
|
||||||
bool isExistingField(string index);
|
bool isExistingField(string index);
|
||||||
|
|
||||||
string getMethod();
|
string getMethod();
|
||||||
|
|
||||||
string getPath();
|
string getPath();
|
||||||
|
|
||||||
string getVersion();
|
string getVersion();
|
||||||
|
|
||||||
void setMethod(string method);
|
void setMethod(string method);
|
||||||
|
|
||||||
void setPath(string path);
|
void setPath(string path);
|
||||||
|
|
||||||
void setVersion(string version);
|
void setVersion(string version);
|
||||||
|
|
||||||
string cgiExport();
|
string cgiExport();
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -9,56 +9,56 @@
|
|||||||
|
|
||||||
|
|
||||||
HttpResponse::HttpResponse() {
|
HttpResponse::HttpResponse() {
|
||||||
this->header = HttpHeader();
|
this->header = HttpHeader();
|
||||||
}
|
}
|
||||||
|
|
||||||
HttpResponse::HttpResponse(Socket *socket) : HttpResponse::HttpResponse() {
|
HttpResponse::HttpResponse(Socket *socket) : HttpResponse::HttpResponse() {
|
||||||
this->parseHeader(socket);
|
this->parseHeader(socket);
|
||||||
}
|
}
|
||||||
|
|
||||||
HttpResponse::HttpResponse(int statuscode, string version) : HttpResponse::HttpResponse(::getStatusCode(statuscode), std::move(version)) {
|
HttpResponse::HttpResponse(int statuscode, string version) : HttpResponse::HttpResponse(::getStatusCode(statuscode), std::move(version)) {
|
||||||
}
|
}
|
||||||
|
|
||||||
HttpResponse::HttpResponse(HttpStatusCode statuscode, string version) : HttpResponse::HttpResponse() {
|
HttpResponse::HttpResponse(HttpStatusCode statuscode, string version) : HttpResponse::HttpResponse() {
|
||||||
this->statuscode = statuscode;
|
this->statuscode = statuscode;
|
||||||
this->version = std::move(version);
|
this->version = std::move(version);
|
||||||
}
|
}
|
||||||
|
|
||||||
void HttpResponse::sendHeader(Socket *socket) {
|
void HttpResponse::sendHeader(Socket *socket) {
|
||||||
socket->send("HTTP/" + version + " " + to_string(statuscode.code) + " " + statuscode.message + "\r\n" +
|
socket->send("HTTP/" + version + " " + to_string(statuscode.code) + " " + statuscode.message + "\r\n" +
|
||||||
header.toString() + "\r\n");
|
header.toString() + "\r\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
string HttpResponse::getField(string index) {
|
string HttpResponse::getField(string index) {
|
||||||
return header.getField(std::move(index));
|
return header.getField(std::move(index));
|
||||||
}
|
}
|
||||||
|
|
||||||
void HttpResponse::setField(string index, string data) {
|
void HttpResponse::setField(string index, string data) {
|
||||||
header.setField(std::move(index), std::move(data));
|
header.setField(std::move(index), std::move(data));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool HttpResponse::isExistingField(string index) {
|
bool HttpResponse::isExistingField(string index) {
|
||||||
return header.isExistingField(std::move(index));
|
return header.isExistingField(std::move(index));
|
||||||
}
|
}
|
||||||
|
|
||||||
HttpStatusCode HttpResponse::getStatusCode() {
|
HttpStatusCode HttpResponse::getStatusCode() {
|
||||||
return statuscode;
|
return statuscode;
|
||||||
}
|
}
|
||||||
|
|
||||||
string HttpResponse::getVersion() {
|
string HttpResponse::getVersion() {
|
||||||
return version;
|
return version;
|
||||||
}
|
}
|
||||||
|
|
||||||
void HttpResponse::setStatusCode(HttpStatusCode statuscode) {
|
void HttpResponse::setStatusCode(HttpStatusCode statuscode) {
|
||||||
this->statuscode = statuscode;
|
this->statuscode = statuscode;
|
||||||
}
|
}
|
||||||
|
|
||||||
void HttpResponse::setStatusCode(int statuscode) {
|
void HttpResponse::setStatusCode(int statuscode) {
|
||||||
this->statuscode = ::getStatusCode(statuscode);
|
this->statuscode = ::getStatusCode(statuscode);
|
||||||
}
|
}
|
||||||
|
|
||||||
void HttpResponse::setVersion(string version) {
|
void HttpResponse::setVersion(string version) {
|
||||||
this->version = std::move(version);
|
this->version = std::move(version);
|
||||||
}
|
}
|
||||||
|
|
||||||
void HttpResponse::parseHeader(Socket *socket) {
|
void HttpResponse::parseHeader(Socket *socket) {
|
||||||
@ -66,5 +66,5 @@ void HttpResponse::parseHeader(Socket *socket) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void HttpResponse::removeField(string index) {
|
void HttpResponse::removeField(string index) {
|
||||||
header.removeField(std::move(index));
|
header.removeField(std::move(index));
|
||||||
}
|
}
|
||||||
|
@ -11,40 +11,40 @@
|
|||||||
|
|
||||||
class HttpResponse {
|
class HttpResponse {
|
||||||
private:
|
private:
|
||||||
HttpHeader header;
|
HttpHeader header;
|
||||||
HttpStatusCode statuscode;
|
HttpStatusCode statuscode;
|
||||||
string version;
|
string version;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
HttpResponse();
|
HttpResponse();
|
||||||
|
|
||||||
explicit HttpResponse(Socket *socket);
|
explicit HttpResponse(Socket *socket);
|
||||||
|
|
||||||
explicit HttpResponse(int statuscode, string version = "1.1");
|
explicit HttpResponse(int statuscode, string version = "1.1");
|
||||||
|
|
||||||
explicit HttpResponse(HttpStatusCode statuscode, string version = "1.1");
|
explicit HttpResponse(HttpStatusCode statuscode, string version = "1.1");
|
||||||
|
|
||||||
void parseHeader(Socket *socket);
|
void parseHeader(Socket *socket);
|
||||||
|
|
||||||
void sendHeader(Socket *socket);
|
void sendHeader(Socket *socket);
|
||||||
|
|
||||||
string getField(string index);
|
string getField(string index);
|
||||||
|
|
||||||
void setField(string index, string data);
|
void setField(string index, string data);
|
||||||
|
|
||||||
bool isExistingField(string index);
|
bool isExistingField(string index);
|
||||||
|
|
||||||
HttpStatusCode getStatusCode();
|
HttpStatusCode getStatusCode();
|
||||||
|
|
||||||
string getVersion();
|
string getVersion();
|
||||||
|
|
||||||
void setStatusCode(HttpStatusCode statuscode);
|
void setStatusCode(HttpStatusCode statuscode);
|
||||||
|
|
||||||
void setStatusCode(int statuscode);
|
void setStatusCode(int statuscode);
|
||||||
|
|
||||||
void setVersion(string version);
|
void setVersion(string version);
|
||||||
|
|
||||||
void removeField(string index);
|
void removeField(string index);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -9,57 +9,57 @@
|
|||||||
|
|
||||||
|
|
||||||
HttpStatusCode httpStatusCodes[] = {
|
HttpStatusCode httpStatusCodes[] = {
|
||||||
HttpStatusCode{100, "Informational", "Continue", ""},
|
HttpStatusCode{100, "Informational", "Continue", ""},
|
||||||
HttpStatusCode{101, "Informational", "Switching Protocols", ""},
|
HttpStatusCode{101, "Informational", "Switching Protocols", ""},
|
||||||
|
|
||||||
HttpStatusCode{200, "Success", "OK", ""},
|
HttpStatusCode{200, "Success", "OK", ""},
|
||||||
HttpStatusCode{201, "Success", "Created", ""},
|
HttpStatusCode{201, "Success", "Created", ""},
|
||||||
HttpStatusCode{202, "Success", "Accepted", ""},
|
HttpStatusCode{202, "Success", "Accepted", ""},
|
||||||
HttpStatusCode{203, "Success", "Non-Authoritative Information", ""},
|
HttpStatusCode{203, "Success", "Non-Authoritative Information", ""},
|
||||||
HttpStatusCode{204, "Success", "No Centent", ""},
|
HttpStatusCode{204, "Success", "No Centent", ""},
|
||||||
HttpStatusCode{205, "Success", "Reset Content", ""},
|
HttpStatusCode{205, "Success", "Reset Content", ""},
|
||||||
HttpStatusCode{206, "Success", "Partial Content", ""},
|
HttpStatusCode{206, "Success", "Partial Content", ""},
|
||||||
|
|
||||||
HttpStatusCode{300, "Redirection", "Multiple Choices", ""},
|
HttpStatusCode{300, "Redirection", "Multiple Choices", ""},
|
||||||
HttpStatusCode{301, "Redirection", "Moved Permanently", ""},
|
HttpStatusCode{301, "Redirection", "Moved Permanently", ""},
|
||||||
HttpStatusCode{302, "Redirection", "Found", ""},
|
HttpStatusCode{302, "Redirection", "Found", ""},
|
||||||
HttpStatusCode{303, "Redirection", "See Other", ""},
|
HttpStatusCode{303, "Redirection", "See Other", ""},
|
||||||
HttpStatusCode{304, "Redirection", "Not Modified", ""},
|
HttpStatusCode{304, "Redirection", "Not Modified", ""},
|
||||||
HttpStatusCode{305, "Redirection", "Use Proxy", ""},
|
HttpStatusCode{305, "Redirection", "Use Proxy", ""},
|
||||||
HttpStatusCode{307, "Redirection", "Temporary Redirect", ""},
|
HttpStatusCode{307, "Redirection", "Temporary Redirect", ""},
|
||||||
|
|
||||||
HttpStatusCode{400, "Client Error", "Bad Request", ""},
|
HttpStatusCode{400, "Client Error", "Bad Request", ""},
|
||||||
HttpStatusCode{401, "Client Error", "Unauthorized", ""},
|
HttpStatusCode{401, "Client Error", "Unauthorized", ""},
|
||||||
HttpStatusCode{402, "Client Error", "Payment Required", ""},
|
HttpStatusCode{402, "Client Error", "Payment Required", ""},
|
||||||
HttpStatusCode{403, "Client Error", "Forbidden", ""},
|
HttpStatusCode{403, "Client Error", "Forbidden", ""},
|
||||||
HttpStatusCode{404, "Client Error", "Not Found", ""},
|
HttpStatusCode{404, "Client Error", "Not Found", ""},
|
||||||
HttpStatusCode{405, "Client Error", "Method Not Allowed", ""},
|
HttpStatusCode{405, "Client Error", "Method Not Allowed", ""},
|
||||||
HttpStatusCode{406, "Client Error", "Not Acceptable", ""},
|
HttpStatusCode{406, "Client Error", "Not Acceptable", ""},
|
||||||
HttpStatusCode{407, "Client Error", "Proxy Authentication Required", ""},
|
HttpStatusCode{407, "Client Error", "Proxy Authentication Required", ""},
|
||||||
HttpStatusCode{408, "Client Error", "Request Timeout", ""},
|
HttpStatusCode{408, "Client Error", "Request Timeout", ""},
|
||||||
HttpStatusCode{409, "Client Error", "Conflict", ""},
|
HttpStatusCode{409, "Client Error", "Conflict", ""},
|
||||||
HttpStatusCode{410, "Client Error", "Gone", ""},
|
HttpStatusCode{410, "Client Error", "Gone", ""},
|
||||||
HttpStatusCode{411, "Client Error", "Length Required", ""},
|
HttpStatusCode{411, "Client Error", "Length Required", ""},
|
||||||
HttpStatusCode{412, "Client Error", "Precondition Failed", ""},
|
HttpStatusCode{412, "Client Error", "Precondition Failed", ""},
|
||||||
HttpStatusCode{413, "Client Error", "Request Entity Too Large", ""},
|
HttpStatusCode{413, "Client Error", "Request Entity Too Large", ""},
|
||||||
HttpStatusCode{414, "Client Error", "Request-URI Too Long", ""},
|
HttpStatusCode{414, "Client Error", "Request-URI Too Long", ""},
|
||||||
HttpStatusCode{415, "Client Error", "Unsupported Media Type", ""},
|
HttpStatusCode{415, "Client Error", "Unsupported Media Type", ""},
|
||||||
HttpStatusCode{416, "Client Error", "Requested Range Not Satisfiable", ""},
|
HttpStatusCode{416, "Client Error", "Requested Range Not Satisfiable", ""},
|
||||||
HttpStatusCode{417, "Client Error", "Expectation Failed", ""},
|
HttpStatusCode{417, "Client Error", "Expectation Failed", ""},
|
||||||
|
|
||||||
HttpStatusCode{500, "Server Error", "Internal Server Error", ""},
|
HttpStatusCode{500, "Server Error", "Internal Server Error", ""},
|
||||||
HttpStatusCode{501, "Server Error", "Not Implemented", ""},
|
HttpStatusCode{501, "Server Error", "Not Implemented", ""},
|
||||||
HttpStatusCode{502, "Server Error", "Bad Gateway", ""},
|
HttpStatusCode{502, "Server Error", "Bad Gateway", ""},
|
||||||
HttpStatusCode{503, "Server Error", "Service Unavailable", ""},
|
HttpStatusCode{503, "Server Error", "Service Unavailable", ""},
|
||||||
HttpStatusCode{504, "Server Error", "Gateway Timeout", ""},
|
HttpStatusCode{504, "Server Error", "Gateway Timeout", ""},
|
||||||
HttpStatusCode{505, "Server Error", "HTTP Version Not Supported", ""},
|
HttpStatusCode{505, "Server Error", "HTTP Version Not Supported", ""},
|
||||||
};
|
};
|
||||||
|
|
||||||
HttpStatusCode getStatusCode(int statuscode) {
|
HttpStatusCode getStatusCode(int statuscode) {
|
||||||
for (HttpStatusCode sc : httpStatusCodes) {
|
for (HttpStatusCode sc : httpStatusCodes) {
|
||||||
if (sc.code == statuscode) {
|
if (sc.code == statuscode) {
|
||||||
return sc;
|
return sc;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
throw (char *) "Invalid status code";
|
throw (char *) "Invalid status code";
|
||||||
}
|
}
|
||||||
|
@ -4,10 +4,10 @@
|
|||||||
#define NECRONDA_HTTP_STATUSCODE
|
#define NECRONDA_HTTP_STATUSCODE
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
short code; // The status code (e.g. 200)
|
short code; // The status code (e.g. 200)
|
||||||
const char *type; // The status type type (e.g Success)
|
const char *type; // The status type type (e.g Success)
|
||||||
const char *message; // The status code message (e.g. OK)
|
const char *message; // The status code message (e.g. OK)
|
||||||
const char *description; // The status code description (currently not used)
|
const char *description; // The status code description (currently not used)
|
||||||
} HttpStatusCode;
|
} HttpStatusCode;
|
||||||
|
|
||||||
HttpStatusCode getStatusCode(int statuscode);
|
HttpStatusCode getStatusCode(int statuscode);
|
||||||
|
@ -6,36 +6,36 @@
|
|||||||
|
|
||||||
stds procopen(const char* command) {
|
stds procopen(const char* command) {
|
||||||
|
|
||||||
int pipes[3][2];
|
int pipes[3][2];
|
||||||
|
|
||||||
pipe(pipes[PARENT_READ_PIPE]);
|
pipe(pipes[PARENT_READ_PIPE]);
|
||||||
pipe(pipes[PARENT_WRITE_PIPE]);
|
pipe(pipes[PARENT_WRITE_PIPE]);
|
||||||
pipe(pipes[PARENT_ERROR_PIPE]);
|
pipe(pipes[PARENT_ERROR_PIPE]);
|
||||||
|
|
||||||
int pid = fork();
|
int pid = fork();
|
||||||
|
|
||||||
if(pid == 0) {
|
if(pid == 0) {
|
||||||
dup2(CHILD_READ_FD, STDIN_FILENO);
|
dup2(CHILD_READ_FD, STDIN_FILENO);
|
||||||
dup2(CHILD_WRITE_FD, STDOUT_FILENO);
|
dup2(CHILD_WRITE_FD, STDOUT_FILENO);
|
||||||
dup2(CHILD_ERROR_FD, STDERR_FILENO);
|
dup2(CHILD_ERROR_FD, STDERR_FILENO);
|
||||||
|
|
||||||
close(CHILD_READ_FD);
|
close(CHILD_READ_FD);
|
||||||
close(CHILD_WRITE_FD);
|
close(CHILD_WRITE_FD);
|
||||||
close(CHILD_ERROR_FD);
|
close(CHILD_ERROR_FD);
|
||||||
|
|
||||||
close(PARENT_READ_FD);
|
close(PARENT_READ_FD);
|
||||||
close(PARENT_WRITE_FD);
|
close(PARENT_WRITE_FD);
|
||||||
close(PARENT_ERROR_FD);
|
close(PARENT_ERROR_FD);
|
||||||
|
|
||||||
system(command);
|
system(command);
|
||||||
exit(0);
|
exit(0);
|
||||||
} else {
|
} else {
|
||||||
close(CHILD_READ_FD);
|
close(CHILD_READ_FD);
|
||||||
close(CHILD_WRITE_FD);
|
close(CHILD_WRITE_FD);
|
||||||
close(CHILD_ERROR_FD);
|
close(CHILD_ERROR_FD);
|
||||||
|
|
||||||
return stds{fdopen(PARENT_WRITE_FD, "w"), fdopen(PARENT_READ_FD, "r"), fdopen(PARENT_ERROR_FD, "r"), (pid_t) pid};
|
return stds{fdopen(PARENT_WRITE_FD, "w"), fdopen(PARENT_READ_FD, "r"), fdopen(PARENT_ERROR_FD, "r"), (pid_t) pid};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -28,10 +28,10 @@
|
|||||||
|
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
FILE* stdin;
|
FILE* stdin;
|
||||||
FILE* stdout;
|
FILE* stdout;
|
||||||
FILE* stderr;
|
FILE* stderr;
|
||||||
pid_t pid;
|
pid_t pid;
|
||||||
} stds;
|
} stds;
|
||||||
|
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user