summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorcflip <cflip@cflip.net>2023-05-30 12:31:34 -0600
committercflip <cflip@cflip.net>2023-05-30 12:31:34 -0600
commit8dbdf132ea82a567d7cef856469fd47c511b4191 (patch)
tree66d87095b94b90a1a66946c0b514cfbe75ae1f10
parent775c4157994ee0ebe9bd951a99bc5d7558128ba4 (diff)
Refactor response building code
This new strategy involves finding the local file path for the given URI, determining what method to use to fulfill the request (read file from disk, use php-cgi, or error), then it writes the response to the client socket.
-rw-r--r--file.c93
-rw-r--r--file.h12
-rw-r--r--http.c13
-rw-r--r--http.h6
-rw-r--r--net.c36
5 files changed, 101 insertions, 59 deletions
diff --git a/file.c b/file.c
index 98b5d50..b94c071 100644
--- a/file.c
+++ b/file.c
@@ -8,81 +8,82 @@
#include <sys/stat.h>
#include <unistd.h>
-int file_handle_request(struct http_request *req, int sockfd)
+const char *file_path_for_uri(const char *uri)
{
- if (strstr(req->uri, ".php") != 0) {
- return file_read_cgi(req->uri, sockfd);
- }
- return file_read(req->uri, sockfd);
-}
-
-int file_read(const char *uri_path, int sockfd)
-{
- /* TODO: Implement this again */
- return 1;
-
- FILE *fp;
struct stat statbuf;
char path[PATH_MAX];
- long len;
+ size_t result_len;
+ char *result;
- /* Prepend the current working directory to the uri path */
getcwd(path, PATH_MAX);
- strncat(path, uri_path, PATH_MAX - 1);
+ strncat(path, uri, PATH_MAX - 1);
- /* Append 'index.html' to directory paths. */
+ /* Append 'index.html' if this is a directory */
stat(path, &statbuf);
if (S_ISDIR(statbuf.st_mode))
strcat(path, "index.html");
- fp = fopen(path, "rb");
- if (fp == NULL) {
- /*
- * File not found is a very common and harmless error, so
- * there's no need to print it out every time.
- */
- if (errno != ENOENT)
- perror("Failed to open file");
- return 0;
+ /* Allocate a string with only the needed size */
+ result_len = strlen(path);
+ result = malloc(result_len + 1);
+ memcpy(result, path, result_len);
+ result[result_len] = '\0';
+ return result;
+}
+
+enum serve_method file_method_for_path(const char *filepath, enum http_res_code *code)
+{
+ if (access(filepath, F_OK) != 0) {
+ *code = HTTP_RESPONSE_NOTFOUND;
+ return SERVE_METHOD_ERROR;
}
- fseek(fp, 0, SEEK_END);
- len = ftell(fp);
- fseek(fp, 0, SEEK_SET);
+ *code = HTTP_RESPONSE_OK;
+ if (strstr(filepath, ".php") != 0)
+ return SERVE_METHOD_PHP;
+
+ return SERVE_METHOD_FILE;
+}
+
+int file_read(const char *filepath, int sockfd)
+{
+ FILE *fp;
+ char ch;
+
+ fp = fopen(filepath, "rb");
+ if (fp == NULL) {
+ perror("Failed to open file");
+ return 1;
+ }
- /*buffer = malloc(len);*/
- /*fread(*buffer, 1, len, fp);*/
+ write(sockfd, "Content-Type: text/html\r\n\r\n", 27);
+ /* TODO: Implement a buffered read from FILE* function */
+ while ((ch = fgetc(fp)) != EOF) {
+ write(sockfd, &ch, 1);
+ }
fclose(fp);
- return len;
+ return 0;
}
-int file_read_cgi(const char *uri_path, int sockfd)
+int file_read_php(const char *filepath, int sockfd)
{
- /* TODO: Lazy copy paste just to get it working */
FILE *fp;
- struct stat statbuf;
char cmdbuf[PATH_MAX];
- char path[PATH_MAX];
char ch;
- /* Prepend the current working directory to the uri path */
- getcwd(path, PATH_MAX);
- strncat(path, uri_path, PATH_MAX - 1);
-
- /* Append 'index.php' to directory paths. */
- stat(path, &statbuf);
- if (S_ISDIR(statbuf.st_mode))
- strcat(path, "index.php");
-
strcpy(cmdbuf, "php-cgi ");
- strcat(cmdbuf, path);
+ strcat(cmdbuf, filepath);
+
+ printf("r %s\n", cmdbuf);
fp = popen(cmdbuf, "r");
if (fp == NULL) {
+ perror("Failed to read command");
return 1;
}
+ /* TODO: Implement a buffered read from FILE* function */
while ((ch = fgetc(fp)) != EOF) {
write(sockfd, &ch, 1);
}
diff --git a/file.h b/file.h
index ee39eae..52d8915 100644
--- a/file.h
+++ b/file.h
@@ -5,9 +5,17 @@
#include "http.h"
-int file_handle_request(struct http_request *, int);
+enum serve_method {
+ SERVE_METHOD_FILE,
+ SERVE_METHOD_PHP,
+ SERVE_METHOD_ERROR
+};
+
+const char *file_path_for_uri(const char *);
+
+enum serve_method file_method_for_path(const char *, enum http_res_code *);
int file_read(const char *, int);
-int file_read_cgi(const char *, int);
+int file_read_php(const char *, int);
#endif
diff --git a/http.c b/http.c
index 40a2b82..41a0435 100644
--- a/http.c
+++ b/http.c
@@ -4,6 +4,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <unistd.h>
struct http_request http_parse_request(const char *reqstr)
{
@@ -30,7 +31,15 @@ void http_free_request(struct http_request *req)
free(req->uri);
}
-int http_build_response(char *res, enum http_res_code code, const char *msg, size_t msglen)
+static const char *response_msg[2] = {
+ "200 OK",
+ "404 Not Found"
+};
+
+void http_response_statusline(enum http_res_code status_code, int sockfd)
{
- return snprintf(res, CFWS_MAX_RESPONSE, "HTTP/1.1 200 OK\r\n%.*s\r\n", msglen, msg);
+ char statusline[64];
+ int len;
+ len = snprintf(statusline, 64, "HTTP/1.1 %s\r\n", response_msg[status_code]);
+ write(sockfd, statusline, len);
}
diff --git a/http.h b/http.h
index 1e97820..3cdc062 100644
--- a/http.h
+++ b/http.h
@@ -11,8 +11,8 @@ enum http_req_method {
};
enum http_res_code {
- HTTP_RESPONSE_OK = 200,
- HTTP_RESPONSE_NOTFOUND = 404
+ HTTP_RESPONSE_OK,
+ HTTP_RESPONSE_NOTFOUND
};
struct http_request {
@@ -23,6 +23,6 @@ struct http_request {
struct http_request http_parse_request(const char *);
void http_free_request(struct http_request *);
-int http_build_response(char *, enum http_res_code, const char *, size_t);
+void http_response_statusline(enum http_res_code, int);
#endif
diff --git a/net.c b/net.c
index c7d075a..ce19fc7 100644
--- a/net.c
+++ b/net.c
@@ -53,20 +53,44 @@ int initialize_server(int port)
void handle_connection(int connfd)
{
- const char *header = "HTTP/1.1 200 OK\r\n";
char readbuf[CFWS_MAXREAD];
struct http_request req;
+ char *filepath;
+ enum http_res_code res_code;
+ enum serve_method method;
+
+ /* Read and parse the HTTP request */
memset(readbuf, 0, CFWS_MAXREAD);
read(connfd, readbuf, CFWS_MAXREAD - 1);
-
req = http_parse_request(readbuf);
- write(connfd, header, strlen(header));
- if (file_handle_request(&req, connfd) != 0) {
- const char *msg = "\r\nCould not find the specified file.";
- write(connfd, msg, strlen(msg));
+ /* Get the local file path for the given URI. */
+ filepath = file_path_for_uri(req.uri);
+
+ printf("GET %s : %s\n", req.uri, filepath);
+
+ /* Determine the method that should be used to serve this file */
+ method = file_method_for_path(filepath, &res_code);
+
+ /* Write the HTTP response status and any required headers */
+ http_response_statusline(res_code, connfd);
+
+ /* Use the chosen method to fill in the rest of the response */
+ switch (method) {
+ case SERVE_METHOD_FILE:
+ file_read(filepath, connfd);
+ break;
+ case SERVE_METHOD_PHP:
+ file_read_php(filepath, connfd);
+ break;
+ case SERVE_METHOD_ERROR: {
+ const char *errmsg = "Content-Type: text/plain\r\n\r\nEpic fail";
+ write(connfd, errmsg, strlen(errmsg));
+ break;
+ }
}
+ free(filepath);
http_free_request(&req);
}