/client.c

http://github.com/nicolasff/webdis · C · 372 lines · 347 code · 20 blank · 5 comment · 3 complexity · 8fc02eb21d31b8bc0cc1a06bf86ab230 MD5 · raw file

  1. #include "client.h"
  2. #include "http_parser.h"
  3. #include "http.h"
  4. #include "server.h"
  5. #include "worker.h"
  6. #include "websocket.h"
  7. #include "cmd.h"
  8. #include "conf.h"
  9. #include <stdlib.h>
  10. #include <string.h>
  11. #include <unistd.h>
  12. #include <errno.h>
  13. #include <hiredis/hiredis.h>
  14. #include <hiredis/async.h>
  15. #define CHECK_ALLOC(c, ptr) if(!(ptr)) { c->failed_alloc = 1; return -1;}
  16. static int
  17. http_client_on_url(struct http_parser *p, const char *at, size_t sz) {
  18. struct http_client *c = p->data;
  19. CHECK_ALLOC(c, c->path = realloc(c->path, c->path_sz + sz + 1));
  20. memcpy(c->path + c->path_sz, at, sz);
  21. c->path_sz += sz;
  22. c->path[c->path_sz] = 0;
  23. return 0;
  24. }
  25. /*
  26. * Called when the body is parsed.
  27. */
  28. static int
  29. http_client_on_body(struct http_parser *p, const char *at, size_t sz) {
  30. struct http_client *c = p->data;
  31. return http_client_add_to_body(c, at, sz);
  32. }
  33. int
  34. http_client_add_to_body(struct http_client *c, const char *at, size_t sz) {
  35. CHECK_ALLOC(c, c->body = realloc(c->body, c->body_sz + sz + 1));
  36. memcpy(c->body + c->body_sz, at, sz);
  37. c->body_sz += sz;
  38. c->body[c->body_sz] = 0;
  39. return 0;
  40. }
  41. static int
  42. http_client_on_header_name(struct http_parser *p, const char *at, size_t sz) {
  43. struct http_client *c = p->data;
  44. size_t n = c->header_count;
  45. /* if we're not adding to the same header name as last time, realloc to add one field. */
  46. if(c->last_cb != LAST_CB_KEY) {
  47. n = ++c->header_count;
  48. CHECK_ALLOC(c, c->headers = realloc(c->headers, n * sizeof(struct http_header)));
  49. memset(&c->headers[n-1], 0, sizeof(struct http_header));
  50. }
  51. /* Add data to the current header name. */
  52. CHECK_ALLOC(c, c->headers[n-1].key = realloc(c->headers[n-1].key,
  53. c->headers[n-1].key_sz + sz + 1));
  54. memcpy(c->headers[n-1].key + c->headers[n-1].key_sz, at, sz);
  55. c->headers[n-1].key_sz += sz;
  56. c->headers[n-1].key[c->headers[n-1].key_sz] = 0;
  57. c->last_cb = LAST_CB_KEY;
  58. return 0;
  59. }
  60. static char *
  61. wrap_filename(const char *val, size_t val_len) {
  62. char format[] = "attachment; filename=\"";
  63. size_t sz = sizeof(format) - 1 + val_len + 1;
  64. char *p = calloc(sz + 1, 1);
  65. memcpy(p, format, sizeof(format)-1); /* copy format */
  66. memcpy(p + sizeof(format)-1, val, val_len); /* copy filename */
  67. p[sz-1] = '"';
  68. return p;
  69. }
  70. /*
  71. * Split query string into key/value pairs, process some of them.
  72. */
  73. static int
  74. http_client_on_query_string(struct http_parser *parser, const char *at, size_t sz) {
  75. struct http_client *c = parser->data;
  76. const char *p = at;
  77. while(p < at + sz) {
  78. const char *key = p, *val;
  79. int key_len, val_len;
  80. char *eq = memchr(key, '=', sz - (p-at));
  81. if(!eq || eq > at + sz) { /* last argument */
  82. break;
  83. } else { /* found an '=' */
  84. char *amp;
  85. val = eq + 1;
  86. key_len = eq - key;
  87. p = eq + 1;
  88. amp = memchr(p, '&', sz - (p-at));
  89. if(!amp || amp > at + sz) {
  90. val_len = at + sz - p; /* last arg */
  91. } else {
  92. val_len = amp - val; /* cur arg */
  93. p = amp + 1;
  94. }
  95. if(key_len == 4 && strncmp(key, "type", 4) == 0) {
  96. c->type = calloc(1 + val_len, 1);
  97. memcpy(c->type, val, val_len);
  98. } else if((key_len == 5 && strncmp(key, "jsonp", 5) == 0)
  99. || (key_len == 8 && strncmp(key, "callback", 8) == 0)) {
  100. c->jsonp = calloc(1 + val_len, 1);
  101. memcpy(c->jsonp, val, val_len);
  102. } else if(key_len == 3 && strncmp(key, "sep", 3) == 0) {
  103. c->separator = calloc(1 + val_len, 1);
  104. memcpy(c->separator, val, val_len);
  105. } else if(key_len == 8 && strncmp(key, "filename", 8) == 0) {
  106. c->filename = wrap_filename(val, val_len);
  107. }
  108. if(!amp) {
  109. break;
  110. }
  111. }
  112. }
  113. return 0;
  114. }
  115. static int
  116. http_client_on_header_value(struct http_parser *p, const char *at, size_t sz) {
  117. struct http_client *c = p->data;
  118. size_t n = c->header_count;
  119. /* Add data to the current header value. */
  120. CHECK_ALLOC(c, c->headers[n-1].val = realloc(c->headers[n-1].val,
  121. c->headers[n-1].val_sz + sz + 1));
  122. memcpy(c->headers[n-1].val + c->headers[n-1].val_sz, at, sz);
  123. c->headers[n-1].val_sz += sz;
  124. c->headers[n-1].val[c->headers[n-1].val_sz] = 0;
  125. c->last_cb = LAST_CB_VAL;
  126. /* react to some values. */
  127. if(strncmp("Expect", c->headers[n-1].key, c->headers[n-1].key_sz) == 0) {
  128. if(sz == 12 && strncasecmp(at, "100-continue", sz) == 0) {
  129. /* support HTTP file upload */
  130. char http100[] = "HTTP/1.1 100 Continue\r\n\r\n";
  131. int ret = write(c->fd, http100, sizeof(http100)-1);
  132. (void)ret;
  133. }
  134. } else if(strncasecmp("Connection", c->headers[n-1].key, c->headers[n-1].key_sz) == 0) {
  135. if(sz == 10 && strncasecmp(at, "Keep-Alive", sz) == 0) {
  136. c->keep_alive = 1;
  137. }
  138. }
  139. return 0;
  140. }
  141. static int
  142. http_client_on_message_complete(struct http_parser *p) {
  143. struct http_client *c = p->data;
  144. /* keep-alive detection */
  145. if (c->parser.flags & F_CONNECTION_CLOSE) {
  146. c->keep_alive = 0;
  147. } else if(c->parser.http_major == 1 && c->parser.http_minor == 1) { /* 1.1 */
  148. c->keep_alive = 1;
  149. }
  150. c->http_version = c->parser.http_minor;
  151. if(p->upgrade && c->w->s->cfg->websockets) { /* WebSocket, don't execute just yet */
  152. c->is_websocket = 1;
  153. return 0;
  154. }
  155. /* handle default root object */
  156. if(c->path_sz == 1 && *c->path == '/' && c->w->s->cfg->default_root) { /* replace */
  157. free(c->path);
  158. c->path = strdup(c->w->s->cfg->default_root);
  159. c->path_sz = strlen(c->path);
  160. }
  161. worker_process_client(c);
  162. http_client_reset(c);
  163. return 0;
  164. }
  165. struct http_client *
  166. http_client_new(struct worker *w, int fd, in_addr_t addr) {
  167. struct http_client *c = calloc(1, sizeof(struct http_client));
  168. c->fd = fd;
  169. c->w = w;
  170. c->addr = addr;
  171. c->s = w->s;
  172. /* parser */
  173. http_parser_init(&c->parser, HTTP_REQUEST);
  174. c->parser.data = c;
  175. /* callbacks */
  176. c->settings.on_url = http_client_on_url;
  177. c->settings.on_query_string = http_client_on_query_string;
  178. c->settings.on_body = http_client_on_body;
  179. c->settings.on_message_complete = http_client_on_message_complete;
  180. c->settings.on_header_field = http_client_on_header_name;
  181. c->settings.on_header_value = http_client_on_header_value;
  182. c->last_cb = LAST_CB_NONE;
  183. return c;
  184. }
  185. void
  186. http_client_reset(struct http_client *c) {
  187. int i;
  188. /* headers */
  189. for(i = 0; i < c->header_count; ++i) {
  190. free(c->headers[i].key);
  191. free(c->headers[i].val);
  192. }
  193. free(c->headers);
  194. c->headers = NULL;
  195. c->header_count = 0;
  196. /* other data */
  197. free(c->body); c->body = NULL;
  198. c->body_sz = 0;
  199. free(c->path); c->path = NULL;
  200. c->path_sz = 0;
  201. free(c->type); c->type = NULL;
  202. free(c->jsonp); c->jsonp = NULL;
  203. free(c->filename); c->filename = NULL;
  204. c->request_sz = 0;
  205. /* no last known header callback */
  206. c->last_cb = LAST_CB_NONE;
  207. /* mark as broken if client doesn't support Keep-Alive. */
  208. if(c->keep_alive == 0) {
  209. c->broken = 1;
  210. }
  211. }
  212. void
  213. http_client_free(struct http_client *c) {
  214. http_client_reset(c);
  215. free(c->buffer);
  216. free(c);
  217. }
  218. int
  219. http_client_read(struct http_client *c) {
  220. char buffer[4096];
  221. int ret;
  222. ret = read(c->fd, buffer, sizeof(buffer));
  223. if(ret <= 0) {
  224. /* broken link, free buffer and client object */
  225. /* disconnect pub/sub client if there is one. */
  226. if(c->pub_sub && c->pub_sub->ac) {
  227. struct cmd *cmd = c->pub_sub;
  228. /* disconnect from all channels */
  229. redisAsyncDisconnect(c->pub_sub->ac);
  230. if(c->pub_sub) c->pub_sub->ac = NULL;
  231. c->pub_sub = NULL;
  232. /* delete command object */
  233. cmd_free(cmd);
  234. }
  235. close(c->fd);
  236. http_client_free(c);
  237. return (int)CLIENT_DISCONNECTED;
  238. }
  239. /* save what we've just read */
  240. c->buffer = realloc(c->buffer, c->sz + ret);
  241. if(!c->buffer) {
  242. return (int)CLIENT_OOM;
  243. }
  244. memcpy(c->buffer + c->sz, buffer, ret);
  245. c->sz += ret;
  246. /* keep track of total sent */
  247. c->request_sz += ret;
  248. return ret;
  249. }
  250. int
  251. http_client_remove_data(struct http_client *c, size_t sz) {
  252. char *buffer;
  253. if(c->sz < sz)
  254. return -1;
  255. /* replace buffer */
  256. CHECK_ALLOC(c, buffer = malloc(c->sz - sz));
  257. memcpy(buffer, c->buffer + sz, c->sz - sz);
  258. free(c->buffer);
  259. c->buffer = buffer;
  260. c->sz -= sz;
  261. return 0;
  262. }
  263. int
  264. http_client_execute(struct http_client *c) {
  265. int nparsed = http_parser_execute(&c->parser, &c->settings, c->buffer, c->sz);
  266. if(!c->is_websocket) {
  267. /* removed consumed data, all has been copied already. */
  268. free(c->buffer);
  269. c->buffer = NULL;
  270. c->sz = 0;
  271. }
  272. return nparsed;
  273. }
  274. /*
  275. * Find header value, returns NULL if not found.
  276. */
  277. const char *
  278. client_get_header(struct http_client *c, const char *key) {
  279. int i;
  280. size_t sz = strlen(key);
  281. for(i = 0; i < c->header_count; ++i) {
  282. if(sz == c->headers[i].key_sz &&
  283. strncasecmp(key, c->headers[i].key, sz) == 0) {
  284. return c->headers[i].val;
  285. }
  286. }
  287. return NULL;
  288. }