mblhttp.h (2989B)
1 #ifndef MBLHTTP_H 2 #define MBLHTTP_H 3 4 #include <ctype.h> 5 #include <stddef.h> 6 #include <stdlib.h> 7 #include <string.h> 8 #include <strings.h> 9 10 struct mbl_http_str { 11 char *ptr; 12 int len; 13 }; 14 15 struct mbl_http_buf { 16 void *ptr; 17 int len; 18 }; 19 20 struct mbl_http_header { 21 struct mbl_http_str key, val; 22 }; 23 24 struct mbl_http_msg { 25 struct mbl_http_str request_line; 26 27 struct mbl_http_header *hdrs; 28 size_t hdrs_len, hdrs_cap; 29 30 struct mbl_http_buf body; 31 }; 32 33 /* please ignore the stray `static inline` functions, this really probably 34 * be split out into its own .c source file, but this is faster and much 35 * less faff :) 36 */ 37 38 static inline int 39 parse_request_line(char **ptr, char *end, struct mbl_http_str *out) 40 { 41 char *start = *ptr; 42 while (start < end) { 43 if (*start++ == '\r' && *start++ == '\n') { 44 out->ptr = *ptr; 45 out->len = (start - *ptr) - 2; 46 47 *ptr = start; 48 49 return 0; 50 } 51 } 52 53 *ptr = start; 54 55 return -1; 56 } 57 58 static inline int 59 parse_request_header(char *ptr, char *end, struct mbl_http_header *out) 60 { 61 char *delim = memchr(ptr, ':', end - ptr); 62 if (!delim) /* malformed http header */ 63 return -1; 64 65 out->key.ptr = ptr; 66 out->key.len = delim - ptr; 67 68 out->val.ptr = ++delim; 69 out->val.len = end - delim; 70 71 /* ltrim key */ 72 while (isspace(*out->key.ptr) && out->key.len) { 73 out->key.ptr++; 74 out->key.len--; 75 } 76 77 /* ltrim val */ 78 while (isspace(*out->val.ptr) && out->val.len) { 79 out->val.ptr++; 80 out->val.len--; 81 } 82 83 return 0; 84 } 85 86 static inline int 87 parse_request_headers(char **ptr, char *end, 88 struct mbl_http_header *hdrs, size_t cap, size_t *len) 89 { 90 char *start = *ptr; 91 92 char term[2] = { '\r', '\n' }; 93 94 *len = 0; 95 96 while (start < end) { 97 char *hdr_begin = start; 98 char *hdr_end = memmem(start, end - start, term, sizeof term); 99 100 if (!hdr_end) /* no \r\n found, malformed http request */ 101 return -1; 102 103 if (hdr_begin == hdr_end) { /* final \r\n */ 104 start = hdr_end + sizeof term; 105 break; 106 } 107 108 /* have header, parse it */ 109 if (*len < cap) { 110 struct mbl_http_header *hdr = hdrs + (*len)++; 111 if (parse_request_header(hdr_begin, hdr_end, hdr) < 0) 112 return -2; 113 } 114 115 start = hdr_end + sizeof term; 116 } 117 118 *ptr = start; 119 120 return 0; 121 } 122 123 static inline int 124 mbl_http_msg_parse(struct mbl_http_msg *msg, char *buf, size_t len, 125 struct mbl_http_header hdrs[], size_t hdrs_cap) 126 { 127 msg->hdrs = hdrs; 128 msg->hdrs_cap = hdrs_cap; 129 130 char *ptr = buf, *end = buf + len; 131 if (parse_request_line(&ptr, end, &msg->request_line) < 0) 132 return -1; 133 134 if (parse_request_headers(&ptr, end, msg->hdrs, msg->hdrs_cap, &msg->hdrs_len) < 0) 135 return -2; 136 137 msg->body.ptr = ptr; 138 msg->body.len = end - ptr; 139 140 return 0; 141 } 142 143 static inline struct mbl_http_header * 144 mbl_http_msg_find_header(struct mbl_http_msg *msg, char const *key, int len) 145 { 146 for (size_t i = 0; i < msg->hdrs_len; i++) { 147 struct mbl_http_header *hdr = msg->hdrs + i; 148 149 if (hdr->key.len != len) 150 continue; 151 152 if (strncasecmp(hdr->key.ptr, key, len) == 0) 153 return hdr; 154 } 155 156 return NULL; 157 } 158 159 #endif /* MBLHTTP_H */