connect method; pipelining fixes
[shim.git] / httpconn.c
blobdcf79003f3b38d14535787f0c8c2e6dba25ad349
2 #include <sys/queue.h>
3 #include <assert.h>
4 #include <stdlib.h>
5 #include <string.h>
7 #include <event2/util.h>
8 #include <event2/event.h>
9 #include <event2/bufferevent.h>
10 #include <event2/buffer.h>
12 #include "httpconn.h"
13 #include "headers.h"
14 #include "util.h"
15 #include "log.h"
17 #define EVENT0(conn, slot) \
18 (conn)->cbs->slot((conn), (conn)->cbarg)
19 #define EVENT1(conn, slot, a) \
20 (conn)->cbs->slot((conn), (a), (conn)->cbarg)
21 #define EVENT2(conn, slot, a, b) \
22 (conn)->cbs->slot((conn), (a), (b), (conn)->cbarg)
23 #define EVENT3(conn, slot, a, b, c) \
24 (conn)->cbs->slot((conn), (a), (b), (c), (conn)->cbarg)
25 #define EVENT4(conn, slot, a, b, c, d) \
26 (conn)->cbs->slot((conn), (a), (b), (c), (d), (conn)->cbarg)
28 /* max amount of data we can have backlogged on outbuf before choaking */
29 static size_t max_write_backlog = 50 * 1024;
31 /* the number of seconds to keep an idle connections hanging around */
32 static struct timeval idle_client_timeout = {120, 0};
33 static struct timeval idle_server_timeout = {120, 0};
35 struct http_conn {
36 enum http_state state;
37 enum http_version vers;
38 enum http_te te;
39 enum http_type type;
40 enum http_te output_te;
41 int choked;
42 int has_body;
43 int read_paused;
44 int tunnel_read_paused;
45 int msg_complete_on_eof;
46 int persistent;
47 const struct http_cbs *cbs;
48 void *cbarg;
49 ev_int64_t body_length;
50 ev_int64_t data_remaining;
51 char *firstline;
52 struct header_list *headers;
53 struct event_base *base;
54 struct bufferevent *bev;
55 struct bufferevent *tunnel_bev;
56 struct evbuffer *inbuf_processed;
59 static int
60 method_from_string(enum http_method *m, const char *method)
62 if (!evutil_ascii_strcasecmp(method, "GET"))
63 *m = METH_GET;
64 else if (!evutil_ascii_strcasecmp(method, "HEAD"))
65 *m = METH_HEAD;
66 else if (!evutil_ascii_strcasecmp(method, "POST"))
67 *m = METH_POST;
68 else if (!evutil_ascii_strcasecmp(method, "PUT"))
69 *m = METH_PUT;
70 else if (!evutil_ascii_strcasecmp(method, "CONNECT"))
71 *m = METH_CONNECT;
72 else {
73 log_warn("method_from_string: unknown method, '%s'", method);
74 return -1;
77 return 0;
80 const char *
81 http_method_to_string(enum http_method m)
83 switch (m) {
84 case METH_GET:
85 return "GET";
86 case METH_HEAD:
87 return "HEAD";
88 case METH_POST:
89 return "POST";
90 case METH_PUT:
91 return "PUT";
92 case METH_CONNECT:
93 return "CONNECT";
96 log_fatal("http_method_to_string: unknown method %d", m);
97 return "???";
100 static int
101 version_from_string(enum http_version *v, const char *vers)
103 if (evutil_ascii_strncasecmp(vers, "HTTP/", 5)) {
104 log_warn("version_from_string: bad http-version, '%s'", vers);
105 return -1;
108 vers += 5;
110 /* XXX this only understands 1.0 and 1.1 */
112 if (!strcmp(vers, "1.0"))
113 *v = HTTP_10;
114 else if (!strcmp(vers, "1.1"))
115 *v = HTTP_11;
116 else {
117 log_warn("version_from_string: unknown http-version, '%s'",
118 vers);
119 return -1;
122 return 0;
125 const char *
126 http_version_to_string(enum http_version v)
128 switch (v) {
129 case HTTP_UNKNOWN:
130 return "HTTP/??";
131 case HTTP_10:
132 return "HTTP/1.0";
133 case HTTP_11:
134 return "HTTP/1.1";
137 log_fatal("http_version_to_string: unknown version %d", v);
138 return "???";
141 static const char *
142 error_code_to_reason_string(int code)
144 switch (code) {
145 case 400:
146 return "Bad Request";
147 case 401:
148 return "Unauthorized";
149 case 403:
150 return "Forbidden";
151 case 404:
152 return "Not Found";
153 case 405:
154 return "Method Not Allowed";
155 case 406:
156 return "Not Acceptable";
157 case 407:
158 return "Proxy Authentication Required";
159 case 408:
160 return "Request Timeout";
161 case 409:
162 return "Conflict";
163 case 410:
164 return "Gone";
165 case 411:
166 return "Length Required";
167 case 412:
168 return "Precondition Failed";
169 case 413:
170 return "Request Entity Too Large";
171 case 414:
172 return "Request-URI Too Long";
173 case 415:
174 return "Unsupported Media Type";
175 case 416:
176 return "Requested Range Not Satisfiable";
177 case 417:
178 return "Expectation Failed";
179 case 421:
180 return "There are too many connections from your internet "
181 "address";
182 case 500:
183 return "Internal Server Error";
184 case 501:
185 return "Not Implemented";
186 case 502:
187 return "Bad Gateway";
188 case 503:
189 return "Service Unavailable";
190 case 504:
191 return "Gateway Timeout";
192 case 505:
193 return "HTTP Version Not Supported";
194 case 530:
195 return "User access denied";
198 return "???";
201 const char *
202 http_conn_error_to_string(enum http_conn_error err)
204 switch (err) {
205 case ERROR_NONE:
206 return "No error";
207 case ERROR_CONNECT_FAILED:
208 return "Connection failed";
209 case ERROR_IDLE_CONN_TIMEDOUT:
210 return "Idle connection timed out";
211 case ERROR_CLIENT_POST_WITHOUT_LENGTH:
212 return "Client post with unknown length";
213 case ERROR_INCOMPLETE_HEADERS:
214 return "Connection terminated while reading headers";
215 case ERROR_INCOMPLETE_BODY:
216 return "Connection terminated prematurely while reading body";
217 case ERROR_HEADER_PARSE_FAILED:
218 return "Invalid headers";
219 case ERROR_CHUNK_PARSE_FAILED:
220 return "Invalid chunked data";
221 case ERROR_WRITE_FAILED:
222 return "Write failed";
223 case ERROR_TUNNEL_CONNECT_FAILED:
224 return "Tunnel connection failed";
225 case ERROR_TUNNEL_CLOSED:
226 return "Tunnel closed";
229 return "???";
232 static void
233 begin_message(struct http_conn *conn)
235 assert(conn->headers == NULL && conn->firstline == NULL);
236 conn->headers = mem_calloc(1, sizeof(*conn->headers));
237 TAILQ_INIT(conn->headers);
238 conn->state = HTTP_STATE_IDLE;
239 if (!conn->read_paused)
240 bufferevent_enable(conn->bev, EV_READ);
241 if (conn->type == HTTP_SERVER)
242 bufferevent_set_timeouts(conn->bev, &idle_server_timeout, NULL);
243 else
244 bufferevent_set_timeouts(conn->bev, &idle_client_timeout, NULL);
247 static void
248 end_message(struct http_conn *conn, enum http_conn_error err)
250 if (conn->firstline)
251 mem_free(conn->firstline);
252 if (conn->headers)
253 headers_clear(conn->headers);
255 if (err != ERROR_NONE || !conn->persistent) {
256 conn->state = HTTP_STATE_MANGLED;
257 http_conn_stop_reading(conn);
258 } else
259 begin_message(conn);
261 if (err != ERROR_NONE)
262 EVENT1(conn, on_error, err);
263 else
264 EVENT0(conn, on_msg_complete);
267 static struct http_request *
268 build_request(struct http_conn *conn)
270 struct http_request *req;
271 struct token_list tokens;
272 struct token *method, *url, *vers;
273 enum http_method m;
274 enum http_version v;
275 struct url *u = NULL;
276 size_t ntokens;
278 assert(conn->type == HTTP_CLIENT);
280 TAILQ_INIT(&tokens);
281 req = NULL;
283 ntokens = tokenize(conn->firstline, " ", 4, &tokens);
284 if (ntokens != 3)
285 goto out;
287 method = TAILQ_FIRST(&tokens);
288 url = TAILQ_NEXT(method, next);
289 vers = TAILQ_NEXT(url, next);
291 if (method_from_string(&m, method->token) < 0 ||
292 version_from_string(&v, vers->token) < 0)
293 goto out;
295 if (m == METH_CONNECT)
296 u = url_connect_tokenize(url->token);
297 else
298 u = url_tokenize(url->token);
299 if (!u)
300 goto out;
302 req = mem_calloc(1, sizeof(*req));
303 req->meth = m;
304 req->vers = v;
305 req->url = u;
306 u = NULL;
307 req->headers = conn->headers;
309 out:
310 url_free(u);
311 token_list_clear(&tokens);
313 return req;
316 static struct http_response *
317 build_response(struct http_conn *conn)
319 struct http_response *resp;
320 struct token_list tokens;
321 struct token *vers, *code, *reason;
322 enum http_version v;
323 int c;
324 size_t ntokens;
326 assert(conn->type == HTTP_SERVER);
328 TAILQ_INIT(&tokens);
329 resp = NULL;
331 ntokens = tokenize(conn->firstline, " ", 2, &tokens);
332 if (ntokens != 3)
333 goto out;
335 vers = TAILQ_FIRST(&tokens);
336 code = TAILQ_NEXT(vers, next);
337 reason = TAILQ_NEXT(code, next);
338 c = atoi(code->token);
340 if (version_from_string(&v, vers->token) < 0 || c < 100 || c > 999)
341 goto out;
343 resp = mem_calloc(1, sizeof(*resp));
344 resp->vers = v;
345 resp->code = c;
346 resp->reason = reason->token;
347 reason->token = NULL; /* so token_list_clear will skip this */
348 resp->headers = conn->headers;
350 out:
351 token_list_clear(&tokens);
353 return resp;
356 /* return -1 failure, 0 incomplete, 1 ok */
357 static int
358 parse_chunk_len(struct http_conn *conn)
360 struct evbuffer *inbuf = bufferevent_get_input(conn->bev);
361 char *line;
362 ev_int64_t len;
364 while ((line = evbuffer_readln(inbuf, NULL, EVBUFFER_EOL_CRLF))) {
365 if (*line == '\0') {
366 mem_free(line);
367 continue;
370 len = get_int(line, 16);
371 mem_free(line);
372 if (len < 0) {
373 log_warn("parse_chunk_len: invalid chunk len");
374 return -1;
377 conn->data_remaining = len;
378 return 1;
381 return 0;
384 static void
385 read_chunk(struct http_conn *conn)
387 struct evbuffer *inbuf = bufferevent_get_input(conn->bev);
388 size_t len;
389 char *line;
390 int ret;
392 while ((len = evbuffer_get_length(inbuf)) > 0) {
393 if (conn->data_remaining < 0) {
394 ret = parse_chunk_len(conn);
395 if (ret <= 0) {
396 if (ret < 0)
397 end_message(conn,
398 ERROR_CHUNK_PARSE_FAILED);
399 return;
401 } else if (conn->data_remaining == 0) {
402 line = evbuffer_readln(inbuf, NULL, EVBUFFER_EOL_CRLF);
403 if (line) {
404 /* XXX doesn't handle trailers */
405 mem_free(line);
406 end_message(conn, ERROR_NONE);
408 return;
409 } else {
410 /* XXX should mind potential overflow */
411 if (len >= (size_t)conn->data_remaining)
412 len = (size_t)conn->data_remaining;
414 evbuffer_remove_buffer(inbuf, conn->inbuf_processed,
415 len);
416 EVENT1(conn, on_read_body, conn->inbuf_processed);
417 conn->data_remaining -= len;
419 if (conn->data_remaining == 0)
420 conn->data_remaining = -1;
425 static void
426 read_body(struct http_conn *conn)
428 struct evbuffer *inbuf = bufferevent_get_input(conn->bev);
429 size_t len;
431 assert(conn->has_body);
433 if (conn->te == TE_CHUNKED) {
434 read_chunk(conn);
435 return;
438 len = evbuffer_get_length(inbuf);
439 if (len) {
440 /* XXX should mind potential overflow */
441 if (conn->data_remaining >= 0 &&
442 len > (size_t)conn->data_remaining) {
443 len = (size_t)conn->data_remaining;
444 evbuffer_remove_buffer(inbuf, conn->inbuf_processed,
445 len);
446 EVENT1(conn, on_read_body, conn->inbuf_processed);
447 } else {
448 evbuffer_add_buffer(conn->inbuf_processed, inbuf);
449 EVENT1(conn, on_read_body, conn->inbuf_processed);
452 conn->data_remaining -= len;
453 if (conn->data_remaining == 0)
454 end_message(conn, ERROR_NONE);
458 static void
459 check_headers(struct http_conn *conn, struct http_request *req,
460 struct http_response *resp)
462 enum http_version vers;
463 int persistent;
464 int tunnel;
465 char *val;
467 conn->te = TE_IDENTITY;
468 conn->has_body = 1;
469 conn->msg_complete_on_eof = 0;
470 conn->data_remaining = -1;
471 conn->body_length = -1;
472 tunnel = 0;
474 if (conn->type == HTTP_CLIENT) {
475 vers = req->vers;
476 conn->has_body = 0;
477 if (req->meth == METH_POST ||
478 req->meth == METH_PUT)
479 conn->has_body = 1;
480 else if (req->meth == METH_CONNECT)
481 tunnel = 1;
482 } else { /* server */
483 vers = resp->vers;
484 if ((resp->code >= 100 && resp->code < 200) ||
485 resp->code == 204 || resp->code == 205 ||
486 resp->code == 304)
487 conn->has_body = 0;
490 /* check headers */
491 if (conn->has_body) {
492 val = headers_find(conn->headers, "transfer-encoding");
493 if (val) {
494 if (!evutil_ascii_strcasecmp(val, "chunked"))
495 conn->te = TE_CHUNKED;
496 mem_free(val);
499 if (conn->te != TE_CHUNKED) {
500 val = headers_find(conn->headers, "content-length");
501 if (val) {
502 ev_int64_t iv;
503 iv = get_int(val, 10);
504 if (iv < 0) {
505 log_warn("http_conn: mangled "
506 "Content-Length");
507 headers_remove(conn->headers,
508 "content-length");
509 } else
510 conn->body_length = iv;
511 mem_free(val);
512 if (conn->body_length == 0)
513 conn->has_body = 0;
514 } else {
515 conn->msg_complete_on_eof = 1;
519 if (conn->type == HTTP_CLIENT && conn->body_length < 0 &&
520 conn->te != TE_CHUNKED) {
521 EVENT1(conn, on_error,
522 ERROR_CLIENT_POST_WITHOUT_LENGTH);
523 return;
526 conn->data_remaining = conn->body_length;
528 assert(vers != HTTP_UNKNOWN);
530 persistent = 0;
531 if (!tunnel && !conn->msg_complete_on_eof && vers == HTTP_11)
532 persistent = 1;
534 if (conn->vers != HTTP_UNKNOWN && conn->vers != vers) {
535 log_warn("http_conn: http version changed!");
536 persistent = 0;
538 conn->vers = vers;
540 if (persistent) {
541 val = headers_find(conn->headers, "connection");
542 if (val) {
543 if (!evutil_ascii_strcasecmp(val, "close"))
544 persistent = 0;
545 mem_free(val);
548 conn->persistent = persistent;
551 static void
552 read_headers(struct http_conn *conn)
554 int failed = 0;
555 struct evbuffer *inbuf = bufferevent_get_input(conn->bev);
556 struct http_request *req = NULL;
557 struct http_response *resp = NULL;
559 assert(conn->state == HTTP_STATE_READ_HEADERS);
561 switch (headers_load(conn->headers, inbuf)) {
562 case -1:
563 end_message(conn, ERROR_HEADER_PARSE_FAILED);
564 return;
565 case 0:
566 return;
567 /* case 1: finished, fall thru */
570 assert(conn->firstline);
572 if (conn->type == HTTP_CLIENT) {
573 req = build_request(conn);
574 if (!req)
575 failed = 1;
576 } else {
577 resp = build_response(conn);
578 if (!resp)
579 failed = 1;
582 mem_free(conn->firstline);
583 conn->firstline = NULL;
585 if (failed) {
586 assert(!req && !resp);
587 end_message(conn, ERROR_HEADER_PARSE_FAILED);
588 return;
591 check_headers(conn, req, resp);
592 conn->headers = NULL;
594 /* ownership of req or resp is now passed on */
595 if (req)
596 EVENT1(conn, on_client_request, req);
597 if (resp)
598 EVENT1(conn, on_server_response, resp);
600 if (conn->state != HTTP_STATE_TUNNEL_CONNECTING) {
601 if (!conn->has_body)
602 end_message(conn, ERROR_NONE);
603 else
604 conn->state = HTTP_STATE_READ_BODY;
608 static void
609 tunnel_transfer_data(struct http_conn *conn, struct bufferevent *to,
610 struct bufferevent *from)
612 struct evbuffer *frombuf = bufferevent_get_input(from);
613 struct evbuffer *tobuf = bufferevent_get_output(to);
615 if (evbuffer_get_length(frombuf) == 0)
616 return;
618 evbuffer_add_buffer(tobuf, frombuf);
619 if (evbuffer_get_length(tobuf) > max_write_backlog) {
620 bufferevent_setwatermark(to, EV_WRITE,
621 max_write_backlog / 2, 0);
622 bufferevent_disable(from, EV_READ);
623 if (from == conn->bev) {
624 log_debug("tunnel: throttling client read");
625 conn->read_paused = 1;
626 } else {
627 log_debug("tunnel: throttling server read");
628 conn->tunnel_read_paused = 1;
633 static void
634 tunnel_writecb(struct bufferevent *bev, void *_conn)
636 struct http_conn *conn = _conn;
638 if (conn->state == HTTP_STATE_TUNNEL_OPEN) {
639 if (conn->tunnel_read_paused && bev == conn->bev) {
640 log_debug("tunnel: unthrottling server read");
641 conn->tunnel_read_paused = 0;
642 bufferevent_enable(conn->tunnel_bev, EV_READ);
643 bufferevent_setwatermark(bev, EV_WRITE, 0, 0);
644 } else if (conn->read_paused && bev == conn->tunnel_bev) {
645 log_debug("tunnel: unthrottling client read");
646 conn->read_paused = 0;
647 bufferevent_enable(conn->bev, EV_READ);
648 bufferevent_setwatermark(bev, EV_WRITE, 0, 0);
650 } else {
651 log_debug("tunnel: flushed!");
652 bufferevent_setcb(conn->bev, NULL, NULL, NULL, NULL);
653 bufferevent_setcb(conn->tunnel_bev, NULL, NULL, NULL, NULL);
654 EVENT1(conn, on_error, ERROR_TUNNEL_CLOSED);
658 static void
659 tunnel_readcb(struct bufferevent *bev, void *_conn)
661 struct http_conn *conn = _conn;
663 if (bev == conn->bev)
664 tunnel_transfer_data(conn, conn->tunnel_bev, bev);
665 else
666 tunnel_transfer_data(conn, conn->bev, bev);
669 static void
670 tunnel_errorcb(struct bufferevent *bev, short what, void *_conn)
672 struct http_conn *conn = _conn;
673 struct evbuffer *buf;
675 switch (conn->state) {
676 case HTTP_STATE_TUNNEL_CONNECTING:
677 assert(bev == conn->tunnel_bev);
678 if (what & BEV_EVENT_CONNECTED) {
679 conn->state = HTTP_STATE_TUNNEL_OPEN;
680 bufferevent_setcb(conn->bev, tunnel_readcb,
681 tunnel_writecb, tunnel_errorcb, conn);
682 bufferevent_enable(conn->bev, EV_READ);
683 bufferevent_enable(conn->tunnel_bev, EV_READ);
684 conn->read_paused = 0;
685 conn->tunnel_read_paused = 0;
686 tunnel_transfer_data(conn, conn->tunnel_bev, conn->bev);
687 evbuffer_add_printf(bufferevent_get_output(conn->bev),
688 "%s 200 Connection established\r\n\r\n",
689 http_version_to_string(conn->vers));
690 } else {
691 bufferevent_setcb(conn->tunnel_bev, NULL, NULL,
692 NULL, NULL);
693 EVENT1(conn, on_error, ERROR_TUNNEL_CONNECT_FAILED);
695 break;
696 case HTTP_STATE_TUNNEL_OPEN:
697 if (bev == conn->bev) {
698 log_debug("tunnel: client closed conn...");
699 bev = conn->tunnel_bev;
700 } else {
701 log_debug("tunnel: server closed conn...");
702 bev = conn->bev;
704 buf = bufferevent_get_output(bev);
705 if (evbuffer_get_length(buf)) {
706 conn->state = HTTP_STATE_TUNNEL_FLUSHING;
707 log_debug("tunnel: flushing %lu bytes...",
708 (unsigned long)evbuffer_get_length(buf));
709 bufferevent_disable(bev, EV_READ);
710 bufferevent_setcb(bev, NULL, tunnel_writecb,
711 tunnel_errorcb, conn);
712 break;
714 /* nothing left to write.. lets just fall thru... */
715 case HTTP_STATE_TUNNEL_FLUSHING:
716 /* an error happend while flushing, lets just give up. */
717 bufferevent_setcb(conn->bev, NULL, NULL, NULL, NULL);
718 bufferevent_setcb(conn->tunnel_bev, NULL, NULL, NULL, NULL);
719 EVENT1(conn, on_error, ERROR_TUNNEL_CLOSED);
720 break;
721 default:
722 log_fatal("tunnel: errorcb called in invalid state!");
726 static void
727 http_errorcb(struct bufferevent *bev, short what, void *_conn)
729 enum http_state state;
730 struct http_conn *conn = _conn;
732 if (conn->state == HTTP_STATE_CONNECTING) {
733 if (what & BEV_EVENT_CONNECTED) {
734 begin_message(conn);
735 EVENT0(conn, on_connect);
736 } else {
737 conn->state = HTTP_STATE_MANGLED;
738 EVENT1(conn, on_error, ERROR_CONNECT_FAILED);
740 return;
743 assert(!(what & BEV_EVENT_CONNECTED));
745 state = conn->state;
746 conn->state = HTTP_STATE_MANGLED;
748 if (what & BEV_EVENT_WRITING) {
749 end_message(conn, ERROR_WRITE_FAILED);
750 return;
753 switch (state) {
754 case HTTP_STATE_IDLE:
755 end_message(conn, ERROR_IDLE_CONN_TIMEDOUT);
756 break;
757 case HTTP_STATE_READ_FIRSTLINE:
758 case HTTP_STATE_READ_HEADERS:
759 end_message(conn, ERROR_INCOMPLETE_HEADERS);
760 break;
761 case HTTP_STATE_READ_BODY:
762 if ((what & BEV_EVENT_EOF) && conn->msg_complete_on_eof)
763 end_message(conn, ERROR_NONE);
764 else
765 end_message(conn, ERROR_INCOMPLETE_BODY);
766 break;
767 default:
768 log_fatal("http_conn: errorcb called in invalid state");
772 static void
773 process_one_step(struct http_conn *conn)
775 struct evbuffer *inbuf = bufferevent_get_input(conn->bev);
777 switch (conn->state) {
778 case HTTP_STATE_IDLE:
779 conn->state = HTTP_STATE_READ_FIRSTLINE;
780 bufferevent_set_timeouts(conn->bev, NULL, NULL);
781 /* fallthru... */
782 case HTTP_STATE_READ_FIRSTLINE:
783 assert(conn->firstline == NULL);
784 conn->firstline = evbuffer_readln(inbuf, NULL,
785 EVBUFFER_EOL_CRLF);
786 if (conn->firstline)
787 conn->state = HTTP_STATE_READ_HEADERS;
788 break;
789 case HTTP_STATE_READ_HEADERS:
790 read_headers(conn);
791 break;
792 case HTTP_STATE_READ_BODY:
793 read_body(conn);
794 break;
795 default:
796 log_fatal("http_conn: read cb called in invalid state");
800 static void
801 process_inbuf(struct http_conn *conn)
803 struct evbuffer *inbuf = bufferevent_get_input(conn->bev);
804 enum http_state state_before;
806 do {
807 state_before = conn->state;
808 process_one_step(conn);
809 } while (!conn->read_paused &&
810 evbuffer_get_length(inbuf) > 0 &&
811 state_before != conn->state);
814 static void
815 http_readcb(struct bufferevent *bev, void *_conn)
817 process_inbuf(_conn);
820 static void
821 http_writecb(struct bufferevent *bev, void *_conn)
823 struct http_conn *conn = _conn;
824 struct evbuffer *outbuf = bufferevent_get_output(bev);
826 if (conn->choked) {
827 bufferevent_setwatermark(bev, EV_WRITE, 0, 0);
828 conn->choked = 0;
829 EVENT0(conn, on_write_more);
830 } else if (evbuffer_get_length(outbuf) == 0)
831 EVENT0(conn, on_flush);
834 struct http_conn *
835 http_conn_new(struct event_base *base, evutil_socket_t sock,
836 enum http_type type, const struct http_cbs *cbs, void *cbarg)
838 struct http_conn *conn;
840 conn = mem_calloc(1, sizeof(*conn));
841 conn->base = base;
842 conn->type = type;
843 conn->cbs = cbs;
844 conn->cbarg = cbarg;
845 conn->bev = bufferevent_socket_new(base, sock,
846 BEV_OPT_CLOSE_ON_FREE);
847 if (!conn->bev)
848 log_fatal("http_conn: failed to create bufferevent");
850 conn->inbuf_processed = evbuffer_new();
851 if (!conn->inbuf_processed)
852 log_fatal("http_conn: failed to create evbuffer");
854 bufferevent_setcb(conn->bev, http_readcb, http_writecb,
855 http_errorcb, conn);
857 if (sock >= 0)
858 begin_message(conn);
860 return conn;
864 http_conn_connect(struct http_conn *conn, struct evdns_base *dns,
865 int family, const char *host, int port)
867 // XXX need SOCKS
868 conn->state = HTTP_STATE_CONNECTING;
869 return bufferevent_socket_connect_hostname(conn->bev, dns, family,
870 host, port);
873 static void
874 deferred_free(evutil_socket_t s, short what, void *arg)
876 struct http_conn *conn = arg;
877 bufferevent_free(conn->bev);
878 if (conn->tunnel_bev)
879 bufferevent_free(conn->tunnel_bev);
880 evbuffer_free(conn->inbuf_processed);
881 mem_free(conn);
884 void
885 http_conn_free(struct http_conn *conn)
887 http_conn_stop_reading(conn);
888 bufferevent_disable(conn->bev, EV_WRITE);
889 bufferevent_setcb(conn->bev, NULL, NULL, NULL, NULL);
890 conn->cbs = NULL;
891 event_base_once(conn->base, -1, EV_TIMEOUT, deferred_free, conn, NULL);
894 void
895 http_conn_write_request(struct http_conn *conn, struct http_request *req)
897 struct evbuffer *outbuf;
899 assert(conn->type == HTTP_SERVER);
901 headers_remove(req->headers, "connection");
902 req->vers = HTTP_11;
904 outbuf = bufferevent_get_output(conn->bev);
906 evbuffer_add_printf(outbuf, "%s %s %s\r\n",
907 http_method_to_string(req->meth),
908 req->url->path,
909 http_version_to_string(req->vers));
911 headers_dump(req->headers, outbuf);
914 void
915 http_conn_write_response(struct http_conn *conn, struct http_response *resp)
917 struct evbuffer *outbuf;
919 assert(conn->type == HTTP_CLIENT);
920 assert(conn->vers != HTTP_UNKNOWN);
922 headers_remove(resp->headers, "connection");
923 headers_remove(resp->headers, "transfer-encoding");
924 resp->vers = conn->vers;
926 if (conn->vers == HTTP_10) {
927 conn->output_te = TE_IDENTITY;
928 headers_add_key_val(resp->headers, "Connection", "close");
929 } else if (conn->output_te == TE_CHUNKED) {
930 headers_add_key_val(resp->headers,
931 "Transfer-Encoding", "chunked");
934 outbuf = bufferevent_get_output(conn->bev);
936 evbuffer_add_printf(outbuf, "%s %d %s\r\n",
937 http_version_to_string(conn->vers),
938 resp->code,
939 resp->reason);
941 headers_dump(resp->headers, outbuf);
945 http_conn_write_buf(struct http_conn *conn, struct evbuffer *buf)
947 struct evbuffer *outbuf;
949 outbuf = bufferevent_get_output(conn->bev);
951 if (conn->output_te == TE_CHUNKED)
952 evbuffer_add_printf(outbuf, "%x\r\n",
953 (unsigned)evbuffer_get_length(buf));
954 evbuffer_add_buffer(outbuf, buf);
955 if (conn->output_te == TE_CHUNKED)
956 evbuffer_add(outbuf, "\r\n", 2);
958 /* have we choked? */
959 if (evbuffer_get_length(outbuf) > max_write_backlog) {
960 bufferevent_setwatermark(conn->bev, EV_WRITE,
961 max_write_backlog / 2, 0);
962 conn->choked = 1;
963 return 0;
966 return 1;
969 void
970 http_conn_write_finished(struct http_conn *conn)
972 if (conn->output_te == TE_CHUNKED)
973 bufferevent_write(conn->bev, "0\r\n\r\n", 5);
974 conn->output_te = TE_IDENTITY;
979 http_conn_current_message_has_body(struct http_conn *conn)
981 return conn->has_body;
984 void
985 http_conn_set_current_message_bodyless(struct http_conn *conn)
987 assert(conn->type == HTTP_SERVER);
988 conn->has_body = 0;
991 enum http_te
992 http_conn_get_current_message_body_encoding(struct http_conn *conn)
994 return conn->te;
997 ev_int64_t
998 http_conn_get_current_message_body_length(struct http_conn *conn)
1000 return conn->body_length;
1003 void
1004 http_conn_set_output_encoding(struct http_conn *conn, enum http_te te)
1006 conn->output_te = te;
1010 http_conn_is_persistent(struct http_conn *conn)
1012 return conn->persistent;
1015 void
1016 http_conn_stop_reading(struct http_conn *conn)
1018 bufferevent_disable(conn->bev, EV_READ);
1019 conn->read_paused = 1;
1022 void
1023 http_conn_start_reading(struct http_conn *conn)
1025 struct evbuffer *inbuf = bufferevent_get_input(conn->bev);
1027 bufferevent_enable(conn->bev, EV_READ);
1028 conn->read_paused = 0;
1029 // XXX this might cause recursion
1030 if (evbuffer_get_length(inbuf) > 0)
1031 process_inbuf(conn);
1034 void
1035 http_conn_flush(struct http_conn *conn)
1037 struct evbuffer *outbuf = bufferevent_get_output(conn->bev);
1039 // XXX this might cause recursion
1040 if (evbuffer_get_length(outbuf) == 0)
1041 EVENT0(conn, on_flush);
1044 void
1045 http_conn_send_error(struct http_conn *conn, int code, const char *fmt, ...)
1047 char length[64];
1048 struct evbuffer *msg;
1049 struct http_response resp;
1050 struct header_list headers;
1052 assert(conn->type == HTTP_CLIENT);
1054 TAILQ_INIT(&headers);
1055 msg = evbuffer_new();
1056 resp.headers = &headers;
1058 conn->output_te = TE_IDENTITY;
1059 resp.vers = HTTP_11;
1060 resp.code = code;
1061 resp.reason = (char*)error_code_to_reason_string(code);
1063 // XXX do something with fmt. make it html friendly
1064 evbuffer_add_printf(msg,
1065 "<html>\n"
1066 "<head>\n"
1067 "<title>%d %s</title>\n"
1068 "</head>\n"
1069 "<body>\n"
1070 "<h1>%d %s</h1>\n"
1071 "</body>\n"
1072 "</html>\n",
1073 code, resp.reason, code, resp.reason);
1075 evutil_snprintf(length, sizeof(length), "%u",
1076 (unsigned)evbuffer_get_length(msg));
1077 headers_add_key_val(&headers, "Content-Type", "text/html");
1078 headers_add_key_val(&headers, "Content-Length", length);
1079 headers_add_key_val(&headers, "Expires", "0");
1080 headers_add_key_val(&headers, "Cache-Control", "no-cache");
1081 headers_add_key_val(&headers, "Pragma", "no-cache");
1083 http_conn_write_response(conn, &resp);
1084 http_conn_write_buf(conn, msg);
1085 headers_clear(&headers);
1086 evbuffer_free(msg);
1090 http_conn_start_tunnel(struct http_conn *conn, struct evdns_base *dns,
1091 int family, const char *host, int port)
1093 assert(conn->type == HTTP_CLIENT);
1094 assert(conn->tunnel_bev == NULL);
1096 http_conn_stop_reading(conn);
1097 conn->tunnel_bev = bufferevent_socket_new(conn->base, -1,
1098 BEV_OPT_CLOSE_ON_FREE);
1099 bufferevent_setcb(conn->tunnel_bev, tunnel_readcb,
1100 tunnel_writecb, tunnel_errorcb, conn);
1101 log_info("tunnel: attempting connection to %s:%d",
1102 log_scrub(host), port);
1103 // XXX need SOCKS
1104 conn->state = HTTP_STATE_TUNNEL_CONNECTING;
1105 return bufferevent_socket_connect_hostname(conn->tunnel_bev, dns,
1106 family, host, port);
1109 void
1110 http_request_free(struct http_request *req)
1112 url_free(req->url);
1113 headers_clear(req->headers);
1114 mem_free(req);
1117 void
1118 http_response_free(struct http_response *resp)
1120 headers_clear(resp->headers);
1121 mem_free(resp->headers);
1122 mem_free(resp->reason);
1123 mem_free(resp);
1126 #ifdef TEST_HTTP
1127 #include <netinet/in.h>
1128 #include <stdio.h>
1129 #include <event2/dns.h>
1130 #include <event2/listener.h>
1132 static void
1133 proxy_connected(struct http_conn *conn, void *arg)
1135 struct http_request req;
1136 struct header_list headers;
1137 struct evbuffer *buf;
1139 TAILQ_INIT(&headers);
1140 req.meth = METH_GET;
1141 req.url = arg;
1142 req.vers = HTTP_11;
1143 req.headers = &headers;
1145 buf = evbuffer_new();
1146 evbuffer_add_printf(buf, "Host: %s\r\n\r\n", req.url->host);
1147 headers_load(&headers, buf);
1148 evbuffer_free(buf);
1150 http_conn_write_request(conn, &req);
1153 static void
1154 proxy_error(struct http_conn *conn, enum http_conn_error err, void *arg)
1156 fprintf(stderr, "error %d\n", err);
1157 http_conn_free(conn);
1160 static void
1161 proxy_request(struct http_conn *conn, struct http_request *req, void *arg)
1163 struct evbuffer *buf;
1165 fprintf(stderr, "request: %s %s %s\n",
1166 http_method_to_string(req->meth),
1167 req->url->path,
1168 http_version_to_string(req->vers));
1170 buf = evbuffer_new();
1171 headers_dump(req->headers, buf);
1172 fwrite(evbuffer_pullup(buf, evbuffer_get_length(buf)), evbuffer_get_length(buf), 1, stderr);
1173 evbuffer_free(buf);
1176 http_conn_send_error(conn, 401);
1179 static void
1180 proxy_response(struct http_conn *conn, struct http_response *resp, void *arg)
1182 struct evbuffer *buf;
1184 fprintf(stderr, "response: %s, %d, %s\n",
1185 http_version_to_string(resp->vers),
1186 resp->code,
1187 resp->reason);
1189 buf = evbuffer_new();
1190 headers_dump(resp->headers, buf);
1191 fwrite(evbuffer_pullup(buf, evbuffer_get_length(buf)), evbuffer_get_length(buf), 1, stderr);
1192 evbuffer_free(buf);
1195 static void
1196 proxy_read_body(struct http_conn *conn, struct evbuffer *buf, void *arg)
1198 size_t len = evbuffer_get_length(buf);
1199 fwrite(evbuffer_pullup(buf, len), len, 1, stderr);
1200 evbuffer_drain(buf, len);
1203 static void
1204 proxy_msg_complete(struct http_conn *conn, void *arg)
1206 fprintf(stderr, "\n...MSG COMPLETE...\n");
1209 static void
1210 proxy_write_more(struct http_conn *conn, void *arg)
1214 static void
1215 proxy_flush(struct http_conn *conn, void *arg)
1217 fprintf(stderr, "\n....FLUSHED...\n");
1220 static struct http_cbs test_proxy_cbs = {
1221 proxy_connected,
1222 proxy_error,
1223 proxy_request,
1224 proxy_response,
1225 proxy_read_body,
1226 proxy_msg_complete,
1227 proxy_write_more,
1228 proxy_flush
1232 static void
1233 clientcb(struct evconnlistener *ecs, evutil_socket_t s,
1234 struct sockaddr *addr, int len, void *arg)
1236 struct http_conn *client;
1238 client = http_conn_new(evconnlistener_get_base(ecs), s, HTTP_CLIENT, &test_proxy_cbs, arg);
1242 main(int argc, char **argv)
1244 struct event_base *base;
1245 struct evdns_base *dns;
1246 struct http_conn *http;
1247 struct url *url;
1249 base = event_base_new();
1251 if (argc < 2) {
1252 struct evconnlistener *ecs;
1253 struct sockaddr_in sin;
1254 memset(&sin, 0, sizeof(sin));
1255 sin.sin_family=AF_INET;
1256 sin.sin_port = htons(8080);
1257 ecs = evconnlistener_new_bind(base, clientcb, NULL, 0,
1258 LEV_OPT_REUSEABLE, &sin, sizeof(sin));
1259 event_base_dispatch(base);
1260 return 0;
1263 url = url_tokenize(argv[1]);
1264 if (!url)
1265 return 0;
1267 if (url->port < 0)
1268 url->port = 80;
1270 dns = evdns_base_new(base, 1);
1272 http = http_conn_new(base, -1, HTTP_SERVER, &test_proxy_cbs, url);
1273 http_conn_connect(http, dns, AF_UNSPEC, url->host, url->port);
1275 event_base_dispatch(base);
1277 return 0;
1280 #endif