Skip to content
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# A Simple Web Server in C
# A Simple Web Server in C -

In this project, we'll finish the implementation of a web server in C.

Expand Down
64 changes: 49 additions & 15 deletions src/cache.c
Original file line number Diff line number Diff line change
Expand Up @@ -9,19 +9,32 @@
*/
struct cache_entry *alloc_entry(char *path, char *content_type, void *content, int content_length)
{
///////////////////
// IMPLEMENT ME! //
///////////////////
char *content_str = (char *) content;


struct cache_entry *entry = malloc(sizeof(struct cache_entry));

entry->path = strdup(path);
entry->content_type = strdup(content_type);

entry->content = strdup(content_str);
entry->content_length = content_length;

return entry;

}

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

/**
Expand Down Expand Up @@ -91,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 *cache = malloc(sizeof(struct cache));

cache->max_size = max_size;
cache->cur_size = 0;

cache->index = hashtable_create(hashsize, NULL);
cache->head = NULL;
cache->tail = NULL;

return cache;
}

void cache_free(struct cache *cache)
Expand Down Expand Up @@ -122,17 +142,31 @@ 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 *oldtail = dllist_remove_tail(cache);
hashtable_delete(cache->index, oldtail->path);
free_entry(oldtail);
}

}

/**
* 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) {
dllist_move_to_head(cache, entry);
return cache->head;
} else {
return NULL;
}
}
88 changes: 79 additions & 9 deletions src/server.c
Original file line number Diff line number Diff line change
Expand Up @@ -54,13 +54,12 @@ int send_response(int fd, char *header, char *content_type, void *body, int cont
char response[max_response_size];

// Build HTTP response and store it in response
int response_length = sprintf(response, "%s\nContent-Type: %s\nContent-Length: %d\nConnection: close\n\n", header, content_type, content_length);

///////////////////
// IMPLEMENT ME! //
///////////////////
memcpy(response+response_length, body, content_length);

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

if (rv < 0) {
perror("send");
Expand All @@ -73,20 +72,24 @@ int send_response(int fd, char *header, char *content_type, void *body, int cont
/**
* Send a /d20 endpoint response
*/
/*
void get_d20(int fd)
{
// Generate a random number between 1 and 20 inclusive

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

int *roll;
roll = (rand() % 20) + 1;
// Use send_response() to send it back as text/plain data
send_response(fd, "HTTP/1.1 200 OK", "text/plain", roll, sizeof(roll));

///////////////////
// IMPLEMENT ME! //
///////////////////
}
*/

/**
* Send a 404 response
Expand Down Expand Up @@ -122,6 +125,70 @@ 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);

//mime_type = mime_type_get(filepath);

/* if( cache_get(cache, filepath) != NULL ) {

printf("Found file in cache!\n");

struct cache_entry *entry = cache_get(cache, filepath);

send_response(fd, "HTTP/1.1 200 OK", entry->content_type, entry->content, entry->content_length);

} else {

printf("loading file from disk\n");

filedata = file_load(filepath);

if(filedata == NULL) {
resp_404(fd);
} else {

printf("storing file in cache\n");

cache_put(cache, filepath, mime_type, filedata->data, filedata->size);
send_response(fd, "HTTP/1.1 200 OK", mime_type, filedata->data, filedata->size);
file_free(filedata);
}

} */

//struct cache_entry *entry = cache_get(cache, filepath);

if ( cache_get(cache, request_path) == NULL ) {

printf("loading file from disk\n");

filedata = file_load(filepath);

mime_type = mime_type_get(filepath);

if(filedata == NULL) {
resp_404(fd);
} else {
printf("storing file in cache\n");
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);
}

} else {

printf("Found file in cache!\n");
struct cache_entry *entry = cache_get(cache, request_path);
send_response(fd, "HTTP/1.1 200 OK", entry->content_type, entry->content, entry->content_length);

}

}

/**
Expand All @@ -144,6 +211,8 @@ void handle_http_request(int fd, struct cache *cache)
{
const int request_buffer_size = 65536; // 64K
char request[request_buffer_size];
char action[100];
char endpoint[100];

// Read request
int bytes_recvd = recv(fd, request, request_buffer_size - 1, 0);
Expand All @@ -153,12 +222,14 @@ 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", action, endpoint);


get_file(fd, cache, endpoint);

// If GET, handle the get endpoints

Expand Down Expand Up @@ -193,7 +264,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.

while(1) {
socklen_t sin_size = sizeof their_addr;

Expand All @@ -213,7 +284,6 @@ int main(void)

// newfd is a new socket descriptor for the new connection.
// listenfd is still listening for new connections.

handle_http_request(newfd, cache);

close(newfd);
Expand Down