diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..55a55806cd470b372e48aec68d7b64052dd4b416
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,32 @@
+CC = gcc
+CFLAGS = -Wall -std=c99 -g
+# modify the flags here ^
+EXE = image_tagger
+OBJ = hashtable.o http-parser.o http-response.o http-server.o
+# add any new object files here ^
+# top (default) target
+all: $(EXE)
+
+# how to link executable
+$(EXE): $(OBJ)
+ $(CC) $(CFLAGS) -o $(EXE) $(OBJ) -lm
+
+# other dependencies
+http-parser.o: http-parser.h hashtable.h
+http-response.o: http-response.h http-parser.h hashtable.h
+http-server.o: http-parser.h
+
+# ^ add any new dependencies here (for example if you add new modules)
+
+
+# phony targets (these targets do not represent actual files)
+.PHONY: clean cleanly all CLEAN
+
+# `make clean` to remove all object files
+# `make CLEAN` to remove all object and executable files
+# `make cleanly` to `make` then immediately remove object files (inefficient)
+clean:
+ rm -f $(OBJ)
+CLEAN: clean
+ rm -f $(EXE)
+cleanly: all clean
\ No newline at end of file
diff --git a/hashtable.c b/hashtable.c
new file mode 100644
index 0000000000000000000000000000000000000000..c4955f3b5110b557992c101d052197373418e44a
--- /dev/null
+++ b/hashtable.c
@@ -0,0 +1,176 @@
+/* This hash table has been adapted by Abhisha Nirmalathas.
+ The original hash table it was adapted from was made
+ by Matt Farrugia <matt.farrugia@unimelb.edu.au, for Design of Algorithms.
+ This hash table uses separate chaining with an array.
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <string.h>
+
+#include "hashtable.h"
+
+typedef struct bucket Bucket;
+struct bucket {
+ char **keys; //array of words
+ char **values; //array of weighted frequencies, lower value is higher frequency
+ int capacity; //space available in bucket
+ int n_elems; //number of elements in bucket
+};
+
+struct table {
+ int size; //number of buckets
+ Bucket *buckets; //list of buckets
+};
+
+/************************************************************************/
+// moves recently accessed key & value to the front of bucket
+void move_to_front(Bucket *bucket, int hash_value);
+
+ unsigned int seed = 73802;
+ unsigned int xor_hash(const char *key, unsigned int size) {
+ unsigned int h = seed;
+
+ int i;
+ for (i = 0; key[i] != '\0'; i++) {
+ h = h ^ ((h << 5) + key[i] + (h >> 2));
+ }
+
+ return h % size;
+ }
+/************************************************************************/
+Bucket *add_to_bucket(Bucket *bucket, char *key, char *value) {
+ /*Adds new key and value to existing bucket*/
+ bucket->n_elems = bucket->n_elems + 1;
+ // allocates more memory if not enough space
+ if (bucket->capacity <= bucket->n_elems){
+ bucket->capacity = 2*(bucket->capacity + 1);
+ bucket->keys = realloc(bucket->keys,sizeof(char*) * (bucket->capacity));
+ bucket->values = realloc(bucket->values,sizeof(char*) * (bucket->capacity));
+ }
+ assert(bucket->keys);
+ assert(bucket->values);
+ //adds new key and avlue to end of bucket
+ bucket->values[bucket->n_elems-1] = value;
+ bucket->keys[bucket->n_elems-1] = key;
+ return bucket;
+}
+/************************************************************************/
+// Warning: does not free bucket->next
+void free_bucket(Bucket bucket) {
+ /*Deallocates memory in bucket*/
+ free(bucket.keys);
+ free(bucket.values);
+}
+
+
+/************************************************************************/
+HashTable *new_hash_table(int size) {
+ /*Builds a new hash table of input size*/
+ HashTable *table = malloc(sizeof *table);
+ assert(table);
+ table->size = size;
+ table->buckets = malloc(size * (sizeof *table->buckets));
+ assert(table->buckets);
+ int i;
+ for (i = 0; i < size; i++) {
+ table->buckets[i].keys = malloc(sizeof(char*));
+ table->buckets[i].values = malloc(sizeof(char*));
+ table->buckets[i].capacity = 0;
+ table->buckets[i].n_elems = 0;
+ }
+ return table;
+}
+/************************************************************************/
+void free_hash_table(HashTable *table) {
+ /*Deallocates memory from hash table*/
+ assert(table != NULL);
+ int i;
+ for (i = 0; i < table->size; i++) {
+ free_bucket(table->buckets[i]);
+ }
+ free(table->buckets);
+ free(table);
+}
+
+/************************************************************************/
+bool equal(char *a, char *b) {
+ /*Returns if a string is equal to another string*/
+ return strcmp(a, b) == 0;
+}
+
+/************************************************************************/
+void hash_table_put(HashTable *table, char *key, char *value) {
+ /*Inserts new key into hash table with weighted value*/
+ assert(table != NULL);
+ assert(key != NULL);
+ int hash_value = xor_hash(key, table->size);
+ // look for existing key
+ Bucket *bucket = &table->buckets[hash_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){
+ /*moves recently accessed key & value to the front of bucket*/
+ char* temp_key;
+ char* temp_value;
+ if (bucket->n_elems <= 1 && index >= bucket->n_elems){
+ return;
+ }
+ // swaps position of first element with recently accessed
+ temp_key = bucket->keys[index];
+ temp_value = bucket->values[index];
+ bucket->keys[index] = bucket->keys[0];
+ bucket->values[index] = bucket->values[0];
+ bucket->values[0] = temp_value;
+ bucket->keys[0] = temp_key;
+}
+/************************************************************************/
+char* hash_table_get(HashTable *table, char *key) {
+ /*Checks if key in hash table and returns value if present*/
+ char* freq = malloc(60*sizeof(char));
+ assert(table != NULL);
+ assert(key != NULL);
+
+ int hash_value = xor_hash(key, table->size);
+
+ // look for existing key
+ Bucket *bucket = &table->buckets[hash_value];
+ for (int i=0; i < bucket->n_elems; i++){
+ if (equal(bucket->keys[i], key)){
+ freq = bucket->values[i];
+ move_to_front(bucket, i);
+ break;
+ }
+ }
+ //returns value of key if found, else return -1
+ return freq;
+}
+/************************************************************************/
+bool hash_table_has(HashTable *table, char *key) {
+ /*Checks if the key exists in hash table*/
+ assert(table != NULL);
+ assert(key != NULL);
+
+ int hash_value = xor_hash(key, table->size);
+
+ // look for existing key
+ Bucket *bucket = &table->buckets[hash_value];
+ for (int i=0; i < bucket->n_elems; i++){
+ if (equal(bucket->keys[i], key)){
+ return true;
+ }
+ }
+ return false;
+}
diff --git a/hashtable.h b/hashtable.h
new file mode 100644
index 0000000000000000000000000000000000000000..9dbea8ad53f09d430fe208a01218e7c76fcdae44
--- /dev/null
+++ b/hashtable.h
@@ -0,0 +1,24 @@
+/* This hash table has been adapted by Abhisha Nirmalathas.
+ The original hash table it was adapted from was made
+ by Matt Farrugia <matt.farrugia@unimelb.edu.au, for Design of Algorithms.
+ This hash table uses separate chaining with an array.
+*/
+#include <stdbool.h>
+
+typedef struct table HashTable;
+
+
+//Creates a new hash table of input size
+HashTable *new_hash_table(int size);
+
+//Deallocates memory from hash table
+void free_hash_table(HashTable *table);
+
+//Inserts new key into hash table with weighted value
+void hash_table_put(HashTable *table, char *key, char *value);
+
+//checks if key in hash table and returns value if present
+char* hash_table_get(HashTable *table, char *key);
+
+//Checks if the key exists in hash table
+bool hash_table_has(HashTable *table, char *key);
diff --git a/http-parser.c b/http-parser.c
new file mode 100644
index 0000000000000000000000000000000000000000..92ac25cc6ef188883581e85713dd7659d90c20ed
--- /dev/null
+++ b/http-parser.c
@@ -0,0 +1,57 @@
+#include <errno.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include "http-parser.h"
+
+#define MAX_URL_SIZE 60
+#define MAX_HEADER_SIZE 300
+#define MAX_VERSION_SIZE 10
+
+Request* parse_request(char* request_message){
+ Request *req = malloc(sizeof *req);
+ assert(req);
+ int n_headers = 10;
+ if (strncmp(request_message, "GET ", 4) == 0){
+ req->method = GET;
+ request_message += 4;
+ printf("Its a get\n");
+ }
+ else if (strncmp(request_message, "POST ", 5) == 0){
+ request_message += 5;
+ req->method = POST;
+ printf("Its a post\n");
+ }
+ req->url = strtok(request_message, " ");
+ request_message += strlen(req->url)+1;
+ req->version = strtok(request_message, "\r\n");
+ request_message+= strlen(req->version)+2;
+ req->header = new_hash_table(10);
+
+ char header_field_name[MAX_HEADER_SIZE];
+ char header_value[MAX_HEADER_SIZE];
+ 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);
+ }
+ if(*request_message != '\r'||*request_message != '\n'){
+ req->body = request_message;
+ }
+ else{
+ req->body = "";
+ }
+ return req;
+}
+
+void free_request(Request* req){
+ free_hash_table(req->header);
+ free(req);
+}
\ No newline at end of file
diff --git a/http-parser.h b/http-parser.h
new file mode 100644
index 0000000000000000000000000000000000000000..501f33206e16e4d32bfdb074f26724f0207e64c2
--- /dev/null
+++ b/http-parser.h
@@ -0,0 +1,22 @@
+#include <stdbool.h>
+#include "hashtable.h"
+typedef enum
+{
+ GET,
+ POST,
+ UNKNOWN
+} METHOD;
+
+typedef struct Request {
+ METHOD method;
+ char *url;
+ char *version;
+ HashTable *header;
+ char *body;
+} Request;
+
+
+//Creates a new hash table of input size
+Request* parse_request(char* request_message);
+
+void free_request(Request* req);
\ No newline at end of file
diff --git a/http-response.c b/http-response.c
new file mode 100644
index 0000000000000000000000000000000000000000..feaf292603afbc30744710008a4b438cf1701840
--- /dev/null
+++ b/http-response.c
@@ -0,0 +1,21 @@
+#include <errno.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include "http-parser.h"
+#include "http-response.h"
+
+#define MAX_URL_SIZE 60
+#define MAX_HEADER_SIZE 300
+#define MAX_VERSION_SIZE 10
+
+Response* redirect(Request* request_message){
+
+}
+
+void free_response(Response* resp){
+ free_hash_table(resp->header);
+ free(resp);
+}
\ No newline at end of file
diff --git a/http-response.h b/http-response.h
new file mode 100644
index 0000000000000000000000000000000000000000..7fdf1ba387488577bb7dd9c36a53da5958f09c72
--- /dev/null
+++ b/http-response.h
@@ -0,0 +1,14 @@
+#include <stdbool.h>
+#include "hashtable.h"
+
+typedef struct Response {
+ int status_code;
+ char *version;
+ HashTable *header;
+ char* phrase;
+ char *body;
+} Response;
+
+
+//Creates a new hash table of input size
+Response *redirect(Request *req);
\ No newline at end of file
diff --git a/http-server.c b/http-server.c
index 562c41267c127adc8fa148673765315713232b6f..c6b45c5017d2f89e4073314c3f7bc51e20fc9ce0 100644
--- a/http-server.c
+++ b/http-server.c
@@ -19,6 +19,7 @@
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
+#include "http-parser.h"
// constants
static char const * const HTTP_200_FORMAT = "HTTP/1.1 200 OK\r\n\
@@ -29,13 +30,7 @@ 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;
-// represents the types of method
-typedef enum
-{
- GET,
- POST,
- UNKNOWN
-} METHOD;
+
bool get_request(char* buff, int sockfd, char* file_name){
// get the size of the file
@@ -68,7 +63,7 @@ bool get_request(char* buff, int sockfd, char* file_name){
bool post_request(char *buff, int sockfd, char* file_name){
// locate the username, it is safe to do so in this sample code, but usually the result is expected to be
// copied to another buffer using strcpy or strncpy to ensure that it will not be overwritten.
- char * username = strstr(buff, "user=") + 5;
+ char * username = strcpy(buff, "user=") + 5;
int username_length = strlen(username);
// the length needs to include the ", " before the username
long added_length = username_length + 2;
@@ -113,6 +108,7 @@ bool post_request(char *buff, int sockfd, char* file_name){
return true;
}
+
static bool handle_http_request(int sockfd)
{
// try to read the request
@@ -133,46 +129,28 @@ static bool handle_http_request(int sockfd)
char * curr = buff;
// parse the method
+ printf("cur is: %s\n\n", curr);
METHOD method = UNKNOWN;
- if (strncmp(curr, "GET ", 4) == 0)
- {
- curr += 4;
- method = GET;
- }
- else if (strncmp(curr, "POST ", 5) == 0)
- {
- curr += 5;
- method = POST;
- }
- else if (write(sockfd, HTTP_400, HTTP_400_LENGTH) < 0)
- {
- perror("write");
- return false;
- }
-
- // sanitise the URI
- while (*curr == '.' || *curr == '/')
- ++curr;
-
-printf("**************THE CURR IS %s\n\n\n", curr);
- if (strncmp(curr, "?start=Start", 12) == 0){
- printf("matches start");
- if (method == GET){
- get_request(buff,sockfd, "3_first_turn.html");
- }
+ Request* req = parse_request(curr);
+ printf("%s\n%s\n", req->url, req->version);
+ if (strncmp(req->url, "?start=Start", 12) == 0){
+ printf("matches start");
+ if (req->method == GET){
+ get_request(buff,sockfd, "3_first_turn.html");
+ }
+ if (req->method == POST){
+ post_request(buff,sockfd, "7_gameover.html");
+ }
}
// assume the only valid request URI is "/" but it can be modified to accept more files
- else if (*curr == ' ')
- if (method == GET)
+
+ else if (*req->url == '/')
+ if (req->method == GET)
{
- if (strncmp(curr, "start=Start", 11) == 0)
- {
- printf("is start start mort");
- }
printf("%s\n", curr);
get_request(buff,sockfd, "1_welcome.html");
}
- else if (method == POST)
+ else if (req->method == POST)
{
post_request(buff,sockfd, "2_start.html");
}
@@ -182,10 +160,11 @@ printf("**************THE CURR IS %s\n\n\n", curr);
// send 404
else if (write(sockfd, HTTP_404, HTTP_404_LENGTH) < 0)
{
+ free_request(req);
perror("write");
return false;
}
-
+ free_request(req);
return true;
}