From ab8bee89bef29bdaef23c74c8bcf68c92a0e04bd Mon Sep 17 00:00:00 2001 From: AM_Myrick Date: Mon, 11 Mar 2019 15:52:04 -0400 Subject: [PATCH 01/10] implements send_response --- src/server.c | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/src/server.c b/src/server.c index ea43306fc..fb4f120ba 100644 --- a/src/server.c +++ b/src/server.c @@ -52,13 +52,32 @@ 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); + timestamp = localtime(&time_res); + strftime(buffer, 50, "%a %b %d %T %Z %Y", timestamp); // Build HTTP response and store it in response /////////////////// // IMPLEMENT ME! // /////////////////// + char *new_body = body; + 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); + + int response_length = strlen(response); + + printf("Response: %s\n", response); // Send it all! int rv = send(fd, response, response_length, 0); @@ -193,7 +212,7 @@ 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. - + resp_404(listenfd); while(1) { socklen_t sin_size = sizeof their_addr; From 2ff4b950436a8dbbd3a6a11469133d77445a473a Mon Sep 17 00:00:00 2001 From: AM_Myrick Date: Mon, 11 Mar 2019 16:25:44 -0400 Subject: [PATCH 02/10] implements get_d20 and handle_http_request --- src/server.c | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/src/server.c b/src/server.c index fb4f120ba..5a061d5a9 100644 --- a/src/server.c +++ b/src/server.c @@ -94,6 +94,10 @@ int send_response(int fd, char *header, char *content_type, void *body, int cont */ void get_d20(int fd) { + 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)); // Generate a random number between 1 and 20 inclusive /////////////////// @@ -172,7 +176,20 @@ void handle_http_request(int fd, struct cache *cache) return; } + char method[200]; + char path[8192]; + + sscanf(request, "%s %s", method, path); + if(strcmp(method, "GET") == 0 & strcmp(path, "/d20") == 0) + { + get_d20(fd); + } + else + { + resp_404(fd); + } + /////////////////// // IMPLEMENT ME! // /////////////////// @@ -212,7 +229,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. - resp_404(listenfd); while(1) { socklen_t sin_size = sizeof their_addr; From 71dd1f45524c30017d8ed6ba732f1a6425fa05c5 Mon Sep 17 00:00:00 2001 From: AM_Myrick Date: Mon, 11 Mar 2019 17:22:02 -0400 Subject: [PATCH 03/10] implements arbitrary file serving --- src/server.c | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/src/server.c b/src/server.c index 5a061d5a9..dd1c83340 100644 --- a/src/server.c +++ b/src/server.c @@ -142,9 +142,24 @@ 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; + + snprintf(filepath, sizeof filepath, "%s/%s", SERVER_ROOT, request_path); + filedata = file_load(filepath); + + if (filedata == NULL) { + // TODO: make this non-fatal + fprintf(stderr, "cannot find %s\n", request_path); + exit(3); + } + + mime_type = mime_type_get(filepath); + + send_response(fd, "HTTP/1.1 200 OK", mime_type, filedata->data, filedata->size); + + file_free(filedata); } /** @@ -187,7 +202,7 @@ void handle_http_request(int fd, struct cache *cache) } else { - resp_404(fd); + get_file(fd, cache, path); } /////////////////// From ca2fb5ca875e90448cc7b6ca8620b839ad997468 Mon Sep 17 00:00:00 2001 From: AM_Myrick Date: Mon, 11 Mar 2019 17:31:54 -0400 Subject: [PATCH 04/10] completes automatic index.html serving --- src/server.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/server.c b/src/server.c index dd1c83340..1febfb640 100644 --- a/src/server.c +++ b/src/server.c @@ -149,8 +149,16 @@ void get_file(int fd, struct cache *cache, char *request_path) snprintf(filepath, sizeof filepath, "%s/%s", SERVER_ROOT, request_path); filedata = file_load(filepath); - if (filedata == NULL) { - // TODO: make this non-fatal + 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); } From dbe6b7f73ec69cadc04506d00d151863d842740c Mon Sep 17 00:00:00 2001 From: AM_Myrick Date: Tue, 12 Mar 2019 16:16:45 -0400 Subject: [PATCH 05/10] completes alloc_entry --- src/cache.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/cache.c b/src/cache.c index c72975cdd..2580aab4d 100644 --- a/src/cache.c +++ b/src/cache.c @@ -9,9 +9,14 @@ */ 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 = path; + new_cache_entry->content_type = content_type; + new_cache_entry->content = content; + new_cache_entry->content_length = content_length; + + return new_cache_entry; } /** From d031ee7d58c479da62106140bc1f8a4a794ec213 Mon Sep 17 00:00:00 2001 From: AM_Myrick Date: Tue, 12 Mar 2019 16:37:43 -0400 Subject: [PATCH 06/10] implements cache_put and cache_entry --- src/cache.c | 31 ++++++++++++++++++++++--------- 1 file changed, 22 insertions(+), 9 deletions(-) diff --git a/src/cache.c b/src/cache.c index 2580aab4d..e48b6aab1 100644 --- a/src/cache.c +++ b/src/cache.c @@ -24,9 +24,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); } /** @@ -127,9 +125,17 @@ 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_move_to_head(cache, new); + hashtable_put(cache->index, path, content); + 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); + free_entry(removed_tail); + cache->cur_size--; + } } /** @@ -137,7 +143,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, path); + return cache->head; + } } From 9196766cfb7701a2f937cbf7b24b9da213de848b Mon Sep 17 00:00:00 2001 From: AM_Myrick Date: Tue, 12 Mar 2019 18:07:13 -0400 Subject: [PATCH 07/10] working on LRU, failing tests --- src/cache.c | 33 +++++++++++++++++++++++++-------- src/cache_tests/cache_tests.c | 4 +++- src/server.c | 8 ++++++++ 3 files changed, 36 insertions(+), 9 deletions(-) diff --git a/src/cache.c b/src/cache.c index e48b6aab1..643bcc3cd 100644 --- a/src/cache.c +++ b/src/cache.c @@ -11,11 +11,21 @@ struct cache_entry *alloc_entry(char *path, char *content_type, void *content, i { struct cache_entry *new_cache_entry = malloc(sizeof(struct cache_entry)); - new_cache_entry->path = path; - new_cache_entry->content_type = content_type; - new_cache_entry->content = content; + // 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 = 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; } @@ -94,9 +104,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) @@ -132,7 +149,7 @@ void cache_put(struct cache *cache, char *path, char *content_type, void *conten if (cache->cur_size > cache->max_size) { struct cache_entry *removed_tail = dllist_remove_tail(cache); - hashtable_delete(cache->index, removed_tail); + hashtable_delete(cache->index, removed_tail->path); free_entry(removed_tail); cache->cur_size--; } @@ -150,7 +167,7 @@ struct cache_entry *cache_get(struct cache *cache, char *path) } else { - dllist_move_to_head(cache, path); + 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..629ea6f62 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; } @@ -56,7 +56,9 @@ char *test_cache_put() struct cache_entry *test_entry_4 = alloc_entry("/4", "image/png", "4", 2); // Add in a single entry to the cache + printf("\n%s\n", "runs"); cache_put(cache, test_entry_1->path, test_entry_1->content_type, test_entry_1->content, test_entry_1->content_length); + printf("\n%s\n", "runs"); // Check that the cache is handling a single entry as expected mu_assert(cache->cur_size == 1, "Your cache_put function did not correctly increment the cur_size field when adding a new cache entry"); mu_assert(cache->head->prev == NULL && cache->tail->next == NULL, "The head and tail of your cache should have NULL prev and next pointers when a new entry is put in an empty cache"); diff --git a/src/server.c b/src/server.c index 1febfb640..f70b766ca 100644 --- a/src/server.c +++ b/src/server.c @@ -145,6 +145,13 @@ void get_file(int fd, struct cache *cache, char *request_path) char filepath[4096]; struct file_data *filedata; char *mime_type; + struct cache_entry *entry = cache_get(cache, request_path); + + if (entry != NULL) + { + send_response(fd, "HTTP/1.1 200 OK", entry->content_type, entry->content, entry->content_length); + return; + } snprintf(filepath, sizeof filepath, "%s/%s", SERVER_ROOT, request_path); filedata = file_load(filepath); @@ -165,6 +172,7 @@ void get_file(int fd, struct cache *cache, char *request_path) 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); From 4d2637d815118750a88d5666904075201be1d55a Mon Sep 17 00:00:00 2001 From: AM_Myrick Date: Tue, 12 Mar 2019 18:45:45 -0400 Subject: [PATCH 08/10] cleans up comments --- src/cache.c | 1 - src/server.c | 35 +++-------------------------------- 2 files changed, 3 insertions(+), 33 deletions(-) diff --git a/src/cache.c b/src/cache.c index 643bcc3cd..4ae87b5f9 100644 --- a/src/cache.c +++ b/src/cache.c @@ -11,7 +11,6 @@ struct cache_entry *alloc_entry(char *path, char *content_type, void *content, i { struct cache_entry *new_cache_entry = malloc(sizeof(struct cache_entry)); - // deep copy new_cache_entry->path = malloc(strlen(path) + 1); strcpy(new_cache_entry->path, path); diff --git a/src/server.c b/src/server.c index f70b766ca..ea60e913b 100644 --- a/src/server.c +++ b/src/server.c @@ -59,11 +59,7 @@ int send_response(int fd, char *header, char *content_type, void *body, int cont timestamp = localtime(&time_res); strftime(buffer, 50, "%a %b %d %T %Z %Y", timestamp); - // Build HTTP response and store it in response - - /////////////////// - // IMPLEMENT ME! // - /////////////////// + char *new_body = body; sprintf(response, "%s\n" @@ -78,7 +74,7 @@ int send_response(int fd, char *header, char *content_type, void *body, int cont int response_length = strlen(response); printf("Response: %s\n", response); - // Send it all! + int rv = send(fd, response, response_length, 0); if (rv < 0) { @@ -98,17 +94,6 @@ void get_d20(int fd) int random_int = rand() % 21; sprintf(body, "%d", random_int); send_response(fd, "HTTP/1.1 200 OK", "text/plain", body, strlen(body)); - // Generate a random number between 1 and 20 inclusive - - /////////////////// - // IMPLEMENT ME! // - /////////////////// - - // Use send_response() to send it back as text/plain data - - /////////////////// - // IMPLEMENT ME! // - /////////////////// } /** @@ -198,8 +183,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) { @@ -220,19 +204,6 @@ void handle_http_request(int fd, struct cache *cache) { get_file(fd, cache, 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() - - // (Stretch) If POST, handle the post request } From 2f258dbe0c07611596880b6cdd8805b9b8e7f2cd Mon Sep 17 00:00:00 2001 From: AM_Myrick Date: Wed, 13 Mar 2019 17:05:29 -0400 Subject: [PATCH 09/10] completes day 4 MVP --- src/cache.c | 5 ++--- src/cache_tests/cache_tests.c | 2 -- src/serverroot/{cat.jpg => cat.png} | Bin 3 files changed, 2 insertions(+), 5 deletions(-) rename src/serverroot/{cat.jpg => cat.png} (100%) diff --git a/src/cache.c b/src/cache.c index 4ae87b5f9..8b84909b8 100644 --- a/src/cache.c +++ b/src/cache.c @@ -142,15 +142,14 @@ void cache_free(struct cache *cache) void cache_put(struct cache *cache, char *path, char *content_type, void *content, int content_length) { struct cache_entry *new = alloc_entry(path, content_type, content, content_length); - dllist_move_to_head(cache, new); - hashtable_put(cache->index, path, content); + 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); - cache->cur_size--; } } diff --git a/src/cache_tests/cache_tests.c b/src/cache_tests/cache_tests.c index 629ea6f62..9e303c31b 100644 --- a/src/cache_tests/cache_tests.c +++ b/src/cache_tests/cache_tests.c @@ -56,9 +56,7 @@ char *test_cache_put() struct cache_entry *test_entry_4 = alloc_entry("/4", "image/png", "4", 2); // Add in a single entry to the cache - printf("\n%s\n", "runs"); cache_put(cache, test_entry_1->path, test_entry_1->content_type, test_entry_1->content, test_entry_1->content_length); - printf("\n%s\n", "runs"); // Check that the cache is handling a single entry as expected mu_assert(cache->cur_size == 1, "Your cache_put function did not correctly increment the cur_size field when adding a new cache entry"); mu_assert(cache->head->prev == NULL && cache->tail->next == NULL, "The head and tail of your cache should have NULL prev and next pointers when a new entry is put in an empty cache"); 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 From 7648d663465f7350a30fc61eb7fe0401cb5bd08d Mon Sep 17 00:00:00 2001 From: AM_Myrick Date: Wed, 13 Mar 2019 17:15:14 -0400 Subject: [PATCH 10/10] fixed so that server.c now serves files from cache --- src/server.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/server.c b/src/server.c index ea60e913b..31e6dd9f1 100644 --- a/src/server.c +++ b/src/server.c @@ -131,15 +131,20 @@ void get_file(int fd, struct cache *cache, char *request_path) 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; } - - snprintf(filepath, sizeof filepath, "%s/%s", SERVER_ROOT, request_path); - filedata = file_load(filepath); + 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);