Skip to content

Commit ffdde1f

Browse files
feat: refactoring constructor
1 parent 05efe3e commit ffdde1f

File tree

2 files changed

+118
-79
lines changed

2 files changed

+118
-79
lines changed

src/handler/cgi_handler.cpp

Lines changed: 108 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -18,59 +18,90 @@
1818

1919
static std::vector<char*> make_envp(std::vector<std::string>& env);
2020

21-
CgiHandler::CgiHandler(const std::string& path, const HttpRequest& saved_request,
22-
const RouteConfig& config)
23-
: path_(path),
24-
saved_request_(saved_request),
25-
config_(config),
26-
headers_off_(0),
27-
output_body_off_(0),
28-
bytes_written_body_(0),
29-
body_length_(saved_request.content_length),
30-
headers_parsed_(false),
31-
headers_sent_(false),
32-
eob_reached_(false),
33-
eof_reached_(false),
34-
eoo_reached_(false),
35-
forced_response_(false),
36-
child_reaped_(false),
37-
pid_(-1)
21+
void CgiHandler::init_state()
3822
{
39-
// setting default values for pipes
4023
input_fd_[0] = -1;
4124
input_fd_[1] = -1;
4225
output_fd_[0] = -1;
4326
output_fd_[1] = -1;
27+
}
4428

45-
// STEP 0 - Check that file exisst and is executable
29+
bool CgiHandler::validate_cgi_target(bool is_interpreter_cgi)
30+
{
4631
struct stat sb;
47-
bool is_interpreter_cgi = !config_.config.cgi.exec_path.empty();
4832

4933
// Script must exist and be a regular file
50-
if (stat(path.c_str(), &sb) == -1 || !S_ISREG(sb.st_mode)) {
34+
if (stat(path_.c_str(), &sb) == -1 || !S_ISREG(sb.st_mode)) {
5135
set_res_and_quit(HttpResponse::kStatusForbidden);
52-
return;
36+
return false;
5337
}
5438

5539
if (!is_interpreter_cgi) {
5640
// Direct CGI → script itself must be executable
57-
if (access(path.c_str(), X_OK) != 0) {
41+
if (access(path_.c_str(), X_OK) != 0) {
5842
set_res_and_quit(HttpResponse::kStatusForbidden);
59-
return;
43+
return false;
6044
}
6145
}
6246
else {
6347
// Interpreter CGI → interpreter must be executable
6448
if (access(config_.config.cgi.exec_path.c_str(), X_OK) != 0) {
6549
set_res_and_quit(HttpResponse::kStatusInternalServerError);
66-
return;
50+
return false;
6751
}
6852
}
53+
return true;
54+
}
6955

70-
// STEP 1 - Prepare key=value pair vector to be passed to child process to set env var
71-
std::vector<std::string> env_strings = build_env_strings();
72-
std::vector<char*> envp = make_envp(env_strings);
73-
char* argv[3];
56+
static std::vector<char*> make_envp(std::vector<std::string>& env)
57+
{
58+
std::vector<char*> envp;
59+
envp.reserve(env.size() + 1);
60+
61+
for (size_t i = 0; i < env.size(); ++i)
62+
envp.push_back(const_cast<char*>(env[i].c_str()));
63+
64+
envp.push_back(NULL);
65+
return envp;
66+
}
67+
68+
std::vector<std::string> CgiHandler::build_env_strings() const
69+
{
70+
std::vector<std::string> env;
71+
72+
env.push_back("REQUEST_METHOD=" + saved_request_.method);
73+
env.push_back("SERVER_PROTOCOL=HTTP/1.1");
74+
env.push_back("PATH_INFO=/");
75+
env.push_back("SCRIPT_NAME=" + saved_request_.path);
76+
env.push_back("QUERY_STRING=" + saved_request_.query_string);
77+
env.push_back("CONTENT_LENGTH=" + to_string(saved_request_.content_length));
78+
if (saved_request_.method == "POST") {
79+
env.push_back("CONTENT_TYPE=application/x-www-form-urlencoded");
80+
}
81+
env.push_back("SERVER_NAME=localhost"); // to be updated based on config
82+
83+
env.push_back("SERVER_PORT=" + to_string(WEBSERV_DEFAULT_PORT));
84+
env.push_back("PATH=/usr/bin:/bin");
85+
86+
env.push_back("GATEWAY_INTERFACE=CGI/1.1");
87+
88+
env.push_back("REQUEST_URI=" + saved_request_.path +
89+
(saved_request_.query_string.empty() ? "" : "?" + saved_request_.query_string));
90+
env.push_back("REDIRECT_STATUS=200"); // VERY IMPORTANT
91+
92+
LOG(DEBUG) << "saved_request_.path = " << saved_request_.path;
93+
94+
for (size_t i = 0; i < env.size(); ++i) {
95+
LOG(DEBUG) << "CGI ENV: " << env[i];
96+
}
97+
98+
return (env);
99+
}
100+
101+
void CgiHandler::build_exec_context(char** argv, bool is_interpreter_cgi)
102+
{
103+
env_strings_ = build_env_strings();
104+
envp_ = make_envp(env_strings_);
74105

75106
if (is_interpreter_cgi) {
76107
// Interpreter-based CGI
@@ -83,20 +114,25 @@ CgiHandler::CgiHandler(const std::string& path, const HttpRequest& saved_request
83114
argv[0] = const_cast<char*>(path_.c_str());
84115
argv[1] = NULL;
85116
}
117+
}
86118

87-
// STEP 2 - set up pipes
119+
bool CgiHandler::setup_pipes()
120+
{
88121
if (saved_request_.method == "POST") {
89122
if (pipe(input_fd_) == -1) {
90123
set_res_and_quit(HttpResponse::kStatusInternalServerError);
91-
return;
124+
return false;
92125
}
93126
}
94127
if (pipe(output_fd_) == -1) {
95128
set_res_and_quit(HttpResponse::kStatusInternalServerError);
96-
return;
129+
return false;
97130
}
131+
return true;
132+
}
98133

99-
// STEP 3 - Fork child process
134+
void CgiHandler::spawn_child(char** argv)
135+
{
100136
pid_ = fork();
101137
if (pid_ == -1) {
102138
set_res_and_quit(HttpResponse::kStatusInternalServerError);
@@ -114,7 +150,7 @@ CgiHandler::CgiHandler(const std::string& path, const HttpRequest& saved_request
114150
close(output_fd_[0]);
115151
dup2(output_fd_[1], STDOUT_FILENO);
116152
close(output_fd_[1]); // as now duplicated to STDOUT
117-
execve(argv[0], argv, envp.data());
153+
execve(argv[0], argv, envp_.data());
118154
// execve(argv[0], argv, envp.data());
119155
_exit(1);
120156
}
@@ -131,6 +167,44 @@ CgiHandler::CgiHandler(const std::string& path, const HttpRequest& saved_request
131167
}
132168
}
133169

170+
CgiHandler::CgiHandler(const std::string& path, const HttpRequest& saved_request,
171+
const RouteConfig& config)
172+
: path_(path),
173+
saved_request_(saved_request),
174+
config_(config),
175+
headers_off_(0),
176+
output_body_off_(0),
177+
bytes_written_body_(0),
178+
body_length_(saved_request.content_length),
179+
headers_parsed_(false),
180+
headers_sent_(false),
181+
eob_reached_(false),
182+
eof_reached_(false),
183+
eoo_reached_(false),
184+
forced_response_(false),
185+
child_reaped_(false),
186+
pid_(-1)
187+
{
188+
// STEP 0 - Set pipe default values
189+
init_state();
190+
191+
// STEP 1 - Check that file exisst and is executable
192+
bool is_interpreter_cgi = !config_.config.cgi.exec_path.empty();
193+
if (validate_cgi_target(is_interpreter_cgi) != true)
194+
return;
195+
196+
// STEP 2 - prepare environment variables and argv for child process
197+
char* argv[3];
198+
build_exec_context(argv, is_interpreter_cgi);
199+
200+
// STEP 3 - set up pipes
201+
if (setup_pipes() != true)
202+
return;
203+
204+
// STEP 4 - Fork child process
205+
spawn_child(argv);
206+
}
207+
134208
CgiHandler::~CgiHandler()
135209
{
136210
if (input_fd_[1] != -1) {
@@ -152,51 +226,6 @@ void CgiHandler::set_res_and_quit(HttpResponse::Status status)
152226
forced_response_ = true;
153227
}
154228

155-
static std::vector<char*> make_envp(std::vector<std::string>& env)
156-
{
157-
std::vector<char*> envp;
158-
envp.reserve(env.size() + 1);
159-
160-
for (size_t i = 0; i < env.size(); ++i)
161-
envp.push_back(const_cast<char*>(env[i].c_str()));
162-
163-
envp.push_back(NULL);
164-
return envp;
165-
}
166-
167-
std::vector<std::string> CgiHandler::build_env_strings() const
168-
{
169-
std::vector<std::string> env;
170-
171-
env.push_back("REQUEST_METHOD=" + saved_request_.method);
172-
env.push_back("SERVER_PROTOCOL=HTTP/1.1");
173-
env.push_back("PATH_INFO=/");
174-
env.push_back("SCRIPT_NAME=" + saved_request_.path);
175-
env.push_back("QUERY_STRING=" + saved_request_.query_string);
176-
env.push_back("CONTENT_LENGTH=" + to_string(saved_request_.content_length));
177-
if (saved_request_.method == "POST") {
178-
env.push_back("CONTENT_TYPE=application/x-www-form-urlencoded");
179-
}
180-
env.push_back("SERVER_NAME=localhost"); // to be updated based on config
181-
182-
env.push_back("SERVER_PORT=" + to_string(WEBSERV_DEFAULT_PORT));
183-
env.push_back("PATH=/usr/bin:/bin");
184-
185-
env.push_back("GATEWAY_INTERFACE=CGI/1.1");
186-
187-
env.push_back("REQUEST_URI=" + saved_request_.path +
188-
(saved_request_.query_string.empty() ? "" : "?" + saved_request_.query_string));
189-
env.push_back("REDIRECT_STATUS=200"); // VERY IMPORTANT
190-
191-
LOG(DEBUG) << "saved_request_.path = " << saved_request_.path;
192-
193-
for (size_t i = 0; i < env.size(); ++i) {
194-
LOG(DEBUG) << "CGI ENV: " << env[i];
195-
}
196-
197-
return (env);
198-
}
199-
200229
bool CgiHandler::child_reaped(void) const
201230
{
202231
if (child_reaped_) {

src/handler/cgi_handler.hpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,10 +56,20 @@ class CgiHandler : public Handler {
5656
bool parse_headers(std::string& cgi_headers, HttpResponse& res);
5757
bool headers_sent() const { return headers_off_ == headers_.size(); }
5858

59+
// constructor helper functions
60+
void init_state();
61+
bool validate_cgi_target(bool is_interpreter_cgi);
62+
void build_exec_context(char** argv, bool is_interpreter_cgi);
63+
bool setup_pipes();
64+
void spawn_child(char** argv);
65+
5966
const std::string path_;
6067
const HttpRequest& saved_request_;
6168
const RouteConfig& config_;
6269

70+
std::vector<char*> envp_;
71+
std::vector<std::string> env_strings_;
72+
6373
// POST/GET - strings used to parse the cgi output
6474
std::string raw_output_;
6575
size_t headers_off_;

0 commit comments

Comments
 (0)