diff --git a/include/file.h b/include/file.h new file mode 100644 index 0000000..3beebd5 --- /dev/null +++ b/include/file.h @@ -0,0 +1,2 @@ +char *gen_file_path(char *path); +int send_file(int fd, char *path); \ No newline at end of file diff --git a/include/mine.h b/include/mine.h new file mode 100644 index 0000000..c28a0e7 --- /dev/null +++ b/include/mine.h @@ -0,0 +1 @@ +char *get_mine_type(char *file_path); \ No newline at end of file diff --git a/include/request.h b/include/request.h new file mode 100644 index 0000000..318d1f2 --- /dev/null +++ b/include/request.h @@ -0,0 +1,5 @@ +char *get_path(char *request); +void gen_header(int status_code, size_t file_size, char *mine_type); +int send_response(int fd, char *path); +void handle_post_request(int fd, char *request); +void handle_get_request(int fd, char *request); \ No newline at end of file diff --git a/include/utils.h b/include/utils.h index fe6de80..f5e415d 100644 --- a/include/utils.h +++ b/include/utils.h @@ -1 +1,2 @@ -void err_msg(char *msg); \ No newline at end of file +void err_msg(char *msg); +char *add_to_front(char **str1, char *str2); \ No newline at end of file diff --git a/src/file.c b/src/file.c new file mode 100644 index 0000000..77e27d3 --- /dev/null +++ b/src/file.c @@ -0,0 +1,35 @@ +#include +#include + +#include "../include/file.h" +#include "../include/utils.h" + +char *gen_file_path(char *req_path) +{ + char *path = (char *)malloc(sizeof req_path); + strcpy(path, req_path); + if (strchr(req_path, '.') == NULL) + { + if (req_path[strlen(req_path) - 1] != '/') + { + path = realloc(path, sizeof path + 1); + path = strcat(path, "/"); + } + path = realloc(path, sizeof path + sizeof "index.html"); + path = strcat(path, "index.html"); + } + + char *webroot = "../static"; + + path = realloc(path, sizeof path + sizeof webroot); + path = add_to_front(&path, webroot); + + return path; +} + +int send_file(int fd, char *req_path) +{ + char *path = gen_file_path(req_path); + + +} \ No newline at end of file diff --git a/src/mine.c b/src/mine.c new file mode 100644 index 0000000..49983de --- /dev/null +++ b/src/mine.c @@ -0,0 +1,5 @@ +#include "../include/mine.h" + +char *get_mine_type(char *file_path) { + +} \ No newline at end of file diff --git a/src/netw.c b/src/netw.c index 5a822ff..479e029 100644 --- a/src/netw.c +++ b/src/netw.c @@ -4,6 +4,7 @@ #include #include +#include "../include/netw.h" #include "../include/utils.h" #define BACKLOG 10 @@ -73,7 +74,12 @@ int get_listener_socket(char *port) return sockfd; } - +/** + * @brief Get address from sockaddr structure + * + * @param {struct sockaddr*} sa + * @return void* +*/ void *get_in_addr(struct sockaddr *sa) { if (sa->sa_family == AF_INET) { diff --git a/src/request.c b/src/request.c new file mode 100644 index 0000000..aa012ce --- /dev/null +++ b/src/request.c @@ -0,0 +1,136 @@ +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "../include/request.h" +#include "../include/utils.h" + +/** + * @brief Get the status message object + * + * @param status_code + * @return char* + */ +char *get_status_message(int status_code) +{ + switch (status_code) + { + case 200: + return "OK"; + case 400: + return "Internal Server Error"; + case 401: + return "Unauthorized"; + case 403: + return "Forbidden"; + case 404: + return "NOT FOUND"; + case 500: + return "Internal Server Error"; + case 501: + return "Not Implemented"; + case 502: + return "Bad Gateway"; + default: + return "None"; + break; + } +} + +/** + * @brief Get the path object + * + * @param request + * @return char* + */ +char *get_path(char *request) +{ + char *tmp = strtok(request, " "); + char *path = strtok(NULL, " "); + + return path; +} + +/** + * @brief Generate header string + * + * @param status_code + * @param file_size + * @param mine_type + * @return char* + */ +char *gen_header(int status_code, size_t file_size, char *mine_type) +{ + char *status_message = get_status_message(status_code); + + time_t now = time(NULL); + struct tm *ptm = gmtime(&now); + char *curr_date = asctime(ptm); + + int header_length = snprintf(NULL, 0, "HTTP/1.1 %d %s\nDate: %s\nConnection: close\nContent-Length: %d\nContent-Type: %s\n\n", status_code, status_message, curr_date, file_size, mine_type); + char *header = (char *)malloc(header_length + 1); + snprintf(header, header_length + 1, "HTTP/1.1 %d %s\nDate: %s\nConnection: close\nContent-Length: %d\nContent-Type: %s\n\n", status_code, status_message, curr_date, file_size, mine_type); + printf("%s\n", header); +} + +/** + * @brief Send HTTP response + * + * @param fd + * @param file_path + * @return int + */ +int send_response(int fd, char *path) +{ + int file_fd; + struct stat stat_buf; + file_fd = open(file_path, O_RDONLY); + fstat(file_fd, &stat_buf); + off_t f_size = stat_buf.st_size; + off_t offset = 0; + + char *mine_type; + + char *header = gen_header(200, f_size, mine_type); + + sendfile(fd, file_fd, &offset, f_size); + close(file_fd); +} + +/** + * @brief Handle POST request + * + * @param fd + * @param request + */ +void handle_post_request(int fd, char *request) +{ + char *not_supported_msg = "HTTP/1.1 501 Not Implemented\nConnection: close\n\n"; + send(fd, not_supported_msg, strlen(not_supported_msg), 0); + printf("POST requests are not supported yet, closing connection\n"); +} + +/** + * @brief Handle get request + * + * @param fd + * @param request + */ +void handle_get_request(int fd, char *request) +{ + char *path = get_path(request); + printf("Client accessed path: %s\n", path); + + int rv = send_response(fd, path); + if (rv < 0) + { + err_msg("couldn't send response"); + } +} \ No newline at end of file diff --git a/src/server.c b/src/server.c index 05267d7..7add287 100644 --- a/src/server.c +++ b/src/server.c @@ -5,11 +5,52 @@ #include #include #include -#include +#include #include #include "../include/netw.h" #include "../include/utils.h" +#include "../include/request.h" + +void handle_connection(int fd) +{ + const size_t request_buffer_size = 512; + char request[request_buffer_size]; + char *prt; + + int bytes_recv = recv(fd, request, request_buffer_size - 1, 0); + + if (bytes_recv < 0) + { + err_msg("failed to receive a request from server"); + return; + } + + // printf("Request:\n%s---\n", request); + + prt = strstr(request, " HTTP/"); + if (prt == NULL) + { + err_msg("non-HTTP request received"); + } + else + { + if (strncmp(request, "GET ", 4) == 0) + { + handle_get_request(fd, request); + } + else if (strncmp(request, "POST ", 5) == 0) + { + handle_post_request(fd, request); + } + else + { + err_msg("unknown request"); + } + } + close(fd); +} + /** * Main */ @@ -44,22 +85,22 @@ int main(int argc, char *argv[]) err_msg("couldn't accept client connection"); continue; } - + + inet_ntop(cli_addr.ss_family, get_in_addr((struct sockaddr *)&cli_addr), s, sizeof s); + printf("\nGot connection from %s\n", s); + // | Doesn't work properly yet // v int pid = fork(); - + if (pid < 0) err_msg("fork failed"); else if (pid == 0) { close(listenfd); - - inet_ntop(cli_addr.ss_family, get_in_addr((struct sockaddr *)&cli_addr), s, sizeof s); - printf("Got connection from %s\n", s); - - // connection(client_fd); // Implement + + handle_connection(client_fd); // Implement exit(0); } else diff --git a/src/utils.c b/src/utils.c index 734dfc6..c8e183d 100644 --- a/src/utils.c +++ b/src/utils.c @@ -1,10 +1,25 @@ #include +#include "../include/utils.h" + /** * @brief Prints error * * @param {char *} msg */ -void err_msg (char *msg) { +void err_msg(char *msg) +{ fprintf(stderr, "Error: %s\n", msg); +} + +char *add_to_front(char **str1, char *str2) +{ + char *tmp = strdup(*str1); + + strcpy(*str1, str2); + strcat(*str1, tmp); + + free(tmp); + + return *str1; } \ No newline at end of file