summarylogtreecommitdiffstats
diff options
context:
space:
mode:
authorM0Rf302015-06-17 15:53:34 +0200
committerM0Rf302015-06-17 15:53:34 +0200
commit7964da81209e11d4db4f1bb69cb64ed88e579700 (patch)
treeca3ad9dfbd23a7ef3a7b6547dc2c0cd92291854f
downloadaur-7964da81209e11d4db4f1bb69cb64ed88e579700.tar.gz
Initial import
-rw-r--r--.SRCINFO18
-rw-r--r--PKGBUILD31
-rw-r--r--libevent-1.4.14.fb-changes.diff697
3 files changed, 746 insertions, 0 deletions
diff --git a/.SRCINFO b/.SRCINFO
new file mode 100644
index 000000000000..03db7afdf584
--- /dev/null
+++ b/.SRCINFO
@@ -0,0 +1,18 @@
+pkgbase = libevent-fb
+ pkgdesc = An event notification library (for HipHop compiler)
+ pkgver = 1.4.14b
+ pkgrel = 2
+ url = http://www.monkey.org/~provos/libevent/
+ arch = i686
+ arch = x86_64
+ license = GPL2
+ depends = glibc
+ provides = libevent
+ options = !libtool
+ source = http://www.monkey.org/~provos/libevent-1.4.14b-stable.tar.gz
+ source = libevent-1.4.14.fb-changes.diff
+ md5sums = a00e037e4d3f9e4fe9893e8a2d27918c
+ md5sums = cde91fe8ec39bbed1319e4114417bd7b
+
+pkgname = libevent-fb
+
diff --git a/PKGBUILD b/PKGBUILD
new file mode 100644
index 000000000000..62ba0d577654
--- /dev/null
+++ b/PKGBUILD
@@ -0,0 +1,31 @@
+# Maintainer: M0Rf30
+
+pkgname=libevent-fb
+pkgver=1.4.14b
+pkgrel=2
+pkgdesc="An event notification library (for HipHop compiler)"
+license=('GPL2')
+arch=('i686' 'x86_64')
+url="http://www.monkey.org/~provos/libevent/"
+depends=('glibc')
+provides=(libevent)
+source=("http://www.monkey.org/~provos/libevent-$pkgver-stable.tar.gz"
+ libevent-1.4.14.fb-changes.diff)
+options=('!libtool')
+
+build() {
+ cd $srcdir/libevent-$pkgver-stable
+ patch -Np1 -i ../libevent-1.4.14.fb-changes.diff
+ sed -i 's#python#python2#' event_rpcgen.py
+ ./configure --prefix=/usr --sysconfdir=/etc
+ make || return 1
+}
+
+package() {
+ cd $srcdir/libevent-$pkgver-stable
+ make DESTDIR=$pkgdir install
+}
+
+md5sums=('a00e037e4d3f9e4fe9893e8a2d27918c'
+ 'cde91fe8ec39bbed1319e4114417bd7b')
+
diff --git a/libevent-1.4.14.fb-changes.diff b/libevent-1.4.14.fb-changes.diff
new file mode 100644
index 000000000000..b8a782071dcb
--- /dev/null
+++ b/libevent-1.4.14.fb-changes.diff
@@ -0,0 +1,697 @@
+diff -rp -U 5 libevent-1.4.14-stable/event.c libevent-1.4.14-stable-fb/event.c
+--- libevent-1.4.14-stable/event.c 2010-06-07 14:40:35.000000000 -0700
++++ libevent-1.4.14-stable-fb/event.c 2010-06-18 16:30:57.000000000 -0700
+@@ -136,14 +136,16 @@ detect_monotonic(void)
+ }
+
+ static int
+ gettime(struct event_base *base, struct timeval *tp)
+ {
++/*
+ if (base->tv_cache.tv_sec) {
+ *tp = base->tv_cache;
+ return (0);
+ }
++*/
+
+ #if defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_MONOTONIC)
+ if (use_monotonic) {
+ struct timespec ts;
+
+@@ -479,11 +481,11 @@ event_base_loop(struct event_base *base,
+ struct timeval tv;
+ struct timeval *tv_p;
+ int res, done;
+
+ /* clear time cache */
+- base->tv_cache.tv_sec = 0;
++ /* base->tv_cache.tv_sec = 0; */
+
+ if (base->sig.ev_signal_added)
+ evsignal_base = base;
+ done = 0;
+ while (!done) {
+@@ -531,17 +533,17 @@ event_base_loop(struct event_base *base,
+
+ /* update last old time */
+ gettime(base, &base->event_tv);
+
+ /* clear time cache */
+- base->tv_cache.tv_sec = 0;
++ /* base->tv_cache.tv_sec = 0; */
+
+ res = evsel->dispatch(base, evbase, tv_p);
+
+ if (res == -1)
+ return (-1);
+- gettime(base, &base->tv_cache);
++ /* gettime(base, &base->tv_cache); */
+
+ timeout_process(base);
+
+ if (base->event_count_active) {
+ event_process_active(base);
+@@ -550,11 +552,11 @@ event_base_loop(struct event_base *base,
+ } else if (flags & EVLOOP_NONBLOCK)
+ done = 1;
+ }
+
+ /* clear time cache */
+- base->tv_cache.tv_sec = 0;
++ /* base->tv_cache.tv_sec = 0; */
+
+ event_debug(("%s: asked to terminate loop.", __func__));
+ return (0);
+ }
+
+Only in libevent-1.4.14-stable-fb: event.c.orig
+diff -rp -U 5 libevent-1.4.14-stable/evhttp.h libevent-1.4.14-stable-fb/evhttp.h
+--- libevent-1.4.14-stable/evhttp.h 2010-06-07 14:40:35.000000000 -0700
++++ libevent-1.4.14-stable-fb/evhttp.h 2010-06-18 16:36:24.000000000 -0700
+@@ -79,16 +79,54 @@ struct evhttp *evhttp_new(struct event_b
+ * to multiple different ports.
+ *
+ * @param http a pointer to an evhttp object
+ * @param address a string containing the IP address to listen(2) on
+ * @param port the port number to listen on
+- * @return a newly allocated evhttp struct
++ * @return 0 on success, -1 on error
+ * @see evhttp_free()
+ */
+ int evhttp_bind_socket(struct evhttp *http, const char *address, u_short port);
+
+ /**
++ * Binds an HTTP server on the specified address and port, using backlog.
++ *
++ * Can be called multiple times to bind the same http server
++ * to multiple different ports.
++ *
++ * @param http a pointer to an evhttp object
++ * @param address a string containing the IP address to listen(2) on
++ * @param port the port number to listen on
++ * @param backlog the backlog value for listen(2)
++ * @return 0 on success, -1 on error
++ * @see evhttp_free()
++ */
++int evhttp_bind_socket_backlog(struct evhttp *http, const char *address, u_short port, int backlog);
++
++/**
++ * Like evhttp_bind_socket(), but returns the socket file descriptor.
++ *
++ * @param http a pointer to an evhttp object
++ * @param address a string containing the IP address to listen(2) on
++ * @param port the port number to listen on
++ * @return Socket file descriptor on success, -1 on failure
++ * @see evhttp_bind_socket()
++ */
++int evhttp_bind_socket_with_fd(struct evhttp *http, const char *address, u_short port);
++
++/**
++ * Like evhttp_bind_socket(), but returns the socket file descriptor.
++ *
++ * @param http a pointer to an evhttp object
++ * @param address a string containing the IP address to listen(2) on
++ * @param port the port number to listen on
++ * @param backlog the backlog value for listen(2)
++ * @return Socket file descriptor on success, -1 on failure
++ * @see evhttp_bind_socket()
++ */
++int evhttp_bind_socket_backlog_fd(struct evhttp *http, const char *address, u_short port, int backlog);
++
++/**
+ * Makes an HTTP server accept connections on the specified socket
+ *
+ * This may be useful to create a socket and then fork multiple instances
+ * of an http server, or when a socket has been communicated via file
+ * descriptor passing in situations where an http servers does not have
+@@ -103,10 +141,25 @@ int evhttp_bind_socket(struct evhttp *ht
+ * @see evhttp_free(), evhttp_bind_socket()
+ */
+ int evhttp_accept_socket(struct evhttp *http, int fd);
+
+ /**
++ * Makes an HTTP server stop accepting connections on the specified socket
++ *
++ * This may be useful when a socket has been sent via file descriptor passing
++ * and is no longer needed by the current process.
++ *
++ * This function does not close the socket.
++ *
++ * @param http a pointer to an evhttp object
++ * @param fd a socket fd that is currently accepting connections
++ * @return 0 on success, -1 on failure.
++ * @see evhttp_accept_socket()
++ */
++int evhttp_del_accept_socket(struct evhttp *http, int fd);
++
++/**
+ * Free the previously created HTTP server.
+ *
+ * Works only if no requests are currently being served.
+ *
+ * @param http the evhttp server object to be freed
+@@ -132,10 +185,25 @@ void evhttp_set_gencb(struct evhttp *,
+ * @param http an evhttp object
+ * @param timeout_in_secs the timeout, in seconds
+ */
+ void evhttp_set_timeout(struct evhttp *, int timeout_in_secs);
+
++/**
++ * Limit the number of simultaneous connections via this http instance.
++ *
++ * @param http an evhttp object
++ * @param nlimit the maximum number of connections, zero is unlimited
++ */
++int evhttp_set_connection_limit(struct evhttp *http, int nlimit);
++
++/**
++ * Return the maximum number of connections allowed for this instance.
++ *
++ * @param http an evhttp object
++ */
++int evhttp_get_connection_limit(struct evhttp *http);
++
+ /* Request/Response functionality */
+
+ /**
+ * Send an HTML error message to the client.
+ *
+@@ -155,10 +223,23 @@ void evhttp_send_error(struct evhttp_req
+ * @param databuf the body of the response
+ */
+ void evhttp_send_reply(struct evhttp_request *req, int code,
+ const char *reason, struct evbuffer *databuf);
+
++/**
++ * Send an HTML reply synchronously as much as possible by calling _begin().
++ * Great for a worker thread to send the reply immediately without queuing up
++ * events back to the loop. Call _end() to send the rest of the packet from
++ * event loop.
++ *
++ * When _begin() returns needs to be fed into _end() as the 1st parameter
++ * "nwritten".
++ */
++int evhttp_send_reply_sync_begin(struct evhttp_request *req, int code,
++ const char *reason, struct evbuffer *databuf);
++void evhttp_send_reply_sync_end(int nwritten, struct evhttp_request *req);
++
+ /* Low-level response interface, for streaming/chunked replies */
+ void evhttp_send_reply_start(struct evhttp_request *, int, const char *);
+ void evhttp_send_reply_chunk(struct evhttp_request *, struct evbuffer *);
+ void evhttp_send_reply_end(struct evhttp_request *);
+
+@@ -208,10 +289,11 @@ struct {
+ char *remote_host;
+ u_short remote_port;
+
+ enum evhttp_request_kind kind;
+ enum evhttp_cmd_type type;
++ char *ext_method; /* webdav methods, for example */
+
+ char *uri; /* uri after HTTP request was parsed */
+
+ char major; /* HTTP Major number */
+ char minor; /* HTTP Minor number */
+@@ -222,10 +304,12 @@ struct {
+ struct evbuffer *input_buffer; /* read data */
+ ev_int64_t ntoread;
+ int chunked:1, /* a chunked request */
+ userdone:1; /* the user has sent all data */
+
++ int referenced;
++
+ struct evbuffer *output_buffer; /* outgoing post or data */
+
+ /* Callback */
+ void (*cb)(struct evhttp_request *, void *);
+ void *cb_arg;
+diff -rp -U 5 libevent-1.4.14-stable/http-internal.h libevent-1.4.14-stable-fb/http-internal.h
+--- libevent-1.4.14-stable/http-internal.h 2010-06-07 14:40:35.000000000 -0700
++++ libevent-1.4.14-stable-fb/http-internal.h 2010-06-18 16:30:57.000000000 -0700
+@@ -114,10 +114,13 @@ struct evhttp {
+ TAILQ_HEAD(boundq, evhttp_bound_socket) sockets;
+
+ TAILQ_HEAD(httpcbq, evhttp_cb) callbacks;
+ struct evconq connections;
+
++ int connection_count;
++ int connection_limit;
++
+ int timeout;
+
+ void (*gencb)(struct evhttp_request *req, void *);
+ void *gencbarg;
+
+diff -rp -U 5 libevent-1.4.14-stable/http.c libevent-1.4.14-stable-fb/http.c
+--- libevent-1.4.14-stable/http.c 2010-06-07 14:40:35.000000000 -0700
++++ libevent-1.4.14-stable-fb/http.c 2010-06-18 16:35:23.000000000 -0700
+@@ -217,10 +217,17 @@ static int evhttp_decode_uri_internal(co
+ char *ret, int always_decode_plus);
+
+ void evhttp_read(int, short, void *);
+ void evhttp_write(int, short, void *);
+
++
++void evhttp_server_drop_connection(struct evhttp_connection *evcon);
++void evhttp_server_add_connection(struct evhttp *http,
++ struct evhttp_connection *evcon);
++void evhttp_pause(struct evhttp *http);
++void evhttp_resume(struct evhttp *http);
++
+ #ifndef HAVE_STRSEP
+ /* strsep replacement for platforms that lack it. Only works if
+ * del is one character long. */
+ static char *
+ strsep(char **s, const char *del)
+@@ -476,21 +483,19 @@ evhttp_make_header_response(struct evhtt
+ */
+ if (req->minor == 0 && is_keepalive)
+ evhttp_add_header(req->output_headers,
+ "Connection", "keep-alive");
+
+- if (req->minor == 1 || is_keepalive) {
+ /*
+ * we need to add the content length if the
+ * user did not give it, this is required for
+ * persistent connections to work.
+ */
+ evhttp_maybe_add_content_length_header(
+ req->output_headers,
+ (long)EVBUFFER_LENGTH(req->output_buffer));
+ }
+- }
+
+ /* Potentially add headers for unidentified content. */
+ if (EVBUFFER_LENGTH(req->output_buffer)) {
+ if (evhttp_find_header(req->output_headers,
+ "Content-Type") == NULL) {
+@@ -685,18 +690,18 @@ evhttp_connection_fail(struct evhttp_con
+
+ void
+ evhttp_write(int fd, short what, void *arg)
+ {
+ struct evhttp_connection *evcon = arg;
+- int n;
+
+ if (what == EV_TIMEOUT) {
+ evhttp_connection_fail(evcon, EVCON_HTTP_TIMEOUT);
+ return;
+ }
+
+- n = evbuffer_write(evcon->output_buffer, fd);
++ if (EVBUFFER_LENGTH(evcon->output_buffer) != 0) {
++ int n = evbuffer_write(evcon->output_buffer, fd);
+ if (n == -1) {
+ event_debug(("%s: evbuffer_write", __func__));
+ evhttp_connection_fail(evcon, EVCON_HTTP_EOF);
+ return;
+ }
+@@ -704,10 +709,11 @@ evhttp_write(int fd, short what, void *a
+ if (n == 0) {
+ event_debug(("%s: write nothing", __func__));
+ evhttp_connection_fail(evcon, EVCON_HTTP_EOF);
+ return;
+ }
++ }
+
+ if (EVBUFFER_LENGTH(evcon->output_buffer) != 0) {
+ evhttp_add_event(&evcon->ev,
+ evcon->timeout, HTTP_WRITE_TIMEOUT);
+ return;
+@@ -1010,15 +1016,13 @@ evhttp_connection_free(struct evhttp_con
+ */
+ while ((req = TAILQ_FIRST(&evcon->requests)) != NULL) {
+ TAILQ_REMOVE(&evcon->requests, req, next);
+ evhttp_request_free(req);
+ }
+-
+- if (evcon->http_server != NULL) {
+- struct evhttp *http = evcon->http_server;
+- TAILQ_REMOVE(&http->connections, evcon, next);
+- }
++
++ if (evcon->http_server != NULL)
++ evhttp_server_drop_connection(evcon);
+
+ if (event_initialized(&evcon->close_ev))
+ event_del(&evcon->close_ev);
+
+ if (event_initialized(&evcon->ev))
+@@ -1099,14 +1103,20 @@ evhttp_connection_reset(struct evhttp_co
+ EVUTIL_CLOSESOCKET(evcon->fd);
+ evcon->fd = -1;
+ }
+ evcon->state = EVCON_DISCONNECTED;
+
+- evbuffer_drain(evcon->input_buffer,
+- EVBUFFER_LENGTH(evcon->input_buffer));
+- evbuffer_drain(evcon->output_buffer,
+- EVBUFFER_LENGTH(evcon->output_buffer));
++ /*
++ * These can grow quite large if processing a large photo or video
++ * upload/download. Instead of keeping the buffers around, just
++ * free and allocate new.
++ */
++ evbuffer_free(evcon->input_buffer);
++ evcon->input_buffer = evbuffer_new();
++
++ evbuffer_free(evcon->output_buffer);
++ evcon->output_buffer = evbuffer_new();
+ }
+
+ static void
+ evhttp_detect_close_cb(int fd, short what, void *arg)
+ {
+@@ -1276,23 +1286,56 @@ evhttp_parse_request_line(struct evhttp_
+ /* Parse the request line */
+ method = strsep(&line, " ");
+ if (line == NULL)
+ return (-1);
+ uri = strsep(&line, " ");
+- if (line == NULL)
+- return (-1);
++ if (line == NULL) {
++ version = "HTTP/1.0";
++ } else {
+ version = strsep(&line, " ");
+ if (line != NULL)
+ return (-1);
++ }
+
+ /* First line */
++ req->ext_method = NULL;
+ if (strcmp(method, "GET") == 0) {
+ req->type = EVHTTP_REQ_GET;
+ } else if (strcmp(method, "POST") == 0) {
+ req->type = EVHTTP_REQ_POST;
+ } else if (strcmp(method, "HEAD") == 0) {
+ req->type = EVHTTP_REQ_HEAD;
++ } else if (strcmp(method, "OPTIONS") == 0) {
++ req->type = EVHTTP_REQ_POST;
++ req->ext_method = "OPTIONS";
++ } else if (strcmp(method, "REPORT") == 0) {
++ req->type = EVHTTP_REQ_POST;
++ req->ext_method = "REPORT";
++ } else if (strcmp(method, "PROPFIND") == 0) {
++ req->type = EVHTTP_REQ_POST;
++ req->ext_method = "PROPFIND";
++ } else if (strcmp(method, "PROPPATH") == 0) {
++ req->type = EVHTTP_REQ_POST;
++ req->ext_method = "PROPPATH";
++ } else if (strcmp(method, "MKCOL") == 0) {
++ req->type = EVHTTP_REQ_POST;
++ req->ext_method = "MKCOL";
++ } else if (strcmp(method, "MKCALENDAR") == 0) {
++ req->type = EVHTTP_REQ_POST;
++ req->ext_method = "MKCALENDAR";
++ } else if (strcmp(method, "PUT") == 0) {
++ req->type = EVHTTP_REQ_POST;
++ req->ext_method = "PUT";
++ } else if (strcmp(method, "DELETE") == 0) {
++ req->type = EVHTTP_REQ_POST;
++ req->ext_method = "DELETE";
++ } else if (strcmp(method, "LOCK") == 0) {
++ req->type = EVHTTP_REQ_POST;
++ req->ext_method = "LOCK";
++ } else if (strcmp(method, "UNLOCK") == 0) {
++ req->type = EVHTTP_REQ_POST;
++ req->ext_method = "UNLOCK";
+ } else {
+ event_debug(("%s: bad method %s on request %p from %s",
+ __func__, method, req, req->remote_host));
+ return (-1);
+ }
+@@ -1961,14 +2004,48 @@ evhttp_send_reply(struct evhttp_request
+ evhttp_response_code(req, code, reason);
+
+ evhttp_send(req, databuf);
+ }
+
++int
++evhttp_send_reply_sync_begin(struct evhttp_request *req, int code,
++ const char *reason, struct evbuffer *databuf) {
++ evhttp_response_code(req, code, reason);
++ struct evhttp_connection *evcon = req->evcon;
++
++ assert(TAILQ_FIRST(&evcon->requests) == req);
++
++ /* xxx: not sure if we really should expose the data buffer this way */
++ if (databuf != NULL)
++ evbuffer_add_buffer(req->output_buffer, databuf);
++
++ /* Adds headers to the response */
++ evhttp_make_header(evcon, req);
++
++ return evbuffer_write(evcon->output_buffer, evcon->fd);
++}
++
++void
++evhttp_send_reply_sync_end(int nwritten, struct evhttp_request *req) {
++ struct evhttp_connection *evcon = req->evcon;
++
++ if (nwritten <= 0) {
++ evhttp_connection_fail(evcon, EVCON_HTTP_EOF);
++ } else if (EVBUFFER_LENGTH(evcon->output_buffer) == 0) {
++ evhttp_send_done(evcon, NULL);
++ } else {
++ evhttp_write_buffer(evcon, evhttp_send_done, NULL);
++ }
++}
++
++
+ void
+ evhttp_send_reply_start(struct evhttp_request *req, int code,
+ const char *reason)
+ {
++ req->referenced = 1;
++
+ evhttp_response_code(req, code, reason);
+ if (req->major == 1 && req->minor == 1) {
+ /* use chunked encoding for HTTP/1.1 */
+ evhttp_add_header(req->output_headers, "Transfer-Encoding",
+ "chunked");
+@@ -1984,10 +2061,12 @@ evhttp_send_reply_chunk(struct evhttp_re
+ struct evhttp_connection *evcon = req->evcon;
+
+ if (evcon == NULL)
+ return;
+
++ if (req->referenced < 0) return;
++
+ if (req->chunked) {
+ evbuffer_add_printf(evcon->output_buffer, "%x\r\n",
+ (unsigned)EVBUFFER_LENGTH(databuf));
+ }
+ evbuffer_add_buffer(evcon->output_buffer, databuf);
+@@ -2005,11 +2084,18 @@ evhttp_send_reply_end(struct evhttp_requ
+ if (evcon == NULL) {
+ evhttp_request_free(req);
+ return;
+ }
+
+- /* we expect no more calls form the user on this request */
++ if (req->referenced < 0) {
++ req->referenced = 0;
++ evhttp_request_free(req);
++ return;
++ }
++ req->referenced = 0;
++
++ /* we expect no more calls form the user on this request */
+ req->userdone = 1;
+
+ if (req->chunked) {
+ evbuffer_add(req->evcon->output_buffer, "0\r\n\r\n", 5);
+ evhttp_write_buffer(req->evcon, evhttp_send_done, NULL);
+@@ -2291,33 +2377,63 @@ accept_socket(int fd, short what, void *
+
+ evhttp_get_request(http, nfd, (struct sockaddr *)&ss, addrlen);
+ }
+
+ int
+-evhttp_bind_socket(struct evhttp *http, const char *address, u_short port)
++evhttp_bind_socket_backlog_fd(struct evhttp *http, const char *address,
++ u_short port, int backlog)
+ {
+ int fd;
+ int res;
+
+ if ((fd = bind_socket(address, port, 1 /*reuse*/)) == -1)
+ return (-1);
+
+- if (listen(fd, 128) == -1) {
++ if (listen(fd, backlog) == -1) {
+ event_warn("%s: listen", __func__);
+ EVUTIL_CLOSESOCKET(fd);
+ return (-1);
+ }
+
+ res = evhttp_accept_socket(http, fd);
+
+- if (res != -1)
++ if (res != -1) {
+ event_debug(("Bound to port %d - Awaiting connections ... ",
+ port));
++ return (fd);
++ }
+
+ return (res);
+ }
+
++static int
++mask_fd(int fd)
++{
++ return fd > 0 ? 0 : fd;
++}
++
++int
++evhttp_bind_socket(struct evhttp *http, const char *address, u_short port)
++{
++ return mask_fd(evhttp_bind_socket_backlog_fd(http, address, port, 128));
++}
++
++int
++evhttp_bind_socket_with_fd(struct evhttp *http, const char *address,
++ u_short port)
++{
++ return evhttp_bind_socket_backlog_fd(http, address, port, 128);
++}
++
++int
++evhttp_bind_socket_backlog(struct evhttp *http, const char *address,
++ u_short port, int backlog)
++{
++ return mask_fd(
++ evhttp_bind_socket_backlog_fd(http, address, port, backlog));
++}
++
+ int
+ evhttp_accept_socket(struct evhttp *http, int fd)
+ {
+ struct evhttp_bound_socket *bound;
+ struct event *ev;
+@@ -2343,10 +2459,29 @@ evhttp_accept_socket(struct evhttp *http
+ TAILQ_INSERT_TAIL(&http->sockets, bound, next);
+
+ return (0);
+ }
+
++int
++evhttp_del_accept_socket(struct evhttp *http, int fd)
++{
++ struct evhttp_bound_socket *bound;
++ TAILQ_FOREACH(bound, &http->sockets, next) {
++ if (bound->bind_ev.ev_fd == fd)
++ break;
++ }
++
++ if (bound == NULL)
++ return (-1);
++
++ TAILQ_REMOVE(&http->sockets, bound, next);
++ event_del(&bound->bind_ev);
++ free(bound);
++
++ return (0);
++}
++
+ static struct evhttp*
+ evhttp_new_object(void)
+ {
+ struct evhttp *http = NULL;
+
+@@ -2525,10 +2660,15 @@ evhttp_request_new(void (*cb)(struct evh
+ }
+
+ void
+ evhttp_request_free(struct evhttp_request *req)
+ {
++ if (req->referenced) {
++ req->referenced = -1;
++ return;
++ }
++
+ if (req->remote_host != NULL)
+ free(req->remote_host);
+ if (req->uri != NULL)
+ free(req->uri);
+ if (req->response_code_line != NULL)
+@@ -2655,17 +2795,76 @@ evhttp_get_request(struct evhttp *http,
+
+ /*
+ * if we want to accept more than one request on a connection,
+ * we need to know which http server it belongs to.
+ */
+- evcon->http_server = http;
+- TAILQ_INSERT_TAIL(&http->connections, evcon, next);
++
++ evhttp_server_add_connection(http, evcon);
+
+ if (evhttp_associate_new_request_with_connection(evcon) == -1)
+ evhttp_connection_free(evcon);
+ }
+
++void
++evhttp_pause(struct evhttp *http)
++{
++ struct evhttp_bound_socket *bound;
++ TAILQ_FOREACH(bound, &http->sockets, next) {
++ event_del(&bound->bind_ev);
++ }
++}
++
++void
++evhttp_resume(struct evhttp *http)
++{
++ struct evhttp_bound_socket *bound;
++ TAILQ_FOREACH(bound, &http->sockets, next) {
++ event_add(&bound->bind_ev, 0);
++ }
++}
++
++int
++evhttp_get_connection_limit(struct evhttp *http)
++{
++ return http->connection_limit;
++}
++
++int
++evhttp_set_connection_limit(struct evhttp *http, int nlimit)
++{
++ int olimit = http->connection_limit;
++ http->connection_limit = nlimit;
++ return olimit;
++}
++
++void
++evhttp_server_add_connection(struct evhttp *http,
++ struct evhttp_connection *evcon)
++{
++ evcon->http_server = http;
++ TAILQ_INSERT_TAIL(&http->connections, evcon, next);
++
++ http->connection_count++;
++ if (http->connection_limit > 0
++ && http->connection_count >= http->connection_limit)
++ {
++ evhttp_pause(http);
++ }
++}
++
++void
++evhttp_server_drop_connection(struct evhttp_connection *evcon)
++{
++ struct evhttp *http = evcon->http_server;
++ TAILQ_REMOVE(&http->connections, evcon, next);
++ http->connection_count--;
++ if (http->connection_limit > 0
++ && http->connection_count < http->connection_limit)
++ {
++ evhttp_resume(http);
++ }
++}
+
+ /*
+ * Network helper functions that we do not want to export to the rest of
+ * the world.
+ */