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 */