diff --git a/hashtable.c b/hashtable.c
index a02d701a184cc1ad77aca95678480583a7b5b54a..4238967ba680b9bac7e68eedbc90db66818c5f27 100644
--- a/hashtable.c
+++ b/hashtable.c
@@ -54,6 +54,8 @@ Bucket *add_to_bucket(Bucket *bucket, char *key, char *value) {
 	//adds new key and avlue to end of bucket
 	bucket->values[bucket->n_elems-1] = value;
 	bucket->keys[bucket->n_elems-1] = key;
+	// printf("key is %s\n\n", bucket->keys[bucket->n_elems-1]);
+	// printf("value is %s\n\n", bucket->values[bucket->n_elems-1]);
 	return bucket;
 }
 /************************************************************************/
@@ -111,14 +113,12 @@ void hash_table_put(HashTable *table, char *key, char *value) {
 	for (int i=0; i < bucket->n_elems; i++){
 		if (equal(bucket->keys[i], key)){
 			bucket->values[i] = value;
-			move_to_front(bucket, i);
 			return;
 		}
 	}
 	// adds key and value as not in hash table
 	bucket = add_to_bucket(bucket, key, value);
 	table->buckets[hash_value] = *bucket;
-	move_to_front(bucket, bucket->n_elems - 1);
 }
 /************************************************************************/
 void move_to_front(Bucket *bucket, int index){
@@ -176,7 +176,7 @@ bool hash_table_has(HashTable *table, char *key) {
 	return false;
 }
 char* print_hash_map(HashTable *table){
-	char* headers = calloc(100,sizeof(char));
+	char* headers = calloc(800,sizeof(char));
 	assert(headers);
 	for (int i = 0; i < table->size; i++) {
 		if (table->buckets[i].n_elems > 0){
@@ -204,4 +204,15 @@ void free_cookie(HashTable *headers) {
 			free(bucket->values[i]);
 		}
 	}
-}
\ No newline at end of file
+}
+
+void free_hash_map(HashTable *table){
+	for (int i = 0; i < table->size; i++) {
+		if (table->buckets[i].n_elems > 0){
+			for (int j=0; j< table->buckets[i].n_elems; j++){
+				free(table->buckets[i].keys[j]);
+				free(table->buckets[i].values[j]);
+			}
+		}
+	}
+}
diff --git a/hashtable.h b/hashtable.h
index 4f503861db0dfb7cb9a084f685148586a1352ab5..0a266fdf7d2e6f37cb38f82f4106e4c9728b12ed 100644
--- a/hashtable.h
+++ b/hashtable.h
@@ -25,4 +25,6 @@ bool hash_table_has(HashTable *table, char *key);
 
 char* print_hash_map(HashTable *table);
 
-void free_cookie(HashTable *headers);
\ No newline at end of file
+void free_cookie(HashTable *headers);
+
+void free_hash_map(HashTable *table);
\ No newline at end of file
diff --git a/http-parser.c b/http-parser.c
index a5a5a27e83f58a38fe73c91a9e568c9d37fb8416..1d80197a72e17b826d2e120b5c2a47f76b931eb5 100644
--- a/http-parser.c
+++ b/http-parser.c
@@ -9,20 +9,20 @@
 #include <string.h>
 #include <assert.h>
 #include "http-parser.h"
+#include "hashtable.h"
 
 // user-determined constants for requests
 #define MAX_URL_SIZE 60
-#define MAX_HEADER_SIZE 600
+#define MAX_HEADER_SIZE 200
 #define MAX_VERSION_SIZE 10
-#define MAX_HEADERS 10
+#define MAX_HEADERS 20
 
 Request* parse_request(char* request_message){
     /**
      * Reads a requests and creates a request object containing the parsed information
      * */
-    Request *req = calloc(1, sizeof(Request));
+    Request *req = calloc(1, sizeof *req);
 	assert(req);
-    memset(req, 0, sizeof(Request));
 
     // parses the method of the request
     if (strncmp(request_message, "GET ", 4) == 0){
@@ -47,20 +47,13 @@ Request* parse_request(char* request_message){
     //parses the headers
     req->header = new_hash_table(MAX_HEADERS);
 
-    char header_field_name[MAX_HEADER_SIZE];
-    char header_value[MAX_HEADER_SIZE];
+    // char *header_field_name = calloc(MAX_HEADER_SIZE, sizeof(char));
+    // char *header_value = calloc(MAX_HEADER_SIZE, sizeof(char));
     while(*request_message != '\r' && *request_message != '\n'){
-    //    printf("req message first char %d\n", *request_message);
-       strcpy(header_field_name,strtok(request_message, " "));
-    //    printf("header field name: %s\n", header_field_name);
-       request_message += strcspn(request_message, " ")+1;
-       strcpy(header_value,strtok(request_message, "\r\n"));
-    //    printf("header value: %s\n", header_value);
-       request_message += strcspn(request_message, "\r\n")+2;
-       hash_table_put(req->header, header_field_name, header_value);
+        request_message = insert_headers(request_message, req);
+    
     }
     request_message += strcspn(request_message, "\r\n")+2;
-
     // parses the body
     if(*request_message != '\r'||*request_message != '\n'){
         req->body = request_message;
@@ -71,10 +64,26 @@ Request* parse_request(char* request_message){
     return req;
 }
 
+char* insert_headers(char* request_message, Request * req){
+    char *header_field_name = calloc(MAX_HEADER_SIZE, sizeof(char));
+    char *header_value = calloc(MAX_HEADER_SIZE, sizeof(char));
+    memset(header_field_name,0,strlen(header_field_name));
+        memset(header_value,0,strlen(header_value));
+        size_t field_len = strcspn(request_message, " ");
+        memcpy(header_field_name, request_message,field_len);
+        request_message += field_len+1;
+        size_t value_len = strcspn(request_message, "\r\n");
+        memcpy(header_value,request_message, value_len);
+       request_message += value_len+2;
+       hash_table_put(req->header, header_field_name, header_value);
+       return request_message;
+}
+
 void free_request(Request* req){
     /**
      * Deallocates memory
      * */
+    free_hash_map(req->header);
     free_hash_table(req->header);
     free(req);
 }
diff --git a/http-parser.h b/http-parser.h
index 203079e02a40928617fcebe05b6c2d1f8dbfadfd..03433854d3b4f6e63972565c8201da129f92b148 100644
--- a/http-parser.h
+++ b/http-parser.h
@@ -27,4 +27,6 @@ typedef struct Request {
 Request* parse_request(char* request_message);
 
 // Deallocates memory
-void free_request(Request* req);
\ No newline at end of file
+void free_request(Request* req);
+
+char* insert_headers(char* request_message, Request * req);
\ No newline at end of file
diff --git a/http-response.c b/http-response.c
index 626b5d95ee0c02f51e5055ec4daacbd8937f5868..66efeb7ae8bdf3db240c0195c4b4cc07c0598cc2 100644
--- a/http-response.c
+++ b/http-response.c
@@ -16,7 +16,7 @@
 #define MAX_URL_SIZE 60
 #define MAX_HEADER_SIZE 300
 #define MAX_VERSION_SIZE 10
-#define MAX_N_HEADERS 2
+#define MAX_N_HEADERS 4
 
 char* cookie_generator(){
     /**
@@ -24,7 +24,7 @@ char* cookie_generator(){
      * */
     char* cookie_value;
     cookie_value = (char*) malloc(sizeof(char)*60);
-    snprintf(cookie_value, 60, "sessionToken=%d; Expires=Wed, 01 Apr 2019 10:10:10 GMT", rand());
+    snprintf(cookie_value, 60, "id=%d", rand() % (111-0+1));
     return cookie_value;
 }
 
@@ -44,7 +44,9 @@ Response* initialise_session(Request* request){
 
     // sets the cookies
     char *cookie = cookie_generator();
+    hash_table_put(resp->header, "Content-length: ", "%ld");
     hash_table_put(resp->header, "Set-cookie: ", cookie);
+    hash_table_put(resp->header, "Content-type: ", "text/html");
 
     // sends empty body
     resp->body="";
@@ -69,8 +71,14 @@ char* parse_response(Response* response){
     strncat(response_string, headers, strlen(headers));
     strcat(response_string, "\r\n");
     strcat(response_string, response->body);
-    // free(headers);
-    return response_string;
+    strcat(response_string, "\r\n");
+    char * new_response_string = calloc(100,sizeof(char));
+    assert(new_response_string);
+    strncpy(new_response_string, response_string, strlen(response_string));
+    free(headers);
+    free(response_string);
+    return new_response_string;
+    // return response_string;
 }
 
 
diff --git a/http-server.c b/http-server.c
index 7317bc02bf79bbdb64dd3b838d4fc7564419bea1..17528a24ab792ac0a12b464115d32be39196d373 100644
--- a/http-server.c
+++ b/http-server.c
@@ -25,6 +25,7 @@
 #include <sys/types.h>
 #include <unistd.h>
 #include "response-formatter.h"
+#include "hashtable.h"
 #include "http-parser.h"
 #include "http-response.h"
 #include "hashtable.h"
@@ -40,7 +41,10 @@ static int const HTTP_400_LENGTH = 47;
 static char const * const HTTP_404 = "HTTP/1.1 404 Not Found\r\nContent-Length: 0\r\n\r\n";
 static int const HTTP_404_LENGTH = 45;
 
-volatile sig_atomic_t kill;
+// global structures required for memory deallocation
+static Request* req;
+static User_list* user_list;
+int keep_alive = 1;
 
 
 bool player_session(char* buff, int sockfd, char* file_name, char* response){
@@ -56,21 +60,23 @@ bool player_session(char* buff, int sockfd, char* file_name, char* response){
         perror("write");
         return false;
     }
-    // send the file
+    // read the content of the HTML file
     int filefd = open(file_name, O_RDONLY);
-    do
-    {
-        n = sendfile(sockfd, filefd, NULL, 2048);
-    }
-    while (n > 0);
+    n = read(filefd, buff, st.st_size);
+    clean_trailing_buffer(buff);
     if (n < 0)
     {
-        perror("sendfile");
+        perror("read");
         close(filefd);
         return false;
     }
     close(filefd);
-    return true;
+    if (write(sockfd, buff, st.st_size) < 0)
+    {
+        perror("write");
+        return false;
+    }
+	return true;
 }
 bool text_render_response(char *buff, int sockfd, char* file_name, char* text){
     /**
@@ -220,7 +226,7 @@ bool text_render_game_play(char *buff, int sockfd, char* file_name, char* text,
 	return true;
 }
 
-static bool handle_http_request(int sockfd, User_list *users){
+static bool handle_http_request(int sockfd, User_list *user_list){
     /**
      * Parses the http request and sends the approapriate response
      * */
@@ -241,71 +247,66 @@ static bool handle_http_request(int sockfd, User_list *users){
 
     char * curr = buff;
     // parse the method
-    Request* req = parse_request(curr);
-    User* user = get_current_user(users, sockfd);
-    // printf("REQUEST BODY IS \n\n%s\n", req->url);
-
+    req = parse_request(curr);
+    char* cookie = hash_table_get(req->header, "Cookie:");
+    int id = atoi(cookie+3);
+    User* user = get_current_user(user_list, id);
     // user should quit game
     if(strncmp(req->body, "quit=Quit", 9)  == 0){
-        printf("run\n\n\n\n\\n");
-        change_player_status(sockfd,users, QUIT);
-        response(buff,sockfd, "7_gameover.html");
-        // free_request(req);
-        // return false;
+        if (user != NULL){
+            change_player_status(id,user_list, QUIT);
+            response(buff,sockfd, "7_gameover.html");
+        }
     }
 
     // user starting game 
     else if (strncmp(req->url, "/?start=Start", 24)  == 0){
-        
         // user on first turn
-        if (req->method == GET){
-            change_player_status(sockfd, users, READY);
-            int round = change_player_round(sockfd, users);
-            game_change(buff,sockfd, "3_first_turn.html", round);
-        }
-        if (req->method == POST){
-            if(strncmp(req->body, "keyword=", 8)  == 0){
-
-                // checks if other player has quit
-                if(should_player_quit(users)){
-                    printf("is quit");
-                    change_player_status(sockfd,users, QUIT);
-                    response(buff,sockfd, "7_gameover.html");
-                    // free_request(req);
-                    // keep_alive = 0;
-                    // return false;
-                }
-
-                // checks if other player has not completed previous round
-                else if (different_round_discard(sockfd,users)){
-                    game_change(buff,sockfd, "5_discarded.html", user->round);
-                }
+        if (user != NULL){
+            if (req->method == GET){
+                change_player_status(id, user_list, READY);
+                int round = change_player_round(id, user_list);
+                game_change(buff,sockfd, "3_first_turn.html", round);
+            }
+            if (req->method == POST){
+                if(strncmp(req->body, "keyword=", 8)  == 0){
 
-                // checks if game won
-                else if(player_won(users)){
-                    response(buff,sockfd, "6_endgame.html");
-                    change_player_status(sockfd, users, WAIT);
-                }
+                    // checks if other player has quit
+                    if(should_player_quit(user_list)){
+                        change_player_status(id,user_list, QUIT);
+                        response(buff,sockfd, "7_gameover.html");
+                    }
 
-                //checks if the other player is not ready and discards keyword
-                else if(!players_ready(users) && user!= NULL){
-                    game_change(buff,sockfd, "5_discarded.html", user->round);
-                    //request(buff,sockfd, "5_discarded.html");
-                }
-                else{
-                    char* keyword = add_keyword(sockfd, users, req->body);
+                    // checks if other player has not completed previous round
+                    else if (different_round_discard(id,user_list)){
+                        game_change(buff,sockfd, "5_discarded.html", user->round);
+                    }
 
-                    // game ends as submitted keyword has been submitted by other player
-                    if(has_match_ended(users, keyword, sockfd)){
+                    // checks if game won
+                    else if(player_won(user_list)){
                         response(buff,sockfd, "6_endgame.html");
-                        change_all_status(users, COMPLETE);
+                        change_player_status(id, user_list, WAIT);
+                    }
+
+                    //checks if the other player is not ready and discards keyword
+                    else if(!players_ready(user_list) && user!= NULL){
+                        game_change(buff,sockfd, "5_discarded.html", user->round);
+                        //request(buff,sockfd, "5_discarded.html");
                     }
                     else{
-                        // keyword hasn't been submitted yet so is accepted and rendered on screen
-                        if(user!= NULL){
-                            char* keywords = return_all_keywords(user);
-                            text_render_game_play(buff,sockfd, "4_accepted.html", keywords, user->round);
-                            free(keywords);
+                        char* keyword = add_keyword(id, user_list, req->body);
+                        // game ends as submitted keyword has been submitted by other player
+                        if(has_match_ended(user_list, keyword, id)){
+                            response(buff,sockfd, "6_endgame.html");
+                            change_all_status(user_list, COMPLETE);
+                        }
+                        else{
+                            // keyword hasn't been submitted yet so is accepted and rendered on screen
+                            if(user!= NULL){
+                                char* keywords = return_all_keywords(user);
+                                text_render_game_play(buff,sockfd, "4_accepted.html", keywords, user->round);
+                                free(keywords);
+                            }
                         }
                     }
                 }
@@ -319,44 +320,40 @@ static bool handle_http_request(int sockfd, User_list *users){
         // user's name stored and rendered on screen
         if (req->method == POST)
         {
-           char *name = strchr(req->body, '=')+1;
-            // printf("**%s**\n", name);
+            size_t name_len = strlen(req->body+5);
+            char *name = calloc(name_len+1, sizeof(char));
+           assert(name);
+           memcpy(name,req->body+5, name_len);
             if (name != NULL){
-                 for (int i=0; i < users->n_users; i++){
-                     if(users->users[i]->id == sockfd){
-                         users->users[i]->name = name;
+                 for (int i=0; i < user_list->n_users; i++){
+                     if(user_list->users[i]->id == id){
+                        user_list->users[i]->name = name;
                      }
                  }
-                // get_request(buff,sockfd, "2_start.html");
                text_render_response(buff,sockfd, "2_start.html", req->body+5);
             }
         }
 
-        // user is created
-        else if (req->method == GET)
+        // new user is created
+        else if (req->method == GET && !hash_table_has(req->header, "Cookie:"))
         {
-            // printf("matches a / url but url isize is %zu\n\n", strlen(req->url));
-            // Response* resp = initialise_session(req);
-            // char* resp_string = parse_response(resp);
-            // printf("COOKIE CREATING RESP %s\n", resp_string);
-            // player_session(buff, sockfd, "1_welcome.html", resp_string);
-            // User* new_player = new_user(sockfd);
-            // add_user(new_player, users);
-            // char* cookie = hash_table_get(resp->header, "Set-cookie: ")+13;
-            // cookie = strtok(cookie, ";");
-            // printf("the cookie token is %s*****\n", cookie);
-            // free(resp_string);
-            // free_response(resp); 
-
-            // ensures user is not already playing/in system
-            for(int i =0; i< users->n_users; i++){
-                if(sockfd == users->users[i]->id){
-                    return false;
-                }
+            // create a new user and assign it a new cookie
+            Response* resp = initialise_session(req);
+            char* resp_string = parse_response(resp);
+            char* cookie = hash_table_get(resp->header, "Set-cookie: ");
+            User* new_player = new_user(atoi(cookie+3));
+            add_user(new_player, user_list);
+            player_session(buff, sockfd, "1_welcome.html", resp_string);
+            free(cookie);
+            free(resp_string);
+            free_response(resp); 
+        }
+        else if (req->method == GET){
+            if (user != NULL){
+                // Resets returning user to round 1
+                user->round = 0;
+                text_render_response(buff,sockfd, "2_start.html", user->name);
             }
-            User* new_player = new_user(sockfd);
-            add_user(new_player, users);
-            response(buff,sockfd, "1_welcome.html");
         }
         else
             // unrecognised methods
@@ -369,25 +366,7 @@ static bool handle_http_request(int sockfd, User_list *users){
         perror("write");
         return false;
     }
-    printf("the numer of users is %d\n", users->n_users);
-    for(int i=0; i < users->n_users; i++){
-        printf("USER ID %d", users->users[i]->id);
-        if(users->users[i]->status == READY){
-            printf("is ready\n");
-        }
-        if(users->users[i]->status == WAIT){
-            printf("is wait\n");
-        }
-        if(users->users[i]->status == QUIT){
-            printf("is quit\n");
-        }
-        if(users->users[i]->status == COMPLETE){
-            printf("is complete\n");
-        }
-        if(users->users[i]->status == RESTART){
-            printf("is restart\n");
-        }
-    }
+    free(cookie);
 	free_request(req);
     return true;
 }
@@ -396,8 +375,10 @@ void exit_handler(int signum){
     /**
      * Closes TCP Connection
     */
-    kill = 1;
-    printf("keep alive changed");
+    keep_alive = 0;
+    if (user_list){
+        free_users(user_list);
+    }
 }
 
 
@@ -433,6 +414,7 @@ int main(int argc, char * argv[])
     // if ip parameter is not specified
     serv_addr.sin_addr.s_addr = inet_addr(argv[1]);
     serv_addr.sin_port = htons(atoi(argv[2]));
+    printf("image_tagger server is now running at IP: %s on port %s\n", argv[1], argv[2]);
     // bind address to socket
     if (bind(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0)
     {
@@ -451,7 +433,7 @@ int main(int argc, char * argv[])
     int maxfd = sockfd;
 
     // game players
-    User_list* users = initialise_player_list();
+    user_list = initialise_player_list();
     signal(SIGINT, exit_handler);
     while (!kill)
     {
@@ -494,7 +476,7 @@ int main(int argc, char * argv[])
                     }
                 }
                 // a request is sent from the client
-                else if (!handle_http_request(i,users))
+                else if (!handle_http_request(i,user_list))
                 {
                     close(i);
                     FD_CLR(i, &masterfds);
@@ -502,7 +484,5 @@ int main(int argc, char * argv[])
             }
         }
     }
-    printf("break loop");
-    free_users(users);
     return 0;
 }
diff --git a/user.c b/user.c
index 1bf913a767920d33a34e19ba387133921d30dd2e..d5cd6a493b7e26c68d4fb673aa6173a376d39da4 100644
--- a/user.c
+++ b/user.c
@@ -11,8 +11,8 @@
 #include "user.h"
 
 // implementation specific constants for users
-#define INITIAL_KEYWORDS 5
-#define INITAL_N_USERS 5
+#define INITIAL_KEYWORDS 20
+#define INITAL_N_USERS 10
 #define INITIAL_KEYWORD_LENGTH 30
 
 User* new_user(int id){
@@ -60,9 +60,6 @@ void resize_keywords(User* user, char* keyword){
     // adds keyword to user
     user->keywords[user->n_keywords] = keyword;
     user->n_keywords++;
-    for(int j=0; j<user->n_keywords; j++){
-        printf("%d: %s\n",j, user->keywords[j]);
-    }
 }
 
 
@@ -108,6 +105,7 @@ void free_users(User_list* user_list){
         //     free(&users->users[i]->keywords[j]);
         // }
         free(user_list->users[i]->keywords);
+        free(user_list->users[i]->name);
         free(user_list->users[i]);
     }
     free(user_list->users);
@@ -118,22 +116,36 @@ bool should_player_quit(User_list* user_list){
     /**
      * Checks if any player has quit, and tells player to quit if so 
      * */
+    int count = 0;
     for(int i=0; i < user_list->n_users; i++){
         if (user_list->users[i]->status == QUIT){
-            return true;
+            count++;
         }
     }
+    // checking edge case of 3 users, with one inactive user that has quit
+    if(count + 1 == user_list->n_users){
+        return true;
+    }
     return false;
 }
 bool players_ready(User_list* user_list){
     /**
      * checks if all players are ready
      * */
+    int count =0;
     for(int i=0; i < user_list->n_users; i++){
+        // other player is not ready
         if (user_list->users[i]->status != READY){
+            count++;
+        }
+        // only one player, need to wait
+        else if (user_list->n_users == 1){
             return false;
         }
     }
+    if(count + 1 == user_list->n_users){
+        return false;
+    }
     return true;
 }
 void change_player_status(int user_id, User_list* user_list, STATUS status){
@@ -195,11 +207,8 @@ bool keyword_match(User* user, char* keyword){
     /**
      * Checks if keyword has already been submitted
      * */
-    printf("keyword is %s\n\n", keyword);
     for(int i=0; i <user->n_keywords;i++){
-        printf("words being matched is with %s and %s\n", keyword, user->keywords[i]);
         if(strcmp(keyword, user->keywords[i]) == 0){
-            printf("match is with %s and %s\n", keyword, user->keywords[i]);
             return true;
         }
     }
@@ -263,9 +272,8 @@ char* return_all_keywords(User* user){
     /**
      * Returns all the keywords for a particular user
      * */
-    printf("%d\n\n\n", user->n_keywords);
     
-    int length = (user->n_keywords)*(INITIAL_KEYWORD_LENGTH+1);
+    int length = (user->n_keywords)*(INITIAL_KEYWORD_LENGTH+3);
     char *keywords = calloc(length, user->n_keywords);
     assert(keywords);
 
@@ -276,6 +284,5 @@ char* return_all_keywords(User* user){
     }
     // terminating byte
     keywords[strlen(keywords)-1] = '\0';
-    printf("**** %s \n   ", keywords);
     return keywords;
 }
\ No newline at end of file