archrelease: copy trunk to extra-x86_64
[arch-packages.git] / apache / repos / extra-x86_64 / nohttp2forprefork.patch
blob8bb337be6092e172128fda0022133bc5ad620e2f
1 From ab03196a879f4064f618a9a45d63c67a67f4b901 Mon Sep 17 00:00:00 2001
2 From: Jim Jagielski <jim@apache.org>
3 Date: Tue, 4 Jul 2017 12:34:15 +0000
4 Subject: [PATCH] Merge r1800689 from trunk:
6 On the trunk:
8 mod_http2: disable and give warning when mpm_prefork is encountered.
9 The server will continue to work, but HTTP/2 will no longer be negotiated.
12 Submitted by: icing
13 Reviewed by: icing, ylavic, jim
16 git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.4.x@1800774 13f79535-47bb-0310-9956-ffa450edef68
17 ---
18 modules/http2/h2_conn.c | 21 +++++++-
19 modules/http2/h2_conn.h | 3 +-
20 modules/http2/h2_mplx.c | 37 +++++++-------
21 modules/http2/h2_mplx.h | 2 +-
22 modules/http2/h2_session.c | 7 +--
23 modules/http2/h2_stream.c | 14 +++++-
24 modules/http2/h2_switch.c | 8 +++
25 modules/http2/h2_util.c | 118 +++++++++++++++++++++------------------------
26 modules/http2/h2_workers.c | 7 +--
27 modules/http2/mod_http2.c | 12 +++++
28 12 files changed, 139 insertions(+), 99 deletions(-)
30 diff --git a/modules/http2/h2_conn.c b/modules/http2/h2_conn.c
31 index fcf6bad4d41..e2502c2f167 100644
32 --- a/modules/http2/h2_conn.c
33 +++ b/modules/http2/h2_conn.c
34 @@ -47,6 +47,7 @@ static struct h2_workers *workers;
35 static h2_mpm_type_t mpm_type = H2_MPM_UNKNOWN;
36 static module *mpm_module;
37 static int async_mpm;
38 +static int mpm_supported = 1;
39 static apr_socket_t *dummy_socket;
41 static void check_modules(int force)
42 @@ -76,11 +77,18 @@ static void check_modules(int force)
43 else if (!strcmp("prefork.c", m->name)) {
44 mpm_type = H2_MPM_PREFORK;
45 mpm_module = m;
46 + /* While http2 can work really well on prefork, it collides
47 + * today's use case for prefork: runnning single-thread app engines
48 + * like php. If we restrict h2_workers to 1 per process, php will
49 + * work fine, but browser will be limited to 1 active request at a
50 + * time. */
51 + mpm_supported = 0;
52 break;
54 else if (!strcmp("simple_api.c", m->name)) {
55 mpm_type = H2_MPM_SIMPLE;
56 mpm_module = m;
57 + mpm_supported = 0;
58 break;
60 else if (!strcmp("mpm_winnt.c", m->name)) {
61 @@ -107,7 +115,6 @@ apr_status_t h2_conn_child_init(apr_pool_t *pool, server_rec *s)
62 int idle_secs = 0;
64 check_modules(1);
66 ap_mpm_query(AP_MPMQ_MAX_THREADS, &max_threads_per_child);
68 status = ap_mpm_query(AP_MPMQ_IS_ASYNC, &async_mpm);
69 @@ -157,6 +164,18 @@ h2_mpm_type_t h2_conn_mpm_type(void)
70 return mpm_type;
73 +const char *h2_conn_mpm_name(void)
75 + check_modules(0);
76 + return mpm_module? mpm_module->name : "unknown";
79 +int h2_mpm_supported(void)
81 + check_modules(0);
82 + return mpm_supported;
85 static module *h2_conn_mpm_module(void)
87 check_modules(0);
88 diff --git a/modules/http2/h2_conn.h b/modules/http2/h2_conn.h
89 index 79948644ae8..7111a6cd69c 100644
90 --- a/modules/http2/h2_conn.h
91 +++ b/modules/http2/h2_conn.h
92 @@ -64,7 +64,8 @@ typedef enum {
94 /* Returns the type of MPM module detected */
95 h2_mpm_type_t h2_conn_mpm_type(void);
97 +const char *h2_conn_mpm_name(void);
98 +int h2_mpm_supported(void);
100 conn_rec *h2_slave_create(conn_rec *master, int slave_id, apr_pool_t *parent);
101 void h2_slave_destroy(conn_rec *slave);
102 diff --git a/modules/http2/h2_mplx.c b/modules/http2/h2_mplx.c
103 index b73bd0d5bfd..214d84ed1f9 100644
104 --- a/modules/http2/h2_mplx.c
105 +++ b/modules/http2/h2_mplx.c
106 @@ -481,9 +481,6 @@ void h2_mplx_release_and_join(h2_mplx *m, apr_thread_cond_t *wait)
108 H2_MPLX_LEAVE(m);
110 - /* 5. unregister again, now that our workers are done */
111 - h2_workers_unregister(m->workers, m);
113 ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, m->c,
114 "h2_mplx(%ld): released", m->id);
116 @@ -662,7 +659,7 @@ apr_status_t h2_mplx_reprioritize(h2_mplx *m, h2_stream_pri_cmp *cmp, void *ctx)
118 static void register_if_needed(h2_mplx *m)
120 - if (!m->is_registered && !h2_iq_empty(m->q)) {
121 + if (!m->aborted && !m->is_registered && !h2_iq_empty(m->q)) {
122 apr_status_t status = h2_workers_register(m->workers, m);
123 if (status == APR_SUCCESS) {
124 m->is_registered = 1;
125 @@ -755,25 +752,27 @@ static h2_task *next_stream_task(h2_mplx *m)
126 return NULL;
129 -h2_task *h2_mplx_pop_task(h2_mplx *m, int *has_more)
130 +apr_status_t h2_mplx_pop_task(h2_mplx *m, h2_task **ptask)
132 - h2_task *task = NULL;
133 + apr_status_t rv = APR_EOF;
135 - H2_MPLX_ENTER_ALWAYS(m);
137 - *has_more = 0;
138 - if (!m->aborted) {
139 - task = next_stream_task(m);
140 - if (task != NULL && !h2_iq_empty(m->q)) {
141 - *has_more = 1;
143 - else {
144 - m->is_registered = 0; /* h2_workers will discard this mplx */
146 + *ptask = NULL;
147 + if (APR_SUCCESS != (rv = apr_thread_mutex_lock(m->lock))) {
148 + return rv;
151 + if (m->aborted) {
152 + rv = APR_EOF;
154 + else {
155 + *ptask = next_stream_task(m);
156 + rv = (*ptask != NULL && !h2_iq_empty(m->q))? APR_EAGAIN : APR_SUCCESS;
158 + if (APR_EAGAIN != rv) {
159 + m->is_registered = 0; /* h2_workers will discard this mplx */
162 H2_MPLX_LEAVE(m);
163 - return task;
164 + return rv;
167 static void task_done(h2_mplx *m, h2_task *task, h2_req_engine *ngn)
168 diff --git a/modules/http2/h2_mplx.h b/modules/http2/h2_mplx.h
169 index 61b1b99aba7..d56c65289c2 100644
170 --- a/modules/http2/h2_mplx.h
171 +++ b/modules/http2/h2_mplx.h
172 @@ -124,7 +124,7 @@ h2_mplx *h2_mplx_create(conn_rec *c, apr_pool_t *master,
174 void h2_mplx_release_and_join(h2_mplx *m, struct apr_thread_cond_t *wait);
176 -struct h2_task *h2_mplx_pop_task(h2_mplx *mplx, int *has_more);
177 +apr_status_t h2_mplx_pop_task(h2_mplx *m, struct h2_task **ptask);
179 void h2_mplx_task_done(h2_mplx *m, struct h2_task *task, struct h2_task **ptask);
181 diff --git a/modules/http2/h2_session.c b/modules/http2/h2_session.c
182 index bc24bb41cdb..da85d7053fd 100644
183 --- a/modules/http2/h2_session.c
184 +++ b/modules/http2/h2_session.c
185 @@ -326,6 +326,7 @@ static int on_frame_recv_cb(nghttp2_session *ng2s,
187 h2_session *session = (h2_session *)userp;
188 h2_stream *stream;
189 + apr_status_t rv = APR_SUCCESS;
191 if (APLOGcdebug(session->c)) {
192 char buffer[256];
193 @@ -346,7 +347,7 @@ static int on_frame_recv_cb(nghttp2_session *ng2s,
194 * trailers */
195 stream = h2_session_stream_get(session, frame->hd.stream_id);
196 if (stream) {
197 - h2_stream_recv_frame(stream, NGHTTP2_HEADERS, frame->hd.flags);
198 + rv = h2_stream_recv_frame(stream, NGHTTP2_HEADERS, frame->hd.flags);
200 break;
201 case NGHTTP2_DATA:
202 @@ -356,7 +357,7 @@ static int on_frame_recv_cb(nghttp2_session *ng2s,
203 H2_STRM_LOG(APLOGNO(02923), stream,
204 "DATA, len=%ld, flags=%d"),
205 (long)frame->hd.length, frame->hd.flags);
206 - h2_stream_recv_frame(stream, NGHTTP2_DATA, frame->hd.flags);
207 + rv = h2_stream_recv_frame(stream, NGHTTP2_DATA, frame->hd.flags);
209 break;
210 case NGHTTP2_PRIORITY:
211 @@ -411,7 +412,7 @@ static int on_frame_recv_cb(nghttp2_session *ng2s,
213 break;
215 - return 0;
216 + return (APR_SUCCESS == rv)? 0 : NGHTTP2_ERR_PROTO;
219 static int h2_session_continue_data(h2_session *session) {
220 diff --git a/modules/http2/h2_stream.c b/modules/http2/h2_stream.c
221 index 4cd2132207e..925f3d6d81d 100644
222 --- a/modules/http2/h2_stream.c
223 +++ b/modules/http2/h2_stream.c
224 @@ -444,7 +444,13 @@ apr_status_t h2_stream_recv_frame(h2_stream *stream, int ftype, int flags)
225 else {
226 /* request HEADER */
227 ap_assert(stream->request == NULL);
228 - ap_assert(stream->rtmp != NULL);
229 + if (stream->rtmp == NULL) {
230 + /* This can only happen, if the stream has received no header
231 + * name/value pairs at all. The lastest nghttp2 version have become
232 + * pretty good at detecting this early. In any case, we have
233 + * to abort the connection here, since this is clearly a protocol error */
234 + return APR_EINVAL;
236 status = h2_request_end_headers(stream->rtmp, stream->pool, eos);
237 if (status != APR_SUCCESS) {
238 return status;
239 @@ -739,9 +745,13 @@ apr_status_t h2_stream_add_header(h2_stream *stream,
240 status = h2_request_add_header(stream->rtmp, stream->pool,
241 name, nlen, value, vlen);
243 - else {
244 + else if (H2_SS_OPEN == stream->state) {
245 status = add_trailer(stream, name, nlen, value, vlen);
247 + else {
248 + status = APR_EINVAL;
251 if (status != APR_SUCCESS) {
252 ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, session->c,
253 H2_STRM_MSG(stream, "header %s not accepted"), name);
254 diff --git a/modules/http2/h2_switch.c b/modules/http2/h2_switch.c
255 index 8a8d56e59ef..5b1247ec700 100644
256 --- a/modules/http2/h2_switch.c
257 +++ b/modules/http2/h2_switch.c
258 @@ -55,6 +55,10 @@ static int h2_protocol_propose(conn_rec *c, request_rec *r,
259 const char **protos = is_tls? h2_tls_protos : h2_clear_protos;
261 (void)s;
262 + if (!h2_mpm_supported()) {
263 + return DECLINED;
266 if (strcmp(AP_PROTOCOL_HTTP1, ap_get_protocol(c))) {
267 /* We do not know how to switch from anything else but http/1.1.
269 @@ -127,6 +131,10 @@ static int h2_protocol_switch(conn_rec *c, request_rec *r, server_rec *s,
270 const char **p = protos;
272 (void)s;
273 + if (!h2_mpm_supported()) {
274 + return DECLINED;
277 while (*p) {
278 if (!strcmp(*p, protocol)) {
279 found = 1;
280 diff --git a/modules/http2/h2_util.c b/modules/http2/h2_util.c
281 index 01b506ac854..04a9311424e 100644
282 --- a/modules/http2/h2_util.c
283 +++ b/modules/http2/h2_util.c
284 @@ -695,16 +695,47 @@ int h2_fifo_count(h2_fifo *fifo)
286 static apr_status_t check_not_empty(h2_fifo *fifo, int block)
288 - if (fifo->count == 0) {
289 + while (fifo->count == 0) {
290 if (!block) {
291 return APR_EAGAIN;
293 - while (fifo->count == 0) {
294 - if (fifo->aborted) {
295 - return APR_EOF;
296 + if (fifo->aborted) {
297 + return APR_EOF;
299 + apr_thread_cond_wait(fifo->not_empty, fifo->lock);
301 + return APR_SUCCESS;
304 +static apr_status_t fifo_push_int(h2_fifo *fifo, void *elem, int block)
306 + if (fifo->aborted) {
307 + return APR_EOF;
310 + if (fifo->set && index_of(fifo, elem) >= 0) {
311 + /* set mode, elem already member */
312 + return APR_EEXIST;
314 + else if (fifo->count == fifo->nelems) {
315 + if (block) {
316 + while (fifo->count == fifo->nelems) {
317 + if (fifo->aborted) {
318 + return APR_EOF;
320 + apr_thread_cond_wait(fifo->not_full, fifo->lock);
322 - apr_thread_cond_wait(fifo->not_empty, fifo->lock);
324 + else {
325 + return APR_EAGAIN;
329 + ap_assert(fifo->count < fifo->nelems);
330 + fifo->elems[nth_index(fifo, fifo->count)] = elem;
331 + ++fifo->count;
332 + if (fifo->count == 1) {
333 + apr_thread_cond_broadcast(fifo->not_empty);
335 return APR_SUCCESS;
337 @@ -718,33 +749,7 @@ static apr_status_t fifo_push(h2_fifo *fifo, void *elem, int block)
340 if ((rv = apr_thread_mutex_lock(fifo->lock)) == APR_SUCCESS) {
341 - if (fifo->set && index_of(fifo, elem) >= 0) {
342 - /* set mode, elem already member */
343 - apr_thread_mutex_unlock(fifo->lock);
344 - return APR_EEXIST;
346 - else if (fifo->count == fifo->nelems) {
347 - if (block) {
348 - while (fifo->count == fifo->nelems) {
349 - if (fifo->aborted) {
350 - apr_thread_mutex_unlock(fifo->lock);
351 - return APR_EOF;
353 - apr_thread_cond_wait(fifo->not_full, fifo->lock);
356 - else {
357 - apr_thread_mutex_unlock(fifo->lock);
358 - return APR_EAGAIN;
362 - ap_assert(fifo->count < fifo->nelems);
363 - fifo->elems[nth_index(fifo, fifo->count)] = elem;
364 - ++fifo->count;
365 - if (fifo->count == 1) {
366 - apr_thread_cond_broadcast(fifo->not_empty);
368 + rv = fifo_push_int(fifo, elem, block);
369 apr_thread_mutex_unlock(fifo->lock);
371 return rv;
372 @@ -760,12 +765,15 @@ apr_status_t h2_fifo_try_push(h2_fifo *fifo, void *elem)
373 return fifo_push(fifo, elem, 0);
376 -static void *pull_head(h2_fifo *fifo)
377 +static apr_status_t pull_head(h2_fifo *fifo, void **pelem, int block)
379 - void *elem;
380 + apr_status_t rv;
382 - ap_assert(fifo->count > 0);
383 - elem = fifo->elems[fifo->head];
384 + if ((rv = check_not_empty(fifo, block)) != APR_SUCCESS) {
385 + *pelem = NULL;
386 + return rv;
388 + *pelem = fifo->elems[fifo->head];
389 --fifo->count;
390 if (fifo->count > 0) {
391 fifo->head = nth_index(fifo, 1);
392 @@ -773,7 +781,7 @@ static void *pull_head(h2_fifo *fifo)
393 apr_thread_cond_broadcast(fifo->not_full);
396 - return elem;
397 + return APR_SUCCESS;
400 static apr_status_t fifo_pull(h2_fifo *fifo, void **pelem, int block)
401 @@ -785,15 +793,7 @@ static apr_status_t fifo_pull(h2_fifo *fifo, void **pelem, int block)
404 if ((rv = apr_thread_mutex_lock(fifo->lock)) == APR_SUCCESS) {
405 - if ((rv = check_not_empty(fifo, block)) != APR_SUCCESS) {
406 - apr_thread_mutex_unlock(fifo->lock);
407 - *pelem = NULL;
408 - return rv;
411 - ap_assert(fifo->count > 0);
412 - *pelem = pull_head(fifo);
414 + rv = pull_head(fifo, pelem, block);
415 apr_thread_mutex_unlock(fifo->lock);
417 return rv;
418 @@ -818,25 +818,17 @@ static apr_status_t fifo_peek(h2_fifo *fifo, h2_fifo_peek_fn *fn, void *ctx, int
419 return APR_EOF;
422 - if ((rv = apr_thread_mutex_lock(fifo->lock)) == APR_SUCCESS) {
423 - if ((rv = check_not_empty(fifo, block)) != APR_SUCCESS) {
424 - apr_thread_mutex_unlock(fifo->lock);
425 - return rv;
426 + if (APR_SUCCESS == (rv = apr_thread_mutex_lock(fifo->lock))) {
427 + if (APR_SUCCESS == (rv = pull_head(fifo, &elem, block))) {
428 + switch (fn(elem, ctx)) {
429 + case H2_FIFO_OP_PULL:
430 + break;
431 + case H2_FIFO_OP_REPUSH:
432 + rv = fifo_push_int(fifo, elem, block);
433 + break;
437 - ap_assert(fifo->count > 0);
438 - elem = pull_head(fifo);
440 apr_thread_mutex_unlock(fifo->lock);
442 - switch (fn(elem, ctx)) {
443 - case H2_FIFO_OP_PULL:
444 - break;
445 - case H2_FIFO_OP_REPUSH:
446 - return h2_fifo_push(fifo, elem);
447 - break;
451 return rv;
453 diff --git a/modules/http2/h2_workers.c b/modules/http2/h2_workers.c
454 index 0bbb65223f7..5abddd4a1d5 100644
455 --- a/modules/http2/h2_workers.c
456 +++ b/modules/http2/h2_workers.c
457 @@ -150,15 +150,16 @@ static void cleanup_zombies(h2_workers *workers)
459 static apr_status_t slot_pull_task(h2_slot *slot, h2_mplx *m)
461 - int has_more;
462 - slot->task = h2_mplx_pop_task(m, &has_more);
463 + apr_status_t rv;
465 + rv = h2_mplx_pop_task(m, &slot->task);
466 if (slot->task) {
467 /* Ok, we got something to give back to the worker for execution.
468 * If we still have idle workers, we let the worker be sticky,
469 * e.g. making it poll the task's h2_mplx instance for more work
470 * before asking back here. */
471 slot->sticks = slot->workers->max_workers;
472 - return has_more? APR_EAGAIN : APR_SUCCESS;
473 + return rv;
475 slot->sticks = 0;
476 return APR_EOF;
477 diff --git a/modules/http2/mod_http2.c b/modules/http2/mod_http2.c
478 index ea399c91a28..420e74c3363 100644
479 --- a/modules/http2/mod_http2.c
480 +++ b/modules/http2/mod_http2.c
481 @@ -65,6 +65,7 @@ typedef struct {
482 } features;
484 static features myfeats;
485 +static int mpm_warned;
487 /* The module initialization. Called once as apache hook, before any multi
488 * processing (threaded or not) happens. It is typically at least called twice,
489 @@ -141,6 +142,17 @@ static int h2_post_config(apr_pool_t *p, apr_pool_t *plog,
490 break;
493 + if (!h2_mpm_supported() && !mpm_warned) {
494 + mpm_warned = 1;
495 + ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s, APLOGNO(10034)
496 + "The mpm module (%s) is not supported by mod_http2. The mpm determines "
497 + "how things are processed in your server. HTTP/2 has more demands in "
498 + "this regard and the currently selected mpm will just not do. "
499 + "This is an advisory warning. Your server will continue to work, but "
500 + "the HTTP/2 protocol will be inactive.",
501 + h2_conn_mpm_name());
504 status = h2_h2_init(p, s);
505 if (status == APR_SUCCESS) {
506 status = h2_switch_init(p, s);