diff --git a/http/client.c b/http/client.c index 864a07c..2c1ed82 100644 --- a/http/client.c +++ b/http/client.c @@ -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"); diff --git a/http/public/greetings.html b/http/public/greetings.html index e69de29..6ce25b8 100644 --- a/http/public/greetings.html +++ b/http/public/greetings.html @@ -0,0 +1,12 @@ + + + + + + Greetings + + + +

Hello, World!

+ + \ No newline at end of file diff --git a/http/public/index.html b/http/public/index.html index e69de29..219d4c4 100644 --- a/http/public/index.html +++ b/http/public/index.html @@ -0,0 +1,12 @@ + + + + + + Index + + + +

This is the index page

+ + \ No newline at end of file diff --git a/http/server.c b/http/server.c index 5b61b9e..a7d99e2 100644 --- a/http/server.c +++ b/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; + } +}