From 0792e1e7a775f95b395a45c78052c842817749c0 Mon Sep 17 00:00:00 2001 From: Azat Khuzhin Date: Wed, 10 Feb 2016 12:37:30 +0300 Subject: [PATCH 1/8] test: increase buffer size for http/data_length_constraints to trigger EPIPE With greater buffer it can't be written with one writev(2), and hence we can trigger more tricky cases, like calling writecb/readcb more then once. Refs: #321 --- test/regress_http.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/test/regress_http.c b/test/regress_http.c index cbe7aea3..bd942578 100644 --- a/test/regress_http.c +++ b/test/regress_http.c @@ -3793,7 +3793,7 @@ http_data_length_constraints_test(void *arg) ev_uint16_t port = 0; struct evhttp_connection *evcon = NULL; struct evhttp_request *req = NULL; - char long_str[8192]; + char long_str[(1<<20) * 3]; test_ok = 0; @@ -3813,10 +3813,10 @@ http_data_length_constraints_test(void *arg) req = evhttp_request_new(http_data_length_constraints_test_done, data->base); tt_assert(req); - memset(long_str, 'a', 8192); - long_str[8191] = '\0'; + memset(long_str, 'a', sizeof(long_str)); + long_str[sizeof(long_str)-1] = '\0'; /* Add the information that we care about */ - evhttp_set_max_headers_size(http, 8191); + evhttp_set_max_headers_size(http, sizeof(long_str)-1); evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost"); evhttp_add_header(evhttp_request_get_output_headers(req), "Longheader", long_str); @@ -3835,7 +3835,7 @@ http_data_length_constraints_test(void *arg) } event_base_dispatch(data->base); - evhttp_set_max_body_size(http, 8190); + evhttp_set_max_body_size(http, sizeof(long_str)-2); req = evhttp_request_new(http_data_length_constraints_test_done, data->base); evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost"); evbuffer_add_printf(evhttp_request_get_output_buffer(req), "%s", long_str); From 680742e1665b85487f10c0ef3df021e3b8e98634 Mon Sep 17 00:00:00 2001 From: Azat Khuzhin Date: Wed, 10 Feb 2016 14:43:18 +0300 Subject: [PATCH 2/8] http: read server response even after server closed the connection Otherwise if we will try to write more data than server can accept (see `evhttp_set_max_body_size()` for libevent server) we will get `EPIPE` and will not try to read server's response which must contain 400 error for now (which is not strictly correct though, it must 413). ``` $ strace regress --no-fork http/data_length_constraints ... connect(10, {sa_family=AF_INET, sin_port=htons(43988), sin_addr=inet_addr("127.0.0.1")}, 16) = -1 EINPROGRESS (Operation now in progress) ... writev(10, [{"POST / HTTP/1.1\r\nHost: somehost\r"..., 60}, {"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"..., 16324}], 2) = 16384 epoll_wait(5, [{EPOLLOUT, {u32=10, u64=10}}, {EPOLLIN, {u32=11, u64=11}}], 32, 50000) = 2 writev(10, [{"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"..., 16384}], 1) = 16384 ioctl(11, FIONREAD, [32768]) = 0 readv(11, [{"POST / HTTP/1.1\r\nHost: somehost\r"..., 4096}], 1) = 4096 epoll_ctl(5, EPOLL_CTL_DEL, 11, 0x7fff09d41e50) = 0 epoll_ctl(5, EPOLL_CTL_ADD, 11, {EPOLLOUT, {u32=11, u64=11}}) = 0 epoll_wait(5, [{EPOLLOUT, {u32=10, u64=10}}, {EPOLLOUT, {u32=11, u64=11}}], 32, 50000) = 2 writev(10, [{"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"..., 16384}], 1) = 16384 writev(11, [{"HTTP/1.1 400 Bad Request\r\nConten"..., 129}, {"\n400 Bad Requ"..., 94}], 2) = 223 epoll_ctl(5, EPOLL_CTL_DEL, 11, 0x7fff09d42080) = 0 shutdown(11, SHUT_WR) = 0 close(11) = 0 epoll_wait(5, [{EPOLLOUT|EPOLLERR|EPOLLHUP, {u32=10, u64=10}}], 32, 50000) = 1 writev(10, [{"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"..., 16384}], 1) = -1 EPIPE (Broken pipe) --- SIGPIPE {si_signo=SIGPIPE, si_code=SI_USER, si_pid=13954, si_uid=1000} --- epoll_ctl(5, EPOLL_CTL_DEL, 10, 0x7fff09d42010) = 0 shutdown(10, SHUT_WR) = -1 ENOTCONN (Transport endpoint is not connected) close(10) = 0 write(1, "\n FAIL ../test/regress_http.c:3"..., 37 ``` Careful reader can ask why it send error even when it didn't read `evcon->max_body_size`, and the answer will be checks for `evcon->max_body_size against `Content-Length` header, which contains ~8MB (-2 bytes). And also if we will not drain the output buffer than we will send buffer that we didn't send in previous request and instead of sending method via `evhttp_make_header()`. Fixes: http/data_length_constraints Refs: #321 v2: do this only under EVHTTP_CON_READ_ON_WRITE_ERROR flag --- http.c | 29 +++++++++++++++++++++++++++++ include/event2/http.h | 4 ++++ 2 files changed, 33 insertions(+) diff --git a/http.c b/http.c index fd7ce3cb..a2d9f878 100644 --- a/http.c +++ b/http.c @@ -1372,6 +1372,28 @@ evhttp_connection_cb_cleanup(struct evhttp_connection *evcon) } } +static void +evhttp_connection_read_on_write_error(struct evhttp_connection *evcon, + struct evhttp_request *req) +{ + struct evbuffer *buf; + + evcon->state = EVCON_READING_FIRSTLINE; + req->kind = EVHTTP_RESPONSE; + + buf = bufferevent_get_output(evcon->bufev); + evbuffer_unfreeze(buf, 1); + evbuffer_drain(buf, evbuffer_get_length(buf)); + evbuffer_freeze(buf, 1); + + bufferevent_setcb(evcon->bufev, + evhttp_read_cb, + NULL, /* evhttp_write_cb */ + evhttp_error_cb, + evcon); + evhttp_connection_start_detectclose(evcon); +} + static void evhttp_error_cb(struct bufferevent *bufev, short what, void *arg) { @@ -1441,6 +1463,12 @@ evhttp_error_cb(struct bufferevent *bufev, short what, void *arg) if (what & BEV_EVENT_TIMEOUT) { evhttp_connection_fail_(evcon, EVREQ_HTTP_TIMEOUT); } else if (what & (BEV_EVENT_EOF|BEV_EVENT_ERROR)) { + if (what & BEV_EVENT_WRITING && + evcon->flags & EVHTTP_CON_READ_ON_WRITE_ERROR) { + evhttp_connection_read_on_write_error(evcon, req); + return; + } + evhttp_connection_fail_(evcon, EVREQ_HTTP_EOF); } else if (what == BEV_EVENT_CONNECTED) { } else { @@ -2344,6 +2372,7 @@ int evhttp_connection_set_flags(struct evhttp_connection *evcon, { int avail_flags = 0; avail_flags |= EVHTTP_CON_REUSE_CONNECTED_ADDR; + avail_flags |= EVHTTP_CON_READ_ON_WRITE_ERROR; if (flags & ~avail_flags || flags > EVHTTP_CON_PUBLIC_FLAGS_END) return 1; diff --git a/include/event2/http.h b/include/event2/http.h index e9978207..c7ed4ccf 100644 --- a/include/event2/http.h +++ b/include/event2/http.h @@ -639,6 +639,10 @@ void evhttp_connection_set_family(struct evhttp_connection *evcon, /* reuse connection address on retry */ #define EVHTTP_CON_REUSE_CONNECTED_ADDR 0x0008 +/* Try to read error, since server may already send and close + * connection, but if at that time we have some data to send then we + * can send get EPIPE and fail, while we can read that HTTP error. */ +#define EVHTTP_CON_READ_ON_WRITE_ERROR 0x0010 /* Padding for public flags, @see EVHTTP_CON_* in http-internal.h */ #define EVHTTP_CON_PUBLIC_FLAGS_END 0x100000 /** From 9fde5189df2722bf58041f03a9d0b69c87dffa8b Mon Sep 17 00:00:00 2001 From: Azat Khuzhin <a3at.mail@gmail.com> Date: Mon, 15 Feb 2016 00:12:54 +0300 Subject: [PATCH 3/8] http: lingering close (like nginx have) for entity-too-large By lingering close I mean something what nginx have for this name, by this term I mean that we need to read all the body even if it's size greater then `max_body_size`, otherwise browsers on win32 (including chrome) failed read the http status - entity-too-large (while on linux chrome for instance are good), and also this includes badly written http clients. Refs: #321 v2: do this only under EVHTTP_SERVER_LINGERING_CLOSE --- http-internal.h | 1 + http.c | 46 +++++++++++++++++++++++++++++++++++++++---- include/event2/http.h | 15 ++++++++++++++ 3 files changed, 58 insertions(+), 4 deletions(-) diff --git a/http-internal.h b/http-internal.h index ba6e49ef..31002e0d 100644 --- a/http-internal.h +++ b/http-internal.h @@ -154,6 +154,7 @@ struct evhttp { size_t default_max_headers_size; ev_uint64_t default_max_body_size; + int flags; const char *default_content_type; /* Bitmask of all HTTP methods that we accept and pass to user diff --git a/http.c b/http.c index a2d9f878..5df8791d 100644 --- a/http.c +++ b/http.c @@ -984,6 +984,25 @@ evhttp_read_trailer(struct evhttp_connection *evcon, struct evhttp_request *req) } } +static void +evhttp_lingering_close(struct evhttp_connection *evcon, struct evhttp_request *req) +{ + struct evbuffer *buf = bufferevent_get_input(evcon->bufev); + + size_t n = evbuffer_get_length(buf); + if (n > (size_t) req->ntoread) + n = (size_t) req->ntoread; + req->ntoread -= n; + req->body_size += n; + + event_debug(("Request body is too long, left " EV_SIZE_FMT, + EV_SIZE_ARG(req->ntoread))); + + evbuffer_drain(buf, n); + if (!req->ntoread) + evhttp_connection_fail_(evcon, EVREQ_HTTP_DATA_TOO_LONG); +} + static void evhttp_read_body(struct evhttp_connection *evcon, struct evhttp_request *req) { @@ -1037,9 +1056,12 @@ evhttp_read_body(struct evhttp_connection *evcon, struct evhttp_request *req) (size_t)req->ntoread > req->evcon->max_body_size)) { /* XXX: The above casted comparison must checked for overflow */ /* failed body length test */ - event_debug(("Request body is too long")); - evhttp_connection_fail_(evcon, - EVREQ_HTTP_DATA_TOO_LONG); + + if (evcon->flags & EVHTTP_CON_LINGERING_CLOSE) + evhttp_lingering_close(evcon, req); + else + evhttp_connection_fail_(evcon, EVREQ_HTTP_DATA_TOO_LONG); + return; } @@ -1055,7 +1077,7 @@ evhttp_read_body(struct evhttp_connection *evcon, struct evhttp_request *req) } } - if (req->ntoread == 0) { + if (!req->ntoread) { bufferevent_disable(evcon->bufev, EV_READ); /* Completed content length */ evhttp_connection_done(evcon); @@ -3719,6 +3741,20 @@ evhttp_set_timeout_tv(struct evhttp* http, const struct timeval* tv) } } +int evhttp_set_flags(struct evhttp *http, int flags) +{ + int avail_flags = 0; + avail_flags |= EVHTTP_SERVER_LINGERING_CLOSE; + + if (flags & ~avail_flags) + return 1; + http->flags &= ~avail_flags; + + http->flags |= flags; + + return 0; +} + void evhttp_set_max_headers_size(struct evhttp* http, ev_ssize_t max_headers_size) { @@ -4091,6 +4127,8 @@ evhttp_get_request_connection( evcon->max_headers_size = http->default_max_headers_size; evcon->max_body_size = http->default_max_body_size; + if (http->flags & EVHTTP_SERVER_LINGERING_CLOSE) + evcon->flags |= EVHTTP_CON_LINGERING_CLOSE; evcon->flags |= EVHTTP_CON_INCOMING; evcon->state = EVCON_READING_FIRSTLINE; diff --git a/include/event2/http.h b/include/event2/http.h index c7ed4ccf..10a7e975 100644 --- a/include/event2/http.h +++ b/include/event2/http.h @@ -373,6 +373,19 @@ void evhttp_set_timeout(struct evhttp *http, int timeout_in_secs); EVENT2_EXPORT_SYMBOL void evhttp_set_timeout_tv(struct evhttp *http, const struct timeval* tv); +/* Read all the clients body, and only after this respond with an error if the + * clients body exceed max_body_size */ +#define EVHTTP_SERVER_LINGERING_CLOSE 0x0001 +/** + * Set connection flags for HTTP server. + * + * @see EVHTTP_SERVER_* + * @return 0 on success, otherwise non zero (for example if flag doesn't + * supported). + */ +EVENT2_EXPORT_SYMBOL +int evhttp_set_flags(struct evhttp *http, int flags); + /* Request/Response functionality */ /** @@ -643,6 +656,8 @@ void evhttp_connection_set_family(struct evhttp_connection *evcon, * connection, but if at that time we have some data to send then we * can send get EPIPE and fail, while we can read that HTTP error. */ #define EVHTTP_CON_READ_ON_WRITE_ERROR 0x0010 +/* @see EVHTTP_SERVER_LINGERING_CLOSE */ +#define EVHTTP_CON_LINGERING_CLOSE 0x0020 /* Padding for public flags, @see EVHTTP_CON_* in http-internal.h */ #define EVHTTP_CON_PUBLIC_FLAGS_END 0x100000 /** From d38a7239749a1642eaae0778d9ddfb1c5d21f442 Mon Sep 17 00:00:00 2001 From: Azat Khuzhin <a3at.mail@gmail.com> Date: Mon, 15 Feb 2016 02:41:19 +0300 Subject: [PATCH 4/8] test: http/data_length_constrains: set EVHTTP_CON_READ_ON_WRITE_ERROR --- test/regress_http.c | 1 + 1 file changed, 1 insertion(+) diff --git a/test/regress_http.c b/test/regress_http.c index bd942578..d7fb4309 100644 --- a/test/regress_http.c +++ b/test/regress_http.c @@ -3801,6 +3801,7 @@ http_data_length_constraints_test(void *arg) evcon = evhttp_connection_base_new(data->base, NULL, "127.0.0.1", port); tt_assert(evcon); + tt_assert(!evhttp_connection_set_flags(evcon, EVHTTP_CON_READ_ON_WRITE_ERROR)); /* also bind to local host */ evhttp_connection_set_local_address(evcon, "127.0.0.1"); From ac448a74d0c0c0947c32be65f64dd56c3cd2bab4 Mon Sep 17 00:00:00 2001 From: Azat Khuzhin <a3at.mail@gmail.com> Date: Mon, 15 Feb 2016 03:26:40 +0300 Subject: [PATCH 5/8] http: take EVHTTP_CON_LINGERING_CLOSE into account for "Expect: 100-Continue" Also since after this patch code became more generic, we now respond with HTTP_ENTITYTOOLARGE even without "Expect: 100-Continue", which is correct by RFC. Refs: #321 v2: remove EVHTTP_CON_ABOUT_TO_CLOSE --- http.c | 30 ++++++++++++++++++++++-------- 1 file changed, 22 insertions(+), 8 deletions(-) diff --git a/http.c b/http.c index 5df8791d..26032b0f 100644 --- a/http.c +++ b/http.c @@ -640,6 +640,14 @@ static int evhttp_connection_incoming_fail(struct evhttp_request *req, enum evhttp_request_error error) { + switch (error) { + case EVREQ_HTTP_DATA_TOO_LONG: + req->response_code = HTTP_ENTITYTOOLARGE; + break; + default: + req->response_code = HTTP_BADREQUEST; + } + switch (error) { case EVREQ_HTTP_TIMEOUT: case EVREQ_HTTP_EOF: @@ -985,7 +993,8 @@ evhttp_read_trailer(struct evhttp_connection *evcon, struct evhttp_request *req) } static void -evhttp_lingering_close(struct evhttp_connection *evcon, struct evhttp_request *req) +evhttp_lingering_close(struct evhttp_connection *evcon, + struct evhttp_request *req) { struct evbuffer *buf = bufferevent_get_input(evcon->bufev); @@ -1002,6 +1011,15 @@ evhttp_lingering_close(struct evhttp_connection *evcon, struct evhttp_request *r if (!req->ntoread) evhttp_connection_fail_(evcon, EVREQ_HTTP_DATA_TOO_LONG); } +static void +evhttp_lingering_fail(struct evhttp_connection *evcon, + struct evhttp_request *req) +{ + if (evcon->flags & EVHTTP_CON_LINGERING_CLOSE) + evhttp_lingering_close(evcon, req); + else + evhttp_connection_fail_(evcon, EVREQ_HTTP_DATA_TOO_LONG); +} static void evhttp_read_body(struct evhttp_connection *evcon, struct evhttp_request *req) @@ -1057,11 +1075,7 @@ evhttp_read_body(struct evhttp_connection *evcon, struct evhttp_request *req) /* XXX: The above casted comparison must checked for overflow */ /* failed body length test */ - if (evcon->flags & EVHTTP_CON_LINGERING_CLOSE) - evhttp_lingering_close(evcon, req); - else - evhttp_connection_fail_(evcon, EVREQ_HTTP_DATA_TOO_LONG); - + evhttp_lingering_fail(evcon, req); return; } @@ -2179,7 +2193,7 @@ evhttp_get_body(struct evhttp_connection *evcon, struct evhttp_request *req) if (req->ntoread > 0) { /* ntoread is ev_int64_t, max_body_size is ev_uint64_t */ if ((req->evcon->max_body_size <= EV_INT64_MAX) && (ev_uint64_t)req->ntoread > req->evcon->max_body_size) { - evhttp_send_error(req, HTTP_ENTITYTOOLARGE, NULL); + evhttp_lingering_fail(evcon, req); return; } } @@ -3352,7 +3366,7 @@ evhttp_handle_request(struct evhttp_request *req, void *arg) req->userdone = 0; if (req->type == 0 || req->uri == NULL) { - evhttp_send_error(req, HTTP_BADREQUEST, NULL); + evhttp_send_error(req, req->response_code, NULL); return; } From addf2b90ae94ad53c90ea5031a70c3037bea1a2f Mon Sep 17 00:00:00 2001 From: Azat Khuzhin <a3at.mail@gmail.com> Date: Mon, 15 Feb 2016 03:46:20 +0300 Subject: [PATCH 6/8] test: http/*: update expected HTTP codes for body exceeds `max_body_size` --- test/regress_http.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/regress_http.c b/test/regress_http.c index d7fb4309..1f326de6 100644 --- a/test/regress_http.c +++ b/test/regress_http.c @@ -3837,7 +3837,7 @@ http_data_length_constraints_test(void *arg) event_base_dispatch(data->base); evhttp_set_max_body_size(http, sizeof(long_str)-2); - req = evhttp_request_new(http_data_length_constraints_test_done, data->base); + req = evhttp_request_new(http_large_entity_test_done, data->base); evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost"); evbuffer_add_printf(evhttp_request_get_output_buffer(req), "%s", long_str); if (evhttp_make_request(evcon, req, EVHTTP_REQ_POST, "/") == -1) { From f41e1b016fa4a667cfc0db293814bfb7f3fed2d1 Mon Sep 17 00:00:00 2001 From: Azat Khuzhin <a3at.mail@gmail.com> Date: Mon, 15 Feb 2016 03:13:02 +0300 Subject: [PATCH 7/8] test: http/non_lingering_close: cover ~EVHTTP_SERVER_LINGERING_CLOSE --- test/regress_http.c | 52 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/test/regress_http.c b/test/regress_http.c index 1f326de6..e57a15b6 100644 --- a/test/regress_http.c +++ b/test/regress_http.c @@ -3862,6 +3862,57 @@ http_data_length_constraints_test(void *arg) evhttp_free(http); } +static void +http_large_entity_non_lingering_test_done(struct evhttp_request *req, void *arg) +{ + tt_assert(!req); +end: + event_base_loopexit(arg, NULL); +} +static void +http_non_lingering_close_test(void *arg) +{ + struct basic_test_data *data = arg; + ev_uint16_t port = 0; + struct evhttp_connection *evcon = NULL; + struct evhttp_request *req = NULL; + char long_str[(1<<20) * 3]; + + test_ok = 0; + + http = http_setup(&port, data->base, 0); + evhttp_set_max_body_size(http, sizeof(long_str)/2); + + evcon = evhttp_connection_base_new(data->base, NULL, "127.0.0.1", port); + tt_assert(evcon); + evhttp_connection_set_local_address(evcon, "127.0.0.1"); + + /* + * At this point, we want to schedule an HTTP GET request + * server using our make request method. + */ + + memset(long_str, 'a', sizeof(long_str)); + long_str[sizeof(long_str)-1] = '\0'; + + req = evhttp_request_new(http_large_entity_non_lingering_test_done, data->base); + tt_assert(req); + evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost"); + evhttp_add_header(evhttp_request_get_output_headers(req), "Expect", "100-continue"); + evbuffer_add_printf(evhttp_request_get_output_buffer(req), "%s", long_str); + if (evhttp_make_request(evcon, req, EVHTTP_REQ_POST, "/") == -1) { + tt_abort_msg("Couldn't make request"); + } + event_base_dispatch(data->base); + + test_ok = 1; + end: + if (evcon) + evhttp_connection_free(evcon); + if (http) + evhttp_free(http); +} + /* * Testing client reset of server chunked connections */ @@ -4305,6 +4356,7 @@ struct testcase_t http_testcases[] = { TT_ISOLATED|TT_OFF_BY_DEFAULT, &basic_setup, NULL }, HTTP(data_length_constraints), + HTTP(non_lingering_close), HTTP(ipv6_for_domain), HTTP(get_addr), From e122ca1eedf9d1293cf0322a34604f0be8a3a2dd Mon Sep 17 00:00:00 2001 From: Azat Khuzhin <a3at.mail@gmail.com> Date: Mon, 15 Feb 2016 03:21:39 +0300 Subject: [PATCH 8/8] test: http/lingering_close: cover EVHTTP_SERVER_LINGERING_CLOSE --- test/regress_http.c | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/test/regress_http.c b/test/regress_http.c index e57a15b6..f2ff818c 100644 --- a/test/regress_http.c +++ b/test/regress_http.c @@ -3870,17 +3870,20 @@ end: event_base_loopexit(arg, NULL); } static void -http_non_lingering_close_test(void *arg) +http_lingering_close_test_impl(void *arg, int lingering) { struct basic_test_data *data = arg; ev_uint16_t port = 0; struct evhttp_connection *evcon = NULL; struct evhttp_request *req = NULL; char long_str[(1<<20) * 3]; + void (*cb)(struct evhttp_request *, void *); test_ok = 0; http = http_setup(&port, data->base, 0); + if (lingering) + tt_assert(!evhttp_set_flags(http, EVHTTP_SERVER_LINGERING_CLOSE)); evhttp_set_max_body_size(http, sizeof(long_str)/2); evcon = evhttp_connection_base_new(data->base, NULL, "127.0.0.1", port); @@ -3895,7 +3898,11 @@ http_non_lingering_close_test(void *arg) memset(long_str, 'a', sizeof(long_str)); long_str[sizeof(long_str)-1] = '\0'; - req = evhttp_request_new(http_large_entity_non_lingering_test_done, data->base); + if (lingering) + cb = http_large_entity_test_done; + else + cb = http_large_entity_non_lingering_test_done; + req = evhttp_request_new(cb, data->base); tt_assert(req); evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost"); evhttp_add_header(evhttp_request_get_output_headers(req), "Expect", "100-continue"); @@ -3912,6 +3919,10 @@ http_non_lingering_close_test(void *arg) if (http) evhttp_free(http); } +static void http_non_lingering_close_test(void *arg) +{ http_lingering_close_test_impl(arg, 0); } +static void http_lingering_close_test(void *arg) +{ http_lingering_close_test_impl(arg, 1); } /* * Testing client reset of server chunked connections @@ -4357,6 +4368,7 @@ struct testcase_t http_testcases[] = { HTTP(data_length_constraints), HTTP(non_lingering_close), + HTTP(lingering_close), HTTP(ipv6_for_domain), HTTP(get_addr),