From: Joseph Coffland Date: Tue, 30 Jan 2018 23:39:41 +0000 (-0800) Subject: Added evhttp max simultaneous connection limiting X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=c62f73f5b57eb4ffa14c3a73fe879d4bda36425c;p=libevent Added evhttp max simultaneous connection limiting --- diff --git a/http-internal.h b/http-internal.h index 9e5b0f95..e03c32db 100644 --- a/http-internal.h +++ b/http-internal.h @@ -145,6 +145,8 @@ struct evhttp { /* All live connections on this host. */ struct evconq connections; + int connection_max; + int connection_cnt; TAILQ_HEAD(vhostsq, evhttp) virtualhosts; diff --git a/http.c b/http.c index c0e7adfc..65530f0c 100644 --- a/http.c +++ b/http.c @@ -1222,6 +1222,7 @@ evhttp_connection_free(struct evhttp_connection *evcon) if (evcon->http_server != NULL) { struct evhttp *http = evcon->http_server; TAILQ_REMOVE(&http->connections, evcon, next); + http->connection_cnt--; } if (event_initialized(&evcon->retry_ev)) { @@ -3852,6 +3853,21 @@ evhttp_set_max_body_size(struct evhttp* http, ev_ssize_t max_body_size) http->default_max_body_size = max_body_size; } +void +evhttp_set_max_connections(struct evhttp* http, int max_connections) +{ + if (max_connections < 0) + http->connection_max = 0; + else + http->connection_max = max_connections; +} + +int +evhttp_get_connection_count(struct evhttp* http) +{ + return http->connection_cnt; +} + void evhttp_set_default_content_type(struct evhttp *http, const char *content_type) { @@ -4291,8 +4307,30 @@ evhttp_get_request(struct evhttp *http, evutil_socket_t fd, */ evcon->http_server = http; TAILQ_INSERT_TAIL(&http->connections, evcon, next); + http->connection_cnt++; + + /* send "service unavailable" if we've reached the connection limit */ + if (http->connection_max && http->connection_max < http->connection_cnt) { + struct evhttp_request *req; + + if ((req = evhttp_request_new(evhttp_handle_request, http)) == NULL) { + evhttp_connection_free(evcon); + return; + } + + req->evcon = evcon; /* the request owns the connection */ + req->flags |= EVHTTP_REQ_OWN_CONNECTION; + req->kind = EVHTTP_REQUEST; + /* note, req->remote_host not needed since we don't read */ + + TAILQ_INSERT_TAIL(&evcon->requests, req, next); + + /* send error to client */ + evcon->state = EVCON_WRITING; + bufferevent_enable(evcon->bufev, EV_READ); /* enable close events */ + evhttp_send_error(req, HTTP_SERVUNAVAIL, NULL); - if (evhttp_associate_new_request_with_connection(evcon) == -1) + } else if (evhttp_associate_new_request_with_connection(evcon) == -1) evhttp_connection_free(evcon); } diff --git a/include/event2/http.h b/include/event2/http.h index ed9acf45..2d3e4173 100644 --- a/include/event2/http.h +++ b/include/event2/http.h @@ -222,6 +222,24 @@ void evhttp_set_max_headers_size(struct evhttp* http, ev_ssize_t max_headers_siz EVENT2_EXPORT_SYMBOL void evhttp_set_max_body_size(struct evhttp* http, ev_ssize_t max_body_size); +/** + * Set the maximum number of simultaneous connections for this server. + * A value of zero or less disables the limit. + * + * @param http the http server on which to set the max connection limit + * @param max_connections the maximum number of simultaneous connections or 0 + */ +EVENT2_EXPORT_SYMBOL +void evhttp_set_max_connections(struct evhttp* http, int max_connections); + +/** + * Get the current number of connections. + * + * @return The current number of connections for this server. + */ +EVENT2_EXPORT_SYMBOL +int evhttp_get_connection_count(struct evhttp* http); + /** Set the value to use for the Content-Type header when none was provided. If the content type string is NULL, the Content-Type header will not be