cs-3516-assignment-1/common/http_types.c

118 lines
3.4 KiB
C

#include "http_types.h"
#include <ctype.h>
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
/**
* Identical to strcpy, but left strips ' ' and '\t'
*
* @param dest Buffer to copy to
* @param src Buffer to copy from
*
* @return The destination buffer
*/
static char *strcpy_lstrip(char *dest, const char *src) {
char *dest_cursor;
const char *src_cursor;
bool non_whitespace_hit = false;
for (dest_cursor = dest, src_cursor = src; *src_cursor != '\0'; src_cursor++) {
if (non_whitespace_hit || !(*src_cursor == ' ' || *src_cursor == '\t')) {
non_whitespace_hit = true;
*dest_cursor = *src_cursor;
dest_cursor++;
}
}
*dest_cursor = '\0';
return dest;
}
/**
* Create a new header and append it to the end of the list of existing headers
*
* @param header_name The name of the header
* @param header_contents The contents of the header
* @param existing_header A list of existing headers that this new header should be append to.
* If NULL, no append will take place.
*
* @return The newly created header
*/
struct http_header *insert_header(const char *header_name, const char *header_value, struct http_header *existing_header) {
struct http_header *new_header = calloc(1, sizeof(struct http_header));
int name_length = strlen(header_name) + 1;
new_header->name = malloc(name_length * sizeof(char));
strcpy(new_header->name, header_name);
int contents_length = strlen(header_value) + 1;
new_header->value = malloc(contents_length * sizeof(char));
strcpy_lstrip(new_header->value, header_value);
// If we have an existing header, append it to the end of our list of headers.
if (existing_header != NULL) {
struct http_header *cursor;
// Advance the cursor to the last non-null element
for (cursor = existing_header; cursor->next_header != NULL; cursor = cursor->next_header);
cursor->next_header = new_header;
}
return new_header;
}
/**
* Free all headers in a header list
*
* @param headers The list of headers to free
*/
void free_headers(struct http_header *headers) {
if (headers->next_header != NULL) {
free_headers(headers->next_header);
}
free(headers->name);
free(headers->value);
// next_header should have already been freed by recursion
free(headers);
}
static char *str_lower(const char *s) {
int length = strlen(s) + 1;
char *lower = malloc(length * sizeof(char));
char *lower_cursor = lower;
for (const char *cursor = s; *cursor != '\0'; (cursor++, lower_cursor++)) {
*lower_cursor = tolower(*cursor);
}
return lower;
}
/**
* Performs strcmp on lowercase versions of a and b
*
* @param a A null terminated string.
* @param b A null terminated string.
*
* @return strcmp(lower_a, lower_b)
*/
int case_insensitive_strcmp(const char *a, const char *b) {
char *a_lower = str_lower(a);
char *b_lower = str_lower(b);
int cmp = strcmp(a, b);
free(a_lower);
free(b_lower);
return cmp;
}
/**
* Compare the name of a header to a given name, case insensitively
*
* @param name The name to compare against.
*
* @return The result of strcmp(lower_case_header_name, actual_header_name)
*/
int headercmp(const struct http_header *header, const char *name) {
return case_insensitive_strcmp(header->name, name);
}