Package init
This commit is contained in:
commit
6d8989b915
255
0103-http-add-callback-to-allow-server-to-decline-and-the.patch
Normal file
255
0103-http-add-callback-to-allow-server-to-decline-and-the.patch
Normal file
@ -0,0 +1,255 @@
|
|||||||
|
From 727bcea130eb4beea9b1ea53604b9807f6819a9a Mon Sep 17 00:00:00 2001
|
||||||
|
From: John Fremlin <john@fremlin.org>
|
||||||
|
Date: Fri, 1 Dec 2017 01:29:32 +0000
|
||||||
|
Subject: [PATCH 103/319] http: add callback to allow server to decline (and
|
||||||
|
thereby close) incoming connections.
|
||||||
|
|
||||||
|
This is important, as otherwise clients can easily exhaust the file
|
||||||
|
descriptors available on a libevent HTTP server, which can cause
|
||||||
|
problems in other code which does not handle EMFILE well: for example,
|
||||||
|
see https://github.com/bitcoin/bitcoin/issues/11368
|
||||||
|
|
||||||
|
Closes: #578 (patch cherry picked)
|
||||||
|
---
|
||||||
|
http-internal.h | 2 +
|
||||||
|
http.c | 25 +++++++---
|
||||||
|
include/event2/http.h | 18 ++++++++
|
||||||
|
test/regress_http.c | 125 ++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||||
|
4 files changed, 163 insertions(+), 7 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/http-internal.h b/http-internal.h
|
||||||
|
index b7d21ef..9e5b0f9 100644
|
||||||
|
--- a/http-internal.h
|
||||||
|
+++ b/http-internal.h
|
||||||
|
@@ -170,6 +170,8 @@ struct evhttp {
|
||||||
|
void *gencbarg;
|
||||||
|
struct bufferevent* (*bevcb)(struct event_base *, void *);
|
||||||
|
void *bevcbarg;
|
||||||
|
+ int (*newreqcb)(struct evhttp_request *req, void *);
|
||||||
|
+ void *newreqcbarg;
|
||||||
|
|
||||||
|
struct event_base *base;
|
||||||
|
};
|
||||||
|
diff --git a/http.c b/http.c
|
||||||
|
index b3087b5..f2e4971 100644
|
||||||
|
--- a/http.c
|
||||||
|
+++ b/http.c
|
||||||
|
@@ -3929,6 +3929,14 @@ evhttp_set_bevcb(struct evhttp *http,
|
||||||
|
http->bevcbarg = cbarg;
|
||||||
|
}
|
||||||
|
|
||||||
|
+void
|
||||||
|
+evhttp_set_newreqcb(struct evhttp *http,
|
||||||
|
+ int (*cb)(struct evhttp_request *, void *), void *cbarg)
|
||||||
|
+{
|
||||||
|
+ http->newreqcb = cb;
|
||||||
|
+ http->newreqcbarg = cbarg;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
/*
|
||||||
|
* Request related functions
|
||||||
|
*/
|
||||||
|
@@ -4239,17 +4247,20 @@ evhttp_associate_new_request_with_connection(struct evhttp_connection *evcon)
|
||||||
|
req->evcon = evcon; /* the request ends up owning the connection */
|
||||||
|
req->flags |= EVHTTP_REQ_OWN_CONNECTION;
|
||||||
|
|
||||||
|
- /* We did not present the request to the user user yet, so treat it as
|
||||||
|
- * if the user was done with the request. This allows us to free the
|
||||||
|
- * request on a persistent connection if the client drops it without
|
||||||
|
- * sending a request.
|
||||||
|
+ /* We did not present the request to the user yet, so treat it
|
||||||
|
+ * as if the user was done with the request. This allows us
|
||||||
|
+ * to free the request on a persistent connection if the
|
||||||
|
+ * client drops it without sending a request.
|
||||||
|
*/
|
||||||
|
req->userdone = 1;
|
||||||
|
-
|
||||||
|
- TAILQ_INSERT_TAIL(&evcon->requests, req, next);
|
||||||
|
-
|
||||||
|
req->kind = EVHTTP_REQUEST;
|
||||||
|
|
||||||
|
+ if (http->newreqcb && http->newreqcb(req, http->newreqcbarg) == -1) {
|
||||||
|
+ evhttp_request_free(req);
|
||||||
|
+ return (-1);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ TAILQ_INSERT_TAIL(&evcon->requests, req, next);
|
||||||
|
|
||||||
|
evhttp_start_read_(evcon);
|
||||||
|
|
||||||
|
diff --git a/include/event2/http.h b/include/event2/http.h
|
||||||
|
index 2a41303..ed9acf4 100644
|
||||||
|
--- a/include/event2/http.h
|
||||||
|
+++ b/include/event2/http.h
|
||||||
|
@@ -298,6 +298,24 @@ EVENT2_EXPORT_SYMBOL
|
||||||
|
void evhttp_set_bevcb(struct evhttp *http,
|
||||||
|
struct bufferevent *(*cb)(struct event_base *, void *), void *arg);
|
||||||
|
|
||||||
|
+
|
||||||
|
+/**
|
||||||
|
+ Set a callback which allows the user to note or throttle incoming requests.
|
||||||
|
+
|
||||||
|
+ The requests are not populated with HTTP level information. They
|
||||||
|
+ are just associated to a connection.
|
||||||
|
+
|
||||||
|
+ If the callback returns -1, the associated connection is terminated
|
||||||
|
+ and the request is closed.
|
||||||
|
+
|
||||||
|
+ @param http the evhttp server object for which to set the callback
|
||||||
|
+ @param cb the callback to invoke for incoming connections
|
||||||
|
+ @param arg an context argument for the callback
|
||||||
|
+ */
|
||||||
|
+EVENT2_EXPORT_SYMBOL
|
||||||
|
+void evhttp_set_newreqcb(struct evhttp *http,
|
||||||
|
+ int (*cb)(struct evhttp_request*, void *), void *arg);
|
||||||
|
+
|
||||||
|
/**
|
||||||
|
Adds a virtual host to the http server.
|
||||||
|
|
||||||
|
diff --git a/test/regress_http.c b/test/regress_http.c
|
||||||
|
index b761df0..c459910 100644
|
||||||
|
--- a/test/regress_http.c
|
||||||
|
+++ b/test/regress_http.c
|
||||||
|
@@ -4604,6 +4604,129 @@ http_request_extra_body_test(void *arg)
|
||||||
|
evbuffer_free(body);
|
||||||
|
}
|
||||||
|
|
||||||
|
+struct http_newreqcb_test_state
|
||||||
|
+{
|
||||||
|
+ int connections_started;
|
||||||
|
+ int connections_noticed;
|
||||||
|
+ int connections_throttled;
|
||||||
|
+ int connections_good;
|
||||||
|
+ int connections_error;
|
||||||
|
+ int connections_done;
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
+static void
|
||||||
|
+http_newreqcb_test_state_check(struct http_newreqcb_test_state* state)
|
||||||
|
+{
|
||||||
|
+ tt_int_op(state->connections_started, >=, 0);
|
||||||
|
+ tt_int_op(state->connections_started, >=, state->connections_noticed);
|
||||||
|
+ tt_int_op(state->connections_throttled, >=, state->connections_error);
|
||||||
|
+
|
||||||
|
+ tt_int_op(state->connections_done, <=, state->connections_started);
|
||||||
|
+ if (state->connections_good + state->connections_error == state->connections_started) {
|
||||||
|
+ tt_int_op(state->connections_throttled, ==, state->connections_error);
|
||||||
|
+ tt_int_op(state->connections_good + state->connections_error, ==, state->connections_done);
|
||||||
|
+ event_base_loopexit(exit_base, NULL);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ return;
|
||||||
|
+end:
|
||||||
|
+ tt_fail();
|
||||||
|
+ exit(17);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static void
|
||||||
|
+http_request_done_newreqcb(struct evhttp_request *req, void *arg)
|
||||||
|
+{
|
||||||
|
+ struct http_newreqcb_test_state* state = arg;
|
||||||
|
+ if (req && evhttp_request_get_response_code(req) == HTTP_OK) {
|
||||||
|
+ ++state->connections_good;
|
||||||
|
+ evhttp_request_set_error_cb(req, NULL);
|
||||||
|
+ }
|
||||||
|
+ ++state->connections_done;
|
||||||
|
+
|
||||||
|
+ http_newreqcb_test_state_check(state);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static void
|
||||||
|
+http_request_error_newreqcb(enum evhttp_request_error err, void *arg)
|
||||||
|
+{
|
||||||
|
+ struct http_newreqcb_test_state* state = arg;
|
||||||
|
+ ++state->connections_error;
|
||||||
|
+
|
||||||
|
+ http_newreqcb_test_state_check(state);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static int
|
||||||
|
+http_newreqcb(struct evhttp_request* req, void *arg)
|
||||||
|
+{
|
||||||
|
+ struct http_newreqcb_test_state* state = arg;
|
||||||
|
+ ++state->connections_noticed;
|
||||||
|
+ http_newreqcb_test_state_check(state);
|
||||||
|
+ if (1 == state->connections_noticed % 7) {
|
||||||
|
+ state->connections_throttled++;
|
||||||
|
+ return -1;
|
||||||
|
+ }
|
||||||
|
+ return 0;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+
|
||||||
|
+static void
|
||||||
|
+http_newreqcb_test(void *arg)
|
||||||
|
+{
|
||||||
|
+ struct basic_test_data *data = arg;
|
||||||
|
+ ev_uint16_t port = 0;
|
||||||
|
+ struct evhttp *http = http_setup(&port, data->base, 0);
|
||||||
|
+ struct evhttp_connection *evcons[100];
|
||||||
|
+ struct http_newreqcb_test_state newreqcb_test_state;
|
||||||
|
+ unsigned n;
|
||||||
|
+
|
||||||
|
+ exit_base = data->base;
|
||||||
|
+ test_ok = 0;
|
||||||
|
+
|
||||||
|
+ memset(&newreqcb_test_state, 0, sizeof(newreqcb_test_state));
|
||||||
|
+ memset(evcons, 0, sizeof(evcons));
|
||||||
|
+
|
||||||
|
+ evhttp_set_newreqcb(http, http_newreqcb, &newreqcb_test_state);
|
||||||
|
+
|
||||||
|
+ for (n = 0; n < sizeof(evcons)/sizeof(evcons[0]); ++n) {
|
||||||
|
+ struct evhttp_connection* evcon = NULL;
|
||||||
|
+ struct evhttp_request *req = NULL;
|
||||||
|
+ evcons[n] = evhttp_connection_base_new(data->base, NULL, "127.0.0.1", port);
|
||||||
|
+ evcon = evcons[n];
|
||||||
|
+ evhttp_connection_set_retries(evcon, 0);
|
||||||
|
+
|
||||||
|
+ tt_assert(evcon);
|
||||||
|
+
|
||||||
|
+ req = evhttp_request_new(http_request_done_newreqcb, &newreqcb_test_state);
|
||||||
|
+ evhttp_add_header(evhttp_request_get_output_headers(req), "Connection", "close");
|
||||||
|
+ evhttp_request_set_error_cb(req, http_request_error_newreqcb);
|
||||||
|
+
|
||||||
|
+ /* We give ownership of the request to the connection */
|
||||||
|
+ if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/test") == -1) {
|
||||||
|
+ tt_abort_msg("Couldn't make request");
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ ++newreqcb_test_state.connections_started;
|
||||||
|
+ http_newreqcb_test_state_check(&newreqcb_test_state);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ event_base_dispatch(data->base);
|
||||||
|
+
|
||||||
|
+ http_newreqcb_test_state_check(&newreqcb_test_state);
|
||||||
|
+ tt_int_op(newreqcb_test_state.connections_throttled, >, 0);
|
||||||
|
+
|
||||||
|
+ end:
|
||||||
|
+ evhttp_free(http);
|
||||||
|
+
|
||||||
|
+ for (n = 0; n < sizeof(evcons)/sizeof(evcons[0]); ++n) {
|
||||||
|
+ if (evcons[n])
|
||||||
|
+ evhttp_connection_free(evcons[n]);
|
||||||
|
+
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+
|
||||||
|
#define HTTP_LEGACY(name) \
|
||||||
|
{ #name, run_legacy_test_fn, TT_ISOLATED|TT_LEGACY, &legacy_setup, \
|
||||||
|
http_##name##_test }
|
||||||
|
@@ -4725,6 +4848,8 @@ struct testcase_t http_testcases[] = {
|
||||||
|
|
||||||
|
HTTP(request_extra_body),
|
||||||
|
|
||||||
|
+ HTTP(newreqcb),
|
||||||
|
+
|
||||||
|
#ifdef EVENT__HAVE_OPENSSL
|
||||||
|
HTTPS(basic),
|
||||||
|
HTTPS(filter_basic),
|
||||||
|
--
|
||||||
|
1.8.3.1
|
||||||
|
|
||||||
|
|
||||||
BIN
libevent-2.1.11-stable.tar.gz
Normal file
BIN
libevent-2.1.11-stable.tar.gz
Normal file
Binary file not shown.
11
libevent-nonettests.patch
Normal file
11
libevent-nonettests.patch
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
diff -up libevent-2.0.21-stable/test/regress_main.c.orig libevent-2.0.21-stable/test/regress_main.c
|
||||||
|
--- libevent-2.0.21-stable/test/regress_main.c.orig 2012-11-02 11:57:00.000000000 -0400
|
||||||
|
+++ libevent-2.0.21-stable/test/regress_main.c 2013-08-21 10:16:26.714288000 -0400
|
||||||
|
@@ -370,7 +370,6 @@ struct testgroup_t testgroups[] = {
|
||||||
|
{ "util/", util_testcases },
|
||||||
|
{ "bufferevent/", bufferevent_testcases },
|
||||||
|
{ "http/", http_testcases },
|
||||||
|
- { "dns/", dns_testcases },
|
||||||
|
{ "evtag/", evtag_testcases },
|
||||||
|
{ "rpc/", rpc_testcases },
|
||||||
|
{ "thread/", thread_testcases },
|
||||||
74
libevent.spec
Normal file
74
libevent.spec
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
Name: libevent
|
||||||
|
Version: 2.1.11
|
||||||
|
Release: 1
|
||||||
|
Summary: An event notification library
|
||||||
|
|
||||||
|
License: BSD
|
||||||
|
URL: http://libevent.org/
|
||||||
|
Source0: https://github.com/libevent/libevent/releases/download/release-%{version}-stable/libevent-%{version}-stable.tar.gz
|
||||||
|
|
||||||
|
BuildRequires: gcc doxygen openssl-devel libevent
|
||||||
|
|
||||||
|
Patch01: libevent-nonettests.patch
|
||||||
|
Patch02: 0103-http-add-callback-to-allow-server-to-decline-and-the.patch
|
||||||
|
|
||||||
|
%description
|
||||||
|
Libevent additionally provides a sophisticated framework for buffered network IO, with support for sockets,
|
||||||
|
filters, rate-limiting, SSL, zero-copy file transmission, and IOCP.
|
||||||
|
Libevent includes support for several useful protocols, including DNS, HTTP, and a minimal RPC framewor.
|
||||||
|
|
||||||
|
%package devel
|
||||||
|
Summary: Development files for %{name}
|
||||||
|
Requires: %{name} = %{version}-%{release}
|
||||||
|
|
||||||
|
%description devel
|
||||||
|
This package contains the header files and libraries for developing
|
||||||
|
with %{name}.
|
||||||
|
|
||||||
|
%prep
|
||||||
|
%autosetup -n libevent-%{version}-stable -p1
|
||||||
|
|
||||||
|
%build
|
||||||
|
%configure --disable-dependency-tracking --disable-static
|
||||||
|
%make_build
|
||||||
|
|
||||||
|
%install
|
||||||
|
%make_install
|
||||||
|
cp -a %{_libdir}/libevent* %{buildroot}%{_libdir}
|
||||||
|
rm -f %{buildroot}%{_libdir}/*.la
|
||||||
|
|
||||||
|
|
||||||
|
%check
|
||||||
|
make check
|
||||||
|
|
||||||
|
%ldconfig_scriptlets
|
||||||
|
|
||||||
|
%files
|
||||||
|
%doc ChangeLog
|
||||||
|
%license LICENSE
|
||||||
|
%{_libdir}/libevent-2.1.so.*
|
||||||
|
%{_libdir}/libevent_core-2.1.so.*
|
||||||
|
%{_libdir}/libevent_extra-2.1.so.*
|
||||||
|
%{_libdir}/libevent_openssl-2.1.so.*
|
||||||
|
%{_libdir}/libevent_pthreads-2.1.so.*
|
||||||
|
|
||||||
|
%files devel
|
||||||
|
%{_includedir}/*.h
|
||||||
|
%dir %{_includedir}/event2
|
||||||
|
%{_includedir}/event2/*.h
|
||||||
|
%{_libdir}/libevent.so
|
||||||
|
%{_libdir}/libevent_core.so
|
||||||
|
%{_libdir}/libevent_extra.so
|
||||||
|
%{_libdir}/libevent_openssl.so
|
||||||
|
%{_libdir}/libevent_pthreads.so
|
||||||
|
%{_libdir}/pkgconfig/libevent.pc
|
||||||
|
%{_libdir}/pkgconfig/libevent_core.pc
|
||||||
|
%{_libdir}/pkgconfig/libevent_extra.pc
|
||||||
|
%{_libdir}/pkgconfig/libevent_openssl.pc
|
||||||
|
%{_libdir}/pkgconfig/libevent_pthreads.pc
|
||||||
|
%{_bindir}/event_rpcgen.*
|
||||||
|
|
||||||
|
|
||||||
|
%changelog
|
||||||
|
* Tue Aug 27 2019 openEuler Buildteam <buildteam@openeuler.org> - 2.1.11-1
|
||||||
|
- Package init
|
||||||
Loading…
x
Reference in New Issue
Block a user