ws

ws.git
git clone git://git.lenczewski.org/ws.git
Log | Files | Refs | LICENSE

http.h (2550B)


      1 #ifndef HTTP_H
      2 #define HTTP_H
      3 
      4 #ifndef _POSIX_C_SOURCE
      5 # define _POSIX_C_SOURCE 1
      6 #endif
      7 
      8 #include <assert.h>
      9 #include <ctype.h>
     10 #include <string.h>
     11 #include <strings.h>
     12 
     13 #include "arena.h"
     14 
     15 #define HTTP_TERMINATOR "\r\n\r\n"
     16 
     17 static inline int
     18 http_receive_msg(int sock, char *buf, size_t cap, char **terminator)
     19 {
     20 	char *term = NULL;
     21 	size_t len = 0, cur = 0;
     22 
     23 	do {
     24 		ssize_t res = recv(sock, buf + len, cap - len, 0);
     25 		if (res < 0) return -1;
     26 		len += res;
     27 
     28 		size_t lower_bound = (cur < 4) ? 0 : (cur - 4);
     29 		term = memmem(buf + lower_bound, len - lower_bound,
     30 			      HTTP_TERMINATOR, 4);
     31 		cur += res;
     32 	} while (len < cap && !term);
     33 
     34 	*term = 0;
     35 
     36 	*terminator = term;
     37 
     38 	return 0;
     39 }
     40 
     41 struct http_header {
     42 	char *key, *val;
     43 	struct http_header *next;
     44 };
     45 
     46 static inline struct http_header *
     47 http_header_find(struct http_header *headers, char const *key)
     48 {
     49 	while (headers) {
     50 		if (strcasecmp(headers->key, key) == 0)
     51 			return headers;
     52 
     53 		headers = headers->next;
     54 	}
     55 
     56 	return NULL;
     57 }
     58 
     59 static inline int
     60 http_header_has_value(struct http_header const *header, char const *value)
     61 {
     62 	char *cur = header->val, *tok;
     63 	do {
     64 		// header values are comma-delimited
     65 		tok = strchrnul(cur, ',');
     66 
     67 		while (isspace(*cur)) cur++; // trim leading whitespace
     68 
     69 		char *end = tok, save;
     70 		if (isspace(*(end - 1))) end--; // if character preceeding ',' is whitespace
     71 		while (isspace(*end)) end--; // trim trailing whitespace
     72 
     73 		save = *end;
     74 		*end = '\0';
     75 
     76 		if (strstr(cur, value))
     77 			return 1;
     78 
     79 		*end = save;
     80 		cur = ++tok;
     81 	} while (*tok);
     82 
     83 	return 0;
     84 }
     85 
     86 struct http_msg {
     87 	char *leader;
     88 	struct http_header *headers;
     89 };
     90 
     91 static inline int
     92 http_parse_msg(struct arena *arena, char *buf, struct http_msg *out)
     93 {
     94 	char *saveptr = NULL;
     95 	out->leader = strtok_r(buf, "\r\n", &saveptr);
     96 
     97 	out->headers = NULL;
     98 
     99 	char *hdr = NULL;
    100 	while ((hdr = strtok_r(NULL, "\r\n", &saveptr))) {
    101 		struct http_header *header = ARENA_ALLOC_SIZED(arena, struct http_header);
    102 		if (!header) return -1;
    103 
    104 		char *val;
    105 		header->key = strtok_r(hdr, ":", &val);
    106 
    107 		while (isspace(*val)) val++; // trim leading whitespace
    108 
    109 		header->val = val;
    110 
    111 		header->next = out->headers;
    112 		out->headers = header;
    113 	}
    114 
    115 	return 0;
    116 }
    117 
    118 static inline void
    119 http_print_msg(struct http_msg const *msg)
    120 {
    121 	printf("http msg:\n");
    122 
    123 	printf("=====\n");
    124 
    125 	printf("LEADER: %s\n", msg->leader);
    126 
    127 	printf("=====\n");
    128 
    129 	printf("HEADERS:\n");
    130 
    131 	struct http_header *headers = msg->headers;
    132 	while (headers) {
    133 		printf("\t%s = %s\n", headers->key, headers->val);
    134 		headers = headers->next;
    135 	}
    136 }
    137 
    138 #endif /* HTTP_H */