Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(#21): CGI parsing done #51

Merged
merged 13 commits into from
Apr 26, 2024
7 changes: 1 addition & 6 deletions .github/workflows/compile-check.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ jobs:
uses: actions/checkout@v3

- name: Set up C++ environment
uses: aminya/setup-cpp@v1
uses: egor-tensin/setup-gcc@v1.3
with:
compiler: gcc

Expand All @@ -30,10 +30,5 @@ jobs:
- name: Checkout repository
uses: actions/checkout@v3

- name: Set up C++ environment
uses: aminya/setup-cpp@v1
with:
compiler: gcc

- name: Build project
run: make
2 changes: 2 additions & 0 deletions .resources/cgi-bin/file.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
#!/usr/bin/python3
print("hello worled")
3 changes: 3 additions & 0 deletions .resources/cgi-bin/file.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
#!/bin/sh
echo "Hello, World Bash!"
sleep 20
2 changes: 2 additions & 0 deletions .resources/notes/CGI_ref
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
https://www.oreilly.com/library/view/cgi-programming-on/9781565921689/04_chapter-01.html //good aticla for CGi
http://www.mnuwer.dbasedeveloper.co.uk/dlearn/web/session01.htm
19 changes: 19 additions & 0 deletions configs/cgitest.config
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
http {
server {
listen 8080;
client_max_body_size 1M;
server_name localhost;

root ./.resources;
index index.html index.htm;

location / {
root ./.resources/sample_pages;
}

error_page 404 /404.html;
location = /404.html {
root ./.resources/sample_pages;
}
}
}
7 changes: 7 additions & 0 deletions curl.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
curl -X GET http://localhost:8080/cgi-bin/file.sh?name=hashim \
-H "Host: Linode.com" \
-H "User-Agent: Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.1.8) Gecko/20091102 Firefox/3.5.5" \
-H "Accept-Encoding: gzip,deflate" \
-H "Accept-Charset: ISO-8859-1,utf-8" \
-H "Cache-Control: no-cache" \
-d $'body\r\n'
274 changes: 212 additions & 62 deletions sources/CGI/Cgi.cpp
Original file line number Diff line number Diff line change
@@ -1,20 +1,76 @@
#include "Cgi.hpp"
/* ************************************************************************** */
/* */
/* ::: :::::::: */
/* Cgi.cpp :+: :+: :+: */
/* +:+ +:+ +:+ */
/* By: hmohamed <hmohamed@student.42abudhabi.ae> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2024/02/23 12:44:51 by hmohamed #+# #+# */
/* Updated: 2024/04/25 14:04:56 by hmohamed ### ########.fr */
/* */
/* ************************************************************************** */

static char** headers_to_env(const vsp& headers);
static string get_uri(string res);
static string get_query_string(string res);
#include "Cgi.hpp"

Cgi::Cgi(const Request& request)
string getStingQuery(string res)
{
string resource = request.get_resource();
headers = request.get_headers();
environment = headers_to_env(headers);
filePath = get_uri(resource);
queryString = get_query_string(resource);

arguments = new char*[2];
arguments[0] = const_cast<char*>(filePath.c_str());
arguments[1] = NULL;
string resn;
size_t qu;
size_t length;

qu = res.find('?', 0);
length = res.length();
cout<< "the ? :" << qu <<endl;
cout << "lingth:" << length << endl;
resn = res.substr(qu + 1, length);
//result = const_cast<char *>(res.substr(0,qu).c_str());
cout << resn << endl;
return (resn);
}


string geturi(string res)
{
string resn;
size_t qu;

qu = res.find('?', 0);
resn = res.substr(0, qu);
//result = const_cast<char *>(res.substr(0,qu).c_str());
cout << resn << endl;
cout<< "test" << qu <<endl;
return (resn);
}

Cgi::Cgi(const Request &request, const ServerConfig &config): body(request.get_body())
{
string res;

(void)config;
res = const_cast<char *>(request.get_resource().c_str());
filePath = (geturi(res));
headers = request.get_headers();
environment = headersToEnv(request, res, config);
timer = request.timer;
//filePath = const_cast<char *>(geturi(request.get_resource())->c_str());
//queryString = getStingQuery(res);
//filePath = const_cast<char *> (request.get_resource().c_str());
// // Check if the Python script exists
// if (access(filePath, X_OK) == -1)
// {
// std::cerr << "Error: Python script not found or does not have execution permission." << std::endl;
// return ;
// }
cout<< "file path :" << filePath << endl;
arguments = new char *[2];
arguments[0] = const_cast<char *>(filePath.c_str());
arguments[1] = NULL;

// Print out the environment variables
for (int i = 0; environment[i] != NULL; ++i)
{
std::cout << environment[i] << std::endl;
}
}

Cgi::~Cgi()
Expand All @@ -25,6 +81,71 @@ Cgi::~Cgi()
delete[] arguments;
}

char ** Cgi::headersToEnv(const Request &request, const string res, const ServerConfig &config)
{
std::vector<char *> envVector;

(void)config;
(void)request;

string queryString = getStingQuery(res);;
// Iterate through headers
for (vsp::iterator it = headers.begin(); it != headers.end(); ++it)
{
size_t len = it->first.size() + it->second.size() + 2;
char *envEntry = new char[len];
std::snprintf(envEntry, len, "%s=%s", it->first.c_str(), it->second.c_str());
envVector.push_back(envEntry);
}

// std::string gateway_interface = "GATEWAY_INTERFACE=CGI/1.1";
// envVector.push_back(const_cast<char *>(gateway_interface.c_str()));

envVector.push_back(strdup("GATEWAY_INTERFACE=CGI/1.1"));
envVector.push_back(strdup("SERVER_PROTOCOL=HTTP/1.1"));
string val;
val = "SERVER_NAME=" + config.serverName;
envVector.push_back(strdup(val.c_str()));
val = "SERVER_SOFTWARE=" + config.serverName + "/1.0";
envVector.push_back(strdup(val.c_str()));
val = "SERVER_PORT=" + ws_itoa(config.listenerPort);
envVector.push_back(strdup(val.c_str()));
val = "REQUEST_URI=" + request.get_resource();
envVector.push_back(strdup(val.c_str()));
queryString = getStingQuery(res);
// val = "QUERY_STRING=" + queryString;
// envVector.push_back(strdup(val.c_str()));
// "REQUEST_METHOD"
// "PATH_INFO"
// "PATH_TRANSLATED"
// "QUERY_STRING"
// "REMOTEaddr"
// "REMOTE_IDENT"
// "REMOTE_USER"


char* token = strtok(const_cast<char *>(queryString.c_str()), "&");

//cout << token +3 <<endl;
// Iterate through the tokens and push integers onto the stack
while (token != NULL) {
envVector.push_back(strdup(token));
token = strtok(NULL, "&");
}

// Allocate memory for char* array
char **envp = new char *[envVector.size() + 1];

// Copy pointers from vector to char* array
for (size_t i = 0; i < envVector.size(); ++i)
{
envp[i] = envVector[i];
}
envp[envVector.size()] = NULL;

return envp;
}

void Cgi::execute(const string& outputFile)
{
int fd[2];
Expand Down Expand Up @@ -81,6 +202,7 @@ void Cgi::execute(const string& outputFile)
close(fd[0]);
}


string Cgi::execute(void)
{
int fd[2];
Expand All @@ -92,6 +214,7 @@ string Cgi::execute(void)
cerr << "Error creating pipe: " << strerror(errno) << endl;
return NULL;
}
cout<< "FBB" << filePath << endl;

// Fork the process
// TODO fix forking here for sleep
Expand All @@ -113,65 +236,92 @@ string Cgi::execute(void)
}

// Parent process
close(fd[1]); // Close the write end of the pipe

// Wait for the child process to finish
int status;
waitpid(id, &status, 0);
close(fd[1]); // Close the write end of the pipe
int status;
// Wait for the child process to finish or until timeout
while (true) {
// Check if the timeout duration has been reached
if (timer.is_timeout()) {
std::cerr << "Timeout reached. Exiting." << std::endl;
// Terminate the child process
kill(id, SIGTERM);
break;
}

// Read the response from the pipe
char buffer[91];
ssize_t bytesRead;
while ((bytesRead = read(fd[0], buffer, 90)) > 0)
res_body.append(buffer, bytesRead);
// Check if the child process has finished
if (waitpid(id, &status, WNOHANG) == id) {
// Child process has finished
// Read from the pipe
char buffer[1024];
ssize_t bytesRead = read(fd[0], buffer, sizeof(buffer));
if (bytesRead > 0) {
res_body.append(buffer, bytesRead);
} else if (bytesRead == 0) {
break;
} else {
// Error while reading from the pipe
if (errno == EAGAIN || errno == EWOULDBLOCK) {
// No data available yet, continue waiting
usleep(100000);
continue;
} else {
std::cerr << "Error reading from pipe: " << strerror(errno) << std::endl;
break;
}
}
break;
}
usleep(100000);
}


close(fd[0]);
return (res_body);
}

static char** headers_to_env(const vsp& headers)
{
vector<char*> envVector;
// static char** headers_to_env(const vsp& headers)
// {
// vector<char*> envVector;

// Iterate through headers
vsp::const_iterator end = headers.end();
for (vsp::const_iterator it = headers.begin(); it != end; ++it) {
size_t len = it->first.size() + it->second.size() + 2;
char* envEntry = new char[len];
std::snprintf(envEntry, len, "%s=%s", it->first.c_str(), it->second.c_str());
envVector.push_back(envEntry);
}
// // Iterate through headers
// vsp::const_iterator end = headers.end();
// for (vsp::const_iterator it = headers.begin(); it != end; ++it) {
// size_t len = it->first.size() + it->second.size() + 2;
// char* envEntry = new char[len];
// std::snprintf(envEntry, len, "%s=%s", it->first.c_str(), it->second.c_str());
// envVector.push_back(envEntry);
// }

// Allocate memory for char* array
char** envp = new char*[envVector.size() + 1];
// // Allocate memory for char* array
// char** envp = new char*[envVector.size() + 1];

// Copy pointers from vector to char* array
for (size_t i = 0; i < envVector.size(); ++i)
envp[i] = envVector[i];
envp[envVector.size()] = NULL;
// // Copy pointers from vector to char* array
// for (size_t i = 0; i < envVector.size(); ++i)
// envp[i] = envVector[i];
// envp[envVector.size()] = NULL;

return envp;
}
// return envp;
// }

static string get_uri(string res)
{
string resn;
size_t qu;
// static string get_uri(string res)
// {
// string resn;
// size_t qu;

qu = res.find('?', 0);
resn = res.substr(0, qu);
// result = const_cast<char *>(res.substr(0,qu).c_str());
return (resn);
}
// qu = res.find('?', 0);
// resn = res.substr(0, qu);
// // result = const_cast<char *>(res.substr(0,qu).c_str());
// return (resn);
// }

static string get_query_string(string res)
{
string resn;
size_t qu;
size_t length;
// static string get_query_string(string res)
// {
// string resn;
// size_t qu;
// size_t length;

qu = res.find('?', 0);
length = res.length();
resn = res.substr(qu + 1, length);
return (resn);
}
// qu = res.find('?', 0);
// length = res.length();
// resn = res.substr(qu + 1, length);
// return (resn);
// }
Loading
Loading