Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Ian Cameron C Web Server #306

Open
wants to merge 13 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
77 changes: 76 additions & 1 deletion src/cache.c
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,24 @@ struct cache_entry *alloc_entry(char *path, char *content_type, void *content, i
///////////////////
// IMPLEMENT ME! //
///////////////////
//allocate space for the struct were going to return
struct cache_entry *ce = malloc(sizeof *ce); //size of dereference ce if dereffed it is cache_entry
//set all fields to values being passed in to initialize
//have a pointer to something but have to make sure what you are pointing to persists(make sure it doesnt accidentally get freed)
ce->path = malloc(strlen(path) + 1); //so make a copy of path we know will persist. +1 for null terminator
strcpy(ce->path, path); //(dest, args) copy path into allocated memory. this is deep copy.

ce->content_type = malloc(strlen(content_type) +1);
strcpy(ce->content_type, content_type);

ce->content = malloc(content_length); //content is void pointer so dont know what type so cant use strlen, but know its length so can use that
memcpy(ce->content, content, content_length); //(dest, src, size)

ce->content_length = content_length; //int so dont have to malloc

ce->prev = ce->next = NULL;

return ce;
}

/**
Expand All @@ -22,6 +40,12 @@ void free_entry(struct cache_entry *entry)
///////////////////
// IMPLEMENT ME! //
///////////////////
//have to free the cache entry passed in but have to free everything we malloc'ed space for
//free everything in stucture, then free the structure itself so entry last
free(entry->path);
free(entry->content_type);
free(entry->content);
free(entry);
}

/**
Expand Down Expand Up @@ -93,7 +117,19 @@ struct cache *cache_create(int max_size, int hashsize)
{
///////////////////
// IMPLEMENT ME! //
///////////////////
/////////////////// going in opposite order from cache free below. also refer to cache struct in cache.h
//allocate cache
struct cache *cache = malloc(sizeof *cache);
//functions in hashtable.h and c
cache->index = hashtable_create(hashsize, NULL); //size and pointer to a function (that takes in certain values and returns int)
//initialize head and tail null
cache->head = cache->tail = NULL;

cache->max_size = max_size; //int so dont allocate space

cache->cur_size = 0;

return cache;
}

void cache_free(struct cache *cache)
Expand All @@ -113,6 +149,15 @@ void cache_free(struct cache *cache)
free(cache);
}

void clean_lru(struct cache *cache)
{
while (cache->cur_size > cache->max_size) {
struct cache_entry *oldtail = dllist_remove_tail(cache);

hashtable_delete(cache->index, oldtail->path);
free_entry(oldtail);
}
}
/**
* Store an entry in the cache
*
Expand All @@ -125,6 +170,26 @@ void cache_put(struct cache *cache, char *path, char *content_type, void *conten
///////////////////
// IMPLEMENT ME! //
///////////////////
//Allocate a new cache entry with the passed parameters
struct cache_entry *ce = alloc_entry(path, content_type, content, content_length);
//Insert the entry at the head of the doubly-linked list
dllist_insert_head(cache, ce);
//Store the entry in the hashtable as well, indexed by the entry's path
hashtable_put(cache->index, ce->path, ce);
//Increment the current size of the cache
cache->cur_size++;
clean_lru(cache);
//If the cache size is greater than the max size
// if (cache->cur_size > cache->max_size) {
// //Remove the cache entry at the tail of the linked list
// dllist_remove_tail(ce);
// //Remove that same entry from the hashtable, using the entry's path and the hashtable_delete function
// hashtable_delete(ce->path, ce);
// //Free the cache entry
// cache_free(ce);
// //Ensure the size counter for the number of entries in the cache is correct
// cache->cur_size--;
// }
}

/**
Expand All @@ -135,4 +200,14 @@ struct cache_entry *cache_get(struct cache *cache, char *path)
///////////////////
// IMPLEMENT ME! //
///////////////////
//Attempt to find the cache entry pointer by path in the hash table. If not found, return NULL
struct cache_entry *ce = hashtable_get(cache->index, path);

if (ce == NULL) {
return NULL;
}
//Move the cache entry to the head of the doubly-linked list
dllist_move_to_head(cache, ce);
//Return the cache entry pointer
return ce;
}
2 changes: 2 additions & 0 deletions src/cache.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ struct cache_entry {
int content_length;
void *content;

//time_t timestamp; //added for comparison implementing cache get/put

struct cache_entry *prev, *next; // Doubly-linked list
};

Expand Down
8 changes: 4 additions & 4 deletions src/cache_tests/cache_tests.c
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ char *test_cache_put()
mu_assert(check_cache_entries(cache->head, test_entry_1) == 0, "Your cache_put function did not put an entry into the head of the empty cache with the expected form");
mu_assert(check_cache_entries(cache->tail, test_entry_1) == 0, "Your cache_put function did not put an entry into the tail of the empty cache with the expected form");
mu_assert(check_cache_entries(hashtable_get(cache->index, "/1"), test_entry_1) == 0, "Your cache_put function did not put the expected entry into the hashtable");

// Add in a second entry to the cache
cache_put(cache, test_entry_2->path, test_entry_2->content_type, test_entry_2->content, test_entry_2->content_length);
// Check that the cache is handling both entries as expected
Expand All @@ -72,7 +72,7 @@ char *test_cache_put()
mu_assert(check_cache_entries(cache->tail, test_entry_1) == 0, "Your cache_put function did not move the oldest entry in the cache to the tail of the cache");
mu_assert(check_cache_entries(cache->head->next, test_entry_1) == 0, "Your cache_put function did not correctly set the head->next pointer of the cache");
mu_assert(check_cache_entries(hashtable_get(cache->index, "/2"), test_entry_2) == 0, "Your cache_put function did not put the expected entry into the hashtable");

// Add in a third entry to the cache
cache_put(cache, test_entry_3->path, test_entry_3->content_type, test_entry_3->content, test_entry_3->content_length);
// Check that the cache is handling all three entries as expected
Expand All @@ -83,7 +83,7 @@ char *test_cache_put()
mu_assert(check_cache_entries(cache->head->next->next, test_entry_1) == 0, "Your cache_put function did not update the head->next->next pointer to point to the tail entry");
mu_assert(check_cache_entries(cache->tail->prev, test_entry_2) == 0, "Your cache_put function did not update the tail->prev pointer to poin to the second-to-last entry");
mu_assert(check_cache_entries(cache->tail, test_entry_1) == 0, "Your cache_put function did not correctly update the tail pointer of the cache");

// Add in a fourth entry to the cache
cache_put(cache, test_entry_4->path, test_entry_4->content_type, test_entry_4->content, test_entry_4->content_length);
// Check that the cache removed the oldest entry and is handling the three most-recent entries correctly
Expand All @@ -94,7 +94,7 @@ char *test_cache_put()
mu_assert(check_cache_entries(cache->head->next->next, test_entry_2) == 0, "Your cache_put function did not update the head->next->next pointer to point to the tail entry");
mu_assert(check_cache_entries(cache->tail->prev, test_entry_3) == 0, "Your cache_put function did not update the tail->prev pointer to poin to the second-to-last entry");
mu_assert(check_cache_entries(cache->tail, test_entry_2) == 0, "Your cache_put function did not correctly handle the tail of an already-full cache");

cache_free(cache);

return NULL;
Expand Down
95 changes: 82 additions & 13 deletions src/server.c
Original file line number Diff line number Diff line change
Expand Up @@ -52,16 +52,38 @@ 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];

// Build HTTP response and store it in response

///////////////////
// IMPLEMENT ME! //
///////////////////
//time
time_t rawtime;
struct tm *info;
time (&rawtime);
info = localtime(&rawtime);

//build header
int response_length = snprintf(response, max_response_size,
"%s\n"
"Date: %s" //asctime adds its own new line
"Content-Type: %s\n"
"Content-Length: %d\n"
"Connection: close\n"
"\n",
//"%s\n", //taking body off the response header and creating separate send
header, asctime(info), content_type, content_length //,body
);

// Send it all!
int rv = send(fd, response, response_length, 0);

if (rv < 0) {
perror("send");
}
//refactor this (creating another send) to accommodate png so send body (and its length) separately from the response so still only one request
rv = send(fd, body, content_length, 0);

if (rv < 0) {
perror("send");
}
Expand All @@ -76,16 +98,18 @@ 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! //
///////////////////
char str[4];
int random_number = rand() % 21; //num = (rand() % (upper – lower + 1)) + lower
sprintf(str, "%d\n", random_number);

// Use send_response() to send it back as text/plain data

///////////////////
// IMPLEMENT ME! //
///////////////////
send_response(fd, "HTTP/1.1 200 OK", "text/plain", str, strlen(str));
}

/**
Expand Down Expand Up @@ -122,6 +146,37 @@ void get_file(int fd, struct cache *cache, char *request_path)
///////////////////
// IMPLEMENT ME! //
///////////////////
//read file
char filepath[4096];
struct file_data *filedata; //loads file into memory and returns pointer to data
char *mime_type;
//fetch file.
//append path user requests (which != filepath) to server root (3490/index.html)
snprintf(filepath, sizeof filepath, "%s%s", SERVER_ROOT, request_path);
printf("\"%s\"\n", filepath);

//time comparison for expiration of cache (implemented with cache put/get)
struct cache_entry *ce = cache_get(cache, filepath);
//expire then refresh file and delete item out of cache (eg if cur time less that time greater than 1min)
if (time(NULL) - ce->timestamp > 60) { //timestamp decl in struct cache_entry in cache.h so know when it was created

}

//load that file
filedata = file_load(filepath);
//if file not found
if (filedata == NULL)
{
resp_404(fd);
return;
}
//get mimetype
mime_type = mime_type_get(filepath);
printf("%s\n", mime_type);
//send file out
send_response(fd, "HTTP/1.1 200 OK", mime_type, filedata->data, filedata->size);
//then free data bc loaded these data into memory
file_free(filedata);
}

/**
Expand All @@ -130,18 +185,20 @@ void get_file(int fd, struct cache *cache, char *request_path)
* "Newlines" in HTTP can be \r\n (carriage return followed by newline) or \n
* (newline) or \r (carriage return).
*/
char *find_start_of_body(char *header)
{
///////////////////
// IMPLEMENT ME! // (Stretch)
///////////////////
}
// char *find_start_of_body(char *header)
// {
// ///////////////////
// // IMPLEMENT ME! // (Stretch)
// ///////////////////
// (void)header;
// }

/**
* Handle HTTP request and send response
*/
void handle_http_request(int fd, struct cache *cache)
{
(void)cache; //rememember to remove all these voids. reeeeeeeeemember!
const int request_buffer_size = 65536; // 64K
char request[request_buffer_size];

Expand All @@ -153,20 +210,32 @@ void handle_http_request(int fd, struct cache *cache)
return;
}


///////////////////
// IMPLEMENT ME! //
///////////////////

// Read the three components of the first request line
char method[512];
char path[8192];

sscanf(request, "%s %s", method, path);
printf("method: \"%s\"\n", method);
printf("path: \"%s\"\n", 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) { //strcmp returns 0 if equal
get_d20(fd);
} else {
get_file(fd, NULL, path);
//resp_404(fd); //used 404 before completing get_file
}
}

// (Stretch) If POST, handle the post request
//if (strcmp(method, "POST") == 0)
}

/**
Expand Down
File renamed without changes