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

Andre Myrick - C Web Server #305

Open
wants to merge 10 commits into
base: master
Choose a base branch
from
64 changes: 49 additions & 15 deletions src/cache.c
Original file line number Diff line number Diff line change
Expand Up @@ -9,19 +9,31 @@
*/
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;
}

/**
* Deallocate a cache entry
*/
void free_entry(struct cache_entry *entry)
{
///////////////////
// IMPLEMENT ME! //
///////////////////
free(entry);
}

/**
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -122,17 +141,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! //
///////////////////
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->path);
free_entry(removed_tail);
cache->cur_size--;
}
}

/**
* Retrieve an entry from the cache
*/
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;
}
}
4 changes: 3 additions & 1 deletion src/cache_tests/cache_tests.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

Expand All @@ -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");
Expand Down
105 changes: 71 additions & 34 deletions src/server.c
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand All @@ -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));
}

/**
Expand Down Expand Up @@ -119,9 +127,40 @@ 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);

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);

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);
}

/**
Expand All @@ -144,28 +183,27 @@ 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;
}

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
}

Expand Down Expand Up @@ -193,7 +231,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;

Expand Down