From: Stefan Eissing Date: Sat, 14 May 2016 11:49:01 +0000 (+0000) Subject: Merge of 1742260,1742359,1742444,1742445,1742446,1742447,1742460,1743335,1743517... X-Git-Tag: 2.4.21~169 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=3b0efe42b895f0378c8a727ce9e68ee74c02d85d;p=apache Merge of 1742260,1742359,1742444,1742445,1742446,1742447,1742460,1743335,1743517,1743788 from trunk: mod_http2/mod_proxy_http2 update with latest changes from trunk to 1.5.4. Update of CMake and Netware makefiles. git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.4.x@1743815 13f79535-47bb-0310-9956-ffa450edef68 --- diff --git a/CHANGES b/CHANGES index e1a3b49d45..58f7712adb 100644 --- a/CHANGES +++ b/CHANGES @@ -2,6 +2,12 @@ Changes with Apache 2.4.21 + *) mod_proxy_http2: new experimental http2 proxy module for h2: and h2c: proxy + urls. Part of the httpd mod_proxy framework, common settings apply. + Requests from the same HTTP/2 frontend connection against the same backend + are aggregated on a single connection. + [Stefan Eissing] + *) mod_http2: slave connections have conn_rec->aborted flag set when a stream has been reset by the client. [Stefan Eissing] diff --git a/CMakeLists.txt b/CMakeLists.txt index fd45a27c46..b5da0b6166 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -319,6 +319,7 @@ SET(MODULE_LIST "modules/proxy/mod_proxy_http+I+Apache proxy HTTP module. Requires and is enabled by --enable-proxy." "modules/proxy/mod_proxy_scgi+I+Apache proxy SCGI module. Requires and is enabled by --enable-proxy." "modules/proxy/mod_proxy_wstunnel+I+Apache proxy Websocket Tunnel module. Requires and is enabled by --enable-proxy." + "modules/http2/mod_proxy_http2+i+Apache proxy HTTP/2 module. Requires --enable-proxy." "modules/session/mod_session+I+session module" "modules/session/mod_session_cookie+I+session cookie module" "modules/session/mod_session_crypto+i+session crypto module" @@ -430,6 +431,13 @@ IF(LIBXML2_FOUND) ENDIF() SET(mod_proxy_scgi_extra_libs mod_proxy) SET(mod_proxy_wstunnel_extra_libs mod_proxy) +SET(mod_proxy_http2_requires NGHTTP2_FOUND) +SET(mod_proxy_http2_extra_defines ssize_t=long) +SET(mod_proxy_http2_extra_includes ${NGHTTP2_INCLUDE_DIR}) +SET(mod_proxy_http2_extra_libs ${NGHTTP2_LIBRARIES} mod_proxy) +SET(mod_proxy_http2_extra_sources + modules/http2/h2_proxy_session.c modules/http2/h2_util.c +) SET(mod_ratelimit_extra_defines AP_RL_DECLARE_EXPORT) SET(mod_sed_extra_sources modules/filters/regexp.c modules/filters/sed0.c diff --git a/modules/http2/NWGNUmod_http2 b/modules/http2/NWGNUmod_http2 index 5a6a60b36f..e9c48a4009 100644 --- a/modules/http2/NWGNUmod_http2 +++ b/modules/http2/NWGNUmod_http2 @@ -389,6 +389,7 @@ $(OBJDIR)/mod_http2.imp : NWGNUmod_http2 @echo $(DL) nghttp2_session_callbacks_set_send_callback,$(DL) >> $@ @echo $(DL) nghttp2_session_client_new2,$(DL) >> $@ @echo $(DL) nghttp2_session_consume,$(DL) >> $@ + @echo $(DL) nghttp2_session_consume_connection,$(DL) >> $@ @echo $(DL) nghttp2_session_del,$(DL) >> $@ @echo $(DL) nghttp2_session_get_remote_settings,$(DL) >> $@ @echo $(DL) nghttp2_session_get_stream_user_data,$(DL) >> $@ diff --git a/modules/http2/h2_h2.c b/modules/http2/h2_h2.c index 5329f3171a..825cd77e78 100644 --- a/modules/http2/h2_h2.c +++ b/modules/http2/h2_h2.c @@ -485,9 +485,9 @@ int h2_is_acceptable_connection(conn_rec *c, int require_all) if (strncmp("TLS", val, 3) || !strcmp("TLSv1", val) || !strcmp("TLSv1.1", val)) { - ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, c, APLOGNO(03050) - "h2_h2(%ld): tls protocol not suitable: %s", - (long)c->id, val); + ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, c, APLOGNO(03050) + "h2_h2(%ld): tls protocol not suitable: %s", + (long)c->id, val); return 0; } } diff --git a/modules/http2/h2_mplx.c b/modules/http2/h2_mplx.c index 3ae02f4fd2..da5829f3a9 100644 --- a/modules/http2/h2_mplx.c +++ b/modules/http2/h2_mplx.c @@ -465,8 +465,10 @@ static int task_print(void *ctx, void *val) { h2_mplx *m = ctx; h2_task *task = val; - h2_stream *stream = h2_ihash_get(m->streams, task->stream_id); - if (task->request) { + + if (task && task->request) { + h2_stream *stream = h2_ihash_get(m->streams, task->stream_id); + ap_log_cerror(APLOG_MARK, APLOG_WARNING, 0, m->c, /* NO APLOGNO */ "->03198: h2_stream(%s): %s %s %s -> %s %d" "[orph=%d/started=%d/done=%d]", @@ -488,6 +490,15 @@ static int task_print(void *ctx, void *val) return 1; } +static int task_abort_connection(void *ctx, void *val) +{ + h2_task *task = val; + if (task->c) { + task->c->aborted = 1; + } + return 1; +} + apr_status_t h2_mplx_release_and_join(h2_mplx *m, apr_thread_cond_t *wait) { apr_status_t status; @@ -537,6 +548,8 @@ apr_status_t h2_mplx_release_and_join(h2_mplx *m, apr_thread_cond_t *wait) * and workers *should* return in a timely fashion. */ for (i = 0; m->workers_busy > 0; ++i) { + h2_ihash_iter(m->tasks, task_abort_connection, m); + m->join_wait = wait; status = apr_thread_cond_timedwait(wait, m->lock, apr_time_from_sec(wait_secs)); @@ -762,12 +775,17 @@ apr_status_t h2_mplx_out_open(h2_mplx *m, int stream_id, h2_response *response) static apr_status_t out_close(h2_mplx *m, h2_task *task) { apr_status_t status = APR_SUCCESS; - h2_stream *stream = h2_ihash_get(m->streams, task->stream_id); + h2_stream *stream; - if (!task || !stream) { + if (!task) { return APR_ECONNABORTED; } - + + stream = h2_ihash_get(m->streams, task->stream_id); + if (!stream) { + return APR_ECONNABORTED; + } + if (!task->response && !task->rst_error) { /* In case a close comes before a response was created, * insert an error one so that our streams can properly diff --git a/modules/http2/h2_proxy_session.c b/modules/http2/h2_proxy_session.c index 27aa440af1..34b584909d 100644 --- a/modules/http2/h2_proxy_session.c +++ b/modules/http2/h2_proxy_session.c @@ -23,8 +23,6 @@ #include "mod_http2.h" #include "h2.h" -#include "h2_int_queue.h" -#include "h2_request.h" #include "h2_util.h" #include "h2_proxy_session.h" @@ -212,7 +210,7 @@ static void process_proxy_header(request_rec *r, const char *n, const char *v) int i; for (i = 0; transform_hdrs[i].name; ++i) { - if (!strcasecmp(transform_hdrs[i].name, n)) { + if (!h2_casecmpstr(transform_hdrs[i].name, n)) { dconf = ap_get_module_config(r->per_dir_config, &proxy_module); apr_table_add(r->headers_out, n, (*transform_hdrs[i].func)(r, dconf, v)); @@ -338,10 +336,10 @@ static int on_data_chunk_recv(nghttp2_session *ngh2, uint8_t flags, stream = nghttp2_session_get_stream_user_data(ngh2, stream_id); if (!stream) { - ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, stream->r, APLOGNO(03358) - "h2_proxy_session(%s): recv data chunk for " - "unknown stream %d, ignored", - session->id, stream_id); + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ap_server_conf, APLOGNO(03358) + "h2_proxy_session(%s): recv data chunk for " + "unknown stream %d, ignored", + session->id, stream_id); return 0; } @@ -355,10 +353,10 @@ static int on_data_chunk_recv(nghttp2_session *ngh2, uint8_t flags, b = apr_bucket_transient_create((const char*)data, len, stream->r->connection->bucket_alloc); APR_BRIGADE_INSERT_TAIL(stream->output, b); - if (flags & NGHTTP2_DATA_FLAG_EOF) { - b = apr_bucket_flush_create(stream->r->connection->bucket_alloc); - APR_BRIGADE_INSERT_TAIL(stream->output, b); - } + /* always flush after a DATA frame, as we have no other indication + * of buffer use */ + b = apr_bucket_flush_create(stream->r->connection->bucket_alloc); + APR_BRIGADE_INSERT_TAIL(stream->output, b); ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, stream->r, APLOGNO(03359) "h2_proxy_session(%s): pass response data for " @@ -424,9 +422,9 @@ static ssize_t stream_data_read(nghttp2_session *ngh2, int32_t stream_id, *data_flags = 0; stream = nghttp2_session_get_stream_user_data(ngh2, stream_id); if (!stream) { - ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, stream->r, APLOGNO(03361) - "h2_proxy_stream(%s): data_read, stream %d not found", - stream->session->id, stream_id); + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ap_server_conf, APLOGNO(03361) + "h2_proxy_stream(%s): data_read, stream %d not found", + stream->session->id, stream_id); return NGHTTP2_ERR_CALLBACK_FAILURE; } @@ -554,9 +552,11 @@ static apr_status_t session_start(h2_proxy_session *session) apr_socket_t *s; s = ap_get_conn_socket(session->c); +#if (!defined(WIN32) && !defined(NETWARE)) || defined(DOXYGEN) if (s) { ap_sock_disable_nagle(s); } +#endif settings[0].settings_id = NGHTTP2_SETTINGS_ENABLE_PUSH; settings[0].value = 0; @@ -581,6 +581,7 @@ static apr_status_t open_stream(h2_proxy_session *session, const char *url, h2_proxy_stream *stream; apr_uri_t puri; const char *authority, *scheme, *path; + apr_status_t status; stream = apr_pcalloc(r->pool, sizeof(*stream)); @@ -593,9 +594,12 @@ static apr_status_t open_stream(h2_proxy_session *session, const char *url, stream->input = apr_brigade_create(stream->pool, session->c->bucket_alloc); stream->output = apr_brigade_create(stream->pool, session->c->bucket_alloc); - stream->req = h2_request_create(1, stream->pool, 0); + stream->req = h2_req_create(1, stream->pool, 0); + + status = apr_uri_parse(stream->pool, url, &puri); + if (status != APR_SUCCESS) + return status; - apr_uri_parse(stream->pool, url, &puri); scheme = (strcmp(puri.scheme, "h2")? "http" : "https"); authority = puri.hostname; if (!ap_strchr_c(authority, ':') && puri.port @@ -604,8 +608,8 @@ static apr_status_t open_stream(h2_proxy_session *session, const char *url, authority = apr_psprintf(stream->pool, "%s:%d", authority, puri.port); } path = apr_uri_unparse(stream->pool, &puri, APR_URI_UNP_OMITSITEPART); - h2_request_make(stream->req, stream->pool, r->method, scheme, - authority, path, r->headers_in); + h2_req_make(stream->req, stream->pool, r->method, scheme, + authority, path, r->headers_in); /* Tuck away all already existing cookies */ stream->saves = apr_table_make(r->pool, 2); @@ -647,11 +651,6 @@ static apr_status_t submit_stream(h2_proxy_session *session, h2_proxy_stream *st session->id, stream->req->authority, stream->req->path, rv); } - else { - ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, session->c, - "h2_proxy_session(%s-%d): submit %s%s", - session->id, rv, stream->req->authority, stream->req->path); - } if (rv > 0) { stream->id = rv; @@ -768,7 +767,7 @@ apr_status_t h2_proxy_session_submit(h2_proxy_session *session, apr_status_t status; status = open_stream(session, url, r, &stream); - if (status == OK) { + if (status == APR_SUCCESS) { ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(03381) "process stream(%d): %s %s%s, original: %s", stream->id, stream->req->method, @@ -884,7 +883,7 @@ static void ev_init(h2_proxy_session *session, int arg, const char *msg) { switch (session->state) { case H2_PROXYS_ST_INIT: - if (h2_ihash_is_empty(session->streams)) { + if (h2_ihash_empty(session->streams)) { transit(session, "init", H2_PROXYS_ST_IDLE); } else { @@ -991,7 +990,7 @@ static void ev_no_io(h2_proxy_session *session, int arg, const char *msg) * CPU cycles. Ideally, we'd like to do a blocking read, but that * is not possible if we have scheduled tasks and wait * for them to produce something. */ - if (h2_ihash_is_empty(session->streams)) { + if (h2_ihash_empty(session->streams)) { if (!is_accepting_streams(session)) { /* We are no longer accepting new streams and have * finished processing existing ones. Time to leave. */ @@ -1295,7 +1294,7 @@ static int done_iter(void *udata, void *val) void h2_proxy_session_cleanup(h2_proxy_session *session, h2_proxy_request_done *done) { - if (session->streams && !h2_ihash_is_empty(session->streams)) { + if (session->streams && !h2_ihash_empty(session->streams)) { cleanup_iter_ctx ctx; ctx.session = session; ctx.done = done; @@ -1334,7 +1333,7 @@ static int win_update_iter(void *udata, void *val) void h2_proxy_session_update_window(h2_proxy_session *session, conn_rec *c, apr_off_t bytes) { - if (session->streams && !h2_ihash_is_empty(session->streams)) { + if (session->streams && !h2_ihash_empty(session->streams)) { win_update_ctx ctx; ctx.session = session; ctx.c = c; diff --git a/modules/http2/h2_proxy_session.h b/modules/http2/h2_proxy_session.h index 7078981c7a..52be5c6b37 100644 --- a/modules/http2/h2_proxy_session.h +++ b/modules/http2/h2_proxy_session.h @@ -20,7 +20,7 @@ #include -struct h2_int_queue; +struct h2_iqueue; struct h2_ihash_t; typedef enum { @@ -74,7 +74,7 @@ struct h2_proxy_session { apr_interval_time_t wait_timeout; struct h2_ihash_t *streams; - struct h2_int_queue *suspended; + struct h2_iqueue *suspended; apr_size_t remote_max_concurrent; int last_stream_id; /* last stream id processed by backend, or 0 */ diff --git a/modules/http2/h2_session.c b/modules/http2/h2_session.c index 79b3fbc563..ce5c5c771b 100644 --- a/modules/http2/h2_session.c +++ b/modules/http2/h2_session.c @@ -57,7 +57,7 @@ static int h2_session_status_from_apr_status(apr_status_t rv) return NGHTTP2_ERR_WOULDBLOCK; } else if (APR_STATUS_IS_EOF(rv)) { - return NGHTTP2_ERR_EOF; + return NGHTTP2_ERR_EOF; } return NGHTTP2_ERR_PROTO; } diff --git a/modules/http2/h2_util.c b/modules/http2/h2_util.c index e6fe45965f..4cfa1649e4 100644 --- a/modules/http2/h2_util.c +++ b/modules/http2/h2_util.c @@ -1465,7 +1465,7 @@ int h2_util_frame_print(const nghttp2_frame *frame, char *buffer, size_t maxlen) } case NGHTTP2_GOAWAY: { size_t len = (frame->goaway.opaque_data_len < s_len)? - frame->goaway.opaque_data_len : s_len-1; + frame->goaway.opaque_data_len : s_len-1; memcpy(scratch, frame->goaway.opaque_data, len); scratch[len] = '\0'; return apr_snprintf(buffer, maxlen, "GOAWAY[error=%d, reason='%s', " diff --git a/modules/http2/h2_version.h b/modules/http2/h2_version.h index 13cd3df244..a3c13d9a46 100644 --- a/modules/http2/h2_version.h +++ b/modules/http2/h2_version.h @@ -26,7 +26,7 @@ * @macro * Version number of the http2 module as c string */ -#define MOD_HTTP2_VERSION "1.5.3" +#define MOD_HTTP2_VERSION "1.5.4" /** * @macro @@ -34,7 +34,7 @@ * release. This is a 24 bit number with 8 bits for major number, 8 bits * for minor and 8 bits for patch. Version 1.2.3 becomes 0x010203. */ -#define MOD_HTTP2_VERSION_NUM 0x010503 +#define MOD_HTTP2_VERSION_NUM 0x010504 #endif /* mod_h2_h2_version_h */ diff --git a/modules/http2/mod_proxy_http2.c b/modules/http2/mod_proxy_http2.c index 6722cb7333..d551f24e81 100644 --- a/modules/http2/mod_proxy_http2.c +++ b/modules/http2/mod_proxy_http2.c @@ -21,7 +21,6 @@ #include "mod_proxy_http2.h" -#include "h2_int_queue.h" #include "h2_request.h" #include "h2_util.h" #include "h2_version.h" @@ -126,12 +125,12 @@ static int proxy_http2_canon(request_rec *r, char *url) apr_port_t port, def_port; /* ap_port_of_scheme() */ - if (strncasecmp(url, "h2c:", 4) == 0) { + if (h2_casecmpstrn(url, "h2c:", 4) == 0) { url += 4; scheme = "h2c"; http_scheme = "http"; } - else if (strncasecmp(url, "h2:", 3) == 0) { + else if (h2_casecmpstrn(url, "h2:", 3) == 0) { url += 3; scheme = "h2"; http_scheme = "https"; @@ -260,7 +259,7 @@ static apr_status_t add_request(h2_proxy_session *session, request_rec *r) apr_table_setn(r->notes, "proxy-source-port", apr_psprintf(r->pool, "%hu", ctx->p_conn->connection->local_addr->port)); status = h2_proxy_session_submit(session, url, r); - if (status != OK) { + if (status != APR_SUCCESS) { ap_log_cerror(APLOG_MARK, APLOG_ERR, status, r->connection, APLOGNO(03351) "pass request body failed to %pI (%s) from %s (%s)", ctx->p_conn->addr, ctx->p_conn->hostname ? @@ -378,7 +377,7 @@ static apr_status_t proxy_engine_run(h2_proxy_ctx *ctx) { status = s2; break; } - if (!ctx->next && h2_ihash_is_empty(ctx->session->streams)) { + if (!ctx->next && h2_ihash_empty(ctx->session->streams)) { break; } } @@ -605,6 +604,7 @@ cleanup: /* Still more to do, tear down old conn and start over */ if (ctx->p_conn) { ctx->p_conn->close = 1; + /*only in trunk so far */ /*proxy_run_detach_backend(r, ctx->p_conn);*/ ap_proxy_release_connection(ctx->proxy_func, ctx->p_conn, ctx->server); ctx->p_conn = NULL; @@ -618,7 +618,8 @@ cleanup: /* close socket when errors happened or session shut down (EOF) */ ctx->p_conn->close = 1; } -/* proxy_run_detach_backend(ctx->rbase, ctx->p_conn);*/ + /*only in trunk so far */ + /*proxy_run_detach_backend(ctx->rbase, ctx->p_conn);*/ ap_proxy_release_connection(ctx->proxy_func, ctx->p_conn, ctx->server); ctx->p_conn = NULL; }