@@ -41,7 +41,17 @@ static std::string to_string_size_t(size_t v)
4141 return oss.str ();
4242}
4343
44- void CgiHandler::setEnvVar (std::vector<std::string>& child_env_var)
44+ std::string build_error_response (HttpResponse::Status status, std::string inline_body)
45+ {
46+ HttpResponse res;
47+ res.code = status;
48+ res.content_type = " text/html; charset=UTF-8" ;
49+ res.inline_body = inline_body;
50+ std::string headers = res.to_string ();
51+ return (headers);
52+ }
53+
54+ void CgiHandler::set_env_var (std::vector<std::string>& child_env_var)
4555{
4656 child_env_var.push_back (" REQUEST_METHOD=" + saved_request_.method );
4757 child_env_var.push_back (" SCRIPT_FILENAME=" + saved_request_.path );
@@ -54,6 +64,7 @@ void CgiHandler::setEnvVar(std::vector<std::string>& child_env_var)
5464 child_env_var.push_back (" SERVER_NAME=localhost" ); // to be updated based on config or removed
5565 child_env_var.push_back (" SERVER_PROTOCOL=HTTP/1.1" );
5666 child_env_var.push_back (" SERVER_PORT=" + to_string_size_t (WEBSERV_DEFAULT_PORT));
67+ child_env_var.push_back (" PATH=/usr/bin:/bin" );
5768}
5869
5970// constructor needs to query the request, create the env var,
@@ -68,40 +79,47 @@ CgiHandler::CgiHandler(const std::string& path, const HttpRequest& saved_request
6879 body_length_(saved_request.content_length),
6980 headers_parsed_(false ),
7081 headers_sent_(false ),
82+ eob_reached_(false ),
7183 eoo_reached_(false ),
72- child_reaped_(false ),
73- pipe_blocked_(false )
84+ child_reaped_(false )
7485{
75- input_fd [0 ] = -1 ;
76- input_fd [1 ] = -1 ;
77- output_fd [0 ] = -1 ;
78- output_fd [1 ] = -1 ;
86+ input_fd_ [0 ] = -1 ;
87+ input_fd_ [1 ] = -1 ;
88+ output_fd_ [0 ] = -1 ;
89+ output_fd_ [1 ] = -1 ;
7990
8091 // STEP 0 - Check that file exisst and is executable
8192 struct stat sb;
82- if (stat (path.data (), &sb) == -1 || !S_ISREG (sb.st_mode ) ||
83- !(sb.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH)) || access (path.data (), X_OK) != 0 ) {
84- // error
93+ if (stat (path.c_str (), &sb) == -1 || !S_ISREG (sb.st_mode ) ||
94+ !(sb.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH)) || access (path.c_str (), X_OK) != 0 ) {
95+ headers_ = build_error_response (HttpResponse::kStatusForbidden , " <h1>403 Forbidden</h1>" );
96+ headers_parsed_ = true ;
97+ headers_sent_ = false ;
98+ headers_off_ = 0 ;
99+ eoo_reached_ = true ;
100+ child_reaped_ = true ;
101+ return ;
85102 }
86103
87104 // STEP 1 - Prepare key=value pair vector to be passed to child process to set env var
88105 std::vector<std::string> child_env_var;
89106 std::vector<char *> envp;
90- setEnvVar (child_env_var); // -> will be passed to execve( , , char *envp[])
107+ set_env_var (child_env_var); // -> will be passed to execve( , , char *envp[])
91108
92109 // STEP 2 - set up pipes
93110 if (saved_request_.method == " POST" ) {
94- if (pipe (input_fd ) == -1 ) {
111+ if (pipe (input_fd_ ) == -1 ) {
95112 // some error to be sent
96113 return ;
97114 }
98115 }
99116
100- if (pipe (output_fd ) == -1 ) {
117+ if (pipe (output_fd_ ) == -1 ) {
101118 // some error to be sent
102119 return ;
103120 }
104121
122+ LOG (DEBUG) << " CgiHandler constructed" ;
105123 // STEP 3 - Fork child process
106124 pid_ = fork ();
107125 if (pid_ == -1 ) {
@@ -112,14 +130,14 @@ CgiHandler::CgiHandler(const std::string& path, const HttpRequest& saved_request
112130 if (pid_ == 0 ) { // child process - setting up pipes
113131 // closing the write end and replacing STDIN by the read end of the input pipe
114132 if (saved_request_.method == " POST" ) {
115- close (input_fd [1 ]);
116- dup2 (input_fd [0 ], STDIN_FILENO);
117- close (input_fd [0 ]); // as now duplicated to STDIN
133+ close (input_fd_ [1 ]);
134+ dup2 (input_fd_ [0 ], STDIN_FILENO);
135+ close (input_fd_ [0 ]); // as now duplicated to STDIN
118136 }
119137 // closing the read end and replacing STDOUT by the write end of the output pipe
120- close (output_fd [0 ]);
121- dup2 (output_fd [1 ], STDOUT_FILENO);
122- close (output_fd [1 ]); // as now duplicated to STDOUT
138+ close (output_fd_ [0 ]);
139+ dup2 (output_fd_ [1 ], STDOUT_FILENO);
140+ close (output_fd_ [1 ]); // as now duplicated to STDOUT
123141
124142 std::vector<char *> envp;
125143 envp.reserve (child_env_var.size () + 1 );
@@ -140,36 +158,36 @@ CgiHandler::CgiHandler(const std::string& path, const HttpRequest& saved_request
140158 // parent process - setting up pipes
141159 // closing read end of input_fd
142160 if (saved_request_.method == " POST" ) {
143- close (input_fd [0 ]);
144- fcntl (input_fd [1 ], F_SETFL, O_NONBLOCK);
161+ close (input_fd_ [0 ]);
162+ fcntl (input_fd_ [1 ], F_SETFL, O_NONBLOCK);
145163 }
146164 // closing write end of the output_fd
147- close (output_fd [1 ]);
148- fcntl (output_fd [0 ], F_SETFL, O_NONBLOCK);
165+ close (output_fd_ [1 ]);
166+ fcntl (output_fd_ [0 ], F_SETFL, O_NONBLOCK);
149167 }
150168}
151169
152170CgiHandler::~CgiHandler ()
153171{
154- if (input_fd [1 ] != -1 ) {
155- close (input_fd [1 ]);
156- input_fd [1 ] = -1 ;
172+ if (input_fd_ [1 ] != -1 ) {
173+ close (input_fd_ [1 ]);
174+ input_fd_ [1 ] = -1 ;
157175 }
158176
159- if (output_fd [0 ] != -1 ) {
160- close (output_fd [0 ]);
161- output_fd [0 ] = -1 ;
177+ if (output_fd_ [0 ] != -1 ) {
178+ close (output_fd_ [0 ]);
179+ output_fd_ [0 ] = -1 ;
162180 }
163181}
164182
165- int CgiHandler::childReaped (void )
183+ int CgiHandler::child_reaped (void ) const
166184{
167185 if (child_reaped_) {
168- // LOG(DEBUG) << "child_reaped == true";
186+ LOG (DEBUG) << " child_reaped == true" ;
169187 return 1 ;
170188 }
171189
172- int status;
190+ int status = 0 ;
173191 pid_t r = waitpid (pid_, &status, WNOHANG);
174192 if (r == 0 ) {
175193 return 0 ;
@@ -186,16 +204,6 @@ int CgiHandler::childReaped(void)
186204 return 0 ;
187205}
188206
189- std::string build_error_response (HttpResponse::Status status, std::string inline_body)
190- {
191- HttpResponse res;
192- res.code = status;
193- res.content_type = " text/html; charset=UTF-8" ;
194- res.inline_body = inline_body;
195- std::string headers_ = res.to_string ();
196- return (headers_);
197- }
198-
199207int CgiHandler::parse_headers (std::string& cgi_headers, HttpResponse& res)
200208{
201209 // Extract status code
@@ -242,9 +250,6 @@ bool CgiHandler::has_output() const
242250
243251size_t CgiHandler::read_data (char * buf, size_t n)
244252{
245- LOG (DEBUG) << " read_data()" ;
246- childReaped ();
247-
248253 if (headers_parsed_ && !headers_sent_) {
249254 size_t remain = headers_.size () - headers_off_;
250255 size_t to_copy = std::min (remain, n);
@@ -274,16 +279,16 @@ size_t CgiHandler::read_data(char* buf, size_t n)
274279
275280 char tmp[4096 ];
276281
277- ssize_t bytes_read = read (output_fd [0 ], tmp, sizeof (tmp));
282+ ssize_t bytes_read = read (output_fd_ [0 ], tmp, sizeof (tmp));
278283 LOG (DEBUG) << " bytes_read = " << bytes_read;
279284 if (bytes_read == 0 ) {
280285 eoo_reached_ = true ;
281- close (output_fd [0 ]);
282- output_fd [0 ] = -1 ;
286+ close (output_fd_ [0 ]);
287+ output_fd_ [0 ] = -1 ;
283288 return 0 ; // finished reading
284289 }
285290 if (bytes_read < 0 ) {
286- if (errno == EAGAIN || errno || EWOULDBLOCK) {
291+ if (errno == EAGAIN || errno == EWOULDBLOCK) {
287292 return 0 ; // pipe not available for read
288293 }
289294 headers_.append (
@@ -293,21 +298,26 @@ size_t CgiHandler::read_data(char* buf, size_t n)
293298 headers_sent_ = false ;
294299 headers_off_ = 0 ;
295300 eoo_reached_ = true ;
296- pipe_blocked_ = false ;
297301 return 0 ;
298302 }
299303
300304 if (!headers_parsed_) {
301305 raw_output_.append (tmp, bytes_read);
302306
303307 size_t header_end = raw_output_.find (" \r\n\r\n " );
308+ size_t sep_len = 4 ;
309+
310+ if (header_end == std::string::npos) {
311+ header_end = raw_output_.find (" \n\n " );
312+ sep_len = 2 ;
313+ }
304314 if (header_end == std::string::npos) {
305315 // Still waiting for full CGI header block
306316 return 0 ;
307317 }
308318
309319 std::string cgi_headers = raw_output_.substr (0 , header_end);
310- std::string remainder = raw_output_.substr (header_end + 4 );
320+ std::string remainder = raw_output_.substr (header_end + sep_len );
311321
312322 HttpResponse res;
313323 if (parse_headers (cgi_headers, res) != 0 ) {
@@ -335,12 +345,12 @@ size_t CgiHandler::read_data(char* buf, size_t n)
335345 return 0 ;
336346}
337347
338- // We never write to this handler (read-only)
339348size_t CgiHandler::write_data (const char * buf, size_t n)
340349{
341- ssize_t bytes = write (input_fd[1 ], buf, n);
350+ LOG (DEBUG) << " Attempt to write to pipe" ;
351+ ssize_t bytes = write (input_fd_[1 ], buf, n);
342352 if (bytes < 0 ) {
343- if (errno == EAGAIN || errno || EWOULDBLOCK) {
353+ if (errno == EAGAIN || errno == EWOULDBLOCK) {
344354 return 0 ; // pipe not available for write
345355 }
346356 eob_reached_ = true ;
@@ -360,8 +370,8 @@ size_t CgiHandler::write_data(const char* buf, size_t n)
360370
361371 return (bytes);
362372 }
363- close (input_fd [1 ]);
364- input_fd [1 ] = -1 ;
373+ close (input_fd_ [1 ]);
374+ input_fd_ [1 ] = -1 ;
365375 LOG (INFO) << " CgiHandler : Body fully written to STDIN" ;
366376 return (0 );
367377}
0 commit comments