diff options
-rw-r--r-- | file.c | 93 | ||||
-rw-r--r-- | file.h | 12 | ||||
-rw-r--r-- | http.c | 13 | ||||
-rw-r--r-- | http.h | 6 | ||||
-rw-r--r-- | net.c | 36 |
5 files changed, 101 insertions, 59 deletions
@@ -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); } @@ -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 @@ -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); } @@ -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 @@ -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); } |