Skip to content

Commit 526a39f

Browse files
author
Stefan Eissing
committed
v1.0.15, fixes for early connection closes
1 parent a121324 commit 526a39f

12 files changed

+148
-83
lines changed

ChangeLog

+8
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,11 @@
1+
v1.0.15
2+
--------------------------------------------------------------------------------
3+
* fixed busy loops on random connection errors
4+
* fixed connection state for event MPM that shutdown child with 'G' status
5+
* changed default for H2KeepAliveTimeout. For async MPMs (event), will leave
6+
keepalive handling to the MPM. For sync (worker, prefork), will default to
7+
whatever is set for H2Timeout.
8+
19
v1.0.14
210
--------------------------------------------------------------------------------
311
* fixed segfault on connection shutdown

configure.ac

+1-1
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
#
1515

1616
AC_PREREQ([2.69])
17-
AC_INIT([mod_http2], [1.0.14], [[email protected]])
17+
AC_INIT([mod_http2], [1.0.15], [[email protected]])
1818

1919
LT_PREREQ([2.2.6])
2020
LT_INIT()

mod_http2/h2_config.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ static h2_config defconf = {
6060
1, /* HTTP/2 server push enabled */
6161
NULL, /* map of content-type to priorities */
6262
5, /* normal connection timeout */
63-
5, /* keepalive timeout */
63+
-1, /* keepalive timeout */
6464
0, /* stream timeout */
6565
};
6666

mod_http2/h2_conn.c

+31-7
Original file line numberDiff line numberDiff line change
@@ -158,47 +158,71 @@ apr_status_t h2_conn_setup(h2_ctx *ctx, conn_rec *c, request_rec *r)
158158
static apr_status_t h2_conn_process(h2_ctx *ctx)
159159
{
160160
h2_session *session;
161+
apr_status_t status;
161162

162163
session = h2_ctx_session_get(ctx);
163164
if (session->c->cs) {
164165
session->c->cs->sense = CONN_SENSE_DEFAULT;
165166
}
166167

167-
h2_session_process(session, async_mpm);
168+
status = h2_session_process(session, async_mpm);
168169

169170
session->c->keepalive = AP_CONN_KEEPALIVE;
170171
if (session->c->cs) {
171172
session->c->cs->state = CONN_STATE_WRITE_COMPLETION;
172173
}
173174

175+
if (APR_STATUS_IS_EOF(status)
176+
|| APR_STATUS_IS_ECONNRESET(status)
177+
|| APR_STATUS_IS_ECONNABORTED(status)) {
178+
/* fatal, probably client just closed connection. emergency shutdown */
179+
/* Make sure this connection gets closed properly. */
180+
ap_log_cerror( APLOG_MARK, APLOG_DEBUG, 0, session->c,
181+
"h2_session(%ld): aborted", session->id);
182+
session->c->keepalive = AP_CONN_CLOSE;
183+
184+
h2_ctx_clear(session->c);
185+
h2_session_abort(session, status);
186+
h2_session_eoc_callback(session);
187+
/* hereafter session might be gone */
188+
return APR_ECONNABORTED;
189+
}
190+
174191
if (session->state == H2_SESSION_ST_CLOSING) {
175192
ap_log_cerror( APLOG_MARK, APLOG_DEBUG, 0, session->c,
176-
"h2_session(%ld): done", session->id);
193+
"h2_session(%ld): closing", session->id);
177194
/* Make sure this connection gets closed properly. */
178-
ap_update_child_status_from_conn(session->c->sbh, SERVER_CLOSING, session->c);
179195
session->c->keepalive = AP_CONN_CLOSE;
180196

197+
h2_ctx_clear(session->c);
181198
h2_session_close(session);
182199
/* hereafter session may be gone */
183200
}
201+
else if (session->state == H2_SESSION_ST_ABORTED) {
202+
ap_log_cerror( APLOG_MARK, APLOG_DEBUG, 0, session->c,
203+
"h2_session(%ld): already aborted", session->id);
204+
return APR_ECONNABORTED;
205+
}
184206

185-
return DONE;
207+
return APR_SUCCESS;
186208
}
187209

188210
apr_status_t h2_conn_run(struct h2_ctx *ctx, conn_rec *c)
189211
{
190212
int mpm_state = 0;
213+
apr_status_t status;
191214
do {
192-
h2_conn_process(ctx);
215+
status = h2_conn_process(ctx);
193216

194217
if (ap_mpm_query(AP_MPMQ_MPM_STATE, &mpm_state)) {
195218
break;
196219
}
197-
} while (!async_mpm
220+
} while (!async_mpm
221+
&& status == APR_SUCCESS
198222
&& c->keepalive == AP_CONN_KEEPALIVE
199223
&& mpm_state != AP_MPMQ_STOPPING);
200224

201-
return DONE;
225+
return status;
202226
}
203227

204228

mod_http2/h2_conn_io.c

+36-15
Original file line numberDiff line numberDiff line change
@@ -93,29 +93,35 @@ int h2_conn_io_is_buffered(h2_conn_io *io)
9393
return io->bufsize > 0;
9494
}
9595

96+
typedef struct {
97+
conn_rec *c;
98+
h2_conn_io *io;
99+
} pass_out_ctx;
100+
96101
static apr_status_t pass_out(apr_bucket_brigade *bb, void *ctx)
97102
{
98-
h2_conn_io *io = (h2_conn_io*)ctx;
103+
pass_out_ctx *pctx = ctx;
104+
conn_rec *c = pctx->c;
99105
apr_status_t status;
100106
apr_off_t bblen;
101107

102108
if (APR_BRIGADE_EMPTY(bb)) {
103109
return APR_SUCCESS;
104110
}
105111

106-
ap_update_child_status(io->connection->sbh, SERVER_BUSY_WRITE, NULL);
112+
ap_update_child_status(c->sbh, SERVER_BUSY_WRITE, NULL);
107113
status = apr_brigade_length(bb, 0, &bblen);
108114
if (status == APR_SUCCESS) {
109-
ap_log_cerror(APLOG_MARK, APLOG_TRACE4, 0, io->connection,
115+
ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, c,
110116
"h2_conn_io(%ld): pass_out brigade %ld bytes",
111-
io->connection->id, (long)bblen);
112-
status = ap_pass_brigade(io->connection->output_filters, bb);
113-
if (status == APR_SUCCESS) {
114-
io->bytes_written += (apr_size_t)bblen;
115-
io->last_write = apr_time_now();
117+
c->id, (long)bblen);
118+
status = ap_pass_brigade(c->output_filters, bb);
119+
if (status == APR_SUCCESS && pctx->io) {
120+
pctx->io->bytes_written += (apr_size_t)bblen;
121+
pctx->io->last_write = apr_time_now();
116122
}
117-
apr_brigade_cleanup(bb);
118123
}
124+
apr_brigade_cleanup(bb);
119125
return status;
120126
}
121127

@@ -169,7 +175,10 @@ apr_status_t h2_conn_io_write(h2_conn_io *io,
169175
const char *buf, size_t length)
170176
{
171177
apr_status_t status = APR_SUCCESS;
178+
pass_out_ctx ctx;
172179

180+
ctx.c = io->connection;
181+
ctx.io = io;
173182
io->unflushed = 1;
174183
if (io->bufsize > 0) {
175184
ap_log_cerror(APLOG_MARK, APLOG_TRACE4, 0, io->connection,
@@ -183,8 +192,9 @@ apr_status_t h2_conn_io_write(h2_conn_io *io,
183192
while (length > 0 && (status == APR_SUCCESS)) {
184193
apr_size_t avail = io->bufsize - io->buflen;
185194
if (avail <= 0) {
195+
186196
bucketeer_buffer(io);
187-
status = pass_out(io->output, io);
197+
status = pass_out(io->output, &ctx);
188198
io->buflen = 0;
189199
}
190200
else if (length > avail) {
@@ -205,7 +215,7 @@ apr_status_t h2_conn_io_write(h2_conn_io *io,
205215
else {
206216
ap_log_cerror(APLOG_MARK, APLOG_TRACE4, status, io->connection,
207217
"h2_conn_io: writing %ld bytes to brigade", (long)length);
208-
status = apr_brigade_write(io->output, pass_out, io, buf, length);
218+
status = apr_brigade_write(io->output, pass_out, &ctx, buf, length);
209219
}
210220

211221
return status;
@@ -242,9 +252,11 @@ apr_status_t h2_conn_io_consider_flush(h2_conn_io *io)
242252
return status;
243253
}
244254

245-
static apr_status_t h2_conn_io_flush_int(h2_conn_io *io, int force)
255+
static apr_status_t h2_conn_io_flush_int(h2_conn_io *io, int force, int eoc)
246256
{
247257
if (io->unflushed || force) {
258+
pass_out_ctx ctx;
259+
248260
if (io->buflen > 0) {
249261
/* something in the buffer, put it in the output brigade */
250262
ap_log_cerror(APLOG_MARK, APLOG_TRACE4, 0, io->connection,
@@ -262,20 +274,29 @@ static apr_status_t h2_conn_io_flush_int(h2_conn_io *io, int force)
262274
"h2_conn_io: flush");
263275
/* Send it out */
264276
io->unflushed = 0;
265-
return pass_out(io->output, io);
277+
278+
ctx.c = io->connection;
279+
ctx.io = eoc? NULL : io;
280+
return pass_out(io->output, &ctx);
266281
/* no more access after this, as we might have flushed an EOC bucket
267282
* that de-allocated us all. */
268283
}
269284
return APR_SUCCESS;
270285
}
271286

287+
apr_status_t h2_conn_io_write_eoc(h2_conn_io *io, apr_bucket *b)
288+
{
289+
APR_BRIGADE_INSERT_TAIL(io->output, b);
290+
return h2_conn_io_flush_int(io, 1, 1);
291+
}
292+
272293
apr_status_t h2_conn_io_flush(h2_conn_io *io)
273294
{
274-
return h2_conn_io_flush_int(io, 1);
295+
return h2_conn_io_flush_int(io, 1, 0);
275296
}
276297

277298
apr_status_t h2_conn_io_pass(h2_conn_io *io)
278299
{
279-
return h2_conn_io_flush_int(io, 0);
300+
return h2_conn_io_flush_int(io, 0, 0);
280301
}
281302

mod_http2/h2_conn_io.h

+1
Original file line numberDiff line numberDiff line change
@@ -60,5 +60,6 @@ apr_status_t h2_conn_io_consider_flush(h2_conn_io *io);
6060

6161
apr_status_t h2_conn_io_pass(h2_conn_io *io);
6262
apr_status_t h2_conn_io_flush(h2_conn_io *io);
63+
apr_status_t h2_conn_io_write_eoc(h2_conn_io *io, apr_bucket *b);
6364

6465
#endif /* defined(__mod_h2__h2_conn_io__) */

mod_http2/h2_mplx.c

+12-3
Original file line numberDiff line numberDiff line change
@@ -264,21 +264,30 @@ apr_status_t h2_mplx_release_and_join(h2_mplx *m, apr_thread_cond_t *wait)
264264
workers_unregister(m);
265265
status = apr_thread_mutex_lock(m->lock);
266266
if (APR_SUCCESS == status) {
267+
int i;
268+
267269
/* disable WINDOW_UPDATE callbacks */
268270
h2_mplx_set_consumed_cb(m, NULL, NULL);
269271
while (!h2_io_set_iter(m->stream_ios, stream_done_iter, m)) {
270272
/* iterator until all h2_io have been orphaned or destroyed */
271273
}
272274

273275
release(m, 0);
274-
while (m->refs > 0) {
276+
for (i = 0; m->refs > 0; ++i) {
277+
275278
m->join_wait = wait;
276279
ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, m->c,
277280
"h2_mplx(%ld): release_join, refs=%d, waiting...",
278281
m->id, m->refs);
279-
apr_thread_cond_wait(wait, m->lock);
282+
283+
status = apr_thread_cond_timedwait(wait, m->lock, apr_time_from_sec(2));
284+
if (APR_STATUS_IS_TIMEUP(status)) {
285+
ap_log_cerror(APLOG_MARK, APLOG_INFO, 0, m->c,
286+
"h2_mplx(%ld): release timeup %d, refs=%d, waiting...",
287+
m->id, i, m->refs);
288+
}
280289
}
281-
ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, m->c,
290+
ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, m->c,
282291
"h2_mplx(%ld): release_join -> destroy, (#ios=%ld)",
283292
m->id, (long)h2_io_set_size(m->stream_ios));
284293
apr_thread_mutex_unlock(m->lock);

0 commit comments

Comments
 (0)