diff --git a/src/cache.c b/src/cache.c index c72975cdd..260f4e783 100644 --- a/src/cache.c +++ b/src/cache.c @@ -9,9 +9,13 @@ */ struct cache_entry *alloc_entry(char *path, char *content_type, void *content, int content_length) { - /////////////////// - // IMPLEMENT ME! // - /////////////////// + struct cache_entry *new_entry = malloc(sizeof(cache_entry)); + new_entry->path = path; + new_entry->content_type = content_type; + new_entry->content_length = content_length; + new_entry->content = content; + + return new_entry; } /** @@ -19,9 +23,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 +96,13 @@ 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(max_size, hashsize); + cache->max_size = max_size; + cache->cur_size = 0; + + return cache; } void cache_free(struct cache *cache) @@ -122,9 +131,32 @@ void cache_free(struct cache *cache) */ void cache_put(struct cache *cache, char *path, char *content_type, void *content, int content_length) { - /////////////////// - // IMPLEMENT ME! // - /////////////////// +// Allocate a new cache entry with the passed parameters. DONE +// Insert the entry at the head of the doubly-linked list. DONE +// Store the entry in the hashtable as well, indexed by the entry's path. DONE +// Increment the current size of the cache. +// If the cache size is greater than the max size: +// Remove the cache entry at the tail of the linked list. +// Remove that same entry from the hashtable, using the entry's path and the hashtable_delete function. +// Free the cache entry. +// Ensure the size counter for the number of entries in the cache is correct. + + struct cache_entry *new_entry = alloc_entry(path, content_type, content, content_length); + dllist_insert_head(cache, new_entry); + hashtable_put(cache->index, path, new_entry); + cache->cur_size++; + + if (cache->cur_size > cache->max_size) { + struct cache_entry *removed_entry = dllist_remove_tail(cache); + hashtable_delete(cache->index, removed_entry->path); + free_entry(removed_entry); + cache->cur_size = cache->max_size; + } + + free_entry(new_entry); + + + } /** @@ -132,7 +164,15 @@ 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){ + dllist_move_to_head(cache, entry); + + } else { + printf("Page not in cache/n"); + } + + return entry; + } diff --git a/src/cache.h b/src/cache.h index f64c976ad..45d7accf8 100644 --- a/src/cache.h +++ b/src/cache.h @@ -2,22 +2,22 @@ #define _WEBCACHE_H_ // Individual hash table entry -struct cache_entry { +typedef struct cache_entry { char *path; // Endpoint path--key to the cache char *content_type; int content_length; void *content; struct cache_entry *prev, *next; // Doubly-linked list -}; +} cache_entry; // A cache -struct cache { +typedef struct cache { struct hashtable *index; struct cache_entry *head, *tail; // Doubly-linked list int max_size; // Maxiumum number of entries int cur_size; // Current number of entries -}; +}cache; extern struct cache_entry *alloc_entry(char *path, char *content_type, void *content, int content_length); extern void free_entry(struct cache_entry *entry); diff --git a/src/server.c b/src/server.c index ea43306fc..2c38ab9c9 100644 --- a/src/server.c +++ b/src/server.c @@ -15,7 +15,6 @@ * * (Posting data is harder to test from a browser.) */ - #include #include #include @@ -33,12 +32,9 @@ #include "file.h" #include "mime.h" #include "cache.h" - -#define PORT "3490" // the port users will be connecting to - +#define PORT "8584" // the port users will be connecting to #define SERVER_FILES "./serverfiles" #define SERVER_ROOT "./serverroot" - /** * Send an HTTP response * @@ -50,42 +46,40 @@ */ int send_response(int fd, char *header, char *content_type, void *body, int content_length) { - const int max_response_size = 262144; + const int max_response_size = 65536*5; char response[max_response_size]; + int response_length; // Build HTTP response and store it in response + time_t t = time(NULL); + struct tm *date = localtime(&t); - /////////////////// - // IMPLEMENT ME! // - /////////////////// + response_length = sprintf(response,"%s\nDate: %sConnection: close\nContent-length: %d\nContent-Type: %s\n\n" \ + ,header,asctime(date),content_length,content_type); - // Send it all! - int rv = send(fd, response, response_length, 0); + // NOTE: Dont use sprintf to add body into response because it doesn't play well with void ptr. + memcpy(response+response_length, body, content_length); + + printf("RESPONSE LENGTH: %d\n\n", response_length); + // Send it all! + int rv = send(fd, response, response_length+content_length, 0); if (rv < 0) { perror("send"); } - return rv; } - - /** * Send a /d20 endpoint response */ void get_d20(int fd) { - // Generate a random number between 1 and 20 inclusive - - /////////////////// - // IMPLEMENT ME! // - /////////////////// + srand(time(NULL)); - // Use send_response() to send it back as text/plain data + char random[5]; + sprintf(random,"%d\n", 1 + rand() % 20); - /////////////////// - // IMPLEMENT ME! // - /////////////////// + send_response(fd, "HTTP/1.1 200 OK", "text/plain", random, strlen(random) ); } /** @@ -119,11 +113,23 @@ void resp_404(int fd) */ void get_file(int fd, struct cache *cache, char *request_path) { - /////////////////// - // IMPLEMENT ME! // - /////////////////// -} + char filepath[1024]; + + snprintf(filepath, sizeof filepath, "./serverroot%s",request_path); + + + struct file_data *filedata = file_load(filepath); + if (filedata == NULL){ + resp_404(fd); + return; + } + + char *mime_type = mime_type_get(request_path); + + send_response(fd,"HTTP/1.1 200 OK", mime_type, filedata->data, filedata->size ); + file_free(filedata); +} /** * Search for the end of the HTTP header * @@ -136,7 +142,6 @@ char *find_start_of_body(char *header) // IMPLEMENT ME! // (Stretch) /////////////////// } - /** * Handle HTTP request and send response */ @@ -144,31 +149,32 @@ 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) { perror("recv"); return; } + + // make sure req is correct + printf("request: %s\n", request); + char http_method[20], endpoint[20]; + sscanf(request, "%s %s",http_method, endpoint); + + if (strcmp(http_method,"GET") == 0) + { + if (strcmp(endpoint, "/d20")==0) + { + get_d20(fd); + } else { + get_file(fd,cache,endpoint); + } - /////////////////// - // 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 + } else { + resp_404(fd); + } } - /** * Main */ @@ -177,23 +183,19 @@ int main(void) int newfd; // listen on sock_fd, new connection on newfd struct sockaddr_storage their_addr; // connector's address information char s[INET6_ADDRSTRLEN]; - struct cache *cache = cache_create(10, 0); - // Get a listening socket int listenfd = get_listener_socket(PORT); - if (listenfd < 0) { 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 // 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; @@ -205,22 +207,23 @@ int main(void) continue; } + // Print out a message that we got the connection inet_ntop(their_addr.ss_family, get_in_addr((struct sockaddr *)&their_addr), s, sizeof s); printf("server: got connection from %s\n", s); - + + + // resp_404(newfd); test send_response() + // newfd is a new socket descriptor for the new connection. // listenfd is still listening for new connections. handle_http_request(newfd, cache); - close(newfd); } // Unreachable code - return 0; -} - +} \ No newline at end of file diff --git a/src/serverroot/drake.jpg b/src/serverroot/drake.jpg new file mode 100644 index 000000000..e71c9aef7 Binary files /dev/null and b/src/serverroot/drake.jpg differ