diff --git a/src/cache.c b/src/cache.c index c72975cdd..eaa0e25f3 100644 --- a/src/cache.c +++ b/src/cache.c @@ -9,9 +9,23 @@ */ struct cache_entry *alloc_entry(char *path, char *content_type, void *content, int content_length) { - /////////////////// - // IMPLEMENT ME! // - /////////////////// + struct cache_entry *new_cache_entry = malloc(sizeof *new_cache_entry); + + // Deep copy + new_cache_entry->path = malloc(strlen(path) + 1); + strcpy(new_cache_entry->path, path); + + new_cache_entry->content_type = malloc(strlen(content_type) + 1); + strcpy(new_cache_entry->content_type, content_type); + + new_cache_entry->content_length = content_length; + + new_cache_entry->content = malloc(content_length); + memcpy(new_cache_entry->content, content, content_length); + + new_cache_entry->prev = new_cache_entry->next = NULL; + + return new_cache_entry; } /** @@ -19,9 +33,10 @@ struct cache_entry *alloc_entry(char *path, char *content_type, void *content, i */ void free_entry(struct cache_entry *entry) { - /////////////////// - // IMPLEMENT ME! // - /////////////////// + free(entry->path); + free(entry->content_type); + free(entry->content); + free(entry); } /** @@ -91,9 +106,14 @@ struct cache_entry *dllist_remove_tail(struct cache *cache) */ struct cache *cache_create(int max_size, int hashsize) { - /////////////////// - // IMPLEMENT ME! // - /////////////////// + struct cache *cache = malloc(sizeof *cache); + + cache->index = hashtable_create(hashsize, NULL); + cache->head = cache->tail = NULL; + cache->cur_size = 0; + cache->max_size = max_size; + + return cache; } void cache_free(struct cache *cache) @@ -122,9 +142,22 @@ void cache_free(struct cache *cache) */ void cache_put(struct cache *cache, char *path, char *content_type, void *content, int content_length) { - /////////////////// - // IMPLEMENT ME! // - /////////////////// + struct cache_entry *entry = alloc_entry(path, content_type, content, content_length); + + dllist_insert_head(cache, entry); + + hashtable_put(cache->index, path, entry); + + cache->cur_size++; + + if (cache->cur_size > cache->max_size) { + struct cache_entry *removed_cache_entry = dllist_remove_tail(cache); + hashtable_delete(cache->index, removed_cache_entry->path); + free_entry(removed_cache_entry); + if (cache->cur_size != cache->max_size) { + cache->cur_size = cache->max_size; + } + } } /** @@ -132,7 +165,12 @@ void cache_put(struct cache *cache, char *path, char *content_type, void *conten */ struct cache_entry *cache_get(struct cache *cache, char *path) { - /////////////////// - // IMPLEMENT ME! // - /////////////////// + struct cache_entry *entry = hashtable_get(cache->index, path); + + if (entry == NULL) { + return NULL; + } + + dllist_move_to_head(cache, entry); + return entry; } diff --git a/src/file.c b/src/file.c index 5277a92f4..4df9579ec 100644 --- a/src/file.c +++ b/src/file.c @@ -72,4 +72,4 @@ void file_free(struct file_data *filedata) { free(filedata->data); free(filedata); -} \ No newline at end of file +} diff --git a/src/server.c b/src/server.c index ea43306fc..2b6b81e4f 100644 --- a/src/server.c +++ b/src/server.c @@ -52,12 +52,30 @@ int send_response(int fd, char *header, char *content_type, void *body, int cont { const int max_response_size = 262144; char response[max_response_size]; - + + // Generate date + time_t rawtime; + struct tm *current_time; + time(&rawtime); + current_time = localtime(&rawtime); + // Build HTTP response and store it in response - - /////////////////// - // IMPLEMENT ME! // - /////////////////// + sprintf(response, + "%s\n" + "Date: %s" // Example: Wed Dec 20 13:05:11 PST 2017 + "Connection: close\n" + "Content-Length: %d\n" + "Content-Type: %s\n" + "\n" + "%s", + header, + asctime(current_time), + content_length, + content_type, + body + ); + + int response_length = strlen(response); // Send it all! int rv = send(fd, response, response_length, 0); @@ -76,16 +94,13 @@ int send_response(int fd, char *header, char *content_type, void *body, int cont void get_d20(int fd) { // Generate a random number between 1 and 20 inclusive + srand(time(NULL)); + char random_number_string[20]; + int random_number = rand() % 20; + sprintf(random_number_string, "%d", random_number); - /////////////////// - // IMPLEMENT ME! // - /////////////////// - // Use send_response() to send it back as text/plain data - - /////////////////// - // IMPLEMENT ME! // - /////////////////// + send_response(fd, "HTTP/1.1 200 OK", "text/plain", random_number_string, strlen(random_number_string)); } /** @@ -94,7 +109,7 @@ void get_d20(int fd) void resp_404(int fd) { char filepath[4096]; - struct file_data *filedata; + struct file_data *filedata; char *mime_type; // Fetch the 404.html file @@ -119,9 +134,26 @@ void resp_404(int fd) */ void get_file(int fd, struct cache *cache, char *request_path) { - /////////////////// - // IMPLEMENT ME! // - /////////////////// + char filepath[4096]; + struct file_data *filedata; + char *mime_type; + struct cache_entry *cached_file = cache_get(cache, request_path); + + if (cached_file != NULL) { + send_response(fd, "HTTP/1.1 200 OK", cached_file->content_type, cached_file->content, cached_file->content_length); + } else { + sprintf(filepath, "./serverroot%s", request_path); + + mime_type = mime_type_get(filepath); + + filedata = file_load(filepath); + + send_response(fd, "HTTP/1.1 200 OK", mime_type, filedata->data, filedata->size); + + cache_put(cache, request_path, mime_type, filedata->data, filedata->size); + + file_free(filedata); + } } /** @@ -144,6 +176,8 @@ void handle_http_request(int fd, struct cache *cache) { const int request_buffer_size = 65536; // 64K char request[request_buffer_size]; + char method[200]; + char path[8192]; // Read request int bytes_recvd = recv(fd, request, request_buffer_size - 1, 0); @@ -153,19 +187,22 @@ void handle_http_request(int fd, struct cache *cache) return; } - - /////////////////// - // IMPLEMENT ME! // - /////////////////// - // Read the three components of the first request line - + sscanf(request, "%s %s", method, path); + // If GET, handle the get endpoints - - // Check if it's /d20 and handle that special case - // Otherwise serve the requested file by calling get_file() - - + if (strcmp(method, "GET") == 0) { + if (strcmp(path, "/d20") == 0) { + // Check if it's /d20 and handle that special case + get_d20(fd); + } else if (path != NULL) { + // Otherwise serve the requested file by calling get_file() + get_file(fd, cache, path); + } else { + resp_404(fd); + } + } + // (Stretch) If POST, handle the post request } @@ -187,7 +224,7 @@ int main(void) fprintf(stderr, "webserver: fatal error getting listening socket\n"); exit(1); } - + printf("webserver: waiting for connections on port %s...\n", PORT); // This is the main loop that accepts incoming connections and