#include "http_types.h" #include #include #include #include /** * 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); }