diff --git a/src/cache.c b/src/cache.c index c72975cdd..8b84909b8 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(struct cache_entry)); + + 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 = malloc(content_length); + memcpy(new_cache_entry->content, content, content_length); + + new_cache_entry->content_length = content_length; + + new_cache_entry->prev = NULL; + new_cache_entry->next = NULL; + + return new_cache_entry; } /** @@ -19,9 +33,7 @@ struct cache_entry *alloc_entry(char *path, char *content_type, void *content, i */ void free_entry(struct cache_entry *entry) { - /////////////////// - // IMPLEMENT ME! // - /////////////////// + free(entry); } /** @@ -91,9 +103,16 @@ struct cache_entry *dllist_remove_tail(struct cache *cache) */ struct cache *cache_create(int max_size, int hashsize) { - /////////////////// - // IMPLEMENT ME! // - /////////////////// + struct cache *new_cache = malloc(sizeof(struct cache)); + struct hashtable *hash_table = hashtable_create(hashsize, NULL); + + new_cache->head = NULL; + new_cache->tail = NULL; + new_cache->cur_size = 0; + new_cache->max_size = max_size; + new_cache->index = hash_table; + + return new_cache; } void cache_free(struct cache *cache) @@ -122,9 +141,16 @@ 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 *new = alloc_entry(path, content_type, content, content_length); + dllist_insert_head(cache, new); + hashtable_put(cache->index, new->path, &new->path); + cache->cur_size++; + if (cache->cur_size > cache->max_size) + { + struct cache_entry *removed_tail = dllist_remove_tail(cache); + hashtable_delete(cache->index, removed_tail->path); + free_entry(removed_tail); + } } /** @@ -132,7 +158,14 @@ 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! // - /////////////////// + void *data = hashtable_get(cache->index, path); + if (data == NULL) + { + return NULL; + } + else + { + dllist_move_to_head(cache, data); + return cache->head; + } } diff --git a/src/cache_tests/cache_tests.c b/src/cache_tests/cache_tests.c index 5e245d005..9e303c31b 100644 --- a/src/cache_tests/cache_tests.c +++ b/src/cache_tests/cache_tests.c @@ -41,7 +41,7 @@ char *test_cache_alloc_entry() mu_assert(ce->content_length == content_len, "Your alloc_entry function did not allocate the content_length field to the expected length"); free_entry(ce); - + return NULL; } diff --git a/src/server.c b/src/server.c index ea43306fc..31e6dd9f1 100644 --- a/src/server.c +++ b/src/server.c @@ -52,14 +52,29 @@ 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]; + time_t time_res; + struct tm *timestamp; + char buffer[50]; + time(&time_res); - // Build HTTP response and store it in response + timestamp = localtime(&time_res); + strftime(buffer, 50, "%a %b %d %T %Z %Y", timestamp); + + char *new_body = body; - /////////////////// - // IMPLEMENT ME! // - /////////////////// + sprintf(response, "%s\n" + "Date: %s\n" + "Connection: close\n" + "Content-Length: %d\n" + "Content-Type: %s\n" + "\n" + "%s\n", + header, buffer, content_length, content_type, new_body); - // Send it all! + int response_length = strlen(response); + + printf("Response: %s\n", response); + int rv = send(fd, response, response_length, 0); if (rv < 0) { @@ -75,17 +90,10 @@ 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 - - /////////////////// - // IMPLEMENT ME! // - /////////////////// - - // Use send_response() to send it back as text/plain data - - /////////////////// - // IMPLEMENT ME! // - /////////////////// + char body[3]; + int random_int = rand() % 21; + sprintf(body, "%d", random_int); + send_response(fd, "HTTP/1.1 200 OK", "text/plain", body, strlen(body)); } /** @@ -119,9 +127,45 @@ 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 *entry = cache_get(cache, request_path); + + snprintf(filepath, sizeof filepath, "%s/%s", SERVER_ROOT, request_path); + filedata = file_load(filepath); + + if (entry != NULL) + { + send_response(fd, "HTTP/1.1 200 OK", entry->content_type, entry->content, entry->content_length); + printf("\n%s\n", "from cache"); + return; + } + else + { + cache_put(cache, request_path, mime_type_get(filepath), filedata->data, filedata->size); + } + + if (filedata == NULL & strcmp(request_path, "/") == 0) { + fprintf(stderr, "cannot find %s\n", request_path); + snprintf(filepath, sizeof filepath, "%s/index.html", SERVER_ROOT); + filedata = file_load(filepath); + mime_type = mime_type_get(filepath); + send_response(fd, "HTTP/1.1 200 OK", mime_type, filedata->data, filedata->size); + file_free(filedata); + return; + } + else if (filedata == NULL) { + fprintf(stderr, "cannot find %s\n", request_path); + exit(3); + } + + mime_type = mime_type_get(filepath); + + cache_put(cache, request_path, mime_type, filedata->data, filedata->size); + send_response(fd, "HTTP/1.1 200 OK", mime_type, filedata->data, filedata->size); + + file_free(filedata); } /** @@ -144,8 +188,7 @@ void handle_http_request(int fd, struct cache *cache) { const int request_buffer_size = 65536; // 64K char request[request_buffer_size]; - - // Read request + int bytes_recvd = recv(fd, request, request_buffer_size - 1, 0); if (bytes_recvd < 0) { @@ -153,19 +196,19 @@ void handle_http_request(int fd, struct cache *cache) return; } + char method[200]; + char path[8192]; + + sscanf(request, "%s %s", method, path); - /////////////////// - // IMPLEMENT ME! // - /////////////////// - - // Read the three components of the first request line - - // 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 & strcmp(path, "/d20") == 0) + { + get_d20(fd); + } + else + { + get_file(fd, cache, path); + } // (Stretch) If POST, handle the post request } @@ -193,7 +236,6 @@ int main(void) // This is the main loop that accepts incoming connections and // forks a handler process to take care of it. The main parent // process then goes back to waiting for new connections. - while(1) { socklen_t sin_size = sizeof their_addr; diff --git a/src/serverroot/cat.jpg b/src/serverroot/cat.png similarity index 100% rename from src/serverroot/cat.jpg rename to src/serverroot/cat.png