diff --git a/Makefile b/Makefile
index 34a2077..a4b8202 100644
--- a/Makefile
+++ b/Makefile
@@ -1,26 +1,22 @@
-all: server
+# ----- Variables for customization -----
+CC = gcc # Compiler (you can change to clang if desired)
+CFLAGS = -g3 -Wall -Wextra -fsanitize=address,undefined # Standard flags + debugging & warnings
+LDFLAGS = # Linker flags, if any
+# ----- Automatic dependency tracking -----
+SRCS := $(wildcard *.c) # Find all .c source files
+OBJS := $(SRCS:.c=.o) # Corresponding object files (.o)
+HDRS := $(SRCS:.c=.h)
+
+# ----- Targets -----
+server: $(OBJS)
+ $(CC) $(CFLAGS) $(OBJS) -o server $(LDFLAGS)
+
+# Create object files from source files
+%.o: %.c %.h
+ $(CC) $(CFLAGS) -c $< -o $@
+
+# Phony target for cleaning
+.PHONY: clean
clean:
- @rm -rf *.o
- @rm -rf server
-
-server: main.o server.o request.o header.o utils.o response.o
- gcc -g3 -fsanitize=address,undefined -o server $^
-
-main.o: main.c
- gcc -g3 -fsanitize=address,undefined -c -o main.o main.c
-
-server.o: server.c server.h
- gcc -g3 -fsanitize=address,undefined -c -o server.o server.c
-
-request.o: request.c request.h
- gcc -g3 -fsanitize=address,undefined -c -o request.o request.c
-
-response.o: response.c response.h
- gcc -g3 -fsanitize=address,undefined -c -o response.o response.c
-
-header.o: header.c header.h
- gcc -g3 -fsanitize=address,undefined -c -o header.o header.c
-
-utils.o: utils.c utils.h
- gcc -g3 -fsanitize=address,undefined -c -o utils.o utils.c
+ rm -f $(OBJS) server
diff --git a/clicked.html b/clicked.html
index beb9256..3721df5 100644
--- a/clicked.html
+++ b/clicked.html
@@ -1 +1 @@
-
It works!
+see?
diff --git a/header.c b/header.c
index d5f3a79..deec1d2 100644
--- a/header.c
+++ b/header.c
@@ -1,8 +1,9 @@
#include "header.h"
+#include
struct Header header_constructor(char *key, char *value) {
struct Header header;
- header.key = key;
- header.value = value;
+ header.key = strdup(key);
+ header.value = strdup(value);
return header;
}
diff --git a/index.html b/index.html
index a20480d..c9d14c9 100644
--- a/index.html
+++ b/index.html
@@ -1,7 +1,23 @@
-
+
+
+
+
+
Michael Thomson
+
+
-
-
-
+
+
+
+ Michael Thomson
+ Welcome to my site! doesn't it have so much content? I know, right?
+ It even has reactivity!
+
+
+
+
+
+
+
diff --git a/main.c b/main.c
index 6eb7587..d674725 100644
--- a/main.c
+++ b/main.c
@@ -1,8 +1,19 @@
+#include "request.h"
#include "server.h"
#include
+char *home(struct Request request) {
+ return read_file("index.html");
+}
+
+char *clicked(struct Request request) {
+ return read_file("clicked.html");
+}
+
int main(void) {
struct Server server = server_constructor("3000");
+ add_route(&server, "GET", "/", home);
+ add_route(&server, "POST", "/clicked", clicked);
launch(&server);
return EXIT_SUCCESS;
}
diff --git a/response.c b/response.c
index f83ef51..148008e 100644
--- a/response.c
+++ b/response.c
@@ -1,23 +1,31 @@
#include "response.h"
#include "header.h"
#include
+#include
#include
#define MAX_BUFFER_SIZE 2048
-struct Response response_constructor(char *version, char *status, char *body,
- int num_headers, struct Header *headers) {
+struct Response response_constructor(char *version, char *status, char *body) {
struct Response response;
- response.version = version;
- response.status = status;
- response.body = body;
- response.num_headers = num_headers;
- response.headers = headers;
+ response.version = strdup(version);
+ response.status = strdup(status);
+ response.body = strdup(body);
+ response.num_headers = 0;
+ response.headers = NULL;
return response;
}
+void add_header(struct Response *response, char *key, char *value) {
+ struct Header header = header_constructor(key, value);
+ response->headers = realloc(
+ response->headers, sizeof(struct Header) * (response->num_headers + 1));
+ response->headers[response->num_headers++] = header;
+}
+
void response_to_string(char *buf, struct Response *response) {
char headers[MAX_BUFFER_SIZE];
+ headers[0] = '\0';
for (int i = 0; i < response->num_headers; i++) {
strcat(headers, response->headers[i].key);
@@ -26,6 +34,7 @@ void response_to_string(char *buf, struct Response *response) {
strcat(headers, "\r\n");
}
+
snprintf(buf, MAX_BUFFER_SIZE, "%s %s\r\n%s\r\n%s", response->version,
response->status, headers, response->body);
}
diff --git a/response.h b/response.h
index c021a0e..5c71aac 100644
--- a/response.h
+++ b/response.h
@@ -13,9 +13,10 @@ struct Response {
struct Header *headers;
};
-struct Response response_constructor(char *version, char *status, char *body,
- int num_headers, struct Header *headers);
+struct Response response_constructor(char *version, char *status, char *body);
void response_to_string(char *buf, struct Response *response);
+void add_header(struct Response *response, char *key, char *value);
+
#endif // !RESPONSE_H
diff --git a/route.c b/route.c
new file mode 100644
index 0000000..bf1af16
--- /dev/null
+++ b/route.c
@@ -0,0 +1,12 @@
+#include
+
+#include "route.h"
+
+struct Route route_constructor(char *target, char *method,
+ Route_Callback route_callback) {
+ struct Route route;
+ route.target = strdup(target);
+ route.method = strdup(method);
+ route.route_callback = route_callback;
+ return route;
+}
diff --git a/route.h b/route.h
new file mode 100644
index 0000000..ceba521
--- /dev/null
+++ b/route.h
@@ -0,0 +1,17 @@
+#ifndef ROUTE_H
+#define ROUTE_H
+
+#include "request.h"
+
+typedef char *(*Route_Callback)(struct Request request);
+
+struct Route {
+ char *target;
+ char *method;
+ Route_Callback route_callback;
+};
+
+struct Route route_constructor(char *target, char *method,
+ Route_Callback route_callback);
+
+#endif // !ROUTE_H
diff --git a/server b/server
index 1d595ce..3258c4f 100755
Binary files a/server and b/server differ
diff --git a/server.c b/server.c
index 805c02e..891f6fc 100644
--- a/server.c
+++ b/server.c
@@ -8,9 +8,9 @@
#include
#include
-#include "header.h"
#include "request.h"
#include "response.h"
+#include "route.h"
#include "server.h"
#define MAX_BUFFER_SIZE 2048
@@ -18,12 +18,32 @@
int sockfd;
-struct Server server_constructor(char *PORT) {
+struct Server server_constructor(const char *PORT) {
struct Server server;
server.PORT = PORT;
+ server.num_routes = 0;
+ server.routes = NULL;
return server;
}
+void add_route(struct Server *server, char *method, char *target,
+ Route_Callback route_callback) {
+ struct Route route = route_constructor(target, method, route_callback);
+ server->routes =
+ realloc(server->routes, sizeof(struct Route) * (server->num_routes + 1));
+ server->routes[server->num_routes++] = route;
+}
+
+struct Route *match_route(struct Server *server, char *method, char *target) {
+ for (int i = 0; i < server->num_routes; i++) {
+ if (strcmp(server->routes[i].target, target) == 0 &&
+ strcmp(server->routes[i].method, method) == 0) {
+ return &server->routes[i];
+ }
+ }
+ return NULL;
+}
+
void sigchld_handler(int s) {
// waitpid() might overwrite errno, so we save and restore it:
int saved_errno = errno;
@@ -90,7 +110,7 @@ static void start(const char *PORT) {
}
}
-char *read_file(char *filename, size_t *file_size) {
+char *read_file(char *filename) {
// read in file
FILE *fp = fopen(filename, "r");
if (fp == NULL) {
@@ -100,11 +120,11 @@ char *read_file(char *filename, size_t *file_size) {
// Calculate the content length
fseek(fp, 0, SEEK_END);
- *file_size = ftell(fp);
+ size_t file_size = ftell(fp);
rewind(fp);
// allocate memory for file contents
- char *buffer = malloc(*file_size + 1);
+ char *buffer = malloc(file_size + 1);
if (buffer == NULL) {
fprintf(stderr, "read_file: memory allocation failed.\n");
fclose(fp);
@@ -112,8 +132,8 @@ char *read_file(char *filename, size_t *file_size) {
}
// Read the file contents into buffer
- size_t bytes_read = fread(buffer, 1, *file_size, fp);
- if (bytes_read != *file_size) {
+ size_t bytes_read = fread(buffer, 1, file_size, fp);
+ if (bytes_read != file_size) {
fprintf(stderr, "read_file: error reading file.\n");
free(buffer);
fclose(fp);
@@ -121,41 +141,37 @@ char *read_file(char *filename, size_t *file_size) {
}
fclose(fp);
- buffer[*file_size] = '\0';
+ buffer[file_size] = '\0';
return buffer;
}
-void respond(int *client_fd) {
-
+void respond(struct Server *server, int *client_fd) {
+ // Recieve request
char buf[MAX_BUFFER_SIZE];
recv(*client_fd, buf, MAX_BUFFER_SIZE, 0);
+ // Parse request
struct Request request = request_constructor(buf);
- printf("%s %s %s\n", request.method, request.target, request.version);
+ // Match route and get body content
+ struct Route *matched_route =
+ match_route(server, request.method, request.target);
- char *filename;
- if (strcmp(request.target, "/") == 0) {
- filename = "index.html";
- } else if (strcmp(request.target, "/clicked") == 0) {
- filename = "clicked.html";
+ struct Response response;
+ if (matched_route == NULL) {
+ response = response_constructor("HTTP/1.1", NOT_FOUND, "Not found");
} else {
- filename = "404.html";
+ char *body = matched_route->route_callback(request);
+ response = response_constructor("HTTP/1.1", OK, body);
}
- size_t body_length;
- char *body = read_file(filename, &body_length);
+ // calculate content length
+ char body_length[12];
+ snprintf(body_length, sizeof(body_length), "%lu", strlen(response.body));
+ add_header(&response, "Content-Length", body_length);
- // Create the Content-Length header
- struct Header headers[MAX_HEADER_NUM];
- char contentLength[MAX_BUFFER_SIZE];
- snprintf(contentLength, sizeof(contentLength), "%zu", body_length);
- headers[0] = header_constructor("Content-Length", contentLength);
-
- // construct response
- struct Response response =
- response_constructor("HTTP/1.1", OK, body, 1, headers);
+ printf("%s %s -> %s\n", request.method, request.target, response.status);
// send response string
char response_string[MAX_BUFFER_SIZE];
@@ -165,8 +181,6 @@ void respond(int *client_fd) {
perror("send content");
exit(1);
}
-
- free(body);
}
void launch(struct Server *server) {
@@ -185,7 +199,7 @@ void launch(struct Server *server) {
if (!fork()) {
close(sockfd);
- respond(&client_fd);
+ respond(server, &client_fd);
close(client_fd);
exit(0);
}
diff --git a/server.h b/server.h
index c7ff4af..5851e4c 100644
--- a/server.h
+++ b/server.h
@@ -2,15 +2,23 @@
#define SERVER_H
#include "header.h"
+#include "route.h"
#define BACKLOG 128
struct Server {
const char *PORT;
+ struct Route *routes;
+ int num_routes;
};
-struct Server server_constructor(char *PORT);
+struct Server server_constructor(const char *PORT);
+
+void add_route(struct Server *server, char *method, char *target,
+ Route_Callback route_callback);
void launch(struct Server *server);
+char *read_file(char *filename);
+
#endif // !SERVER_H