Working
This commit is contained in:
2
run.sh
2
run.sh
@ -4,4 +4,4 @@ make && \
|
|||||||
echo -e "-- Successfully finished compiling!\n" && \
|
echo -e "-- Successfully finished compiling!\n" && \
|
||||||
sleep 0.0625 && \
|
sleep 0.0625 && \
|
||||||
echo -e "-- Starting Server...\n" && \
|
echo -e "-- Starting Server...\n" && \
|
||||||
./bin/necronda-server
|
authbind ./bin/necronda-server
|
||||||
|
12
src/URI.cpp
12
src/URI.cpp
@ -50,6 +50,7 @@ URI::URI(string webroot, string reqpath) {
|
|||||||
if (webroot[webroot.length() - 1] == '/') {
|
if (webroot[webroot.length() - 1] == '/') {
|
||||||
webroot.erase(webroot.length() - 1);
|
webroot.erase(webroot.length() - 1);
|
||||||
}
|
}
|
||||||
|
reqpath = url_decode(reqpath);
|
||||||
if (reqpath.find("/../") != string::npos) {
|
if (reqpath.find("/../") != string::npos) {
|
||||||
throw (char *) "Invalid path";
|
throw (char *) "Invalid path";
|
||||||
}
|
}
|
||||||
@ -116,8 +117,9 @@ string URI::getFilePath() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
string URI::getRelativeFilePath() {
|
string URI::getRelativeFilePath() {
|
||||||
string rel = getRelativePath();
|
string str = getFilePath();
|
||||||
// TODO
|
long len = getWebRoot().length();
|
||||||
|
return str.substr(len, str.length() - len);
|
||||||
}
|
}
|
||||||
|
|
||||||
string URI::getNewPath() {
|
string URI::getNewPath() {
|
||||||
@ -127,7 +129,7 @@ string URI::getNewPath() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (relpath != reqpath) {
|
if (relpath != reqpath) {
|
||||||
return relpath + (queryinit? "?" + query : "");
|
return url_encode(relpath) + (queryinit? "?" + query : "");
|
||||||
} else {
|
} else {
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
@ -138,7 +140,7 @@ FILE *URI::openFile() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
string URI::getFilePathInfo() {
|
string URI::getFilePathInfo() {
|
||||||
return getAbsolutePath().erase(getFilePath().length(), getAbsolutePath().length());
|
return ""; //getAbsolutePath().erase(getFilePath().length(), getAbsolutePath().length());
|
||||||
}
|
}
|
||||||
|
|
||||||
string URI::getFileType() {
|
string URI::getFileType() {
|
||||||
@ -146,7 +148,7 @@ string URI::getFileType() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool URI::isStatic() {
|
bool URI::isStatic() {
|
||||||
return true;
|
return getExtension(filepath) != "php";
|
||||||
}
|
}
|
||||||
|
|
||||||
string URI::getQuery() {
|
string URI::getQuery() {
|
||||||
|
181
src/client.cpp
181
src/client.cpp
@ -19,18 +19,23 @@
|
|||||||
#include "necronda-server.h"
|
#include "necronda-server.h"
|
||||||
#include "network/http/HttpStatusCode.h"
|
#include "network/http/HttpStatusCode.h"
|
||||||
#include "URI.h"
|
#include "URI.h"
|
||||||
|
#include "procopen.h"
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Writes log messages to the console
|
* Writes log messages to the console
|
||||||
* @param prefix The connection prefix
|
* @param prefix The connection prefix
|
||||||
* @param string The string to be written
|
* @param str The string to be written
|
||||||
*/
|
*/
|
||||||
void log(const char *prefix, const string &string) {
|
void log(const char *prefix, const string &str) {
|
||||||
printf("%s%s\r\n", prefix, string.c_str());
|
printf("%s%s\r\n", prefix, str.c_str());
|
||||||
flush(cout);
|
flush(cout);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void log_error(const char *prefix, const string &str) {
|
||||||
|
log(prefix, "\x1B[1;31m" + str + "\x1B[0m");
|
||||||
|
}
|
||||||
|
|
||||||
string getETag(string filename) {
|
string getETag(string filename) {
|
||||||
ifstream etags = ifstream("/var/necronda/ETags");
|
ifstream etags = ifstream("/var/necronda/ETags");
|
||||||
|
|
||||||
@ -106,6 +111,24 @@ string getETag(string filename) {
|
|||||||
return md5;
|
return md5;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
#include <wait.h>
|
||||||
|
|
||||||
|
long getPosition(std::string str, char c, int occurence) {
|
||||||
|
int tempOccur = 0;
|
||||||
|
int num = 0;
|
||||||
|
for (auto it : str) {
|
||||||
|
num++;
|
||||||
|
if (it == c) {
|
||||||
|
if (++tempOccur == occurence) {
|
||||||
|
return num;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handles (keep-alive) HTTP connections
|
* Handles (keep-alive) HTTP connections
|
||||||
* @param prefix The connection prefix
|
* @param prefix The connection prefix
|
||||||
@ -114,8 +137,9 @@ string getETag(string filename) {
|
|||||||
* @param num The Connection Number in the client
|
* @param num The Connection Number in the client
|
||||||
* @return Should the server wait for another header?
|
* @return Should the server wait for another header?
|
||||||
*/
|
*/
|
||||||
bool connection_handler(const char *prefix, Socket *socket, long id, long num) {
|
bool connection_handler(const char *preprefix, const char *col1, const char *col2, Socket *socket, long id, long num) {
|
||||||
bool error = false;
|
bool error = false;
|
||||||
|
char *prefix = (char *) preprefix;
|
||||||
try {
|
try {
|
||||||
HttpConnection req(socket);
|
HttpConnection req(socket);
|
||||||
try {
|
try {
|
||||||
@ -131,19 +155,32 @@ bool connection_handler(const char *prefix, Socket *socket, long id, long num) {
|
|||||||
req.respond(400);
|
req.respond(400);
|
||||||
} else {
|
} else {
|
||||||
string host = req.getField("Host");
|
string host = req.getField("Host");
|
||||||
|
long pos = host.find(':');
|
||||||
|
if (pos != string::npos) {
|
||||||
|
host.erase(pos, host.length() - pos);
|
||||||
|
}
|
||||||
|
|
||||||
string str = string(prefix);
|
FILE *name = popen(("dig +time=1 -x " + socket->getPeerAddress()->toString() +
|
||||||
unsigned long pos = str.find('[', 8);
|
" | grep -oP \"^[^;].*\\t\\K([^ ]*)\\w\"").c_str(), "r");
|
||||||
string n = str.substr(0, 8) + host + str.substr(pos - 1, str.length() - pos + 1);
|
char hostbuffer[1024];
|
||||||
|
memset(hostbuffer, 0, 1024);
|
||||||
|
size_t size = fread(hostbuffer, 1, 1024, name);
|
||||||
|
hostbuffer[size - 1] = 0; // remove \n
|
||||||
|
if (size <= 1) {
|
||||||
|
sprintf(hostbuffer, "%s", socket->getPeerAddress()->toString().c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
char buffer[1024];
|
||||||
|
sprintf(buffer, "[\x1B[1m%s\x1B[0m][%i]%s[%s][%i]%s ", host.c_str(), socket->getSocketPort(), col1,
|
||||||
|
hostbuffer, socket->getPeerPort(), col2);
|
||||||
|
|
||||||
char buffer[256];
|
|
||||||
sprintf(buffer, "%s", n.c_str());
|
|
||||||
prefix = buffer;
|
prefix = buffer;
|
||||||
|
|
||||||
URI path = URI(getWebRoot(host), req.getPath());
|
URI path = URI(getWebRoot(host), req.getPath());
|
||||||
log(prefix, req.getMethod() + " " + req.getPath());
|
log(prefix, "\x1B[1m" + req.getMethod() + " " + req.getPath() + "\x1B[0m");
|
||||||
|
|
||||||
FILE *file = path.openFile();
|
FILE *file = path.openFile();
|
||||||
|
pid_t childpid = 0;
|
||||||
|
|
||||||
if (!path.getNewPath().empty()) {
|
if (!path.getNewPath().empty()) {
|
||||||
req.redirect(302, path.getNewPath());
|
req.redirect(302, path.getNewPath());
|
||||||
@ -157,6 +194,8 @@ bool connection_handler(const char *prefix, Socket *socket, long id, long num) {
|
|||||||
|
|
||||||
if (type.find("inode/") == 0) {
|
if (type.find("inode/") == 0) {
|
||||||
req.respond(403);
|
req.respond(403);
|
||||||
|
} else if (path.getRelativeFilePath().find("/.") != string::npos) {
|
||||||
|
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()));
|
||||||
@ -183,7 +222,6 @@ bool connection_handler(const char *prefix, Socket *socket, long id, long num) {
|
|||||||
if (req.getMethod() != "GET" && req.getMethod() != "POST" && req.getMethod() != "PUT") {
|
if (req.getMethod() != "GET" && req.getMethod() != "POST" && req.getMethod() != "PUT") {
|
||||||
invalidMethod = true;
|
invalidMethod = true;
|
||||||
}
|
}
|
||||||
system("php");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (invalidMethod) {
|
if (invalidMethod) {
|
||||||
@ -191,15 +229,82 @@ bool connection_handler(const char *prefix, Socket *socket, long id, long num) {
|
|||||||
} else if (etag) {
|
} else if (etag) {
|
||||||
req.respond(304);
|
req.respond(304);
|
||||||
} else {
|
} else {
|
||||||
|
int statuscode = 200;
|
||||||
|
if (!path.isStatic()) {
|
||||||
|
string cmd = (string) "env -i" +
|
||||||
|
" REDIRECT_STATUS=" + cli_encode("CGI") +
|
||||||
|
" DOCUMENT_ROOT=" + cli_encode(getWebRoot(host)) +
|
||||||
|
" " + req.cgiExport() +
|
||||||
|
(req.isExistingField("Content-Length")?" CONTENT_LENGTH="+cli_encode(req.getField("Content-Length")):"") +
|
||||||
|
(req.isExistingField("Content-Type")?" CONTENT_TYPE="+cli_encode(req.getField("Content-Type")):"") +
|
||||||
|
((socket->isSecured())?" HTTPS=on":"") +
|
||||||
|
" PATH_INFO=" + cli_encode(path.getFilePathInfo()) +
|
||||||
|
" PATH_TRANSLATED=" + cli_encode(path.getAbsolutePath()) +
|
||||||
|
" QUERY_STRING=" + cli_encode(path.getQuery()) +
|
||||||
|
" REMOTE_ADDR=" + cli_encode(socket->getPeerAddress()->toString()) +
|
||||||
|
" REMOTE_HOST=" + cli_encode(hostbuffer) +
|
||||||
|
" REMOTE_PORT=" + cli_encode(to_string(socket->getPeerPort())) +
|
||||||
|
" REQUEST_METHOD=" + cli_encode(req.getMethod()) +
|
||||||
|
" REQUEST_URI=" + cli_encode(req.getPath()) +
|
||||||
|
" SCRIPT_FILENAME=" + cli_encode(path.getFilePath()) +
|
||||||
|
" SCRIPT_NAME=" + cli_encode(path.getRelativePath()) +
|
||||||
|
" SERVER_ADMIN=" + cli_encode("lorenz.stechauner@gmail.com") +
|
||||||
|
" SERVER_NAME=" + cli_encode(host) +
|
||||||
|
" SERVER_PORT=" + cli_encode(to_string(socket->getSocketPort())) +
|
||||||
|
" SERVER_SOFTWARE=" + cli_encode("Necronda 3.0") +
|
||||||
|
" SERVER_PROTOCOL=" + cli_encode("HTTP/1.1") +
|
||||||
|
" GATEWAY_INTERFACE=" + cli_encode("CGI/1.1") +
|
||||||
|
" /usr/bin/php-cgi";
|
||||||
|
|
||||||
bool compress = type.find("text/") == 0 && req.isExistingField("Accept-Encoding") &&
|
stds pipes = procopen(cmd.c_str());
|
||||||
|
childpid = pipes.pid;
|
||||||
|
|
||||||
|
char fdbuffer[4096];
|
||||||
|
if (req.getMethod() == "POST" || req.getMethod() == "PUT") {
|
||||||
|
long len = req.isExistingField("Content-Length") ? strtol(req.getField("Content-Length").c_str(), nullptr, 10) : -1;
|
||||||
|
socket->receive(pipes.stdin);
|
||||||
|
}
|
||||||
|
fclose(pipes.stdin);
|
||||||
|
|
||||||
|
string line;
|
||||||
|
while (!(line = read_line(pipes.stderr)).empty()) {
|
||||||
|
log_error(prefix, line);
|
||||||
|
}
|
||||||
|
fclose(pipes.stderr);
|
||||||
|
|
||||||
|
while (!(line = read_line(pipes.stdout)).empty()) {
|
||||||
|
long pos = line.find(':');
|
||||||
|
string index = line.substr(0, pos);
|
||||||
|
string data = line.substr(pos+1, line.length() - pos);
|
||||||
|
|
||||||
|
while (index[0] == ' ') index.erase(index.begin() + 0);
|
||||||
|
while (index[index.length() - 1] == ' ') index.erase(index.end() - 1);
|
||||||
|
while (data[0] == ' ') data.erase(data.begin() + 0);
|
||||||
|
while (data[data.length() - 1] == ' ') data.erase(data.end() - 1);
|
||||||
|
|
||||||
|
if (index == "Location") {
|
||||||
|
statuscode = 303;
|
||||||
|
}
|
||||||
|
|
||||||
|
req.setField(index, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
fclose(file);
|
||||||
|
file = pipes.stdout;
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
bool compress = path.isStatic() && type.find("text/") == 0 && req.isExistingField("Accept-Encoding") &&
|
||||||
req.getField("Accept-Encoding").find("deflate") != string::npos;
|
req.getField("Accept-Encoding").find("deflate") != string::npos;
|
||||||
|
|
||||||
if (compress) {
|
if (compress) {
|
||||||
req.setField("Accept-Ranges", "none");
|
req.setField("Accept-Ranges", "none");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (req.isExistingField("Range")) {
|
if (compress && req.isExistingField("Range")) {
|
||||||
|
req.respond(416);
|
||||||
|
} 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);
|
||||||
@ -231,16 +336,39 @@ bool connection_handler(const char *prefix, Socket *socket, long id, long num) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
req.respond(200, file, compress);
|
req.respond(statuscode, file, compress);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fclose(file);
|
fclose(file);
|
||||||
|
if (childpid > 0) {
|
||||||
|
waitpid(childpid, nullptr, 0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
HttpStatusCode status = req.getStatusCode();
|
HttpStatusCode status = req.getStatusCode();
|
||||||
log(prefix, to_string(status.code) + " " + status.message + " (" + formatTime(req.getDuration()) + ")");
|
int code = status.code;
|
||||||
|
string color = "";
|
||||||
|
string comment = "";
|
||||||
|
if ((code >= 200 && code < 300) || code == 304) {
|
||||||
|
color = "\x1B[1;32m"; // Success (Cached): Green
|
||||||
|
} else if (code >= 100 && code < 200) {
|
||||||
|
color = "\x1B[1;93m"; // Continue: Yellow
|
||||||
|
} else if (code >= 300 && code < 400) {
|
||||||
|
color = "\x1B[1;93m"; // Redirect: Yellow
|
||||||
|
comment = " -> " +
|
||||||
|
(req.isExistingResponseField("Location") ? req.getResponseField("Location") : "<invalid>");
|
||||||
|
} else if (code >= 400 && code < 500) {
|
||||||
|
color = "\x1B[1;31m"; // Client Error: Red
|
||||||
|
//comment = " -> " + req.getPath();
|
||||||
|
} else if (code >= 500 & code < 600) {
|
||||||
|
color = "\x1B[1;31m"; // Server Error: Red
|
||||||
|
//comment = " -> " + req.getPath();
|
||||||
|
}
|
||||||
|
log(prefix,
|
||||||
|
color + to_string(status.code) + " " + status.message + comment + " (" + formatTime(req.getDuration()) +
|
||||||
|
")\x1B[0m");
|
||||||
} 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()) + ")");
|
||||||
@ -290,26 +418,25 @@ bool connection_handler(const char *prefix, Socket *socket, long id, long num) {
|
|||||||
*/
|
*/
|
||||||
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 *col2 = "\x1B[0m";
|
||||||
{
|
{
|
||||||
char const *col1;
|
|
||||||
char const *col2 = "\x1B[0m";
|
|
||||||
auto group = (int) (id % 6);
|
auto group = (int) (id % 6);
|
||||||
if (group == 0) {
|
if (group == 0) {
|
||||||
col1 = "\x1B[1;31m";
|
col1 = "\x1B[0;31m"; // Red
|
||||||
} else if (group == 1) {
|
} else if (group == 1) {
|
||||||
col1 = "\x1B[1;32m";
|
col1 = "\x1B[0;32m"; // Green
|
||||||
} else if (group == 2) {
|
} else if (group == 2) {
|
||||||
col1 = "\x1B[1;34m";
|
col1 = "\x1B[0;34m"; // Blue
|
||||||
} else if (group == 3) {
|
} else if (group == 3) {
|
||||||
col1 = "\x1B[1;33m";
|
col1 = "\x1B[0;33m"; // Yellow
|
||||||
} else if (group == 4) {
|
} else if (group == 4) {
|
||||||
col1 = "\x1B[1;35m";
|
col1 = "\x1B[0;35m"; // Magenta
|
||||||
} else {
|
} else {
|
||||||
col1 = "\x1B[1;36m";
|
col1 = "\x1B[0;36m"; // Cyan
|
||||||
}
|
}
|
||||||
string *a = new string((string)
|
string *a = new string("[" + socket->getSocketAddress()->toString() + "][" +
|
||||||
col1 + "[" + socket->getSocketAddress()->toString() + "][" +
|
to_string(socket->getSocketPort()) + "]" + col1 +
|
||||||
to_string(socket->getSocketPort()) + "]" +
|
|
||||||
"[" + socket->getPeerAddress()->toString() + "][" + to_string(socket->getPeerPort()) +
|
"[" + socket->getPeerAddress()->toString() + "][" + to_string(socket->getPeerPort()) +
|
||||||
"]" + col2 + " ");
|
"]" + col2 + " ");
|
||||||
prefix = a->c_str();
|
prefix = a->c_str();
|
||||||
@ -338,7 +465,7 @@ void client_handler(Socket *socket, long id, bool ssl) {
|
|||||||
|
|
||||||
long reqnum = 0;
|
long reqnum = 0;
|
||||||
if (!err) {
|
if (!err) {
|
||||||
while (connection_handler(prefix, socket, id, ++reqnum));
|
while (connection_handler(prefix, col1, col2, socket, id, ++reqnum));
|
||||||
reqnum--;
|
reqnum--;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -142,6 +142,75 @@ string getWebRoot(string host) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
string url_decode(string url) {
|
||||||
|
long pos = 0;
|
||||||
|
while ((pos = url.find('+', pos + 1)) != string::npos) {
|
||||||
|
url.replace(pos, 1, 1, ' ');
|
||||||
|
}
|
||||||
|
pos = 0;
|
||||||
|
while ((pos = url.find('%', pos + 1)) != string::npos) {
|
||||||
|
const char *num = url.substr(pos + 1, 2).c_str();
|
||||||
|
auto c = (char) strtol(num, nullptr, 16);
|
||||||
|
url.erase(pos, 3);
|
||||||
|
url.insert(pos, 1, c);
|
||||||
|
}
|
||||||
|
|
||||||
|
return url;
|
||||||
|
}
|
||||||
|
|
||||||
|
string url_encode(string url) {
|
||||||
|
char buff[4];
|
||||||
|
for (long pos = 0; pos < url.length(); pos++) {
|
||||||
|
auto c = (unsigned char) url[pos];
|
||||||
|
if (c < ' ' || c > '~' || c == ' ' || c == '#' || c == '?' || c == '&' || c == '=' || c == '\\' || c == '%') {
|
||||||
|
sprintf(buff, "%%%02X", c);
|
||||||
|
url.replace(pos, 1, buff);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return url;
|
||||||
|
}
|
||||||
|
|
||||||
|
string html_decode(string text) {
|
||||||
|
return text;
|
||||||
|
}
|
||||||
|
|
||||||
|
string html_encode(string text) {
|
||||||
|
return text;
|
||||||
|
}
|
||||||
|
|
||||||
|
string cli_encode(string text) {
|
||||||
|
char buff[5];
|
||||||
|
for (long pos = 0; pos < text.length(); 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 == '-')) {
|
||||||
|
sprintf(buff, "\\%.1s", &c);
|
||||||
|
text.replace(pos, 1, buff);
|
||||||
|
pos++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return text;
|
||||||
|
}
|
||||||
|
|
||||||
|
string read_line(FILE* file) {
|
||||||
|
char *line = nullptr;
|
||||||
|
size_t len = 0;
|
||||||
|
ssize_t read;
|
||||||
|
if ((read = getline(&line, &len, file)) < 0) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
string l = string(line);
|
||||||
|
if (l[l.length()-1] == '\n') {
|
||||||
|
l.erase(l.length()-1);
|
||||||
|
}
|
||||||
|
if (l[l.length()-1] == '\r') {
|
||||||
|
l.erase(l.length()-1);
|
||||||
|
}
|
||||||
|
return l;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#include "procopen.cpp"
|
||||||
#include "network/Address.cpp"
|
#include "network/Address.cpp"
|
||||||
#include "network/Socket.cpp"
|
#include "network/Socket.cpp"
|
||||||
#include "URI.cpp"
|
#include "URI.cpp"
|
||||||
|
@ -33,5 +33,17 @@ string getTimestamp(time_t time);
|
|||||||
|
|
||||||
long getFileSize(string filename);
|
long getFileSize(string filename);
|
||||||
|
|
||||||
|
string url_decode(string url);
|
||||||
|
|
||||||
|
string url_encode(string url);
|
||||||
|
|
||||||
|
string html_decode(string text);
|
||||||
|
|
||||||
|
string html_encode(string text);
|
||||||
|
|
||||||
|
string cli_encode(string text);
|
||||||
|
|
||||||
|
string read_line(FILE *file);
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
41
src/procopen.cpp
Normal file
41
src/procopen.cpp
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
//
|
||||||
|
// Created by lorenz on 5/30/18.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "procopen.h"
|
||||||
|
|
||||||
|
stds procopen(const char* command) {
|
||||||
|
|
||||||
|
int pipes[3][2];
|
||||||
|
|
||||||
|
pipe(pipes[PARENT_READ_PIPE]);
|
||||||
|
pipe(pipes[PARENT_WRITE_PIPE]);
|
||||||
|
pipe(pipes[PARENT_ERROR_PIPE]);
|
||||||
|
|
||||||
|
int pid = fork();
|
||||||
|
|
||||||
|
if(pid == 0) {
|
||||||
|
dup2(CHILD_READ_FD, STDIN_FILENO);
|
||||||
|
dup2(CHILD_WRITE_FD, STDOUT_FILENO);
|
||||||
|
dup2(CHILD_ERROR_FD, STDERR_FILENO);
|
||||||
|
|
||||||
|
close(CHILD_READ_FD);
|
||||||
|
close(CHILD_WRITE_FD);
|
||||||
|
close(CHILD_ERROR_FD);
|
||||||
|
|
||||||
|
close(PARENT_READ_FD);
|
||||||
|
close(PARENT_WRITE_FD);
|
||||||
|
close(PARENT_ERROR_FD);
|
||||||
|
|
||||||
|
system(command);
|
||||||
|
exit(0);
|
||||||
|
} else {
|
||||||
|
close(CHILD_READ_FD);
|
||||||
|
close(CHILD_WRITE_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};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
41
src/procopen.h
Normal file
41
src/procopen.h
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
//
|
||||||
|
// Created by lorenz on 5/30/18.
|
||||||
|
//
|
||||||
|
|
||||||
|
|
||||||
|
#include <zconf.h>
|
||||||
|
#include <cstdlib>
|
||||||
|
#include <cstdio>
|
||||||
|
|
||||||
|
#ifndef NECRONDA_PROCOPEN
|
||||||
|
#define NECRONDA_PROCOPEN
|
||||||
|
|
||||||
|
|
||||||
|
#define PARENT_WRITE_PIPE 0
|
||||||
|
#define PARENT_READ_PIPE 1
|
||||||
|
#define PARENT_ERROR_PIPE 2
|
||||||
|
|
||||||
|
#define READ_FD 0
|
||||||
|
#define WRITE_FD 1
|
||||||
|
|
||||||
|
#define PARENT_READ_FD ( pipes[PARENT_READ_PIPE][READ_FD] )
|
||||||
|
#define PARENT_WRITE_FD ( pipes[PARENT_WRITE_PIPE][WRITE_FD] )
|
||||||
|
#define PARENT_ERROR_FD ( pipes[PARENT_ERROR_PIPE][READ_FD] )
|
||||||
|
|
||||||
|
#define CHILD_READ_FD ( pipes[PARENT_WRITE_PIPE][READ_FD] )
|
||||||
|
#define CHILD_WRITE_FD ( pipes[PARENT_READ_PIPE][WRITE_FD] )
|
||||||
|
#define CHILD_ERROR_FD ( pipes[PARENT_ERROR_PIPE][WRITE_FD] )
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
FILE* stdin;
|
||||||
|
FILE* stdout;
|
||||||
|
FILE* stderr;
|
||||||
|
pid_t pid;
|
||||||
|
} stds;
|
||||||
|
|
||||||
|
|
||||||
|
stds procopen(const char* command);
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
Reference in New Issue
Block a user