#include "request_handling.h" #include #include #include #include /** * Identical to strcpy, but strips a trailing '\r\n' * * @param dest Buffer to copy to * @param src Buffer to copy from * * @return The destination buffer */ static char *strcpy_no_crlf(char *dest, const char *src) { char *dest_cursor; const char *src_cursor; char *last_dest_cursor = NULL; const char *last_src_cursor = NULL; for (dest_cursor = dest, src_cursor = src; *src_cursor != '\0'; src_cursor++) { if (last_src_cursor != NULL && *last_src_cursor == '\r' && *src_cursor == '\n') { // Replace the \r with a null term. *last_dest_cursor = '\0'; return dest; } *dest_cursor = *src_cursor; last_dest_cursor = dest_cursor; last_src_cursor = src_cursor; dest_cursor++; } *dest_cursor = '\0'; return dest; } /** * Parse a request line into a request_line * * @param line The line to parse. * @param parsed_line A pointer to a request_line. Values must be freed by caller. * * @return -1 if malformed, 0 if well formed. */ int parse_request_line(const char *line, struct request_line *parsed_line) { int line_size = strlen(line) + 1; char *raw_line = malloc(line_size * sizeof(char)); strcpy(raw_line, line); char *method = strtok(raw_line, " "); if (method == NULL) { free(raw_line); return -1; } int method_size = strlen(method) + 1; parsed_line->method = malloc(method_size * sizeof(char)); strcpy_no_crlf(parsed_line->method, method); char *uri = strtok(NULL, " "); if (uri == NULL) { free(raw_line); free(parsed_line->method); return -1; } int uri_size = strlen(uri) + 1; parsed_line->uri = malloc(uri_size * sizeof(char)); strcpy_no_crlf(parsed_line->uri, uri); char *http_version = strtok(NULL, " "); if (http_version == NULL) { free(raw_line); free(parsed_line->method); free(parsed_line->uri); return -1; } int version_size = strlen(http_version) + 1; parsed_line->http_version = malloc(version_size * sizeof(char)); strcpy_no_crlf(parsed_line->http_version, http_version); free(raw_line); return 0; } /** * Free a request_line made by parse_request_line * * @param parsed_line The request_line made by parse_request_line */ void free_request_line_items(struct request_line *parsed_line) { if (parsed_line->http_version != NULL) { free(parsed_line->http_version); } if (parsed_line->method != NULL) { free(parsed_line->method); } if (parsed_line->uri != NULL) { free(parsed_line->uri); } } /** * Gets a FILE from a given uri. * * @param uri The uri in the request line. * @param req_file A pointer to a requested_file struct. * * @return -1 For an I/O error, 0 if successful. */ enum file_result get_file_from_uri(const char *uri, struct requested_file *req_file) { const char *resource = uri; if (strcmp(uri, "/") == 0) { resource = "TMDG.html"; } else if (*uri == '/') { // If our uri starts with a slash, we can ignore it. resource++; } struct stat file_stat; int stat_result = stat(resource, &file_stat); if (stat_result == -1) { return RESULT_IO_ERROR; } if (S_ISDIR(file_stat.st_mode)) { return RESULT_NOT_FILE; } FILE *open_file = fopen(resource, "rb"); if (open_file == NULL) { return RESULT_IO_ERROR; } rewind(open_file); req_file->size = file_stat.st_size; req_file->file = open_file; return RESULT_FILE_OK; }