Skip to content

Integrating Cache into Server #315

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 5 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
70 changes: 55 additions & 15 deletions src/cache.c
Original file line number Diff line number Diff line change
Expand Up @@ -9,19 +9,24 @@
*/
struct cache_entry *alloc_entry(char *path, char *content_type, void *content, int content_length)
{
///////////////////
// IMPLEMENT ME! //
///////////////////
struct cache_entry *new_entry = malloc(sizeof(cache_entry));
new_entry->path = path;
new_entry->content_type = content_type;
new_entry->content_length = content_length;
new_entry->content = content;

return new_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 +96,13 @@ 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(max_size, hashsize);
cache->max_size = max_size;
cache->cur_size = 0;

return cache;
}

void cache_free(struct cache *cache)
Expand Down Expand Up @@ -122,17 +131,48 @@ void cache_free(struct cache *cache)
*/
void cache_put(struct cache *cache, char *path, char *content_type, void *content, int content_length)
{
///////////////////
// IMPLEMENT ME! //
///////////////////
// Allocate a new cache entry with the passed parameters. DONE
// Insert the entry at the head of the doubly-linked list. DONE
// Store the entry in the hashtable as well, indexed by the entry's path. DONE
// Increment the current size of the cache.
// If the cache size is greater than the max size:
// Remove the cache entry at the tail of the linked list.
// Remove that same entry from the hashtable, using the entry's path and the hashtable_delete function.
// Free the cache entry.
// Ensure the size counter for the number of entries in the cache is correct.

struct cache_entry *new_entry = alloc_entry(path, content_type, content, content_length);
dllist_insert_head(cache, new_entry);
hashtable_put(cache->index, path, new_entry);
cache->cur_size++;

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

free_entry(new_entry);



}

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

} else {
printf("Page not in cache/n");
}

return entry;

}
8 changes: 4 additions & 4 deletions src/cache.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,22 +2,22 @@
#define _WEBCACHE_H_

// Individual hash table entry
struct cache_entry {
typedef struct cache_entry {
char *path; // Endpoint path--key to the cache
char *content_type;
int content_length;
void *content;

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

// A cache
struct cache {
typedef 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
};
}cache;

extern struct cache_entry *alloc_entry(char *path, char *content_type, void *content, int content_length);
extern void free_entry(struct cache_entry *entry);
Expand Down
113 changes: 58 additions & 55 deletions src/server.c
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@
*
* (Posting data is harder to test from a browser.)
*/

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
Expand All @@ -33,12 +32,9 @@
#include "file.h"
#include "mime.h"
#include "cache.h"

#define PORT "3490" // the port users will be connecting to

#define PORT "8584" // the port users will be connecting to
#define SERVER_FILES "./serverfiles"
#define SERVER_ROOT "./serverroot"

/**
* Send an HTTP response
*
Expand All @@ -50,42 +46,40 @@
*/
int send_response(int fd, char *header, char *content_type, void *body, int content_length)
{
const int max_response_size = 262144;
const int max_response_size = 65536*5;
char response[max_response_size];
int response_length;

// Build HTTP response and store it in response
time_t t = time(NULL);
struct tm *date = localtime(&t);

///////////////////
// IMPLEMENT ME! //
///////////////////
response_length = sprintf(response,"%s\nDate: %sConnection: close\nContent-length: %d\nContent-Type: %s\n\n" \
,header,asctime(date),content_length,content_type);

// Send it all!
int rv = send(fd, response, response_length, 0);
// NOTE: Dont use sprintf to add body into response because it doesn't play well with void ptr.
memcpy(response+response_length, body, content_length);

printf("RESPONSE LENGTH: %d\n\n", response_length);

// Send it all!
int rv = send(fd, response, response_length+content_length, 0);
if (rv < 0) {
perror("send");
}

return rv;
}


/**
* Send a /d20 endpoint response
*/
void get_d20(int fd)
{
// Generate a random number between 1 and 20 inclusive

///////////////////
// IMPLEMENT ME! //
///////////////////
srand(time(NULL));

// Use send_response() to send it back as text/plain data
char random[5];
sprintf(random,"%d\n", 1 + rand() % 20);

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

/**
Expand Down Expand Up @@ -119,11 +113,23 @@ void resp_404(int fd)
*/
void get_file(int fd, struct cache *cache, char *request_path)
{
///////////////////
// IMPLEMENT ME! //
///////////////////
}
char filepath[1024];

snprintf(filepath, sizeof filepath, "./serverroot%s",request_path);


struct file_data *filedata = file_load(filepath);

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

char *mime_type = mime_type_get(request_path);

send_response(fd,"HTTP/1.1 200 OK", mime_type, filedata->data, filedata->size );
file_free(filedata);
}
/**
* Search for the end of the HTTP header
*
Expand All @@ -136,39 +142,39 @@ char *find_start_of_body(char *header)
// IMPLEMENT ME! // (Stretch)
///////////////////
}

/**
* Handle HTTP request and send response
*/
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;
}

// make sure req is correct
printf("request: %s\n", request);

char http_method[20], endpoint[20];
sscanf(request, "%s %s",http_method, endpoint);

if (strcmp(http_method,"GET") == 0)
{
if (strcmp(endpoint, "/d20")==0)
{
get_d20(fd);
} else {
get_file(fd,cache,endpoint);
}

///////////////////
// 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()


// (Stretch) If POST, handle the post request
} else {
resp_404(fd);
}
}

/**
* Main
*/
Expand All @@ -177,23 +183,19 @@ int main(void)
int newfd; // listen on sock_fd, new connection on newfd
struct sockaddr_storage their_addr; // connector's address information
char s[INET6_ADDRSTRLEN];

struct cache *cache = cache_create(10, 0);

// Get a listening socket
int listenfd = get_listener_socket(PORT);

if (listenfd < 0) {
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
// 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 @@ -205,22 +207,23 @@ int main(void)
continue;
}


// Print out a message that we got the connection
inet_ntop(their_addr.ss_family,
get_in_addr((struct sockaddr *)&their_addr),
s, sizeof s);
printf("server: got connection from %s\n", s);



// resp_404(newfd); test send_response()

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

handle_http_request(newfd, cache);

close(newfd);
}

// Unreachable code

return 0;
}

}
Binary file added src/serverroot/drake.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.