mirror of
https://github.com/libevent/libevent.git
synced 2025-01-31 09:12:55 +08:00
Merge remote-tracking branch 'origin/pr/182'
This commit is contained in:
commit
7fd4941465
@ -74,6 +74,7 @@ struct evhttp_connection {
|
||||
#define EVHTTP_CON_INCOMING 0x0001 /* only one request on it ever */
|
||||
#define EVHTTP_CON_OUTGOING 0x0002 /* multiple requests possible */
|
||||
#define EVHTTP_CON_CLOSEDETECT 0x0004 /* detecting if persistent close */
|
||||
#define EVHTTP_CON_AUTOFREE 0x0008 /* set when we want to auto free the connection */
|
||||
|
||||
struct timeval timeout; /* timeout for events */
|
||||
int retry_cnt; /* retry count */
|
||||
|
34
http.c
34
http.c
@ -769,6 +769,7 @@ evhttp_connection_done(struct evhttp_connection *evcon)
|
||||
{
|
||||
struct evhttp_request *req = TAILQ_FIRST(&evcon->requests);
|
||||
int con_outgoing = evcon->flags & EVHTTP_CON_OUTGOING;
|
||||
int free_evcon = 0;
|
||||
|
||||
if (con_outgoing) {
|
||||
/* idle or close the connection */
|
||||
@ -801,6 +802,12 @@ evhttp_connection_done(struct evhttp_connection *evcon)
|
||||
* need to detect if the other side closes it.
|
||||
*/
|
||||
evhttp_connection_start_detectclose(evcon);
|
||||
} else if ((evcon->flags & EVHTTP_CON_AUTOFREE)) {
|
||||
/*
|
||||
* If we have no more requests that need completion
|
||||
* and we're not waiting for the connection to close
|
||||
*/
|
||||
free_evcon = 1;
|
||||
}
|
||||
} else {
|
||||
/*
|
||||
@ -819,6 +826,16 @@ evhttp_connection_done(struct evhttp_connection *evcon)
|
||||
if (con_outgoing && ((req->flags & EVHTTP_USER_OWNED) == 0)) {
|
||||
evhttp_request_free(req);
|
||||
}
|
||||
|
||||
/* If this was the last request of an outgoing connection and we're
|
||||
* not waiting to receive a connection close event and we want to
|
||||
* automatically free the connection. We check to ensure our request
|
||||
* list is empty one last time just in case our callback added a
|
||||
* new request.
|
||||
*/
|
||||
if (free_evcon && TAILQ_FIRST(&evcon->requests) == NULL) {
|
||||
evhttp_connection_free(evcon);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@ -1174,6 +1191,11 @@ evhttp_connection_free(struct evhttp_connection *evcon)
|
||||
mm_free(evcon);
|
||||
}
|
||||
|
||||
void
|
||||
evhttp_connection_free_on_completion(struct evhttp_connection *evcon) {
|
||||
evcon->flags |= EVHTTP_CON_AUTOFREE;
|
||||
}
|
||||
|
||||
void
|
||||
evhttp_connection_set_local_address(struct evhttp_connection *evcon,
|
||||
const char *address)
|
||||
@ -1243,6 +1265,7 @@ evhttp_connection_reset_(struct evhttp_connection *evcon)
|
||||
|
||||
shutdown(evcon->fd, EVUTIL_SHUT_WR);
|
||||
evutil_closesocket(evcon->fd);
|
||||
bufferevent_setfd(evcon->bufev, -1);
|
||||
evcon->fd = -1;
|
||||
}
|
||||
|
||||
@ -1385,6 +1408,17 @@ evhttp_error_cb(struct bufferevent *bufev, short what, void *arg)
|
||||
*/
|
||||
EVUTIL_ASSERT(evcon->state == EVCON_IDLE);
|
||||
evhttp_connection_reset_(evcon);
|
||||
|
||||
/*
|
||||
* If we have no more requests that need completion
|
||||
* and we want to auto-free the connection when all
|
||||
* requests have been completed.
|
||||
*/
|
||||
if (TAILQ_FIRST(&evcon->requests) == NULL
|
||||
&& (evcon->flags & EVHTTP_CON_OUTGOING)
|
||||
&& (evcon->flags & EVHTTP_CON_AUTOFREE)) {
|
||||
evhttp_connection_free(evcon);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -675,6 +675,14 @@ void evhttp_connection_set_max_body_size(struct evhttp_connection* evcon,
|
||||
EVENT2_EXPORT_SYMBOL
|
||||
void evhttp_connection_free(struct evhttp_connection *evcon);
|
||||
|
||||
/** Disowns a given connection object
|
||||
*
|
||||
* Can be used to tell libevent to free the connection object after
|
||||
* the last request has completed or failed.
|
||||
*/
|
||||
EVENT2_EXPORT_SYMBOL
|
||||
void evhttp_connection_free_on_completion(struct evhttp_connection *evcon);
|
||||
|
||||
/** sets the ip address from which http connections are made */
|
||||
EVENT2_EXPORT_SYMBOL
|
||||
void evhttp_connection_set_local_address(struct evhttp_connection *evcon,
|
||||
|
@ -1159,6 +1159,63 @@ http_connection_async_test(void *arg)
|
||||
regress_clean_dnsserver();
|
||||
}
|
||||
|
||||
static void
|
||||
http_autofree_connection_test(void *arg)
|
||||
{
|
||||
struct basic_test_data *data = arg;
|
||||
ev_uint16_t port = 0;
|
||||
struct evhttp_connection *evcon = NULL;
|
||||
struct evhttp_request *req[2] = { NULL };
|
||||
|
||||
test_ok = 0;
|
||||
http = http_setup(&port, data->base, 0);
|
||||
|
||||
evcon = evhttp_connection_base_new(data->base, NULL, "127.0.0.1", port);
|
||||
tt_assert(evcon);
|
||||
|
||||
/*
|
||||
* At this point, we want to schedule two request to the HTTP
|
||||
* server using our make request method.
|
||||
*/
|
||||
req[0] = evhttp_request_new(http_request_empty_done, data->base);
|
||||
req[1] = evhttp_request_new(http_request_empty_done, data->base);
|
||||
|
||||
/* Add the information that we care about */
|
||||
evhttp_add_header(evhttp_request_get_output_headers(req[0]), "Host", "somehost");
|
||||
evhttp_add_header(evhttp_request_get_output_headers(req[0]), "Connection", "close");
|
||||
evhttp_add_header(evhttp_request_get_output_headers(req[0]), "Empty", "itis");
|
||||
evhttp_add_header(evhttp_request_get_output_headers(req[1]), "Host", "somehost");
|
||||
evhttp_add_header(evhttp_request_get_output_headers(req[1]), "Connection", "close");
|
||||
evhttp_add_header(evhttp_request_get_output_headers(req[1]), "Empty", "itis");
|
||||
|
||||
/* We give ownership of the request to the connection */
|
||||
if (evhttp_make_request(evcon, req[0], EVHTTP_REQ_GET, "/test") == -1) {
|
||||
tt_abort_msg("couldn't make request");
|
||||
}
|
||||
if (evhttp_make_request(evcon, req[1], EVHTTP_REQ_GET, "/test") == -1) {
|
||||
tt_abort_msg("couldn't make request");
|
||||
}
|
||||
|
||||
/*
|
||||
* Tell libevent to free the connection when the request completes
|
||||
* We then set the evcon pointer to NULL since we don't want to free it
|
||||
* when this function ends.
|
||||
*/
|
||||
evhttp_connection_free_on_completion(evcon);
|
||||
evcon = NULL;
|
||||
|
||||
event_base_dispatch(data->base);
|
||||
|
||||
/* at this point, the http server should have no connection */
|
||||
tt_assert(TAILQ_FIRST(&http->connections) == NULL);
|
||||
|
||||
end:
|
||||
if (evcon)
|
||||
evhttp_connection_free(evcon);
|
||||
if (http)
|
||||
evhttp_free(http);
|
||||
}
|
||||
|
||||
static void
|
||||
http_request_never_call(struct evhttp_request *req, void *arg)
|
||||
{
|
||||
@ -3897,6 +3954,7 @@ struct testcase_t http_testcases[] = {
|
||||
HTTP(failure),
|
||||
HTTP(connection),
|
||||
HTTP(persist_connection),
|
||||
HTTP(autofree_connection),
|
||||
HTTP(connection_async),
|
||||
HTTP(close_detection),
|
||||
HTTP(close_detection_delay),
|
||||
|
Loading…
x
Reference in New Issue
Block a user