Skip to content

Stefano - C-Web-Server #309

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

Open
wants to merge 9 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
68 changes: 53 additions & 15 deletions src/cache.c
Original file line number Diff line number Diff line change
Expand Up @@ -9,19 +9,34 @@
*/
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 *new_cache_entry);

// 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_length = content_length;

new_cache_entry->content = malloc(content_length);
memcpy(new_cache_entry->content, content, content_length);

new_cache_entry->prev = new_cache_entry->next = NULL;

return new_cache_entry;
}

/**
* Deallocate a cache entry
*/
void free_entry(struct cache_entry *entry)
{
///////////////////
// IMPLEMENT ME! //
///////////////////
free(entry->path);
free(entry->content_type);
free(entry->content);
free(entry);
}

/**
Expand Down Expand Up @@ -91,9 +106,14 @@ 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(hashsize, NULL);
cache->head = cache->tail = NULL;
cache->cur_size = 0;
cache->max_size = max_size;

return cache;
}

void cache_free(struct cache *cache)
Expand Down Expand Up @@ -122,17 +142,35 @@ 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 *entry = alloc_entry(path, content_type, content, content_length);

dllist_insert_head(cache, entry);

hashtable_put(cache->index, path, entry);

cache->cur_size++;

if (cache->cur_size > cache->max_size) {
struct cache_entry *removed_cache_entry = dllist_remove_tail(cache);
hashtable_delete(cache->index, removed_cache_entry->path);
free_entry(removed_cache_entry);
if (cache->cur_size != cache->max_size) {
cache->cur_size = cache->max_size;
}
}
}

/**
* Retrieve an entry from the cache
*/
struct cache_entry *cache_get(struct cache *cache, char *path)
{
///////////////////
// IMPLEMENT ME! //
///////////////////
struct cache_entry *entry = hashtable_get(cache->index, path);

if (entry == NULL) {
return NULL;
}

dllist_move_to_head(cache, entry);
return entry;
}
2 changes: 1 addition & 1 deletion src/file.c
Original file line number Diff line number Diff line change
Expand Up @@ -72,4 +72,4 @@ void file_free(struct file_data *filedata)
{
free(filedata->data);
free(filedata);
}
}
95 changes: 66 additions & 29 deletions src/server.c
Original file line number Diff line number Diff line change
Expand Up @@ -52,12 +52,30 @@ 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];


// Generate date
time_t rawtime;
struct tm *current_time;
time(&rawtime);
current_time = localtime(&rawtime);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is pretty much exactly what I have. Well done.


// Build HTTP response and store it in response

///////////////////
// IMPLEMENT ME! //
///////////////////
sprintf(response,
"%s\n"
"Date: %s" // Example: Wed Dec 20 13:05:11 PST 2017
"Connection: close\n"
"Content-Length: %d\n"
"Content-Type: %s\n"
"\n"
"%s",
header,
asctime(current_time),
content_length,
content_type,
body
);

int response_length = strlen(response);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can also set int response_length = sprintf(...), which returns the length of the sprintf.


// Send it all!
int rv = send(fd, response, response_length, 0);
Expand All @@ -76,16 +94,13 @@ 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
srand(time(NULL));
char random_number_string[20];
int random_number = rand() % 20;
sprintf(random_number_string, "%d", random_number);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's smart to print this to a string because of what send_response() accepts.


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

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

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

/**
Expand All @@ -94,7 +109,7 @@ void get_d20(int fd)
void resp_404(int fd)
{
char filepath[4096];
struct file_data *filedata;
struct file_data *filedata;
char *mime_type;

// Fetch the 404.html file
Expand All @@ -119,9 +134,26 @@ 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 *cached_file = cache_get(cache, request_path);

if (cached_file != NULL) {
send_response(fd, "HTTP/1.1 200 OK", cached_file->content_type, cached_file->content, cached_file->content_length);
} else {
sprintf(filepath, "./serverroot%s", request_path);

mime_type = mime_type_get(filepath);

filedata = file_load(filepath);

send_response(fd, "HTTP/1.1 200 OK", mime_type, filedata->data, filedata->size);

cache_put(cache, request_path, mime_type, filedata->data, filedata->size);

file_free(filedata);
}
}

/**
Expand All @@ -144,6 +176,8 @@ void handle_http_request(int fd, struct cache *cache)
{
const int request_buffer_size = 65536; // 64K
char request[request_buffer_size];
char method[200];
char path[8192];

// Read request
int bytes_recvd = recv(fd, request, request_buffer_size - 1, 0);
Expand All @@ -153,19 +187,22 @@ void handle_http_request(int fd, struct cache *cache)
return;
}


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

// Read the three components of the first request line

sscanf(request, "%s %s", method, path);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You'll also want to add an http_version to this sscanf.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the feedback Grant! I'll try to incorporate it today.


// 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) {
// Check if it's /d20 and handle that special case
get_d20(fd);
} else if (path != NULL) {
// Otherwise serve the requested file by calling get_file()
get_file(fd, cache, path);
} else {
resp_404(fd);
}
}

// (Stretch) If POST, handle the post request
}

Expand All @@ -187,7 +224,7 @@ int main(void)
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
Expand Down