summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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);
}