138 lines
3.6 KiB
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;
|
|
}
|