diff --git a/.gitignore b/.gitignore index 27e7ffc..b85a2fa 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,7 @@ *.out *.o *.html +*.tgz !public/*.html http/client http/server diff --git a/http/Makefile b/http/Makefile index 9abf385..2980989 100644 --- a/http/Makefile +++ b/http/Makefile @@ -24,4 +24,8 @@ clean: $(RM) $(TARGET_1) $(RM) $(TARGET_2) $(RM) *.o - $(RM) *.html \ No newline at end of file + $(RM) *.html + $(RM) *.tgz + +package: + tar -cvzf server.tgz $(TARGET_1).c $(TARGET_2).c shared public Makefile diff --git a/http/server.c b/http/server.c index a7d99e2..8540fbc 100644 --- a/http/server.c +++ b/http/server.c @@ -14,10 +14,8 @@ #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 * setup_server_response(char* dir, char* filename, int current_session, int sockfd); +static char * setup_server_response(char* dir, char* ifile, char* request); 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); @@ -67,21 +65,40 @@ int main(int argc, char *argv[]) { incoming.sin_family = AF_INET; //< Use IPv4 int sockfd = create_server_socket(port, incoming); //< Define a server socket + int current_session = 0; socklen_t peer_addr_size = sizeof(struct sockaddr_in); - /// Start accepting connections - int current_session = accept(sockfd, (struct sockaddr*) &incoming, &peer_addr_size); //< Save the current session + while(1) { //< Accept connections until terminated + /// Start accepting connections + current_session = accept(sockfd, (struct sockaddr*) &incoming, &peer_addr_size); //< Save the current session - /// Setup the server response - response = setup_server_response(dir, ifile, current_session, 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 = malloc (sizeof (char) * __INT16_MAX__); - /// Send the response to the client - if(send(current_session, response, strlen(response) + 1, 0) < 0) { - (void) fprintf(stderr, "ERROR: Could not send the response to the client\n"); - close(current_session); - close(sockfd); - exit(EXIT_FAILURE); + 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); + } + + /// Setup the server response + response = setup_server_response(dir, ifile, request); + + /// Send the response to the client + if(send(current_session, response, strlen(response) + 1, 0) < 0) { + (void) fprintf(stderr, "ERROR: Could not send the response to the client\n"); + close(current_session); + close(sockfd); + exit(EXIT_FAILURE); + } + } } close(current_session); @@ -153,80 +170,80 @@ static int create_server_socket(uint16_t port, struct sockaddr_in incoming) { /** * @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 the server receives an invalid requests, a 400 header is build and the function adds it to response * 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 + * If anything other than a GET request is received, a 501 header is build and the function adds it to response * 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 + * ifile - the name of the indexfile + * request - the request of the client * @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__]; +static char * setup_server_response(char* dir, char* ifile, char* request) { + char *response = malloc (sizeof (char) * __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 method[4]; + strncpy(method, request, 3); //< Get the request type + method[3] = 0; //< Add terminating string - char header[__INT8_MAX__ + 100]; + char header[__INT8_MAX__ + 100]; - if(strcmp(method, "GET") == 0) { - char *body = get_file_contents(dir, filename); + if(strcmp(method, "GET") == 0) { + char *body = NULL; + char *delim = strstr(request, "/"); + char *req_file = strtok(delim, " "); //< Get the requested file - 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; + if(strlen(req_file) == 1) { + body = get_file_contents(dir, ifile); } + else { + char *rest = strstr(request, "HTTP/1.1"); + rest = strtok(rest, "\r\n"); + if(rest == NULL) { + strcpy( + header, + "HTTP/1.1 400 Bad Request\r\nConnection: close\r\n\r\n" + ); //< Build the 400 header + strcat(response, header); + } else { + body = get_file_contents(dir, req_file + 1); + (void) fprintf(stdout, "GET: %s\n", req_file); + } + } + + if(body != NULL) { + time_t current_time; + time(¤t_time); + struct tm * tm = gmtime(¤t_time); + char time_string[50]; + + strftime(time_string, 50, "%a, %d %b %y %H:%M:%S %Z", tm); + + snprintf( + header, + sizeof header, + "HTTP/1.1 200 OK\r\nDate: %s\r\nContent-Length: %ld\r\nConnection: close\r\n\r\n", + time_string, strlen(body) + ); //< Build the 200 header + strcat(response, header); + strcat(response, body); + } else { + strcpy( + header, + "HTTP/1.1 404 Not Found\r\nConnection: close\r\n\r\n" + ); //< Build the 404 header + strcat(response, header); + } + } else { + strcpy( + header, + "HTTP/1.1 501 Not Implemented\r\nConnection: close\r\n\r\n" + ); //< Build 501 the header + strcat(response, header); } + return response; } /** @@ -256,77 +273,8 @@ static char * get_file_contents(char *dir, char *filename) { int file_length = ftell(file); //< Get file length fseek(file, 0, SEEK_SET); //< Set the position to begining of stream res = malloc(file_length); //< Allocate memory for the file contents - - if(res != 0) { - fread(res, 1, file_length, file); //< Read the contents into res - } else { - return " "; - } + fread(res, 1, file_length, file); //< Read the contents into res 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; - } -}