diff --git a/htdocs/site-3/index.php b/htdocs/site-3/index.php index 8dba1c0..0b68556 100644 --- a/htdocs/site-3/index.php +++ b/htdocs/site-3/index.php @@ -1,5 +1,4 @@ // for strcpy + +CgiEnvironment::CgiEnvironment(const URI &uri, const HttpRequest &request) +{ + env_["GATEWAY_INTERFACE"] = "CGI/1.1"; + env_["SERVER_PROTOCOL"] = "HTTP/1.1"; + env_["REQUEST_METHOD"] = request.getMethod(); + env_["SCRIPT_NAME"] = uri.getBaseName(); + env_["SCRIPT_FILENAME"] = uri.getFullPath(); // Full filesystem path to the script (required by PHP) + env_["QUERY_STRING"] = uri.getQuery(); + env_["REQUEST_URI"] = request.getTarget(); + env_["PATH_INFO"] = uri.getPathInfo(); + + // Only set CONTENT_TYPE and CONTENT_LENGTH if they have values + auto contentType = request.getHeaders().getContentType(); + if (contentType.has_value()) + { + env_["CONTENT_TYPE"] = contentType.value(); + } + auto contentLength = request.getHeaders().getContentLength(); + if (contentLength.has_value()) + { + env_["CONTENT_LENGTH"] = std::to_string(contentLength.value()); + } + + std::string host_port = request.getHeaders().getHost().value_or(""); + size_t colonPos = host_port.find(':'); + std::string host = (colonPos != std::string::npos) ? host_port.substr(0, colonPos) : host_port; + int port = (colonPos != std::string::npos) ? std::stoi(host_port.substr(colonPos + 1)) : 80; + + env_["SERVER_NAME"] = host; + env_["SERVER_PORT"] = std::to_string(port); + env_["REMOTE_ADDR"] = ""; // Placeholder, should be set to actual remote address + env_["REDIRECT_STATUS"] = "200"; // Required by PHP with force-cgi-redirect enabled + +} + +char **CgiEnvironment::toEnvp() const +{ + char **envp = new char *[env_.size() + 1]; + size_t index = 0; + for (std::map::const_iterator it = env_.begin(); it != env_.end(); ++it, ++index) + { + std::string entry = it->first + "=" + it->second; + envp[index] = new char[entry.size() + 1]; + std::strcpy(envp[index], entry.c_str()); + } + envp[index] = nullptr; // Null-terminate the array + return envp; +} \ No newline at end of file diff --git a/webserv/handler/CgiEnvironment.hpp b/webserv/handler/CgiEnvironment.hpp new file mode 100644 index 0000000..a01b4fd --- /dev/null +++ b/webserv/handler/CgiEnvironment.hpp @@ -0,0 +1,21 @@ +#pragma once + +#include +#include +#include "webserv/handler/URI.hpp" +#include "webserv/http/HttpRequest.hpp" +#include "webserv/utils/FileUtils.hpp" +#include "webserv/log/Log.hpp" + +class CgiEnvironment +{ +public: + CgiEnvironment(const URI &uri, const HttpRequest &request); + + [[nodiscard]] char **toEnvp() const; + + +private: + std::map env_; + +}; diff --git a/webserv/handler/CgiHandler.cpp b/webserv/handler/CgiHandler.cpp index 18ced50..3b781a6 100644 --- a/webserv/handler/CgiHandler.cpp +++ b/webserv/handler/CgiHandler.cpp @@ -121,6 +121,7 @@ void CgiHandler::parseCgiOutput() Log::debug("CGI output headers not complete yet"); return; } + // Parse the headers std::string headers(buffer_.begin(), buffer_.begin() + static_cast(headerEnd)); Log::debug("CGI output headers: " + headers); @@ -133,24 +134,51 @@ void CgiHandler::parseCgiOutput() void CgiHandler::parseCgiHeaders(std::string &headers) { Log::trace(LOCATION); + + // Debug: log the raw headers to see what we're getting + Log::debug("Raw CGI headers (length=" + std::to_string(headers.length()) + "): [" + headers + "]"); + size_t start = 0; size_t end = headers.find("\r\n"); while (end != std::string::npos) { std::string header = headers.substr(start, end - start); - Log::debug("CGI header: " + header); - size_t colonPos = header.find(':'); - if (colonPos != std::string::npos) + if (!header.empty()) { - std::string name = header.substr(0, colonPos); - std::string value = header.substr(colonPos + 1); - name = utils::trim(name); - value = utils::trim(value); - response_.addHeader(name, value); + Log::debug("CGI header: [" + header + "]"); + size_t colonPos = header.find(':'); + if (colonPos != std::string::npos) + { + std::string name = header.substr(0, colonPos); + std::string value = header.substr(colonPos + 1); + name = utils::trim(name); + value = utils::trim(value); + response_.addHeader(name, value); + } + else + { + Log::warning("CGI header has no colon: [" + header + "]"); + } } start = end + 2; end = headers.find("\r\n", start); } + + // // Handle the last header (might not have trailing \r\n) + // std::string lastHeader = headers.substr(start); + // if (!lastHeader.empty()) + // { + // Log::debug("Last CGI header: [" + lastHeader + "]"); + // size_t colonPos = lastHeader.find(':'); + // if (colonPos != std::string::npos) + // { + // std::string name = lastHeader.substr(0, colonPos); + // std::string value = lastHeader.substr(colonPos + 1); + // name = utils::trim(name); + // value = utils::trim(value); + // response_.addHeader(name, value); + // } + // } } void CgiHandler::parseCgiBody() diff --git a/webserv/handler/CgiProcess.cpp b/webserv/handler/CgiProcess.cpp index 5a25bb5..3cdead7 100644 --- a/webserv/handler/CgiProcess.cpp +++ b/webserv/handler/CgiProcess.cpp @@ -1,5 +1,6 @@ #include "webserv/handler/CgiProcess.hpp" +#include "webserv/handler/CgiEnvironment.hpp" #include "webserv/http/HttpRequest.hpp" #include "webserv/socket/CgiSocket.hpp" @@ -28,7 +29,6 @@ void CgiProcess::spawn() { const URI &uri = request_.getUri(); auto cgiPath = uri.getCgiPath(); - auto environment = uri.getCGIEnvironment(); // pipes @@ -63,11 +63,12 @@ void CgiProcess::spawn() // Prepare arguments std::string fullPath = uri.getFullPath(); + CgiEnvironment cgiEnv(uri, request_); char *args[] = {const_cast(cgiPath.c_str()), const_cast(fullPath.c_str()), nullptr}; // Log::debug("With args:", {args[0], args[1]}); // TODO: Close all FDs - execve(const_cast(cgiPath.c_str()), args, nullptr); + execve(const_cast(cgiPath.c_str()), args, cgiEnv.toEnvp()); exit(1); } else @@ -114,6 +115,7 @@ void CgiProcess::wait() noexcept } Log::debug("CGI process with PID " + std::to_string(_pid) + " has terminated"); + ; _pid = -1; } } \ No newline at end of file diff --git a/webserv/handler/URI.cpp b/webserv/handler/URI.cpp index ced19a0..25bf6c9 100644 --- a/webserv/handler/URI.cpp +++ b/webserv/handler/URI.cpp @@ -101,7 +101,7 @@ void URI::parseFullpath() } else if (!baseName_.empty()) // not file or dir, but we have a baseName already { - pathInfo_ = FileUtils::joinPath(pathInfo_, baseName_); + pathInfo_ = FileUtils::joinPath(pathInfo_, segment); } else // not file or dir, and no baseName yet { @@ -113,28 +113,28 @@ void URI::parseFullpath() fullPath_ = FileUtils::joinPath(dir_, baseName_); } -std::map URI::getCGIEnvironment() const -{ - std::map env; +// std::map URI::getCGIEnvironment() const +// { +// std::map env; - // URI components - env["REQUEST_URI"] = uriTrimmed_; - env["SCRIPT_NAME"] = getFullPath(); - env["PATH_INFO"] = getPathInfo(); - env["QUERY_STRING"] = getQuery(); +// // URI components +// env["REQUEST_URI"] = uriTrimmed_; +// env["SCRIPT_NAME"] = getFullPath(); +// env["PATH_INFO"] = getPathInfo(); +// env["QUERY_STRING"] = getQuery(); - // Authority components - env["SERVER_NAME"] = config_->get("server_name").value_or(""); - env["SERVER_PORT"] = std::to_string(config_->get("listen").value_or(-1)); - env["REQUEST_SCHEME"] = "HTTP"; +// // Authority components +// env["SERVER_NAME"] = config_->get("server_name").value_or(""); +// env["SERVER_PORT"] = std::to_string(config_->get("listen").value_or(-1)); +// env["REQUEST_SCHEME"] = "HTTP"; - // HTTP context - // env["REQUEST_METHOD"] = requestMethod_; - // env["CONTENT_TYPE"] = contentType_; - // env["CONTENT_LENGTH"] = contentLength_; +// // HTTP context +// // env["REQUEST_METHOD"] = requestMethod_; +// // env["CONTENT_TYPE"] = contentType_; +// // env["CONTENT_LENGTH"] = contentLength_; - return env; -} +// return env; +// } const AConfig *URI::getConfig() const noexcept { diff --git a/webserv/handler/URI.hpp b/webserv/handler/URI.hpp index b9ce7b5..39350d5 100644 --- a/webserv/handler/URI.hpp +++ b/webserv/handler/URI.hpp @@ -6,7 +6,7 @@ #include // for HttpRequest #include -#include // for map + #include // for string, basic_string class LocationConfig; @@ -18,8 +18,6 @@ class URI public: URI(const HttpRequest &request, const ServerConfig &serverConfig); - [[nodiscard]] std::map getCGIEnvironment() const; - [[nodiscard]] bool isFile() const noexcept; [[nodiscard]] bool isDirectory() const noexcept; [[nodiscard]] bool isValid() const noexcept;