Loading CHANGES +3 −0 Original line number Diff line number Diff line -*- coding: utf-8 -*- Changes with Apache 2.4.40 *) mod_proxy_http2: adding support for handling trailers in both directions. PR 63502. [Stefan Eissing] *) mod_proxy_http: forward 100-continue, and minimize race conditions when reusing backend connections. PR 60330. [Yann Ylavic, Jean-Frederic Clere] Loading modules/http2/h2_proxy_session.c +34 −10 Original line number Diff line number Diff line Loading @@ -45,6 +45,7 @@ typedef struct h2_proxy_stream { unsigned int suspended : 1; unsigned int waiting_on_100 : 1; unsigned int waiting_on_ping : 1; unsigned int headers_ended : 1; uint32_t error_code; apr_bucket_brigade *input; Loading @@ -61,6 +62,7 @@ static void dispatch_event(h2_proxy_session *session, h2_proxys_event_t ev, static void ping_arrived(h2_proxy_session *session); static apr_status_t check_suspended(h2_proxy_session *session); static void stream_resume(h2_proxy_stream *stream); static apr_status_t submit_trailers(h2_proxy_stream *stream); static apr_status_t proxy_session_pre_close(void *theconn) Loading Loading @@ -241,7 +243,8 @@ static int add_header(void *table, const char *n, const char *v) return 1; } static void process_proxy_header(h2_proxy_stream *stream, const char *n, const char *v) static void process_proxy_header(apr_table_t *headers, h2_proxy_stream *stream, const char *n, const char *v) { static const struct { const char *name; Loading @@ -262,20 +265,18 @@ static void process_proxy_header(h2_proxy_stream *stream, const char *n, const c if (!dconf->preserve_host) { for (i = 0; transform_hdrs[i].name; ++i) { if (!ap_cstr_casecmp(transform_hdrs[i].name, n)) { apr_table_add(r->headers_out, n, (*transform_hdrs[i].func)(r, dconf, v)); apr_table_add(headers, n, (*transform_hdrs[i].func)(r, dconf, v)); return; } } if (!ap_cstr_casecmp("Link", n)) { dconf = ap_get_module_config(r->per_dir_config, &proxy_module); apr_table_add(r->headers_out, n, h2_proxy_link_reverse_map(r, dconf, apr_table_add(headers, n, h2_proxy_link_reverse_map(r, dconf, stream->real_server_uri, stream->p_server_uri, v)); return; } } apr_table_add(r->headers_out, n, v); apr_table_add(headers, n, v); } static apr_status_t h2_proxy_stream_add_header_out(h2_proxy_stream *stream, Loading @@ -299,8 +300,13 @@ static apr_status_t h2_proxy_stream_add_header_out(h2_proxy_stream *stream, return APR_SUCCESS; } ap_log_cerror(APLOG_MARK, APLOG_TRACE2, 0, stream->session->c, "h2_proxy_stream(%s-%d): on_header %s: %s", stream->session->id, stream->id, n, v); if (!h2_proxy_res_ignore_header(n, nlen)) { char *hname, *hvalue; apr_table_t *headers = (stream->headers_ended? stream->r->trailers_out : stream->r->headers_out); hname = apr_pstrndup(stream->pool, n, nlen); h2_proxy_util_camel_case_header(hname, nlen); Loading @@ -309,7 +315,7 @@ static apr_status_t h2_proxy_stream_add_header_out(h2_proxy_stream *stream, ap_log_cerror(APLOG_MARK, APLOG_TRACE2, 0, stream->session->c, "h2_proxy_stream(%s-%d): got header %s: %s", stream->session->id, stream->id, hname, hvalue); process_proxy_header(stream, hname, hvalue); process_proxy_header(headers, stream, hname, hvalue); } return APR_SUCCESS; } Loading Loading @@ -374,6 +380,7 @@ static void h2_proxy_stream_end_headers_out(h2_proxy_stream *stream) server_name, portstr) ); } if (r->status >= 200) stream->headers_ended = 1; if (APLOGrtrace2(stream->r)) { ap_log_rerror(APLOG_MARK, APLOG_TRACE2, 0, stream->r, Loading Loading @@ -547,9 +554,14 @@ static ssize_t stream_request_data(nghttp2_session *ngh2, int32_t stream_id, stream->data_sent += readlen; ap_log_rerror(APLOG_MARK, APLOG_DEBUG, status, stream->r, APLOGNO(03468) "h2_proxy_stream(%d): request DATA %ld, %ld" " total, flags=%d", stream->id, (long)readlen, (long)stream->data_sent, " total, flags=%d", stream->id, (long)readlen, (long)stream->data_sent, (int)*data_flags); if ((*data_flags & NGHTTP2_DATA_FLAG_EOF) && !apr_is_empty_table(stream->r->trailers_in)) { ap_log_rerror(APLOG_MARK, APLOG_DEBUG, status, stream->r, APLOGNO(03468) "h2_proxy_stream(%d): submit trailers", stream->id); *data_flags |= NGHTTP2_DATA_FLAG_NO_END_STREAM; submit_trailers(stream); } return readlen; } else if (APR_STATUS_IS_EAGAIN(status)) { Loading Loading @@ -736,6 +748,8 @@ static apr_status_t open_stream(h2_proxy_session *session, const char *url, stream->real_server_uri = apr_psprintf(stream->pool, "%s://%s", scheme, authority); stream->p_server_uri = apr_psprintf(stream->pool, "%s://%s", puri.scheme, authority); path = apr_uri_unparse(stream->pool, &puri, APR_URI_UNP_OMITSITEPART); h2_proxy_req_make(stream->req, stream->pool, r->method, scheme, authority, path, r->headers_in); Loading Loading @@ -822,6 +836,16 @@ static apr_status_t submit_stream(h2_proxy_session *session, h2_proxy_stream *st return APR_EGENERAL; } static apr_status_t submit_trailers(h2_proxy_stream *stream) { h2_proxy_ngheader *hd; int rv; hd = h2_proxy_util_nghd_make(stream->pool, stream->r->trailers_in); rv = nghttp2_submit_trailer(stream->session->ngh2, stream->id, hd->nv, hd->nvlen); return rv == 0? APR_SUCCESS: APR_EGENERAL; } static apr_status_t feed_brigade(h2_proxy_session *session, apr_bucket_brigade *bb) { apr_status_t status = APR_SUCCESS; Loading modules/http2/h2_proxy_util.c +22 −0 Original line number Diff line number Diff line Loading @@ -452,6 +452,22 @@ h2_proxy_ngheader *h2_proxy_util_nghd_make_req(apr_pool_t *p, return ngh; } h2_proxy_ngheader *h2_proxy_util_nghd_make(apr_pool_t *p, apr_table_t *headers) { h2_proxy_ngheader *ngh; size_t n; n = 0; apr_table_do(count_header, &n, headers, NULL); ngh = apr_pcalloc(p, sizeof(h2_proxy_ngheader)); ngh->nv = apr_pcalloc(p, n * sizeof(nghttp2_nv)); apr_table_do(add_table_header, ngh, headers, NULL); return ngh; } /******************************************************************************* * header HTTP/1 <-> HTTP/2 conversions ******************************************************************************/ Loading Loading @@ -609,6 +625,7 @@ apr_status_t h2_proxy_req_make(h2_proxy_request *req, apr_pool_t *pool, apr_table_t *headers) { h1_ctx x; const char *val; req->method = method; req->scheme = scheme; Loading @@ -623,6 +640,11 @@ apr_status_t h2_proxy_req_make(h2_proxy_request *req, apr_pool_t *pool, x.pool = pool; x.headers = req->headers; apr_table_do(set_h1_header, &x, headers, NULL); if ((val = apr_table_get(headers, "TE")) && ap_find_token(pool, val, "trailers")) { /* client accepts trailers, forward this information */ apr_table_addn(req->headers, "TE", "trailers"); } apr_table_setn(req->headers, "te", "trailers"); return APR_SUCCESS; } Loading modules/http2/h2_proxy_util.h +2 −0 Original line number Diff line number Diff line Loading @@ -168,6 +168,8 @@ typedef struct h2_proxy_ngheader { h2_proxy_ngheader *h2_proxy_util_nghd_make_req(apr_pool_t *p, const struct h2_proxy_request *req); h2_proxy_ngheader *h2_proxy_util_nghd_make(apr_pool_t *p, apr_table_t *headers); /******************************************************************************* * h2_proxy_request helpers ******************************************************************************/ Loading Loading
CHANGES +3 −0 Original line number Diff line number Diff line -*- coding: utf-8 -*- Changes with Apache 2.4.40 *) mod_proxy_http2: adding support for handling trailers in both directions. PR 63502. [Stefan Eissing] *) mod_proxy_http: forward 100-continue, and minimize race conditions when reusing backend connections. PR 60330. [Yann Ylavic, Jean-Frederic Clere] Loading
modules/http2/h2_proxy_session.c +34 −10 Original line number Diff line number Diff line Loading @@ -45,6 +45,7 @@ typedef struct h2_proxy_stream { unsigned int suspended : 1; unsigned int waiting_on_100 : 1; unsigned int waiting_on_ping : 1; unsigned int headers_ended : 1; uint32_t error_code; apr_bucket_brigade *input; Loading @@ -61,6 +62,7 @@ static void dispatch_event(h2_proxy_session *session, h2_proxys_event_t ev, static void ping_arrived(h2_proxy_session *session); static apr_status_t check_suspended(h2_proxy_session *session); static void stream_resume(h2_proxy_stream *stream); static apr_status_t submit_trailers(h2_proxy_stream *stream); static apr_status_t proxy_session_pre_close(void *theconn) Loading Loading @@ -241,7 +243,8 @@ static int add_header(void *table, const char *n, const char *v) return 1; } static void process_proxy_header(h2_proxy_stream *stream, const char *n, const char *v) static void process_proxy_header(apr_table_t *headers, h2_proxy_stream *stream, const char *n, const char *v) { static const struct { const char *name; Loading @@ -262,20 +265,18 @@ static void process_proxy_header(h2_proxy_stream *stream, const char *n, const c if (!dconf->preserve_host) { for (i = 0; transform_hdrs[i].name; ++i) { if (!ap_cstr_casecmp(transform_hdrs[i].name, n)) { apr_table_add(r->headers_out, n, (*transform_hdrs[i].func)(r, dconf, v)); apr_table_add(headers, n, (*transform_hdrs[i].func)(r, dconf, v)); return; } } if (!ap_cstr_casecmp("Link", n)) { dconf = ap_get_module_config(r->per_dir_config, &proxy_module); apr_table_add(r->headers_out, n, h2_proxy_link_reverse_map(r, dconf, apr_table_add(headers, n, h2_proxy_link_reverse_map(r, dconf, stream->real_server_uri, stream->p_server_uri, v)); return; } } apr_table_add(r->headers_out, n, v); apr_table_add(headers, n, v); } static apr_status_t h2_proxy_stream_add_header_out(h2_proxy_stream *stream, Loading @@ -299,8 +300,13 @@ static apr_status_t h2_proxy_stream_add_header_out(h2_proxy_stream *stream, return APR_SUCCESS; } ap_log_cerror(APLOG_MARK, APLOG_TRACE2, 0, stream->session->c, "h2_proxy_stream(%s-%d): on_header %s: %s", stream->session->id, stream->id, n, v); if (!h2_proxy_res_ignore_header(n, nlen)) { char *hname, *hvalue; apr_table_t *headers = (stream->headers_ended? stream->r->trailers_out : stream->r->headers_out); hname = apr_pstrndup(stream->pool, n, nlen); h2_proxy_util_camel_case_header(hname, nlen); Loading @@ -309,7 +315,7 @@ static apr_status_t h2_proxy_stream_add_header_out(h2_proxy_stream *stream, ap_log_cerror(APLOG_MARK, APLOG_TRACE2, 0, stream->session->c, "h2_proxy_stream(%s-%d): got header %s: %s", stream->session->id, stream->id, hname, hvalue); process_proxy_header(stream, hname, hvalue); process_proxy_header(headers, stream, hname, hvalue); } return APR_SUCCESS; } Loading Loading @@ -374,6 +380,7 @@ static void h2_proxy_stream_end_headers_out(h2_proxy_stream *stream) server_name, portstr) ); } if (r->status >= 200) stream->headers_ended = 1; if (APLOGrtrace2(stream->r)) { ap_log_rerror(APLOG_MARK, APLOG_TRACE2, 0, stream->r, Loading Loading @@ -547,9 +554,14 @@ static ssize_t stream_request_data(nghttp2_session *ngh2, int32_t stream_id, stream->data_sent += readlen; ap_log_rerror(APLOG_MARK, APLOG_DEBUG, status, stream->r, APLOGNO(03468) "h2_proxy_stream(%d): request DATA %ld, %ld" " total, flags=%d", stream->id, (long)readlen, (long)stream->data_sent, " total, flags=%d", stream->id, (long)readlen, (long)stream->data_sent, (int)*data_flags); if ((*data_flags & NGHTTP2_DATA_FLAG_EOF) && !apr_is_empty_table(stream->r->trailers_in)) { ap_log_rerror(APLOG_MARK, APLOG_DEBUG, status, stream->r, APLOGNO(03468) "h2_proxy_stream(%d): submit trailers", stream->id); *data_flags |= NGHTTP2_DATA_FLAG_NO_END_STREAM; submit_trailers(stream); } return readlen; } else if (APR_STATUS_IS_EAGAIN(status)) { Loading Loading @@ -736,6 +748,8 @@ static apr_status_t open_stream(h2_proxy_session *session, const char *url, stream->real_server_uri = apr_psprintf(stream->pool, "%s://%s", scheme, authority); stream->p_server_uri = apr_psprintf(stream->pool, "%s://%s", puri.scheme, authority); path = apr_uri_unparse(stream->pool, &puri, APR_URI_UNP_OMITSITEPART); h2_proxy_req_make(stream->req, stream->pool, r->method, scheme, authority, path, r->headers_in); Loading Loading @@ -822,6 +836,16 @@ static apr_status_t submit_stream(h2_proxy_session *session, h2_proxy_stream *st return APR_EGENERAL; } static apr_status_t submit_trailers(h2_proxy_stream *stream) { h2_proxy_ngheader *hd; int rv; hd = h2_proxy_util_nghd_make(stream->pool, stream->r->trailers_in); rv = nghttp2_submit_trailer(stream->session->ngh2, stream->id, hd->nv, hd->nvlen); return rv == 0? APR_SUCCESS: APR_EGENERAL; } static apr_status_t feed_brigade(h2_proxy_session *session, apr_bucket_brigade *bb) { apr_status_t status = APR_SUCCESS; Loading
modules/http2/h2_proxy_util.c +22 −0 Original line number Diff line number Diff line Loading @@ -452,6 +452,22 @@ h2_proxy_ngheader *h2_proxy_util_nghd_make_req(apr_pool_t *p, return ngh; } h2_proxy_ngheader *h2_proxy_util_nghd_make(apr_pool_t *p, apr_table_t *headers) { h2_proxy_ngheader *ngh; size_t n; n = 0; apr_table_do(count_header, &n, headers, NULL); ngh = apr_pcalloc(p, sizeof(h2_proxy_ngheader)); ngh->nv = apr_pcalloc(p, n * sizeof(nghttp2_nv)); apr_table_do(add_table_header, ngh, headers, NULL); return ngh; } /******************************************************************************* * header HTTP/1 <-> HTTP/2 conversions ******************************************************************************/ Loading Loading @@ -609,6 +625,7 @@ apr_status_t h2_proxy_req_make(h2_proxy_request *req, apr_pool_t *pool, apr_table_t *headers) { h1_ctx x; const char *val; req->method = method; req->scheme = scheme; Loading @@ -623,6 +640,11 @@ apr_status_t h2_proxy_req_make(h2_proxy_request *req, apr_pool_t *pool, x.pool = pool; x.headers = req->headers; apr_table_do(set_h1_header, &x, headers, NULL); if ((val = apr_table_get(headers, "TE")) && ap_find_token(pool, val, "trailers")) { /* client accepts trailers, forward this information */ apr_table_addn(req->headers, "TE", "trailers"); } apr_table_setn(req->headers, "te", "trailers"); return APR_SUCCESS; } Loading
modules/http2/h2_proxy_util.h +2 −0 Original line number Diff line number Diff line Loading @@ -168,6 +168,8 @@ typedef struct h2_proxy_ngheader { h2_proxy_ngheader *h2_proxy_util_nghd_make_req(apr_pool_t *p, const struct h2_proxy_request *req); h2_proxy_ngheader *h2_proxy_util_nghd_make(apr_pool_t *p, apr_table_t *headers); /******************************************************************************* * h2_proxy_request helpers ******************************************************************************/ Loading