From dcbdcae943f34aae0937f0fa9c199074e7623c96 Mon Sep 17 00:00:00 2001 From: Bin Jin Date: Sun, 20 Feb 2011 13:36:38 +0800 Subject: [PATCH] Libevent2 fix: bad default line-extracting strategy Libevent 2 deprecates evbuffer_readline() function, where any sequence of any number of carriage return and linefeed characters is treated like end of line, and introduces better evbuffer_readln(), where termination format can be explicitly set to: \n, [\r]\n, \r\n or already mentioned old behaviour. Change past evbuffer_readline() calls to new redsocks_evbuffer_readline() function. If libevent 2 is present, use there evbuffer_readln() with eol_style set to an optional carriage return, followed by a linefeed (EVBUFFER_EOL_CRLF) instead of obsolete evbuffer_readln(). Important note: Consuming all CR and LF characters in one go (behaviour of evbuffer_readline(), nowadays aliasing to evbuffer_readln() with eol_style set to EVBUFFER_EOL_ANY) hangs up parsing of HTTP request header ending with "\r\n\r\n", because it misses the empty line. Conflicts (resolved): utils.c utils.h --- http-connect.c | 6 +++--- http-relay.c | 8 ++++---- utils.c | 9 +++++++++ utils.h | 1 + 4 files changed, 17 insertions(+), 7 deletions(-) diff --git a/http-connect.c b/http-connect.c index 4ceede8..e34268a 100644 --- a/http-connect.c +++ b/http-connect.c @@ -64,7 +64,7 @@ static char *get_auth_request_header(struct evbuffer *buf) { char *line; for (;;) { - line = evbuffer_readline(buf); + line = redsocks_evbuffer_readline(buf); if (line == NULL || *line == '\0' || strchr(line, ':') == NULL) { free(line); return NULL; @@ -86,7 +86,7 @@ static void httpc_read_cb(struct bufferevent *buffev, void *_arg) if (client->state == httpc_request_sent) { size_t len = EVBUFFER_LENGTH(buffev->input); - char *line = evbuffer_readline(buffev->input); + char *line = redsocks_evbuffer_readline(buffev->input); if (line) { unsigned int code; if (sscanf(line, "HTTP/%*u.%*u %u", &code) == 1) { // 1 == one _assigned_ match @@ -163,7 +163,7 @@ static void httpc_read_cb(struct bufferevent *buffev, void *_arg) return; while (client->state == httpc_reply_came) { - char *line = evbuffer_readline(buffev->input); + char *line = redsocks_evbuffer_readline(buffev->input); if (line) { if (strlen(line) == 0) { client->state = httpc_headers_skipped; diff --git a/http-relay.c b/http-relay.c index b6b3074..4e06860 100644 --- a/http-relay.c +++ b/http-relay.c @@ -130,7 +130,7 @@ static char *get_auth_request_header(struct evbuffer *buf) { char *line; for (;;) { - line = evbuffer_readline(buf); + line = redsocks_evbuffer_readline(buf); if (line == NULL || *line == '\0' || strchr(line, ':') == NULL) { free(line); return NULL; @@ -156,7 +156,7 @@ static void httpr_relay_read_cb(struct bufferevent *buffev, void *_arg) if (client->state == httpr_request_sent) { size_t len = EVBUFFER_LENGTH(buffev->input); - char *line = evbuffer_readline(buffev->input); + char *line = redsocks_evbuffer_readline(buffev->input); if (line) { httpr_buffer_append(&httpr->relay_buffer, line, strlen(line)); httpr_buffer_append(&httpr->relay_buffer, "\r\n", 2); @@ -236,7 +236,7 @@ static void httpr_relay_read_cb(struct bufferevent *buffev, void *_arg) return; while (client->state == httpr_reply_came) { - char *line = evbuffer_readline(buffev->input); + char *line = redsocks_evbuffer_readline(buffev->input); if (line) { httpr_buffer_append(&httpr->relay_buffer, line, strlen(line)); httpr_buffer_append(&httpr->relay_buffer, "\r\n", 2); @@ -491,7 +491,7 @@ static void httpr_client_read_cb(struct bufferevent *buffev, void *_arg) char *line = NULL; int connect_relay = 0; - while (!connect_relay && (line = evbuffer_readline(buffev->input))) { + while (!connect_relay && (line = redsocks_evbuffer_readline(buffev->input))) { int skip_line = 0; int do_drop = 0; diff --git a/utils.c b/utils.c index 8f9aaf6..637fe09 100644 --- a/utils.c +++ b/utils.c @@ -60,6 +60,15 @@ time_t redsocks_time(time_t *t) return retval; } +char *redsocks_evbuffer_readline(struct evbuffer *buf) +{ +#if _EVENT_NUMERIC_VERSION >= 0x02000000 + return evbuffer_readln(buf, NULL, EVBUFFER_EOL_CRLF); +#else + return evbuffer_readline(buf); +#endif +} + struct bufferevent* red_connect_relay(struct sockaddr_in *addr, evbuffercb writecb, everrorcb errorcb, void *cbarg) { struct bufferevent *retval = NULL; diff --git a/utils.h b/utils.h index 4f136fb..aef1ebd 100644 --- a/utils.h +++ b/utils.h @@ -32,6 +32,7 @@ struct sockaddr_in; (type *)( (char *)__mptr - offsetof(type,member) );}) time_t redsocks_time(time_t *t); +char *redsocks_evbuffer_readline(struct evbuffer *buf); struct bufferevent* red_connect_relay(struct sockaddr_in *addr, evbuffercb writecb, everrorcb errorcb, void *cbarg); int red_socket_geterrno(struct bufferevent *buffev); int red_is_socket_connected_ok(struct bufferevent *buffev);