Add functioning server
This commit is contained in:
parent
400c3916ff
commit
a8698e38f9
@ -105,7 +105,7 @@ int main(int argc, char *argv[]) {
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
char reply[sizeof(int32_t)]; //< Set the variable to hold the server response. Set to a big length
|
||||
char reply[__INT16_MAX__]; //< Set the variable to hold the server response. Set to a big length
|
||||
|
||||
if((recv(sockfd, reply, strlen(reply) - 1, 0)) < 0) { //< Receive response from the remote (-1 for the trailing terminating char)
|
||||
(void) fprintf(stderr, "ERROR: Did not receive response from the remote.\n");
|
||||
|
@ -0,0 +1,12 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<title>Greetings</title>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
</head>
|
||||
<body>
|
||||
<h1>Hello, World!</h1>
|
||||
</body>
|
||||
</html>
|
@ -0,0 +1,12 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<title>Index</title>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
</head>
|
||||
<body>
|
||||
<h1>This is the index page</h1>
|
||||
</body>
|
||||
</html>
|
195
http/server.c
195
http/server.c
@ -14,7 +14,10 @@
|
||||
#define LISTEN_BACKLOG 5 //< Define maximum size of the input queue
|
||||
|
||||
static int create_server_socket(uint16_t port, struct sockaddr_in incoming);
|
||||
static char * get_file_contents(char *dir, char *file);
|
||||
static char * setup_server_response(char* dir, char* filename, int current_session, int sockfd);
|
||||
static char * get_file_contents(char* dir, char* filename);
|
||||
static char * wday_to_string(int day);
|
||||
static char * month_to_string(int month);
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
check_opts_number(argc);
|
||||
@ -22,7 +25,7 @@ int main(int argc, char *argv[]) {
|
||||
char *cport = "8080";
|
||||
char *ifile = "index.html";
|
||||
char *dir = NULL;
|
||||
char response[sizeof(int32_t)]; //< To hold the server response
|
||||
char *response; //< To hold the server response
|
||||
int c;
|
||||
|
||||
/// Process the options
|
||||
@ -70,46 +73,8 @@ int main(int argc, char *argv[]) {
|
||||
/// Start accepting connections
|
||||
int current_session = accept(sockfd, (struct sockaddr*) &incoming, &peer_addr_size); //< Save the current session
|
||||
|
||||
if(current_session < 0) {
|
||||
(void) fprintf(stderr, "ERROR: Could not start accepting connections\n");
|
||||
close(sockfd);
|
||||
exit(EXIT_FAILURE);
|
||||
} else {
|
||||
char request[sizeof(int32_t)];
|
||||
|
||||
if(recv(current_session, request, strlen(request) - 1, 0) < 0) {
|
||||
(void) fprintf(stderr, "ERROR: Could not receive connection from client\n");
|
||||
close(current_session);
|
||||
close(sockfd);
|
||||
exit(EXIT_FAILURE);
|
||||
} else {
|
||||
char method[4];
|
||||
strncpy(method, request, 4); //< Get the request type
|
||||
method[3] = 0; //< Add terminating char
|
||||
|
||||
if(strcmp(method, "GET") == 0) {
|
||||
(void) fprintf(stdout, "Got here\n");
|
||||
close(current_session);
|
||||
close(sockfd);
|
||||
} else {
|
||||
fprintf(stderr, "ERROR: Unhandled HTTP request method received\n");
|
||||
char header[sizeof(int8_t) + 100];
|
||||
time_t t = time(NULL);
|
||||
struct tm tm = *localtime(&t);
|
||||
snprintf(
|
||||
header,
|
||||
sizeof header,
|
||||
"HTTP/1.1 501 Not Implemented\r\nDate: %d, %d %d %d %d:%d:%d %s\r\nContent-Length: 0\r\nConnection: close\r\n\r\n",
|
||||
tm.tm_wday, tm.tm_mday, tm.tm_mon, tm.tm_year + 1900, tm.tm_hour, tm.tm_min, tm.tm_sec, tm.tm_zone
|
||||
); //< Build the header
|
||||
|
||||
puts(header);
|
||||
strncpy(response, header, sizeof(header));
|
||||
}
|
||||
close(current_session);
|
||||
close(sockfd);
|
||||
}
|
||||
}
|
||||
/// Setup the server response
|
||||
response = setup_server_response(dir, ifile, current_session, sockfd);
|
||||
|
||||
/// Send the response to the client
|
||||
if(send(current_session, response, strlen(response) + 1, 0) < 0) {
|
||||
@ -185,6 +150,85 @@ static int create_server_socket(uint16_t port, struct sockaddr_in incoming) {
|
||||
return sockfd;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Function to create the HTTP response
|
||||
* @details Gets the client request
|
||||
* If there is no current session, it exits with an error
|
||||
* If the server could not receive a client connection, it exits with an error
|
||||
* If a GET request is received, the function tries to open the resource:
|
||||
* - if it could open it, it builds a 200 header and the file contents as body and adds them to response
|
||||
* - if it could not open it, it builds a 404 header and adds it to response
|
||||
* If anything other than a GET request is received, a 501 header is build, adds it to response and logs it
|
||||
* At the end, it returns the server response with header and body (if available)
|
||||
* @param dir - the directory of the file
|
||||
* filename - the name of the file
|
||||
* current_session - the current client session
|
||||
* sockfd - the socket configuration
|
||||
* @return response - A header with the status code and a body (if available)
|
||||
**/
|
||||
static char * setup_server_response(char* dir, char* filename, int current_session, int sockfd) {
|
||||
if(current_session < 0) {
|
||||
(void) fprintf(stderr, "ERROR: Could not start accepting connections\n");
|
||||
close(current_session);
|
||||
close(sockfd);
|
||||
exit(EXIT_FAILURE);
|
||||
} else {
|
||||
char request[__INT16_MAX__];
|
||||
static char response[__INT16_MAX__];
|
||||
|
||||
if(recv(current_session, request, strlen(request) - 1, 0) < 0) {
|
||||
(void) fprintf(stderr, "ERROR: Could not receive connection from client\n");
|
||||
close(current_session);
|
||||
close(sockfd);
|
||||
exit(EXIT_FAILURE);
|
||||
} else {
|
||||
char method[4];
|
||||
strncpy(method, request, 4); //< Get the request type
|
||||
method[3] = 0; //< Add terminating char
|
||||
|
||||
char header[__INT8_MAX__ + 100];
|
||||
|
||||
if(strcmp(method, "GET") == 0) {
|
||||
char *body = get_file_contents(dir, filename);
|
||||
|
||||
if(body != NULL) {
|
||||
time_t t = time(NULL);
|
||||
struct tm tm = *gmtime(&t);
|
||||
|
||||
char *wday = wday_to_string(tm.tm_wday);
|
||||
char *month = month_to_string(tm.tm_mon + 1);
|
||||
|
||||
snprintf(
|
||||
header,
|
||||
sizeof header,
|
||||
"HTTP/1.1 200 OK\r\nDate: %s, %d %s %d %d:%d:%d %s\r\nContent-Length: %ld\r\nConnection: close\r\n\r\n",
|
||||
wday, tm.tm_mday, month, tm.tm_year + 1900, tm.tm_hour, tm.tm_min, tm.tm_sec, tm.tm_zone, strlen(body)
|
||||
); //< Build the 200 header
|
||||
strcat(response, header);
|
||||
strcat(response, body);
|
||||
} else {
|
||||
snprintf(
|
||||
header,
|
||||
sizeof header,
|
||||
"HTTP/1.1 404 Not Found\r\nConnection: close\r\n\r\n"
|
||||
); //< Build the 404 header
|
||||
strcat(response, header);
|
||||
}
|
||||
} else {
|
||||
fprintf(stderr, "ERROR: Unhandled HTTP request method received\n");
|
||||
snprintf(
|
||||
header,
|
||||
sizeof header,
|
||||
"HTTP/1.1 501 Not ImplementedConnection: close\r\n\r\n"
|
||||
); //< Build 501 the header
|
||||
strcat(response, header);
|
||||
}
|
||||
|
||||
return response;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Function to take the contents of a specified file
|
||||
* @details Gets the contents of the file specified
|
||||
@ -196,7 +240,8 @@ static int create_server_socket(uint16_t port, struct sockaddr_in incoming) {
|
||||
* @return res - The contents of the file, formatted as a string
|
||||
**/
|
||||
static char * get_file_contents(char *dir, char *filename) {
|
||||
char *path = strcpy(dir, filename);
|
||||
char path[strlen(dir) + strlen(filename) + 100]; //< set the variable for the path with a reasonable length
|
||||
snprintf(path, sizeof path, "%s%s", dir, filename);
|
||||
|
||||
FILE *file = NULL;
|
||||
|
||||
@ -221,3 +266,67 @@ static char * get_file_contents(char *dir, char *filename) {
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Function to convert a int weekday to string weekday
|
||||
* @details Gets the weekday as int, converts it to string and returns the string
|
||||
* @param day - the weekday as int
|
||||
* @return the weekday as a string
|
||||
**/
|
||||
static char * wday_to_string(int day) {
|
||||
switch(day) {
|
||||
case 1:
|
||||
return "Mon";
|
||||
case 2:
|
||||
return "Tue";
|
||||
case 3:
|
||||
return "Wed";
|
||||
case 4:
|
||||
return "Thu";
|
||||
case 5:
|
||||
return "Fri";
|
||||
case 6:
|
||||
return "Sat";
|
||||
case 7:
|
||||
return "Sun";
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Function to convert a int month to string month
|
||||
* @details Gets the month as int, converts it to string and returns the string
|
||||
* @param day - the month as int
|
||||
* @return the month as a string
|
||||
**/
|
||||
static char * month_to_string(int month) {
|
||||
switch(month) {
|
||||
case 1:
|
||||
return "Jan";
|
||||
case 2:
|
||||
return "Feb";
|
||||
case 3:
|
||||
return "Mar";
|
||||
case 4:
|
||||
return "Apr";
|
||||
case 5:
|
||||
return "May";
|
||||
case 6:
|
||||
return "Jun";
|
||||
case 7:
|
||||
return "Jul";
|
||||
case 8:
|
||||
return "Aug";
|
||||
case 9:
|
||||
return "Sep";
|
||||
case 10:
|
||||
return "Oct";
|
||||
case 11:
|
||||
return "Nov";
|
||||
case 12:
|
||||
return "Dec";
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user