summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorcflip <cflip@cflip.net>2022-09-15 12:13:20 -0600
committercflip <cflip@cflip.net>2022-09-15 12:13:20 -0600
commitac12ef846b343849317539c84258ab0c5e6b542f (patch)
tree075ce63eeb1a9facd653ef07f1537708bfba6464
parent6266304977eb6bde01b374c53ca2a2a3514cb0d4 (diff)
Add an option to serve CGI exectuables
-rw-r--r--src/main.cpp115
1 files changed, 82 insertions, 33 deletions
diff --git a/src/main.cpp b/src/main.cpp
index 7cd4787..cec6d3e 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -9,19 +9,95 @@
#include "HttpResponse.h"
#include "ServerConnection.h"
+static HttpResponse serve_from_filesystem(HttpRequest request)
+{
+ namespace fs = std::filesystem;
+
+ HttpResponse response;
+ response.add_header("Server", "cfws");
+
+ // Remove leading slash from the path if it exists
+ std::string relative_request_path = request.uri();
+ while (*relative_request_path.begin() == '/')
+ relative_request_path.erase(0, 1);
+
+ fs::path request_path = fs::current_path() / relative_request_path;
+
+ // Look for an index.html if the requested path is a directory
+ if (fs::is_directory(request_path)) {
+ request_path /= "index.html";
+ }
+
+ if (fs::exists(request_path)) {
+ std::string file_path = request_path.string();
+ std::ifstream input_file(file_path);
+ if (!input_file.is_open()) {
+ std::cerr << "Failed to open file " << file_path << std::endl;
+ }
+
+ std::string file_contents((std::istreambuf_iterator<char>(input_file)), std::istreambuf_iterator<char>());
+
+ response.set_status_code(HttpStatusCode::OK);
+ response.add_header("Content-Type", "text/plain");
+ response.set_content(file_contents);
+ } else {
+ response.set_status_code(HttpStatusCode::NotFound);
+ response.add_header("Content-Type", "text/plain");
+ response.set_content("Page not found!");
+ }
+
+ return response;
+}
+
+static HttpResponse serve_from_cgi(const std::string& executable_path, HttpRequest request)
+{
+ HttpResponse response;
+ response.add_header("Server", "cfws");
+
+ std::stringstream sstream;
+
+ FILE* fp = popen(executable_path.c_str(), "r");
+ if (!fp) {
+ perror("cfws: popen");
+ response.set_status_code(HttpStatusCode::InternalServerError);
+ response.add_header("Content-Type", "text/plain");
+ response.set_content("Failed to open CGI executable!");
+ return response;
+ }
+
+ char ch;
+ while ((ch = fgetc(fp)) != EOF)
+ sstream << ch;
+
+ pclose(fp);
+
+ // TODO: We should be able to construct a repsonse from an entire string
+ // instead of always needing to individually set headers and content.
+ response.set_status_code(HttpStatusCode::OK);
+ response.add_header("Content-Type", "text/plain");
+ response.set_content(sstream.str());
+ return response;
+}
+
static option long_options[] = {
+ { "cgi", required_argument, NULL, 'c' },
{ "port", required_argument, NULL, 'p' },
};
int main(int argc, char** argv)
{
int port = 8080;
- namespace fs = std::filesystem;
+ bool in_cgi_mode = false;
+ std::string cgi_program_name;
int c;
int option_index = 0;
- while ((c = getopt_long(argc, argv, "p:", long_options, &option_index)) != -1) {
+ while ((c = getopt_long(argc, argv, "c:p:", long_options, &option_index)) != -1) {
switch (c) {
+ case 'c':
+ in_cgi_mode = true;
+ cgi_program_name = optarg;
+ break;
case 'p':
port = atoi(optarg);
if (port == 0) {
@@ -35,44 +111,17 @@ int main(int argc, char** argv)
}
ServerConnection server(port);
- std::cout << "cfws v0.1.0]\n";
+ std::cout << "Serving a " << (in_cgi_mode ? "CGI exectuable" : "directory") << " on port " << port << std::endl;
while (true) {
- std::cout << "Waiting for connections on port " << port << std::endl;
ClientConnection client = server.accept_client_connection();
HttpRequest request = client.read_request();
-
- // Remove leading slash from the path if it exists
- std::string relative_request_path = request.uri();
- while (*relative_request_path.begin() == '/')
- relative_request_path.erase(0, 1);
-
- fs::path request_path = fs::current_path() / relative_request_path;
-
- // Look for an index.html if the requested path is a directory
- if (fs::is_directory(request_path)) {
- request_path /= "index.html";
- }
-
HttpResponse response;
- response.add_header("Server", "cfws");
-
- if (fs::exists(request_path)) {
- std::string file_path = request_path.string();
- std::ifstream input_file(file_path);
- if (!input_file.is_open()) {
- std::cerr << "Failed to open file " << file_path << std::endl;
- }
-
- std::string file_contents((std::istreambuf_iterator<char>(input_file)), std::istreambuf_iterator<char>());
- response.set_status_code(HttpStatusCode::OK);
- response.add_header("Content-Type", "text/plain");
- response.set_content(file_contents);
+ if (in_cgi_mode) {
+ response = serve_from_cgi(cgi_program_name, request);
} else {
- response.set_status_code(HttpStatusCode::NotFound);
- response.add_header("Content-Type", "text/plain");
- response.set_content("Page not found!");
+ response = serve_from_filesystem(request);
}
client.send(response);