118 lines
3.4 KiB
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);
|
|
}
|