summaryrefslogtreecommitdiffstats
path: root/meta-linaro/recipes-extra/libevent/files
diff options
context:
space:
mode:
Diffstat (limited to 'meta-linaro/recipes-extra/libevent/files')
-rw-r--r--meta-linaro/recipes-extra/libevent/files/LICENSE.txt74
-rw-r--r--meta-linaro/recipes-extra/libevent/files/libevent-1.4.14.fb-changes.diff611
2 files changed, 685 insertions, 0 deletions
diff --git a/meta-linaro/recipes-extra/libevent/files/LICENSE.txt b/meta-linaro/recipes-extra/libevent/files/LICENSE.txt
new file mode 100644
index 0000000..5a315e4
--- /dev/null
+++ b/meta-linaro/recipes-extra/libevent/files/LICENSE.txt
@@ -0,0 +1,74 @@
1Libevent is available for use under the following license, commonly known
2as the 3-clause (or "modified") BSD license:
3
4==============================
5Copyright (c) 2000-2007 Niels Provos <provos@citi.umich.edu>
6Copyright (c) 2007-2010 Niels Provos and Nick Mathewson
7
8Redistribution and use in source and binary forms, with or without
9modification, are permitted provided that the following conditions
10are met:
111. Redistributions of source code must retain the above copyright
12 notice, this list of conditions and the following disclaimer.
132. Redistributions in binary form must reproduce the above copyright
14 notice, this list of conditions and the following disclaimer in the
15 documentation and/or other materials provided with the distribution.
163. The name of the author may not be used to endorse or promote products
17 derived from this software without specific prior written permission.
18
19THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
20IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
21OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
22IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
23INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
24NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29==============================
30
31Portions of Libevent are based on works by others, also made available by
32them under the three-clause BSD license above. The copyright notices are
33available in the corresponding source files; the license is as above. Here's
34a list:
35
36log.c:
37 Copyright (c) 2000 Dug Song <dugsong@monkey.org>
38 Copyright (c) 1993 The Regents of the University of California.
39
40strlcpy.c:
41 Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
42
43win32select.c:
44 Copyright (c) 2003 Michael A. Davis <mike@datanerds.net>
45
46evport.c:
47 Copyright (c) 2007 Sun Microsystems
48
49ht-internal.h:
50 Copyright (c) 2002 Christopher Clark
51
52minheap-internal.h:
53 Copyright (c) 2006 Maxim Yegorushkin <maxim.yegorushkin@gmail.com>
54
55==============================
56
57The arc4module is available under the following, sometimes called the
58"OpenBSD" license:
59
60 Copyright (c) 1996, David Mazieres <dm@uun.org>
61 Copyright (c) 2008, Damien Miller <djm@openbsd.org>
62
63 Permission to use, copy, modify, and distribute this software for any
64 purpose with or without fee is hereby granted, provided that the above
65 copyright notice and this permission notice appear in all copies.
66
67 THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
68 WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
69 MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
70 ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
71 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
72 ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
73 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
74
diff --git a/meta-linaro/recipes-extra/libevent/files/libevent-1.4.14.fb-changes.diff b/meta-linaro/recipes-extra/libevent/files/libevent-1.4.14.fb-changes.diff
new file mode 100644
index 0000000..0f29aac
--- /dev/null
+++ b/meta-linaro/recipes-extra/libevent/files/libevent-1.4.14.fb-changes.diff
@@ -0,0 +1,611 @@
1diff --git a/event.c b/event.c
2index 74ba5c4..06984b8 100644
3--- a/event.c
4+++ b/event.c
5@@ -138,10 +138,12 @@ detect_monotonic(void)
6 static int
7 gettime(struct event_base *base, struct timeval *tp)
8 {
9+/*
10 if (base->tv_cache.tv_sec) {
11 *tp = base->tv_cache;
12 return (0);
13 }
14+*/
15
16 #if defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_MONOTONIC)
17 if (use_monotonic) {
18@@ -481,7 +483,7 @@ event_base_loop(struct event_base *base, int flags)
19 int res, done;
20
21 /* clear time cache */
22- base->tv_cache.tv_sec = 0;
23+ /* base->tv_cache.tv_sec = 0; */
24
25 if (base->sig.ev_signal_added)
26 evsignal_base = base;
27@@ -533,13 +535,13 @@ event_base_loop(struct event_base *base, int flags)
28 gettime(base, &base->event_tv);
29
30 /* clear time cache */
31- base->tv_cache.tv_sec = 0;
32+ /* base->tv_cache.tv_sec = 0; */
33
34 res = evsel->dispatch(base, evbase, tv_p);
35
36 if (res == -1)
37 return (-1);
38- gettime(base, &base->tv_cache);
39+ /* gettime(base, &base->tv_cache); */
40
41 timeout_process(base);
42
43@@ -552,7 +554,7 @@ event_base_loop(struct event_base *base, int flags)
44 }
45
46 /* clear time cache */
47- base->tv_cache.tv_sec = 0;
48+ /* base->tv_cache.tv_sec = 0; */
49
50 event_debug(("%s: asked to terminate loop.", __func__));
51 return (0);
52diff --git a/evhttp.h b/evhttp.h
53index 7ddf720..13c8b79 100644
54--- a/evhttp.h
55+++ b/evhttp.h
56@@ -81,12 +81,50 @@ struct evhttp *evhttp_new(struct event_base *base);
57 * @param http a pointer to an evhttp object
58 * @param address a string containing the IP address to listen(2) on
59 * @param port the port number to listen on
60- * @return a newly allocated evhttp struct
61+ * @return 0 on success, -1 on error
62 * @see evhttp_free()
63 */
64 int evhttp_bind_socket(struct evhttp *http, const char *address, u_short port);
65
66 /**
67+ * Binds an HTTP server on the specified address and port, using backlog.
68+ *
69+ * Can be called multiple times to bind the same http server
70+ * to multiple different ports.
71+ *
72+ * @param http a pointer to an evhttp object
73+ * @param address a string containing the IP address to listen(2) on
74+ * @param port the port number to listen on
75+ * @param backlog the backlog value for listen(2)
76+ * @return 0 on success, -1 on error
77+ * @see evhttp_free()
78+ */
79+int evhttp_bind_socket_backlog(struct evhttp *http, const char *address, u_short port, int backlog);
80+
81+/**
82+ * Like evhttp_bind_socket(), but returns the socket file descriptor.
83+ *
84+ * @param http a pointer to an evhttp object
85+ * @param address a string containing the IP address to listen(2) on
86+ * @param port the port number to listen on
87+ * @return Socket file descriptor on success, -1 on failure
88+ * @see evhttp_bind_socket()
89+ */
90+int evhttp_bind_socket_with_fd(struct evhttp *http, const char *address, u_short port);
91+
92+/**
93+ * Like evhttp_bind_socket(), but returns the socket file descriptor.
94+ *
95+ * @param http a pointer to an evhttp object
96+ * @param address a string containing the IP address to listen(2) on
97+ * @param port the port number to listen on
98+ * @param backlog the backlog value for listen(2)
99+ * @return Socket file descriptor on success, -1 on failure
100+ * @see evhttp_bind_socket()
101+ */
102+int evhttp_bind_socket_backlog_fd(struct evhttp *http, const char *address, u_short port, int backlog);
103+
104+/**
105 * Makes an HTTP server accept connections on the specified socket
106 *
107 * This may be useful to create a socket and then fork multiple instances
108@@ -105,6 +143,21 @@ int evhttp_bind_socket(struct evhttp *http, const char *address, u_short port);
109 int evhttp_accept_socket(struct evhttp *http, int fd);
110
111 /**
112+ * Makes an HTTP server stop accepting connections on the specified socket
113+ *
114+ * This may be useful when a socket has been sent via file descriptor passing
115+ * and is no longer needed by the current process.
116+ *
117+ * This function does not close the socket.
118+ *
119+ * @param http a pointer to an evhttp object
120+ * @param fd a socket fd that is currently accepting connections
121+ * @return 0 on success, -1 on failure.
122+ * @see evhttp_accept_socket()
123+ */
124+int evhttp_del_accept_socket(struct evhttp *http, int fd);
125+
126+/**
127 * Free the previously created HTTP server.
128 *
129 * Works only if no requests are currently being served.
130@@ -134,6 +187,28 @@ void evhttp_set_gencb(struct evhttp *,
131 */
132 void evhttp_set_timeout(struct evhttp *, int timeout_in_secs);
133
134+/**
135+ * Limit the number of simultaneous connections via this http instance.
136+ *
137+ * @param http an evhttp object
138+ * @param nlimit the maximum number of connections, zero is unlimited
139+ */
140+int evhttp_set_connection_limit(struct evhttp *http, int nlimit);
141+
142+/**
143+ * Return the maximum number of connections allowed for this instance.
144+ *
145+ * @param http an evhttp object
146+ */
147+int evhttp_get_connection_limit(struct evhttp *http);
148+
149+/**
150+ * Return the number of connections in this instance.
151+ *
152+ * @param http an evhttp object
153+ */
154+int evhttp_get_connection_count(struct evhttp *http);
155+
156 /* Request/Response functionality */
157
158 /**
159@@ -157,6 +232,19 @@ void evhttp_send_error(struct evhttp_request *req, int error,
160 void evhttp_send_reply(struct evhttp_request *req, int code,
161 const char *reason, struct evbuffer *databuf);
162
163+/**
164+ * Send an HTML reply synchronously as much as possible by calling _begin().
165+ * Great for a worker thread to send the reply immediately without queuing up
166+ * events back to the loop. Call _end() to send the rest of the packet from
167+ * event loop.
168+ *
169+ * When _begin() returns needs to be fed into _end() as the 1st parameter
170+ * "nwritten".
171+ */
172+int evhttp_send_reply_sync_begin(struct evhttp_request *req, int code,
173+ const char *reason, struct evbuffer *databuf);
174+void evhttp_send_reply_sync_end(int nwritten, struct evhttp_request *req);
175+
176 /* Low-level response interface, for streaming/chunked replies */
177 void evhttp_send_reply_start(struct evhttp_request *, int, const char *);
178 void evhttp_send_reply_chunk(struct evhttp_request *, struct evbuffer *);
179@@ -210,6 +298,7 @@ struct {
180
181 enum evhttp_request_kind kind;
182 enum evhttp_cmd_type type;
183+ char *ext_method; /* webdav methods, for example */
184
185 char *uri; /* uri after HTTP request was parsed */
186
187@@ -224,6 +313,8 @@ struct {
188 int chunked:1, /* a chunked request */
189 userdone:1; /* the user has sent all data */
190
191+ int referenced;
192+
193 struct evbuffer *output_buffer; /* outgoing post or data */
194
195 /* Callback */
196diff --git a/http-internal.h b/http-internal.h
197index 9cd03cd..3f60f54 100644
198--- a/http-internal.h
199+++ b/http-internal.h
200@@ -116,6 +116,9 @@ struct evhttp {
201 TAILQ_HEAD(httpcbq, evhttp_cb) callbacks;
202 struct evconq connections;
203
204+ int connection_count;
205+ int connection_limit;
206+
207 int timeout;
208
209 void (*gencb)(struct evhttp_request *req, void *);
210diff --git a/http.c b/http.c
211index efcec40..e10d114 100644
212--- a/http.c
213+++ b/http.c
214@@ -219,6 +219,13 @@ static int evhttp_decode_uri_internal(const char *uri, size_t length,
215 void evhttp_read(int, short, void *);
216 void evhttp_write(int, short, void *);
217
218+
219+void evhttp_server_drop_connection(struct evhttp_connection *evcon);
220+void evhttp_server_add_connection(struct evhttp *http,
221+ struct evhttp_connection *evcon);
222+void evhttp_pause(struct evhttp *http);
223+void evhttp_resume(struct evhttp *http);
224+
225 #ifndef HAVE_STRSEP
226 /* strsep replacement for platforms that lack it. Only works if
227 * del is one character long. */
228@@ -478,7 +485,6 @@ evhttp_make_header_response(struct evhttp_connection *evcon,
229 evhttp_add_header(req->output_headers,
230 "Connection", "keep-alive");
231
232- if (req->minor == 1 || is_keepalive) {
233 /*
234 * we need to add the content length if the
235 * user did not give it, this is required for
236@@ -488,7 +494,6 @@ evhttp_make_header_response(struct evhttp_connection *evcon,
237 req->output_headers,
238 (long)EVBUFFER_LENGTH(req->output_buffer));
239 }
240- }
241
242 /* Potentially add headers for unidentified content. */
243 if (EVBUFFER_LENGTH(req->output_buffer)) {
244@@ -687,14 +692,14 @@ void
245 evhttp_write(int fd, short what, void *arg)
246 {
247 struct evhttp_connection *evcon = arg;
248- int n;
249
250 if (what == EV_TIMEOUT) {
251 evhttp_connection_fail(evcon, EVCON_HTTP_TIMEOUT);
252 return;
253 }
254
255- n = evbuffer_write(evcon->output_buffer, fd);
256+ if (EVBUFFER_LENGTH(evcon->output_buffer) != 0) {
257+ int n = evbuffer_write(evcon->output_buffer, fd);
258 if (n == -1) {
259 event_debug(("%s: evbuffer_write", __func__));
260 evhttp_connection_fail(evcon, EVCON_HTTP_EOF);
261@@ -706,6 +711,7 @@ evhttp_write(int fd, short what, void *arg)
262 evhttp_connection_fail(evcon, EVCON_HTTP_EOF);
263 return;
264 }
265+ }
266
267 if (EVBUFFER_LENGTH(evcon->output_buffer) != 0) {
268 evhttp_add_event(&evcon->ev,
269@@ -1012,11 +1018,9 @@ evhttp_connection_free(struct evhttp_connection *evcon)
270 TAILQ_REMOVE(&evcon->requests, req, next);
271 evhttp_request_free(req);
272 }
273-
274- if (evcon->http_server != NULL) {
275- struct evhttp *http = evcon->http_server;
276- TAILQ_REMOVE(&http->connections, evcon, next);
277- }
278+
279+ if (evcon->http_server != NULL)
280+ evhttp_server_drop_connection(evcon);
281
282 if (event_initialized(&evcon->close_ev))
283 event_del(&evcon->close_ev);
284@@ -1101,10 +1105,16 @@ evhttp_connection_reset(struct evhttp_connection *evcon)
285 }
286 evcon->state = EVCON_DISCONNECTED;
287
288- evbuffer_drain(evcon->input_buffer,
289- EVBUFFER_LENGTH(evcon->input_buffer));
290- evbuffer_drain(evcon->output_buffer,
291- EVBUFFER_LENGTH(evcon->output_buffer));
292+ /*
293+ * These can grow quite large if processing a large photo or video
294+ * upload/download. Instead of keeping the buffers around, just
295+ * free and allocate new.
296+ */
297+ evbuffer_free(evcon->input_buffer);
298+ evcon->input_buffer = evbuffer_new();
299+
300+ evbuffer_free(evcon->output_buffer);
301+ evcon->output_buffer = evbuffer_new();
302 }
303
304 static void
305@@ -1278,19 +1288,52 @@ evhttp_parse_request_line(struct evhttp_request *req, char *line)
306 if (line == NULL)
307 return (-1);
308 uri = strsep(&line, " ");
309- if (line == NULL)
310- return (-1);
311+ if (line == NULL) {
312+ version = "HTTP/1.0";
313+ } else {
314 version = strsep(&line, " ");
315 if (line != NULL)
316 return (-1);
317+ }
318
319 /* First line */
320+ req->ext_method = NULL;
321 if (strcmp(method, "GET") == 0) {
322 req->type = EVHTTP_REQ_GET;
323 } else if (strcmp(method, "POST") == 0) {
324 req->type = EVHTTP_REQ_POST;
325 } else if (strcmp(method, "HEAD") == 0) {
326 req->type = EVHTTP_REQ_HEAD;
327+ } else if (strcmp(method, "OPTIONS") == 0) {
328+ req->type = EVHTTP_REQ_POST;
329+ req->ext_method = "OPTIONS";
330+ } else if (strcmp(method, "REPORT") == 0) {
331+ req->type = EVHTTP_REQ_POST;
332+ req->ext_method = "REPORT";
333+ } else if (strcmp(method, "PROPFIND") == 0) {
334+ req->type = EVHTTP_REQ_POST;
335+ req->ext_method = "PROPFIND";
336+ } else if (strcmp(method, "PROPPATH") == 0) {
337+ req->type = EVHTTP_REQ_POST;
338+ req->ext_method = "PROPPATH";
339+ } else if (strcmp(method, "MKCOL") == 0) {
340+ req->type = EVHTTP_REQ_POST;
341+ req->ext_method = "MKCOL";
342+ } else if (strcmp(method, "MKCALENDAR") == 0) {
343+ req->type = EVHTTP_REQ_POST;
344+ req->ext_method = "MKCALENDAR";
345+ } else if (strcmp(method, "PUT") == 0) {
346+ req->type = EVHTTP_REQ_POST;
347+ req->ext_method = "PUT";
348+ } else if (strcmp(method, "DELETE") == 0) {
349+ req->type = EVHTTP_REQ_POST;
350+ req->ext_method = "DELETE";
351+ } else if (strcmp(method, "LOCK") == 0) {
352+ req->type = EVHTTP_REQ_POST;
353+ req->ext_method = "LOCK";
354+ } else if (strcmp(method, "UNLOCK") == 0) {
355+ req->type = EVHTTP_REQ_POST;
356+ req->ext_method = "UNLOCK";
357 } else {
358 event_debug(("%s: bad method %s on request %p from %s",
359 __func__, method, req, req->remote_host));
360@@ -1963,10 +2006,44 @@ evhttp_send_reply(struct evhttp_request *req, int code, const char *reason,
361 evhttp_send(req, databuf);
362 }
363
364+int
365+evhttp_send_reply_sync_begin(struct evhttp_request *req, int code,
366+ const char *reason, struct evbuffer *databuf) {
367+ evhttp_response_code(req, code, reason);
368+ struct evhttp_connection *evcon = req->evcon;
369+
370+ assert(TAILQ_FIRST(&evcon->requests) == req);
371+
372+ /* xxx: not sure if we really should expose the data buffer this way */
373+ if (databuf != NULL)
374+ evbuffer_add_buffer(req->output_buffer, databuf);
375+
376+ /* Adds headers to the response */
377+ evhttp_make_header(evcon, req);
378+
379+ return evbuffer_write(evcon->output_buffer, evcon->fd);
380+}
381+
382+void
383+evhttp_send_reply_sync_end(int nwritten, struct evhttp_request *req) {
384+ struct evhttp_connection *evcon = req->evcon;
385+
386+ if (nwritten <= 0) {
387+ evhttp_connection_fail(evcon, EVCON_HTTP_EOF);
388+ } else if (EVBUFFER_LENGTH(evcon->output_buffer) == 0) {
389+ evhttp_send_done(evcon, NULL);
390+ } else {
391+ evhttp_write_buffer(evcon, evhttp_send_done, NULL);
392+ }
393+}
394+
395+
396 void
397 evhttp_send_reply_start(struct evhttp_request *req, int code,
398 const char *reason)
399 {
400+ req->referenced = 1;
401+
402 evhttp_response_code(req, code, reason);
403 if (req->major == 1 && req->minor == 1) {
404 /* use chunked encoding for HTTP/1.1 */
405@@ -1986,6 +2063,8 @@ evhttp_send_reply_chunk(struct evhttp_request *req, struct evbuffer *databuf)
406 if (evcon == NULL)
407 return;
408
409+ if (req->referenced < 0) return;
410+
411 if (req->chunked) {
412 evbuffer_add_printf(evcon->output_buffer, "%x\r\n",
413 (unsigned)EVBUFFER_LENGTH(databuf));
414@@ -2007,7 +2086,14 @@ evhttp_send_reply_end(struct evhttp_request *req)
415 return;
416 }
417
418- /* we expect no more calls form the user on this request */
419+ if (req->referenced < 0) {
420+ req->referenced = 0;
421+ evhttp_request_free(req);
422+ return;
423+ }
424+ req->referenced = 0;
425+
426+ /* we expect no more calls form the user on this request */
427 req->userdone = 1;
428
429 if (req->chunked) {
430@@ -2293,7 +2379,8 @@ accept_socket(int fd, short what, void *arg)
431 }
432
433 int
434-evhttp_bind_socket(struct evhttp *http, const char *address, u_short port)
435+evhttp_bind_socket_backlog_fd(struct evhttp *http, const char *address,
436+ u_short port, int backlog)
437 {
438 int fd;
439 int res;
440@@ -2301,7 +2388,7 @@ evhttp_bind_socket(struct evhttp *http, const char *address, u_short port)
441 if ((fd = bind_socket(address, port, 1 /*reuse*/)) == -1)
442 return (-1);
443
444- if (listen(fd, 128) == -1) {
445+ if (listen(fd, backlog) == -1) {
446 event_warn("%s: listen", __func__);
447 EVUTIL_CLOSESOCKET(fd);
448 return (-1);
449@@ -2309,13 +2396,42 @@ evhttp_bind_socket(struct evhttp *http, const char *address, u_short port)
450
451 res = evhttp_accept_socket(http, fd);
452
453- if (res != -1)
454+ if (res != -1) {
455 event_debug(("Bound to port %d - Awaiting connections ... ",
456 port));
457+ return (fd);
458+ }
459
460 return (res);
461 }
462
463+static int
464+mask_fd(int fd)
465+{
466+ return fd > 0 ? 0 : fd;
467+}
468+
469+int
470+evhttp_bind_socket(struct evhttp *http, const char *address, u_short port)
471+{
472+ return mask_fd(evhttp_bind_socket_backlog_fd(http, address, port, 128));
473+}
474+
475+int
476+evhttp_bind_socket_with_fd(struct evhttp *http, const char *address,
477+ u_short port)
478+{
479+ return evhttp_bind_socket_backlog_fd(http, address, port, 128);
480+}
481+
482+int
483+evhttp_bind_socket_backlog(struct evhttp *http, const char *address,
484+ u_short port, int backlog)
485+{
486+ return mask_fd(
487+ evhttp_bind_socket_backlog_fd(http, address, port, backlog));
488+}
489+
490 int
491 evhttp_accept_socket(struct evhttp *http, int fd)
492 {
493@@ -2345,6 +2461,25 @@ evhttp_accept_socket(struct evhttp *http, int fd)
494 return (0);
495 }
496
497+int
498+evhttp_del_accept_socket(struct evhttp *http, int fd)
499+{
500+ struct evhttp_bound_socket *bound;
501+ TAILQ_FOREACH(bound, &http->sockets, next) {
502+ if (bound->bind_ev.ev_fd == fd)
503+ break;
504+ }
505+
506+ if (bound == NULL)
507+ return (-1);
508+
509+ TAILQ_REMOVE(&http->sockets, bound, next);
510+ event_del(&bound->bind_ev);
511+ free(bound);
512+
513+ return (0);
514+}
515+
516 static struct evhttp*
517 evhttp_new_object(void)
518 {
519@@ -2527,6 +2662,11 @@ evhttp_request_new(void (*cb)(struct evhttp_request *, void *), void *arg)
520 void
521 evhttp_request_free(struct evhttp_request *req)
522 {
523+ if (req->referenced) {
524+ req->referenced = -1;
525+ return;
526+ }
527+
528 if (req->remote_host != NULL)
529 free(req->remote_host);
530 if (req->uri != NULL)
531@@ -2657,13 +2797,78 @@ evhttp_get_request(struct evhttp *http, int fd,
532 * if we want to accept more than one request on a connection,
533 * we need to know which http server it belongs to.
534 */
535- evcon->http_server = http;
536- TAILQ_INSERT_TAIL(&http->connections, evcon, next);
537+
538+ evhttp_server_add_connection(http, evcon);
539
540 if (evhttp_associate_new_request_with_connection(evcon) == -1)
541 evhttp_connection_free(evcon);
542 }
543
544+void
545+evhttp_pause(struct evhttp *http)
546+{
547+ struct evhttp_bound_socket *bound;
548+ TAILQ_FOREACH(bound, &http->sockets, next) {
549+ event_del(&bound->bind_ev);
550+ }
551+}
552+
553+void
554+evhttp_resume(struct evhttp *http)
555+{
556+ struct evhttp_bound_socket *bound;
557+ TAILQ_FOREACH(bound, &http->sockets, next) {
558+ event_add(&bound->bind_ev, 0);
559+ }
560+}
561+
562+int
563+evhttp_get_connection_limit(struct evhttp *http)
564+{
565+ return http->connection_limit;
566+}
567+
568+int
569+evhttp_set_connection_limit(struct evhttp *http, int nlimit)
570+{
571+ int olimit = http->connection_limit;
572+ http->connection_limit = nlimit;
573+ return olimit;
574+}
575+
576+int
577+evhttp_get_connection_count(struct evhttp *http)
578+{
579+ return http != NULL ? http->connection_count : 0;
580+}
581+
582+void
583+evhttp_server_add_connection(struct evhttp *http,
584+ struct evhttp_connection *evcon)
585+{
586+ evcon->http_server = http;
587+ TAILQ_INSERT_TAIL(&http->connections, evcon, next);
588+
589+ http->connection_count++;
590+ if (http->connection_limit > 0
591+ && http->connection_count >= http->connection_limit)
592+ {
593+ evhttp_pause(http);
594+ }
595+}
596+
597+void
598+evhttp_server_drop_connection(struct evhttp_connection *evcon)
599+{
600+ struct evhttp *http = evcon->http_server;
601+ TAILQ_REMOVE(&http->connections, evcon, next);
602+ http->connection_count--;
603+ if (http->connection_limit > 0
604+ && http->connection_count < http->connection_limit)
605+ {
606+ evhttp_resume(http);
607+ }
608+}
609
610 /*
611 * Network helper functions that we do not want to export to the rest of