7 #include <event2/util.h>
8 #include <event2/event.h>
9 #include <event2/bufferevent.h>
10 #include <event2/buffer.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};
36 enum http_state state
;
37 enum http_version vers
;
40 enum http_te output_te
;
44 int tunnel_read_paused
;
45 int msg_complete_on_eof
;
47 const struct http_cbs
*cbs
;
49 ev_int64_t body_length
;
50 ev_int64_t data_remaining
;
52 struct header_list
*headers
;
53 struct event_base
*base
;
54 struct bufferevent
*bev
;
55 struct bufferevent
*tunnel_bev
;
56 struct evbuffer
*inbuf_processed
;
60 method_from_string(enum http_method
*m
, const char *method
)
62 if (!evutil_ascii_strcasecmp(method
, "GET"))
64 else if (!evutil_ascii_strcasecmp(method
, "HEAD"))
66 else if (!evutil_ascii_strcasecmp(method
, "POST"))
68 else if (!evutil_ascii_strcasecmp(method
, "PUT"))
70 else if (!evutil_ascii_strcasecmp(method
, "CONNECT"))
73 log_warn("method_from_string: unknown method, '%s'", method
);
81 http_method_to_string(enum http_method m
)
96 log_fatal("http_method_to_string: unknown method %d", m
);
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
);
110 /* XXX this only understands 1.0 and 1.1 */
112 if (!strcmp(vers
, "1.0"))
114 else if (!strcmp(vers
, "1.1"))
117 log_warn("version_from_string: unknown http-version, '%s'",
126 http_version_to_string(enum http_version v
)
137 log_fatal("http_version_to_string: unknown version %d", v
);
142 error_code_to_reason_string(int code
)
146 return "Bad Request";
148 return "Unauthorized";
154 return "Method Not Allowed";
156 return "Not Acceptable";
158 return "Proxy Authentication Required";
160 return "Request Timeout";
166 return "Length Required";
168 return "Precondition Failed";
170 return "Request Entity Too Large";
172 return "Request-URI Too Long";
174 return "Unsupported Media Type";
176 return "Requested Range Not Satisfiable";
178 return "Expectation Failed";
180 return "There are too many connections from your internet "
183 return "Internal Server Error";
185 return "Not Implemented";
187 return "Bad Gateway";
189 return "Service Unavailable";
191 return "Gateway Timeout";
193 return "HTTP Version Not Supported";
195 return "User access denied";
202 http_conn_error_to_string(enum http_conn_error err
)
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";
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
);
244 bufferevent_set_timeouts(conn
->bev
, &idle_client_timeout
, NULL
);
248 end_message(struct http_conn
*conn
, enum http_conn_error err
)
251 mem_free(conn
->firstline
);
253 headers_clear(conn
->headers
);
255 if (err
!= ERROR_NONE
|| !conn
->persistent
) {
256 conn
->state
= HTTP_STATE_MANGLED
;
257 http_conn_stop_reading(conn
);
261 if (err
!= ERROR_NONE
)
262 EVENT1(conn
, on_error
, err
);
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
;
275 struct url
*u
= NULL
;
278 assert(conn
->type
== HTTP_CLIENT
);
283 ntokens
= tokenize(conn
->firstline
, " ", 4, &tokens
);
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)
295 if (m
== METH_CONNECT
)
296 u
= url_connect_tokenize(url
->token
);
298 u
= url_tokenize(url
->token
);
302 req
= mem_calloc(1, sizeof(*req
));
307 req
->headers
= conn
->headers
;
311 token_list_clear(&tokens
);
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
;
326 assert(conn
->type
== HTTP_SERVER
);
331 ntokens
= tokenize(conn
->firstline
, " ", 2, &tokens
);
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)
343 resp
= mem_calloc(1, sizeof(*resp
));
346 resp
->reason
= reason
->token
;
347 reason
->token
= NULL
; /* so token_list_clear will skip this */
348 resp
->headers
= conn
->headers
;
351 token_list_clear(&tokens
);
356 /* return -1 failure, 0 incomplete, 1 ok */
358 parse_chunk_len(struct http_conn
*conn
)
360 struct evbuffer
*inbuf
= bufferevent_get_input(conn
->bev
);
364 while ((line
= evbuffer_readln(inbuf
, NULL
, EVBUFFER_EOL_CRLF
))) {
370 len
= get_int(line
, 16);
373 log_warn("parse_chunk_len: invalid chunk len");
377 conn
->data_remaining
= len
;
385 read_chunk(struct http_conn
*conn
)
387 struct evbuffer
*inbuf
= bufferevent_get_input(conn
->bev
);
392 while ((len
= evbuffer_get_length(inbuf
)) > 0) {
393 if (conn
->data_remaining
< 0) {
394 ret
= parse_chunk_len(conn
);
398 ERROR_CHUNK_PARSE_FAILED
);
401 } else if (conn
->data_remaining
== 0) {
402 line
= evbuffer_readln(inbuf
, NULL
, EVBUFFER_EOL_CRLF
);
404 /* XXX doesn't handle trailers */
406 end_message(conn
, ERROR_NONE
);
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
,
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;
426 read_body(struct http_conn
*conn
)
428 struct evbuffer
*inbuf
= bufferevent_get_input(conn
->bev
);
431 assert(conn
->has_body
);
433 if (conn
->te
== TE_CHUNKED
) {
438 len
= evbuffer_get_length(inbuf
);
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
,
446 EVENT1(conn
, on_read_body
, conn
->inbuf_processed
);
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
);
459 check_headers(struct http_conn
*conn
, struct http_request
*req
,
460 struct http_response
*resp
)
462 enum http_version vers
;
467 conn
->te
= TE_IDENTITY
;
469 conn
->msg_complete_on_eof
= 0;
470 conn
->data_remaining
= -1;
471 conn
->body_length
= -1;
474 if (conn
->type
== HTTP_CLIENT
) {
477 if (req
->meth
== METH_POST
||
478 req
->meth
== METH_PUT
)
480 else if (req
->meth
== METH_CONNECT
)
482 } else { /* server */
484 if ((resp
->code
>= 100 && resp
->code
< 200) ||
485 resp
->code
== 204 || resp
->code
== 205 ||
491 if (conn
->has_body
) {
492 val
= headers_find(conn
->headers
, "transfer-encoding");
494 if (!evutil_ascii_strcasecmp(val
, "chunked"))
495 conn
->te
= TE_CHUNKED
;
499 if (conn
->te
!= TE_CHUNKED
) {
500 val
= headers_find(conn
->headers
, "content-length");
503 iv
= get_int(val
, 10);
505 log_warn("http_conn: mangled "
507 headers_remove(conn
->headers
,
510 conn
->body_length
= iv
;
512 if (conn
->body_length
== 0)
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
);
526 conn
->data_remaining
= conn
->body_length
;
528 assert(vers
!= HTTP_UNKNOWN
);
531 if (!tunnel
&& !conn
->msg_complete_on_eof
&& vers
== HTTP_11
)
534 if (conn
->vers
!= HTTP_UNKNOWN
&& conn
->vers
!= vers
) {
535 log_warn("http_conn: http version changed!");
541 val
= headers_find(conn
->headers
, "connection");
543 if (!evutil_ascii_strcasecmp(val
, "close"))
548 conn
->persistent
= persistent
;
552 read_headers(struct http_conn
*conn
)
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
)) {
563 end_message(conn
, ERROR_HEADER_PARSE_FAILED
);
567 /* case 1: finished, fall thru */
570 assert(conn
->firstline
);
572 if (conn
->type
== HTTP_CLIENT
) {
573 req
= build_request(conn
);
577 resp
= build_response(conn
);
582 mem_free(conn
->firstline
);
583 conn
->firstline
= NULL
;
586 assert(!req
&& !resp
);
587 end_message(conn
, ERROR_HEADER_PARSE_FAILED
);
591 check_headers(conn
, req
, resp
);
592 conn
->headers
= NULL
;
594 /* ownership of req or resp is now passed on */
596 EVENT1(conn
, on_client_request
, req
);
598 EVENT1(conn
, on_server_response
, resp
);
600 if (conn
->state
!= HTTP_STATE_TUNNEL_CONNECTING
) {
602 end_message(conn
, ERROR_NONE
);
604 conn
->state
= HTTP_STATE_READ_BODY
;
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)
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;
627 log_debug("tunnel: throttling server read");
628 conn
->tunnel_read_paused
= 1;
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);
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
);
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
);
666 tunnel_transfer_data(conn
, conn
->bev
, bev
);
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
));
691 bufferevent_setcb(conn
->tunnel_bev
, NULL
, NULL
,
693 EVENT1(conn
, on_error
, ERROR_TUNNEL_CONNECT_FAILED
);
696 case HTTP_STATE_TUNNEL_OPEN
:
697 if (bev
== conn
->bev
) {
698 log_debug("tunnel: client closed conn...");
699 bev
= conn
->tunnel_bev
;
701 log_debug("tunnel: server closed conn...");
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
);
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
);
722 log_fatal("tunnel: errorcb called in invalid state!");
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
) {
735 EVENT0(conn
, on_connect
);
737 conn
->state
= HTTP_STATE_MANGLED
;
738 EVENT1(conn
, on_error
, ERROR_CONNECT_FAILED
);
743 assert(!(what
& BEV_EVENT_CONNECTED
));
746 conn
->state
= HTTP_STATE_MANGLED
;
748 if (what
& BEV_EVENT_WRITING
) {
749 end_message(conn
, ERROR_WRITE_FAILED
);
754 case HTTP_STATE_IDLE
:
755 end_message(conn
, ERROR_IDLE_CONN_TIMEDOUT
);
757 case HTTP_STATE_READ_FIRSTLINE
:
758 case HTTP_STATE_READ_HEADERS
:
759 end_message(conn
, ERROR_INCOMPLETE_HEADERS
);
761 case HTTP_STATE_READ_BODY
:
762 if ((what
& BEV_EVENT_EOF
) && conn
->msg_complete_on_eof
)
763 end_message(conn
, ERROR_NONE
);
765 end_message(conn
, ERROR_INCOMPLETE_BODY
);
768 log_fatal("http_conn: errorcb called in invalid state");
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
);
782 case HTTP_STATE_READ_FIRSTLINE
:
783 assert(conn
->firstline
== NULL
);
784 conn
->firstline
= evbuffer_readln(inbuf
, NULL
,
787 conn
->state
= HTTP_STATE_READ_HEADERS
;
789 case HTTP_STATE_READ_HEADERS
:
792 case HTTP_STATE_READ_BODY
:
796 log_fatal("http_conn: read cb called in invalid state");
801 process_inbuf(struct http_conn
*conn
)
803 struct evbuffer
*inbuf
= bufferevent_get_input(conn
->bev
);
804 enum http_state state_before
;
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
);
815 http_readcb(struct bufferevent
*bev
, void *_conn
)
817 process_inbuf(_conn
);
821 http_writecb(struct bufferevent
*bev
, void *_conn
)
823 struct http_conn
*conn
= _conn
;
824 struct evbuffer
*outbuf
= bufferevent_get_output(bev
);
827 bufferevent_setwatermark(bev
, EV_WRITE
, 0, 0);
829 EVENT0(conn
, on_write_more
);
830 } else if (evbuffer_get_length(outbuf
) == 0)
831 EVENT0(conn
, on_flush
);
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
));
845 conn
->bev
= bufferevent_socket_new(base
, sock
,
846 BEV_OPT_CLOSE_ON_FREE
);
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
,
864 http_conn_connect(struct http_conn
*conn
, struct evdns_base
*dns
,
865 int family
, const char *host
, int port
)
868 conn
->state
= HTTP_STATE_CONNECTING
;
869 return bufferevent_socket_connect_hostname(conn
->bev
, dns
, family
,
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
);
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
);
891 event_base_once(conn
->base
, -1, EV_TIMEOUT
, deferred_free
, conn
, NULL
);
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");
904 outbuf
= bufferevent_get_output(conn
->bev
);
906 evbuffer_add_printf(outbuf
, "%s %s %s\r\n",
907 http_method_to_string(req
->meth
),
909 http_version_to_string(req
->vers
));
911 headers_dump(req
->headers
, outbuf
);
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
),
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);
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
;
985 http_conn_set_current_message_bodyless(struct http_conn
*conn
)
987 assert(conn
->type
== HTTP_SERVER
);
992 http_conn_get_current_message_body_encoding(struct http_conn
*conn
)
998 http_conn_get_current_message_body_length(struct http_conn
*conn
)
1000 return conn
->body_length
;
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
;
1016 http_conn_stop_reading(struct http_conn
*conn
)
1018 bufferevent_disable(conn
->bev
, EV_READ
);
1019 conn
->read_paused
= 1;
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
);
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
);
1045 http_conn_send_error(struct http_conn
*conn
, int code
, const char *fmt
, ...)
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
;
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
,
1067 "<title>%d %s</title>\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
);
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
);
1104 conn
->state
= HTTP_STATE_TUNNEL_CONNECTING
;
1105 return bufferevent_socket_connect_hostname(conn
->tunnel_bev
, dns
,
1106 family
, host
, port
);
1110 http_request_free(struct http_request
*req
)
1113 headers_clear(req
->headers
);
1118 http_response_free(struct http_response
*resp
)
1120 headers_clear(resp
->headers
);
1121 mem_free(resp
->headers
);
1122 mem_free(resp
->reason
);
1127 #include <netinet/in.h>
1129 #include <event2/dns.h>
1130 #include <event2/listener.h>
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
;
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
);
1150 http_conn_write_request(conn
, &req
);
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
);
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
),
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
);
1176 http_conn_send_error(conn
, 401);
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
),
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
);
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
);
1204 proxy_msg_complete(struct http_conn
*conn
, void *arg
)
1206 fprintf(stderr
, "\n...MSG COMPLETE...\n");
1210 proxy_write_more(struct http_conn
*conn
, void *arg
)
1215 proxy_flush(struct http_conn
*conn
, void *arg
)
1217 fprintf(stderr
, "\n....FLUSHED...\n");
1220 static struct http_cbs test_proxy_cbs
= {
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
;
1249 base
= event_base_new();
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
);
1263 url
= url_tokenize(argv
[1]);
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
);