Avoid recursion when processing residual inbuf data.
[shim.git] / httpconn.c
blob032afaf9d750f46744b897c41b560a78941d1d31
1 #include "netheaders.h"
3 #include <sys/queue.h>
4 #include <assert.h>
5 #include <stdarg.h>
6 #include <stdlib.h>
7 #include <string.h>
9 #include <event2/util.h>
10 #include <event2/event.h>
11 #include <event2/bufferevent.h>
12 #include <event2/buffer.h>
14 #include "httpconn.h"
15 #include "conn.h"
16 #include "headers.h"
17 #include "util.h"
18 #include "log.h"
20 #define EVENT0(conn, slot) \
21 (conn)->cbs->slot((conn), (conn)->cbarg)
22 #define EVENT1(conn, slot, a) \
23 (conn)->cbs->slot((conn), (a), (conn)->cbarg)
24 #define EVENT2(conn, slot, a, b) \
25 (conn)->cbs->slot((conn), (a), (b), (conn)->cbarg)
26 #define EVENT3(conn, slot, a, b, c) \
27 (conn)->cbs->slot((conn), (a), (b), (c), (conn)->cbarg)
28 #define EVENT4(conn, slot, a, b, c, d) \
29 (conn)->cbs->slot((conn), (a), (b), (c), (d), (conn)->cbarg)
31 /* max amount of data we can have backlogged on outbuf before choaking */
32 static size_t max_write_backlog = 50 * 1024;
34 /* the number of seconds to keep an idle connections hanging around */
35 static struct timeval idle_client_timeout = {120, 0};
36 static struct timeval idle_server_timeout = {120, 0};
38 struct http_conn {
39 enum http_state state;
40 enum http_version vers;
41 enum http_te te;
42 enum http_type type;
43 enum http_te output_te;
44 int choked;
45 int has_body;
46 int read_paused;
47 int tunnel_read_paused;
48 int msg_complete_on_eof;
49 int persistent;
50 int expect_continue;
51 int will_flush;
52 int will_free;
53 const struct http_cbs *cbs;
54 void *cbarg;
55 ev_int64_t body_length;
56 ev_int64_t data_remaining;
57 char *firstline;
58 struct header_list *headers;
59 struct event_base *base;
60 struct bufferevent *bev;
61 struct bufferevent *tunnel_bev;
62 struct evbuffer *inbuf_processed;
65 static int
66 method_from_string(enum http_method *m, const char *method)
68 if (!evutil_ascii_strcasecmp(method, "GET"))
69 *m = METH_GET;
70 else if (!evutil_ascii_strcasecmp(method, "HEAD"))
71 *m = METH_HEAD;
72 else if (!evutil_ascii_strcasecmp(method, "POST"))
73 *m = METH_POST;
74 else if (!evutil_ascii_strcasecmp(method, "PUT"))
75 *m = METH_PUT;
76 else if (!evutil_ascii_strcasecmp(method, "CONNECT"))
77 *m = METH_CONNECT;
78 else {
79 log_warn("method_from_string: unknown method, '%s'", method);
80 return -1;
83 return 0;
86 const char *
87 http_method_to_string(enum http_method m)
89 switch (m) {
90 case METH_GET:
91 return "GET";
92 case METH_HEAD:
93 return "HEAD";
94 case METH_POST:
95 return "POST";
96 case METH_PUT:
97 return "PUT";
98 case METH_CONNECT:
99 return "CONNECT";
102 log_fatal("http_method_to_string: unknown method %d", m);
103 return "???";
106 static int
107 version_from_string(enum http_version *v, const char *vers)
109 if (evutil_ascii_strncasecmp(vers, "HTTP/", 5)) {
110 log_warn("version_from_string: bad http-version, '%s'", vers);
111 return -1;
114 vers += 5;
116 /* XXX this only understands 1.0 and 1.1 */
118 if (!strcmp(vers, "1.0"))
119 *v = HTTP_10;
120 else if (!strcmp(vers, "1.1"))
121 *v = HTTP_11;
122 else {
123 log_warn("version_from_string: unknown http-version, '%s'",
124 vers);
125 return -1;
128 return 0;
131 const char *
132 http_version_to_string(enum http_version v)
134 switch (v) {
135 case HTTP_UNKNOWN:
136 return "HTTP/??";
137 case HTTP_10:
138 return "HTTP/1.0";
139 case HTTP_11:
140 return "HTTP/1.1";
143 log_fatal("http_version_to_string: unknown version %d", v);
144 return "???";
147 const char *
148 http_conn_error_to_string(enum http_conn_error err)
150 switch (err) {
151 case ERROR_NONE:
152 return "No error";
153 case ERROR_CONNECT_FAILED:
154 return "Connection failed";
155 case ERROR_IDLE_CONN_TIMEDOUT:
156 return "Idle connection timed out";
157 case ERROR_CLIENT_EXPECTATION_FAILED:
158 return "Can't statisfy client's expectation";
159 case ERROR_CLIENT_POST_WITHOUT_LENGTH:
160 return "Client post with unknown length";
161 case ERROR_INCOMPLETE_HEADERS:
162 return "Connection terminated while reading headers";
163 case ERROR_INCOMPLETE_BODY:
164 return "Connection terminated prematurely while reading body";
165 case ERROR_HEADER_PARSE_FAILED:
166 return "Invalid client request";
167 case ERROR_CHUNK_PARSE_FAILED:
168 return "Invalid chunked data";
169 case ERROR_WRITE_FAILED:
170 return "Write failed";
171 case ERROR_TUNNEL_CONNECT_FAILED:
172 return "Tunnel connection failed";
173 case ERROR_TUNNEL_CLOSED:
174 return "Tunnel closed";
177 return "???";
180 static void
181 begin_message(struct http_conn *conn)
183 assert(conn->headers == NULL && conn->firstline == NULL);
184 conn->headers = mem_calloc(1, sizeof(*conn->headers));
185 TAILQ_INIT(conn->headers);
186 conn->state = HTTP_STATE_IDLE;
187 if (!conn->read_paused)
188 bufferevent_enable(conn->bev, EV_READ);
189 // XXX we should have a separate function to tell that server is idle.
190 if (conn->type == HTTP_SERVER)
191 bufferevent_set_timeouts(conn->bev, &idle_server_timeout, NULL);
192 else
193 bufferevent_set_timeouts(conn->bev, &idle_client_timeout, NULL);
196 static void
197 end_message(struct http_conn *conn, enum http_conn_error err)
199 if (conn->firstline)
200 mem_free(conn->firstline);
201 if (conn->headers) {
202 headers_clear(conn->headers);
203 mem_free(conn->headers);
206 conn->firstline = NULL;
207 conn->headers = NULL;
209 if (err != ERROR_NONE || !conn->persistent) {
210 conn->state = HTTP_STATE_MANGLED;
211 http_conn_stop_reading(conn);
212 } else
213 begin_message(conn);
215 if (err != ERROR_NONE)
216 EVENT1(conn, on_error, err);
217 else
218 EVENT0(conn, on_msg_complete);
221 static struct http_request *
222 build_request(struct http_conn *conn)
224 struct http_request *req;
225 struct token_list tokens;
226 struct token *method, *url, *vers;
227 enum http_method m;
228 enum http_version v;
229 struct url *u = NULL;
230 size_t ntokens;
232 assert(conn->type == HTTP_CLIENT);
234 TAILQ_INIT(&tokens);
235 req = NULL;
237 ntokens = tokenize(conn->firstline, " ", 4, &tokens);
238 if (ntokens != 3)
239 goto out;
241 method = TAILQ_FIRST(&tokens);
242 url = TAILQ_NEXT(method, next);
243 vers = TAILQ_NEXT(url, next);
245 if (method_from_string(&m, method->token) < 0 ||
246 version_from_string(&v, vers->token) < 0)
247 goto out;
249 if (m == METH_CONNECT)
250 u = url_connect_tokenize(url->token);
251 else
252 u = url_tokenize(url->token);
253 if (!u)
254 goto out;
256 req = mem_calloc(1, sizeof(*req));
257 req->meth = m;
258 req->vers = v;
259 req->url = u;
260 u = NULL;
261 req->headers = conn->headers;
263 out:
264 url_free(u);
265 token_list_clear(&tokens);
267 return req;
270 static struct http_response *
271 build_response(struct http_conn *conn)
273 struct http_response *resp;
274 struct token_list tokens;
275 struct token *vers, *code, *reason;
276 enum http_version v;
277 int c;
278 size_t ntokens;
280 assert(conn->type == HTTP_SERVER);
282 TAILQ_INIT(&tokens);
283 resp = NULL;
285 ntokens = tokenize(conn->firstline, " ", 2, &tokens);
286 if (ntokens != 3)
287 goto out;
289 vers = TAILQ_FIRST(&tokens);
290 code = TAILQ_NEXT(vers, next);
291 reason = TAILQ_NEXT(code, next);
292 c = atoi(code->token);
294 if (version_from_string(&v, vers->token) < 0 || c < 100 || c > 999)
295 goto out;
297 resp = mem_calloc(1, sizeof(*resp));
298 resp->vers = v;
299 resp->code = c;
300 resp->reason = reason->token;
301 reason->token = NULL; /* so token_list_clear will skip this */
302 resp->headers = conn->headers;
304 out:
305 token_list_clear(&tokens);
307 return resp;
310 /* return -1 failure, 0 incomplete, 1 ok */
311 static int
312 parse_chunk_len(struct http_conn *conn)
314 struct evbuffer *inbuf = bufferevent_get_input(conn->bev);
315 char *line;
316 ev_int64_t len;
318 while ((line = evbuffer_readln(inbuf, NULL, EVBUFFER_EOL_CRLF))) {
319 if (*line == '\0') {
320 mem_free(line);
321 continue;
324 len = get_int(line, 16);
325 mem_free(line);
326 if (len < 0) {
327 log_warn("parse_chunk_len: invalid chunk len");
328 return -1;
331 conn->data_remaining = len;
332 return 1;
335 return 0;
338 static void
339 read_chunk(struct http_conn *conn)
341 struct evbuffer *inbuf = bufferevent_get_input(conn->bev);
342 size_t len;
343 char *line;
344 int ret;
346 while ((len = evbuffer_get_length(inbuf)) > 0) {
347 if (conn->data_remaining < 0) {
348 ret = parse_chunk_len(conn);
349 if (ret <= 0) {
350 if (ret < 0)
351 end_message(conn,
352 ERROR_CHUNK_PARSE_FAILED);
353 return;
355 } else if (conn->data_remaining == 0) {
356 line = evbuffer_readln(inbuf, NULL, EVBUFFER_EOL_CRLF);
357 if (line) {
358 /* XXX doesn't handle trailers */
359 mem_free(line);
360 end_message(conn, ERROR_NONE);
362 return;
363 } else {
364 /* XXX should mind potential overflow */
365 if (len >= (size_t)conn->data_remaining)
366 len = (size_t)conn->data_remaining;
368 evbuffer_remove_buffer(inbuf, conn->inbuf_processed,
369 len);
370 EVENT1(conn, on_read_body, conn->inbuf_processed);
371 conn->data_remaining -= len;
373 if (conn->data_remaining == 0)
374 conn->data_remaining = -1;
379 static void
380 read_body(struct http_conn *conn)
382 struct evbuffer *inbuf = bufferevent_get_input(conn->bev);
383 size_t len;
385 assert(conn->has_body);
387 if (conn->te == TE_CHUNKED) {
388 read_chunk(conn);
389 return;
392 len = evbuffer_get_length(inbuf);
393 if (len) {
394 /* XXX should mind potential overflow */
395 if (conn->data_remaining >= 0 &&
396 len > (size_t)conn->data_remaining) {
397 len = (size_t)conn->data_remaining;
398 evbuffer_remove_buffer(inbuf, conn->inbuf_processed,
399 len);
400 EVENT1(conn, on_read_body, conn->inbuf_processed);
401 } else {
402 evbuffer_add_buffer(conn->inbuf_processed, inbuf);
403 EVENT1(conn, on_read_body, conn->inbuf_processed);
406 conn->data_remaining -= len;
407 if (conn->data_remaining == 0)
408 end_message(conn, ERROR_NONE);
412 static enum http_conn_error
413 check_headers(struct http_conn *conn, struct http_request *req,
414 struct http_response *resp)
416 enum http_version vers;
417 int persistent;
418 int tunnel;
419 char *val;
421 conn->te = TE_IDENTITY;
422 conn->has_body = 1;
423 conn->msg_complete_on_eof = 0;
424 conn->data_remaining = -1;
425 conn->body_length = -1;
426 conn->expect_continue = 0;
427 tunnel = 0;
429 if (conn->type == HTTP_CLIENT) {
430 vers = req->vers;
431 conn->has_body = 0;
432 if (req->meth == METH_POST ||
433 req->meth == METH_PUT)
434 conn->has_body = 1;
435 else if (req->meth == METH_CONNECT)
436 tunnel = 1;
438 val = headers_find(conn->headers, "Expect");
439 if (val) {
440 int cont;
442 cont = !evutil_ascii_strcasecmp(val, "100-continue");
443 mem_free(val);
444 if (cont == 0 || !conn->has_body)
445 return ERROR_CLIENT_EXPECTATION_FAILED;
447 if (cont && req->vers != HTTP_11) {
448 cont = 0;
449 log_info("http: ignoring expect continue from "
450 "old client");
451 headers_remove(conn->headers, "Expect");
454 conn->expect_continue = cont;
456 } else { /* server */
457 vers = resp->vers;
458 if ((resp->code >= 100 && resp->code < 200) ||
459 resp->code == 204 || resp->code == 205 ||
460 resp->code == 304)
461 conn->has_body = 0;
464 /* check headers */
465 if (conn->has_body) {
466 val = headers_find(conn->headers, "transfer-encoding");
467 if (val) {
468 if (!evutil_ascii_strcasecmp(val, "chunked"))
469 conn->te = TE_CHUNKED;
470 mem_free(val);
473 if (conn->te != TE_CHUNKED) {
474 val = headers_find(conn->headers, "content-length");
475 if (val) {
476 ev_int64_t iv;
477 iv = get_int(val, 10);
478 if (iv < 0) {
479 log_warn("http: mangled "
480 "Content-Length");
481 headers_remove(conn->headers,
482 "content-length");
483 } else
484 conn->body_length = iv;
485 mem_free(val);
486 if (conn->body_length == 0)
487 conn->has_body = 0;
488 } else {
489 conn->msg_complete_on_eof = 1;
493 if (conn->type == HTTP_CLIENT && conn->body_length < 0 &&
494 conn->te != TE_CHUNKED)
495 return ERROR_CLIENT_POST_WITHOUT_LENGTH;
497 conn->data_remaining = conn->body_length;
499 assert(vers != HTTP_UNKNOWN);
501 persistent = 0;
502 if (!tunnel && !conn->msg_complete_on_eof && vers == HTTP_11)
503 persistent = 1;
505 if (conn->vers != HTTP_UNKNOWN && conn->vers != vers) {
506 log_warn("http_conn: http version changed!");
507 persistent = 0;
509 conn->vers = vers;
511 if (persistent) {
512 val = headers_find(conn->headers, "connection");
513 if (val) {
514 if (!evutil_ascii_strcasecmp(val, "close"))
515 persistent = 0;
516 mem_free(val);
519 conn->persistent = persistent;
521 return ERROR_NONE;
524 static void
525 read_headers(struct http_conn *conn)
527 int failed = 0;
528 struct evbuffer *inbuf = bufferevent_get_input(conn->bev);
529 struct http_request *req = NULL;
530 struct http_response *resp = NULL;
531 enum http_conn_error err;
533 assert(conn->state == HTTP_STATE_READ_HEADERS);
535 switch (headers_load(conn->headers, inbuf)) {
536 case -1:
537 end_message(conn, ERROR_HEADER_PARSE_FAILED);
538 return;
539 case 0:
540 return;
541 /* case 1: finished, fall thru */
544 assert(conn->firstline);
546 if (conn->type == HTTP_CLIENT) {
547 req = build_request(conn);
548 if (!req)
549 failed = 1;
550 } else {
551 resp = build_response(conn);
552 if (!resp)
553 failed = 1;
556 mem_free(conn->firstline);
557 conn->firstline = NULL;
559 if (failed) {
560 assert(!req && !resp);
561 end_message(conn, ERROR_HEADER_PARSE_FAILED);
562 return;
565 err = check_headers(conn, req, resp);
566 conn->headers = NULL;
568 if (err == ERROR_NONE) {
569 int server_continuation = 0;
571 /* ownership of req or resp is now passed on */
572 if (req)
573 EVENT1(conn, on_client_request, req);
574 if (resp) {
575 if (resp->code == 100) {
576 http_response_free(resp);
577 EVENT0(conn, on_server_continuation);
578 begin_message(conn);
579 server_continuation = 1;
580 } else
581 EVENT1(conn, on_server_response, resp);
584 if (!server_continuation &&
585 conn->state != HTTP_STATE_TUNNEL_CONNECTING) {
586 if (!conn->has_body)
587 end_message(conn, ERROR_NONE);
588 else
589 conn->state = HTTP_STATE_READ_BODY;
591 } else {
592 http_request_free(req);
593 http_response_free(resp);
594 end_message(conn, err);
598 static void
599 tunnel_transfer_data(struct http_conn *conn, struct bufferevent *to,
600 struct bufferevent *from)
602 struct evbuffer *frombuf = bufferevent_get_input(from);
603 struct evbuffer *tobuf = bufferevent_get_output(to);
605 if (evbuffer_get_length(frombuf) == 0)
606 return;
608 evbuffer_add_buffer(tobuf, frombuf);
609 if (evbuffer_get_length(tobuf) > max_write_backlog) {
610 bufferevent_setwatermark(to, EV_WRITE,
611 max_write_backlog / 2, 0);
612 bufferevent_disable(from, EV_READ);
613 if (from == conn->bev) {
614 log_debug("tunnel: throttling client read");
615 conn->read_paused = 1;
616 } else {
617 log_debug("tunnel: throttling server read");
618 conn->tunnel_read_paused = 1;
623 static void
624 tunnel_writecb(struct bufferevent *bev, void *_conn)
626 struct http_conn *conn = _conn;
628 if (conn->state == HTTP_STATE_TUNNEL_OPEN) {
629 if (conn->tunnel_read_paused && bev == conn->bev) {
630 log_debug("tunnel: unthrottling server read");
631 conn->tunnel_read_paused = 0;
632 bufferevent_enable(conn->tunnel_bev, EV_READ);
633 bufferevent_setwatermark(bev, EV_WRITE, 0, 0);
634 } else if (conn->read_paused && bev == conn->tunnel_bev) {
635 log_debug("tunnel: unthrottling client read");
636 conn->read_paused = 0;
637 bufferevent_enable(conn->bev, EV_READ);
638 bufferevent_setwatermark(bev, EV_WRITE, 0, 0);
640 } else {
641 log_debug("tunnel: flushed!");
642 bufferevent_setcb(conn->bev, NULL, NULL, NULL, NULL);
643 bufferevent_setcb(conn->tunnel_bev, NULL, NULL, NULL, NULL);
644 EVENT1(conn, on_error, ERROR_TUNNEL_CLOSED);
648 static void
649 tunnel_readcb(struct bufferevent *bev, void *_conn)
651 struct http_conn *conn = _conn;
653 if (bev == conn->bev)
654 tunnel_transfer_data(conn, conn->tunnel_bev, bev);
655 else
656 tunnel_transfer_data(conn, conn->bev, bev);
659 static void
660 tunnel_errorcb(struct bufferevent *bev, short what, void *_conn)
662 struct http_conn *conn = _conn;
663 struct evbuffer *buf;
665 switch (conn->state) {
666 case HTTP_STATE_TUNNEL_OPEN:
667 if (bev == conn->bev) {
668 log_debug("tunnel: client closed conn...");
669 bev = conn->tunnel_bev;
670 } else {
671 log_debug("tunnel: server closed conn...");
672 bev = conn->bev;
674 buf = bufferevent_get_output(bev);
675 if (evbuffer_get_length(buf)) {
676 conn->state = HTTP_STATE_TUNNEL_FLUSHING;
677 log_debug("tunnel: flushing %lu bytes...",
678 (unsigned long)evbuffer_get_length(buf));
679 bufferevent_disable(bev, EV_READ);
680 bufferevent_setcb(bev, NULL, tunnel_writecb,
681 tunnel_errorcb, conn);
682 break;
684 /* nothing left to write.. lets just fall thru... */
685 case HTTP_STATE_TUNNEL_FLUSHING:
686 /* an error happend while flushing, lets just give up. */
687 bufferevent_setcb(conn->bev, NULL, NULL, NULL, NULL);
688 bufferevent_setcb(conn->tunnel_bev, NULL, NULL, NULL, NULL);
689 EVENT1(conn, on_error, ERROR_TUNNEL_CLOSED);
690 break;
691 default:
692 log_fatal("tunnel: errorcb called in invalid state!");
696 static void
697 tunnel_connectcb(struct bufferevent *bev, int ok, void *_conn)
699 struct http_conn *conn = _conn;
701 assert(conn->state == HTTP_STATE_TUNNEL_CONNECTING);
703 if (ok) {
704 conn->state = HTTP_STATE_TUNNEL_OPEN;
705 bufferevent_setcb(conn->tunnel_bev, tunnel_readcb,
706 tunnel_writecb, tunnel_errorcb, conn);
707 bufferevent_enable(conn->bev, EV_READ);
708 bufferevent_enable(conn->tunnel_bev, EV_READ);
709 conn->read_paused = 0;
710 conn->tunnel_read_paused = 0;
711 tunnel_transfer_data(conn, conn->tunnel_bev, conn->bev);
712 evbuffer_add_printf(bufferevent_get_output(conn->bev),
713 "%s 200 Connection established\r\n\r\n",
714 http_version_to_string(conn->vers));
715 } else {
716 bufferevent_setcb(conn->tunnel_bev, NULL, NULL,
717 NULL, NULL);
718 EVENT1(conn, on_error, ERROR_TUNNEL_CONNECT_FAILED);
722 static void
723 http_errorcb(struct bufferevent *bev, short what, void *_conn)
725 enum http_state state;
726 struct http_conn *conn = _conn;
728 assert(!(what & BEV_EVENT_CONNECTED));
730 state = conn->state;
731 conn->state = HTTP_STATE_MANGLED;
733 if (what & BEV_EVENT_WRITING) {
734 end_message(conn, ERROR_WRITE_FAILED);
735 return;
738 switch (state) {
739 case HTTP_STATE_IDLE:
740 end_message(conn, ERROR_IDLE_CONN_TIMEDOUT);
741 break;
742 case HTTP_STATE_READ_FIRSTLINE:
743 case HTTP_STATE_READ_HEADERS:
744 end_message(conn, ERROR_INCOMPLETE_HEADERS);
745 break;
746 case HTTP_STATE_READ_BODY:
747 if ((what & BEV_EVENT_EOF) && conn->msg_complete_on_eof)
748 end_message(conn, ERROR_NONE);
749 else
750 end_message(conn, ERROR_INCOMPLETE_BODY);
751 break;
752 default:
753 log_fatal("http_conn: errorcb called in invalid state");
757 static void
758 process_one_step(struct http_conn *conn)
760 struct evbuffer *inbuf = bufferevent_get_input(conn->bev);
762 switch (conn->state) {
763 case HTTP_STATE_IDLE:
764 conn->state = HTTP_STATE_READ_FIRSTLINE;
765 bufferevent_set_timeouts(conn->bev, NULL, NULL);
766 /* fallthru... */
767 case HTTP_STATE_READ_FIRSTLINE:
768 assert(conn->firstline == NULL);
769 conn->firstline = evbuffer_readln(inbuf, NULL,
770 EVBUFFER_EOL_CRLF);
771 if (conn->firstline)
772 conn->state = HTTP_STATE_READ_HEADERS;
773 break;
774 case HTTP_STATE_READ_HEADERS:
775 read_headers(conn);
776 break;
777 case HTTP_STATE_READ_BODY:
778 read_body(conn);
779 break;
780 default:
781 log_fatal("http_conn: read cb called in invalid state");
785 static void
786 process_inbuf(struct http_conn *conn)
788 struct evbuffer *inbuf = bufferevent_get_input(conn->bev);
789 enum http_state state_before;
791 if (evbuffer_get_length(inbuf) == 0)
792 return;
794 do {
795 state_before = conn->state;
796 process_one_step(conn);
797 } while (!conn->read_paused &&
798 evbuffer_get_length(inbuf) > 0 &&
799 state_before != conn->state);
802 static void
803 http_readcb(struct bufferevent *bev, void *_conn)
805 process_inbuf(_conn);
808 static void
809 http_writecb(struct bufferevent *bev, void *_conn)
811 struct http_conn *conn = _conn;
812 struct evbuffer *outbuf = bufferevent_get_output(bev);
814 if (conn->choked) {
815 bufferevent_setwatermark(bev, EV_WRITE, 0, 0);
816 conn->choked = 0;
817 EVENT0(conn, on_write_more);
818 } else if (evbuffer_get_length(outbuf) == 0) {
819 if (!conn->will_flush)
820 EVENT0(conn, on_flush);
824 static void
825 http_connectcb(struct bufferevent *bev, int ok, void *_conn)
827 struct http_conn *conn = _conn;
829 assert(conn->state == HTTP_STATE_CONNECTING);
830 bufferevent_setcb(conn->bev, http_readcb, http_writecb,
831 http_errorcb, conn);
833 if (ok) {
834 begin_message(conn);
835 EVENT0(conn, on_connect);
836 } else {
837 conn->state = HTTP_STATE_MANGLED;
838 EVENT1(conn, on_error, ERROR_CONNECT_FAILED);
843 struct http_conn *
844 http_conn_new(struct event_base *base, evutil_socket_t sock,
845 enum http_type type, const struct http_cbs *cbs, void *cbarg)
847 struct http_conn *conn;
849 conn = mem_calloc(1, sizeof(*conn));
850 conn->base = base;
851 conn->type = type;
852 conn->cbs = cbs;
853 conn->cbarg = cbarg;
854 conn->bev = bufferevent_socket_new(base, sock,
855 BEV_OPT_CLOSE_ON_FREE);
856 if (!conn->bev)
857 log_fatal("http_conn: failed to create bufferevent");
859 conn->inbuf_processed = evbuffer_new();
860 if (!conn->inbuf_processed)
861 log_fatal("http_conn: failed to create evbuffer");
863 if (type != HTTP_SERVER)
864 bufferevent_setcb(conn->bev, http_readcb, http_writecb,
865 http_errorcb, conn);
867 if (sock >= 0)
868 begin_message(conn);
870 return conn;
874 http_conn_connect(struct http_conn *conn, struct evdns_base *dns,
875 int family, const char *host, int port)
877 assert(conn->type == HTTP_SERVER);
878 conn->state = HTTP_STATE_CONNECTING;
879 return conn_connect_bufferevent(conn->bev, dns, family, host, port,
880 http_connectcb, conn);
883 static void
884 deferred_free(evutil_socket_t s, short what, void *arg)
886 struct http_conn *conn = arg;
887 bufferevent_free(conn->bev);
888 if (conn->tunnel_bev)
889 bufferevent_free(conn->tunnel_bev);
890 evbuffer_free(conn->inbuf_processed);
891 mem_free(conn);
894 void
895 http_conn_free(struct http_conn *conn)
897 if (conn->will_free)
898 return;
900 conn->will_free = 1;
901 http_conn_stop_reading(conn);
902 bufferevent_disable(conn->bev, EV_WRITE);
903 bufferevent_setcb(conn->bev, NULL, NULL, NULL, NULL);
904 conn->cbs = NULL;
905 event_base_once(conn->base, -1, EV_TIMEOUT, deferred_free, conn, NULL);
908 void
909 http_conn_write_request(struct http_conn *conn, struct http_request *req)
911 struct evbuffer *outbuf;
913 assert(conn->type == HTTP_SERVER);
915 headers_remove(req->headers, "connection");
916 req->vers = HTTP_11;
918 outbuf = bufferevent_get_output(conn->bev);
920 evbuffer_add_printf(outbuf, "%s %s %s\r\n",
921 http_method_to_string(req->meth),
922 req->url->path,
923 http_version_to_string(req->vers));
925 headers_dump(req->headers, outbuf);
929 http_conn_expect_continue(struct http_conn *conn)
931 return conn->expect_continue;
934 void
935 http_conn_write_continue(struct http_conn *conn)
937 struct evbuffer *outbuf;
939 if (conn->expect_continue) {
940 log_debug("httpconn: writing continue status");
941 outbuf = bufferevent_get_output(conn->bev);
942 conn->expect_continue = 0;
943 assert(conn->vers == HTTP_11);
944 evbuffer_add_printf(outbuf, "HTTP/1.1 100 Continue\r\n\r\n");
948 void
949 http_conn_write_response(struct http_conn *conn, struct http_response *resp)
951 struct evbuffer *outbuf;
953 assert(conn->type == HTTP_CLIENT);
954 assert(conn->vers != HTTP_UNKNOWN);
956 headers_remove(resp->headers, "connection");
957 headers_remove(resp->headers, "transfer-encoding");
958 resp->vers = conn->vers;
960 if (conn->vers == HTTP_10 || !conn->persistent) {
961 if (conn->vers == HTTP_10)
962 conn->output_te = TE_IDENTITY;
963 headers_add_key_val(resp->headers, "Connection", "close");
965 if (conn->output_te == TE_CHUNKED) {
966 headers_add_key_val(resp->headers,
967 "Transfer-Encoding", "chunked");
970 outbuf = bufferevent_get_output(conn->bev);
972 evbuffer_add_printf(outbuf, "%s %d %s\r\n",
973 http_version_to_string(conn->vers),
974 resp->code,
975 resp->reason);
977 headers_dump(resp->headers, outbuf);
981 http_conn_write_buf(struct http_conn *conn, struct evbuffer *buf)
983 struct evbuffer *outbuf;
985 outbuf = bufferevent_get_output(conn->bev);
987 if (conn->output_te == TE_CHUNKED)
988 evbuffer_add_printf(outbuf, "%x\r\n",
989 (unsigned)evbuffer_get_length(buf));
990 evbuffer_add_buffer(outbuf, buf);
991 if (conn->output_te == TE_CHUNKED)
992 evbuffer_add(outbuf, "\r\n", 2);
994 /* have we choked? */
995 if (evbuffer_get_length(outbuf) > max_write_backlog) {
996 bufferevent_setwatermark(conn->bev, EV_WRITE,
997 max_write_backlog / 2, 0);
998 conn->choked = 1;
999 return 0;
1002 return 1;
1005 void
1006 http_conn_write_finished(struct http_conn *conn)
1008 if (conn->output_te == TE_CHUNKED)
1009 bufferevent_write(conn->bev, "0\r\n\r\n", 5);
1010 conn->output_te = TE_IDENTITY;
1015 http_conn_current_message_has_body(struct http_conn *conn)
1017 return conn->has_body;
1020 void
1021 http_conn_set_current_message_bodyless(struct http_conn *conn)
1023 assert(conn->type == HTTP_SERVER);
1024 conn->has_body = 0;
1027 enum http_te
1028 http_conn_get_current_message_body_encoding(struct http_conn *conn)
1030 return conn->te;
1033 ev_int64_t
1034 http_conn_get_current_message_body_length(struct http_conn *conn)
1036 return conn->body_length;
1039 void
1040 http_conn_set_output_encoding(struct http_conn *conn, enum http_te te)
1042 conn->output_te = te;
1046 http_conn_is_persistent(struct http_conn *conn)
1048 return conn->persistent;
1051 void
1052 http_conn_disable_persistence(struct http_conn *conn)
1054 conn->persistent = 0;
1057 void
1058 http_conn_stop_reading(struct http_conn *conn)
1060 bufferevent_disable(conn->bev, EV_READ);
1061 conn->read_paused = 1;
1064 static void
1065 deferred_process_inbuf(evutil_socket_t s, short what, void *_conn)
1067 process_inbuf(_conn);
1070 void
1071 http_conn_start_reading(struct http_conn *conn)
1073 struct evbuffer *inbuf = bufferevent_get_input(conn->bev);
1075 bufferevent_enable(conn->bev, EV_READ);
1076 conn->read_paused = 0;
1077 if (evbuffer_get_length(inbuf) > 0)
1078 event_base_once(conn->base, -1, EV_TIMEOUT,
1079 deferred_process_inbuf, conn, NULL);
1082 static void
1083 deferred_flush(evutil_socket_t fd, short what, void *_conn)
1085 struct http_conn *conn = _conn;
1086 struct evbuffer *outbuf = bufferevent_get_output(conn->bev);
1088 if (evbuffer_get_length(outbuf) == 0) {
1089 conn->will_flush = 0;
1090 EVENT0(conn, on_flush);
1094 void
1095 http_conn_flush(struct http_conn *conn)
1097 assert(!conn->will_free);
1098 conn->will_flush = 1;
1099 event_base_once(conn->base, -1, EV_TIMEOUT, deferred_flush, conn, NULL);
1102 void
1103 http_conn_send_error(struct http_conn *conn, int code, const char *fmt, ...)
1105 char length[64];
1106 char reason[256];
1107 struct evbuffer *msg;
1108 struct http_response resp;
1109 struct header_list headers;
1110 va_list ap;
1112 assert(conn->type == HTTP_CLIENT);
1114 TAILQ_INIT(&headers);
1115 msg = evbuffer_new();
1116 resp.headers = &headers;
1118 if (conn->vers == HTTP_UNKNOWN)
1119 conn->vers = HTTP_11;
1122 va_start(ap, fmt);
1123 evutil_vsnprintf(reason, sizeof(reason), fmt, ap);
1124 va_end(ap);
1126 conn->output_te = TE_IDENTITY;
1127 resp.vers = HTTP_11;
1128 resp.code = code;
1129 resp.reason = reason;
1131 evbuffer_add_printf(msg,
1132 "<html>\n"
1133 "<head>\n"
1134 "<title>%d %s</title>\n"
1135 "</head>\n"
1136 "<body>\n"
1137 "<h1>%s</h1>\n"
1138 "</body>\n"
1139 "</html>\n",
1140 code, resp.reason, resp.reason);
1142 evutil_snprintf(length, sizeof(length), "%u",
1143 (unsigned)evbuffer_get_length(msg));
1144 headers_add_key_val(&headers, "Content-Type", "text/html");
1145 headers_add_key_val(&headers, "Content-Length", length);
1146 headers_add_key_val(&headers, "Expires", "0");
1147 headers_add_key_val(&headers, "Cache-Control", "no-cache");
1148 headers_add_key_val(&headers, "Pragma", "no-cache");
1150 http_conn_write_response(conn, &resp);
1151 http_conn_write_buf(conn, msg);
1152 headers_clear(&headers);
1153 evbuffer_free(msg);
1157 http_conn_start_tunnel(struct http_conn *conn, struct evdns_base *dns,
1158 int family, const char *host, int port)
1160 assert(conn->type == HTTP_CLIENT);
1161 assert(conn->tunnel_bev == NULL);
1163 http_conn_stop_reading(conn);
1164 conn->tunnel_bev = bufferevent_socket_new(conn->base, -1,
1165 BEV_OPT_CLOSE_ON_FREE);
1166 bufferevent_setcb(conn->bev, tunnel_readcb,
1167 tunnel_writecb, tunnel_errorcb, conn);
1168 log_info("tunnel: attempting connection to %s:%d",
1169 log_scrub(host), port);
1170 conn->state = HTTP_STATE_TUNNEL_CONNECTING;
1171 return conn_connect_bufferevent(conn->tunnel_bev, dns, family,
1172 host, port, tunnel_connectcb, conn);
1175 void
1176 http_request_free(struct http_request *req)
1178 if (!req)
1179 return;
1181 url_free(req->url);
1182 headers_clear(req->headers);
1183 mem_free(req);
1186 void
1187 http_response_free(struct http_response *resp)
1189 if (!resp)
1190 return;
1192 headers_clear(resp->headers);
1193 mem_free(resp->headers);
1194 mem_free(resp->reason);
1195 mem_free(resp);
1198 #ifdef TEST_HTTP
1199 #include <netinet/in.h>
1200 #include <stdio.h>
1201 #include <event2/dns.h>
1202 #include <event2/listener.h>
1204 static void
1205 proxy_connected(struct http_conn *conn, void *arg)
1207 struct http_request req;
1208 struct header_list headers;
1209 struct evbuffer *buf;
1211 TAILQ_INIT(&headers);
1212 req.meth = METH_GET;
1213 req.url = arg;
1214 req.vers = HTTP_11;
1215 req.headers = &headers;
1217 buf = evbuffer_new();
1218 evbuffer_add_printf(buf, "Host: %s\r\n\r\n", req.url->host);
1219 headers_load(&headers, buf);
1220 evbuffer_free(buf);
1222 http_conn_write_request(conn, &req);
1225 static void
1226 proxy_error(struct http_conn *conn, enum http_conn_error err, void *arg)
1228 fprintf(stderr, "error %d\n", err);
1229 http_conn_free(conn);
1232 static void
1233 proxy_request(struct http_conn *conn, struct http_request *req, void *arg)
1235 struct evbuffer *buf;
1237 fprintf(stderr, "request: %s %s %s\n",
1238 http_method_to_string(req->meth),
1239 req->url->path,
1240 http_version_to_string(req->vers));
1242 buf = evbuffer_new();
1243 headers_dump(req->headers, buf);
1244 fwrite(evbuffer_pullup(buf, evbuffer_get_length(buf)), evbuffer_get_length(buf), 1, stderr);
1245 evbuffer_free(buf);
1248 http_conn_send_error(conn, 401);
1251 static void
1252 proxy_response(struct http_conn *conn, struct http_response *resp, void *arg)
1254 struct evbuffer *buf;
1256 fprintf(stderr, "response: %s, %d, %s\n",
1257 http_version_to_string(resp->vers),
1258 resp->code,
1259 resp->reason);
1261 buf = evbuffer_new();
1262 headers_dump(resp->headers, buf);
1263 fwrite(evbuffer_pullup(buf, evbuffer_get_length(buf)), evbuffer_get_length(buf), 1, stderr);
1264 evbuffer_free(buf);
1267 static void
1268 proxy_read_body(struct http_conn *conn, struct evbuffer *buf, void *arg)
1270 size_t len = evbuffer_get_length(buf);
1271 fwrite(evbuffer_pullup(buf, len), len, 1, stderr);
1272 evbuffer_drain(buf, len);
1275 static void
1276 proxy_msg_complete(struct http_conn *conn, void *arg)
1278 fprintf(stderr, "\n...MSG COMPLETE...\n");
1281 static void
1282 proxy_write_more(struct http_conn *conn, void *arg)
1286 static void
1287 proxy_flush(struct http_conn *conn, void *arg)
1289 fprintf(stderr, "\n....FLUSHED...\n");
1292 static struct http_cbs test_proxy_cbs = {
1293 proxy_connected,
1294 proxy_error,
1295 proxy_request,
1296 proxy_response,
1297 proxy_read_body,
1298 proxy_msg_complete,
1299 proxy_write_more,
1300 proxy_flush
1304 static void
1305 clientcb(struct evconnlistener *ecs, evutil_socket_t s,
1306 struct sockaddr *addr, int len, void *arg)
1308 struct http_conn *client;
1310 client = http_conn_new(evconnlistener_get_base(ecs), s, HTTP_CLIENT, &test_proxy_cbs, arg);
1314 main(int argc, char **argv)
1316 struct event_base *base;
1317 struct evdns_base *dns;
1318 struct http_conn *http;
1319 struct url *url;
1321 base = event_base_new();
1323 if (argc < 2) {
1324 struct evconnlistener *ecs;
1325 struct sockaddr_in sin;
1326 memset(&sin, 0, sizeof(sin));
1327 sin.sin_family=AF_INET;
1328 sin.sin_port = htons(8080);
1329 ecs = evconnlistener_new_bind(base, clientcb, NULL, 0,
1330 LEV_OPT_REUSEABLE, &sin, sizeof(sin));
1331 event_base_dispatch(base);
1332 return 0;
1335 url = url_tokenize(argv[1]);
1336 if (!url)
1337 return 0;
1339 if (url->port < 0)
1340 url->port = 80;
1342 dns = evdns_base_new(base, 1);
1344 http = http_conn_new(base, -1, HTTP_SERVER, &test_proxy_cbs, url);
1345 http_conn_connect(http, dns, AF_UNSPEC, url->host, url->port);
1347 event_base_dispatch(base);
1349 return 0;
1352 #endif