cs-3516-assignment-1/server/request_handling.c

138 lines
3.6 KiB
C

#include "request_handling.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
/**
* 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;
}