-
Notifications
You must be signed in to change notification settings - Fork 1
/
server.c
146 lines (119 loc) · 3.66 KB
/
server.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
#include "server.h"
#include <stdlib.h>
#include <unistd.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <string.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <time.h>
Route routes[MAX_ROUTES];
int route_count = 0;
time_t raw;
struct tm * timeinfo;
void init_server(Server *server, int port){
server->port = port;
server->addrlen = sizeof(server->address);
if((server->server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0){
perror("socket failed");
exit(EXIT_FAILURE);
}
server->address.sin_family = AF_INET;
server->address.sin_addr.s_addr = INADDR_ANY;
server->address.sin_port = htons(port);
if(bind(server->server_fd, (struct sockaddr*)&server->address, server->addrlen) < 0){
perror("binding failed");
exit(EXIT_FAILURE);
}
}
void start_server(Server *server){
if(listen(server->server_fd, 5) < 0){
perror("listening failed");
exit(EXIT_FAILURE);
}
printf("Server is listening on Port %d\n", server->port);
int new_socket;
while((new_socket = accept(server->server_fd, (struct sockaddr*)&server->address, (socklen_t*)&server->addrlen)) >= 0){
handle_client(new_socket);
}
if(new_socket < 0){
perror("accept failed");
exit(EXIT_FAILURE);
}
}
void handle_client(int client_socket){
char buffer[BUFFER_SIZE] = {0};
int valread = recv(client_socket, buffer, BUFFER_SIZE - 1, MSG_PEEK);
if(client_socket < 0){
perror("recv failed");
exit(EXIT_FAILURE);
}
char method[METHOD_BUFFER_SIZE] = {0}, path[PATH_BUFFER_SIZE] = {0};
sscanf(buffer, "%s %s", method, path);
logger(method, path);
if(strcmp(method, "GET") == 0){
handle_route(client_socket, path);
}else{
handle_route_not_found(client_socket);
}
close(client_socket);
}
void add_route(char *route, char *file_path){
if(route_count < MAX_ROUTES){
routes[route_count].route = route;
routes[route_count].file_path = file_path;
route_count++;
}
}
void handle_route(int client_socket, char *route){
for(int i=0; i<route_count; i++){
if(strcmp(route, routes[i].route) == 0){
serve_file(client_socket, routes[i].file_path);
return;
}
}
handle_route_not_found(client_socket);
}
void handle_route_not_found(int client_socket){
char *resp = "HTTP/1.1 404 Not Found\r\n"
"Content-Length: 13\r\n\r\n"
"404 Not Found";
send(client_socket, resp, strlen(resp), 0);
}
void serve_file(int client_socket, char *file_path){
int file = open(file_path, O_RDONLY);
if(file < 0){
handle_route_not_found(client_socket);
return;
}
struct stat file_stat;
fstat(file, &file_stat);
char response_header[BUFFER_SIZE];
snprintf(response_header, BUFFER_SIZE, "HTTP/1.1 200 OK\r\nContent-Length: %lld\r\nContent-Type: %s\r\n\r\n", file_stat.st_size, get_mime_type(file_path));
send(client_socket, response_header, strlen(response_header), 0);
char file_buffer[BUFFER_SIZE];
ssize_t bytes_read;
while((bytes_read = read(file, file_buffer, BUFFER_SIZE)) > 0){
send(client_socket, file_buffer, bytes_read, 0);
}
close(file);
}
char* get_mime_type(char *file_path){
char *ext = strrchr(file_path, '.');
if(!ext) return "text/plain";
if(strcmp(ext, ".html") == 0) return "text/html";
if(strcmp(ext, ".css") == 0) return "text/css";
if(strcmp(ext, ".js") == 0) return "application/javascript";
if(strcmp(ext, ".json") == 0) return "application/json";
if(strcmp(ext, ".png") == 0) return "image/png";
if(strcmp(ext, ".jpg") == 0) return "image/jpeg";
if(strcmp(ext, ".gif") == 0) return "image/gif";
return "text/plain";
}
void logger(char *method, char *path){
char buffer[TIME_BUFFER_SIZE];
time(&raw);
timeinfo = localtime(&raw);
strftime(buffer, TIME_BUFFER_SIZE, "[%a %b %d %H:%M:%S %Y]", timeinfo);
printf("%s %s %s\n", buffer, method, path);
}