Skip to content
Binary file added example/sprintf_example
Binary file not shown.
35 changes: 35 additions & 0 deletions example/sprintf_example.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
#include <stdio.h>
#include <string.h>

/*
HTTP/1.1 200 OK\n
Date: .... <--- would be here but not in this example
Content-Type: text/html\n
Content-Length: %d\n
Connection: close\n
\n <--- needs to be a new line that separates header from body
<Body goes here>
*/

// Example of how to build a response
int main(void)
{
// buffer to hold the res data
char response[500000];

char *body = "<h1>Hello, world!</h1>";
int length = strlen(body);

// Let's build the actual response now
sprintf(response,
"HTTP/1.1 200 OK\n"
"Content-Type: text/html\n"
"Content-Length: %d\n"
"Connection: close\n"
"\n"
"%s",
length, body);

printf("%s", response);
return 0;
}
Binary file added example/sscanf_example
Binary file not shown.
27 changes: 27 additions & 0 deletions example/sscanf_example.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
#include <stdio.h>

/*
given this request, how do we parse (extract important parts of it) it?
GET /foobar HTTP/1.1
Host: www.example.com
Connection: close

*/

int main(void)
{
char *s = "GET /foobar HTTP/1.1\nHost: www.example.com\nConnection: close\n";

// buffer to hold the method
char method[200];
// buffer to hold the path
char path[8192];

// take some string, supply a format specifier
// %s %s pulls out the first two strings which will be the GET and path
sscanf(s, "%s %s", method, path);

printf("method: %s\n", method);
printf("path: %s\n", path);
return 0;
}
114 changes: 87 additions & 27 deletions src/cache.c
Original file line number Diff line number Diff line change
Expand Up @@ -3,25 +3,42 @@
#include <string.h>
#include "hashtable.h"
#include "cache.h"

// day 2 stuff
/**
* Allocate a cache entry
*/
struct cache_entry *alloc_entry(char *path, char *content_type, void *content, int content_length)
{
///////////////////
// IMPLEMENT ME! //
///////////////////
// free spaces for cache entry
struct cache_entry *new_entry = malloc(sizeof(struct cache_entry));

// deep copy path
new_entry->path = malloc(strlen(path) + 1);
strcpy(new_entry->path, path);
// deep copy content type
new_entry->content_type = malloc(strlen(content_type) + 1);
strcpy(new_entry->content_type, content_type);
// deep copy content length
new_entry->content_length = malloc(strlen(content_length) + 1);
memcpy(new_entry->content_length, content, content_length);

new_entry->content_length = content_length;
new_entry->prev = new_entry->next = NULL;

return new_entry;
}

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

/**
Expand All @@ -30,10 +47,13 @@ void free_entry(struct cache_entry *entry)
void dllist_insert_head(struct cache *cache, struct cache_entry *ce)
{
// Insert at the head of the list
if (cache->head == NULL) {
if (cache->head == NULL)
{
cache->head = cache->tail = ce;
ce->prev = ce->next = NULL;
} else {
}
else
{
cache->head->prev = ce;
ce->next = cache->head;
ce->prev = NULL;
Expand All @@ -46,13 +66,16 @@ void dllist_insert_head(struct cache *cache, struct cache_entry *ce)
*/
void dllist_move_to_head(struct cache *cache, struct cache_entry *ce)
{
if (ce != cache->head) {
if (ce == cache->tail) {
if (ce != cache->head)
{
if (ce == cache->tail)
{
// We're the tail
cache->tail = ce->prev;
cache->tail->next = NULL;

} else {
}
else
{
// We're neither the head nor the tail
ce->prev->next = ce->next;
ce->next->prev = ce->prev;
Expand All @@ -65,10 +88,9 @@ void dllist_move_to_head(struct cache *cache, struct cache_entry *ce)
}
}


/**
* Removes the tail from the list and returns it
*
*
* NOTE: does not deallocate the tail
*/
struct cache_entry *dllist_remove_tail(struct cache *cache)
Expand All @@ -85,15 +107,21 @@ struct cache_entry *dllist_remove_tail(struct cache *cache)

/**
* Create a new cache
*
*
* max_size: maximum number of entries in the cache
* hashsize: hashtable size (0 for default)
*/
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 = 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 All @@ -102,7 +130,8 @@ void cache_free(struct cache *cache)

hashtable_destroy(cache->index);

while (cur_entry != NULL) {
while (cur_entry != NULL)
{
struct cache_entry *next_entry = cur_entry->next;

free_entry(cur_entry);
Expand All @@ -117,22 +146,53 @@ void cache_free(struct cache *cache)
* Store an entry in the cache
*
* This will also remove the least-recently-used items as necessary.
*
*
* NOTE: doesn't check for duplicate cache entries
*/
void cache_put(struct cache *cache, char *path, char *content_type, void *content, int content_length)
{
///////////////////
// IMPLEMENT ME! //
///////////////////
// Allocate a new cache entry
struct cache_entry *new_entry = alloc_entry(path, content_type, content, content_length);

// Insert the entry at the head of the dll
dllist_insert_head(cache, new_entry);

// Store the entry into the hashtable
hashtable_put(cache->index, path, new_entry);

// Increment the current size of the cache
cache->cur_size += 1;

// If the cache size is greater than max size
if (cache->cur_size > cache->max_size)
{
// Remove the entry from dll tail
struct cache_entry *old_entry = dllist_remove_tail(cache);
// remove the entry from hash
hashtable_delete(cache->index, old_entry->path);
// Free the cache entry
free_entry(old_entry);
// bring down current size to be no bigger than max size
if (cache->cur_size > cache->max_size)
{
cache->cur_size -= 1;
}
}
}

/**
* Retrieve an entry from the cache
*/
struct cache_entry *cache_get(struct cache *cache, char *path)
{
///////////////////
// IMPLEMENT ME! //
///////////////////
// if entry at index is NULL
if (hashtable_get(cache->index, path) == NULL)
{
return NULL;
}
else
{ // Move entry to head of the dll
dllist_move_to_head(cache, hashtable_get(cache->index, path));
return cache->head;
}
}
12 changes: 7 additions & 5 deletions src/cache.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,9 @@
#define _WEBCACHE_H_

// Individual hash table entry
struct cache_entry {
char *path; // Endpoint path--key to the cache
struct cache_entry
{ // each entry is a node
char *path; // Endpoint path--key to the cache
char *content_type;
int content_length;
void *content;
Expand All @@ -12,11 +13,12 @@ struct cache_entry {
};

// A cache
struct cache {
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
int max_size; // Maxiumum number of entries
int cur_size; // Current number of entries
};

extern struct cache_entry *alloc_entry(char *path, char *content_type, void *content, int content_length);
Expand Down
Loading