summaryrefslogtreecommitdiffstats
path: root/modules/http2
diff options
context:
space:
mode:
authorStefan Eissing <icing@apache.org>2023-06-28 13:22:49 +0200
committerStefan Eissing <icing@apache.org>2023-06-28 13:22:49 +0200
commit77ae6da62cbe4a26ae8643007562cd2cdeec2a77 (patch)
tree94cc797c244478aae090096601c3830ffaaa63f0 /modules/http2
parenttests: add the websockets python module version checks needed for our CI infra (diff)
downloadapache2-77ae6da62cbe4a26ae8643007562cd2cdeec2a77.tar.xz
apache2-77ae6da62cbe4a26ae8643007562cd2cdeec2a77.zip
*) mod_http2: new directive `H2ProxyRequests on|off` to enable handling
of HTTP/2 requests in a forward proxy configuration. General forward proxying is enabled via `ProxyRequests`. If the HTTP/2 protocol is also enabled for such a server/host, this new directive is needed in addition. git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@1910656 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'modules/http2')
-rw-r--r--modules/http2/h2_config.c24
-rw-r--r--modules/http2/h2_config.h1
-rw-r--r--modules/http2/h2_request.c35
3 files changed, 58 insertions, 2 deletions
diff --git a/modules/http2/h2_config.c b/modules/http2/h2_config.c
index 7f9f18078c..e87b1c82a4 100644
--- a/modules/http2/h2_config.c
+++ b/modules/http2/h2_config.c
@@ -77,6 +77,7 @@ typedef struct h2_config {
int output_buffered;
apr_interval_time_t stream_timeout;/* beam timeout */
int max_data_frame_len; /* max # bytes in a single h2 DATA frame */
+ int proxy_requests; /* act as forward proxy */
int h2_websockets; /* if mod_h2 negotiating WebSockets */
} h2_config;
@@ -116,6 +117,7 @@ static h2_config defconf = {
1, /* stream output buffered */
-1, /* beam timeout */
0, /* max DATA frame len, 0 == no extra limit */
+ 0, /* forward proxy */
0, /* WebSockets negotiation, enabled */
};
@@ -163,6 +165,7 @@ void *h2_config_create_svr(apr_pool_t *pool, server_rec *s)
conf->output_buffered = DEF_VAL;
conf->stream_timeout = DEF_VAL;
conf->max_data_frame_len = DEF_VAL;
+ conf->proxy_requests = DEF_VAL;
conf->h2_websockets = DEF_VAL;
return conf;
}
@@ -213,6 +216,7 @@ static void *h2_config_merge(apr_pool_t *pool, void *basev, void *addv)
n->padding_always = H2_CONFIG_GET(add, base, padding_always);
n->stream_timeout = H2_CONFIG_GET(add, base, stream_timeout);
n->max_data_frame_len = H2_CONFIG_GET(add, base, max_data_frame_len);
+ n->proxy_requests = H2_CONFIG_GET(add, base, proxy_requests);
n->h2_websockets = H2_CONFIG_GET(add, base, h2_websockets);
return n;
}
@@ -305,6 +309,8 @@ static apr_int64_t h2_srv_config_geti64(const h2_config *conf, h2_config_var_t v
return H2_CONFIG_GET(conf, &defconf, stream_timeout);
case H2_CONF_MAX_DATA_FRAME_LEN:
return H2_CONFIG_GET(conf, &defconf, max_data_frame_len);
+ case H2_CONF_PROXY_REQUESTS:
+ return H2_CONFIG_GET(conf, &defconf, proxy_requests);
case H2_CONF_WEBSOCKETS:
return H2_CONFIG_GET(conf, &defconf, h2_websockets);
default:
@@ -369,6 +375,8 @@ static void h2_srv_config_seti(h2_config *conf, h2_config_var_t var, int val)
case H2_CONF_MAX_DATA_FRAME_LEN:
H2_CONFIG_SET(conf, max_data_frame_len, val);
break;
+ case H2_CONF_PROXY_REQUESTS:
+ H2_CONFIG_SET(conf, proxy_requests, val);
case H2_CONF_WEBSOCKETS:
H2_CONFIG_SET(conf, h2_websockets, val);
break;
@@ -981,6 +989,20 @@ static const char *h2_conf_set_stream_timeout(cmd_parms *cmd,
return NULL;
}
+static const char *h2_conf_set_proxy_requests(cmd_parms *cmd,
+ void *dirconf, const char *value)
+{
+ if (!strcasecmp(value, "On")) {
+ CONFIG_CMD_SET(cmd, dirconf, H2_CONF_PROXY_REQUESTS, 1);
+ return NULL;
+ }
+ else if (!strcasecmp(value, "Off")) {
+ CONFIG_CMD_SET(cmd, dirconf, H2_CONF_PROXY_REQUESTS, 0);
+ return NULL;
+ }
+ return "value must be On or Off";
+}
+
void h2_get_workers_config(server_rec *s, int *pminw, int *pmaxw,
apr_time_t *pidle_limit)
{
@@ -1050,6 +1072,8 @@ const command_rec h2_cmds[] = {
RSRC_CONF, "maximum number of bytes in a single HTTP/2 DATA frame"),
AP_INIT_TAKE2("H2EarlyHint", h2_conf_add_early_hint, NULL,
OR_FILEINFO|OR_AUTHCFG, "add a a 'Link:' header for a 103 Early Hints response."),
+ AP_INIT_TAKE1("H2ProxyRequests", h2_conf_set_proxy_requests, NULL,
+ OR_FILEINFO, "Enables forward proxy requests via HTTP/2"),
AP_INIT_TAKE1("H2WebSockets", h2_conf_set_websockets, NULL,
RSRC_CONF, "off to disable WebSockets over HTTP/2"),
AP_END_CMD
diff --git a/modules/http2/h2_config.h b/modules/http2/h2_config.h
index 1c8f86509f..15242db522 100644
--- a/modules/http2/h2_config.h
+++ b/modules/http2/h2_config.h
@@ -44,6 +44,7 @@ typedef enum {
H2_CONF_OUTPUT_BUFFER,
H2_CONF_STREAM_TIMEOUT,
H2_CONF_MAX_DATA_FRAME_LEN,
+ H2_CONF_PROXY_REQUESTS,
H2_CONF_WEBSOCKETS,
} h2_config_var_t;
diff --git a/modules/http2/h2_request.c b/modules/http2/h2_request.c
index 4e363ab0aa..135a465cfd 100644
--- a/modules/http2/h2_request.c
+++ b/modules/http2/h2_request.c
@@ -38,6 +38,7 @@
#include "h2_private.h"
#include "h2_config.h"
+#include "h2_conn_ctx.h"
#include "h2_push.h"
#include "h2_request.h"
#include "h2_util.h"
@@ -292,8 +293,14 @@ apr_bucket *h2_request_create_bucket(const h2_request *req, request_rec *r)
if (!ap_cstr_casecmp("CONNECT", req->method)) {
uri = req->authority;
}
- else if (req->scheme && (ap_cstr_casecmp(req->scheme, "http") &&
- ap_cstr_casecmp(req->scheme, "https"))) {
+ else if (h2_config_cgeti(c, H2_CONF_PROXY_REQUESTS)) {
+ /* Forward proxying: always absolute uris */
+ uri = apr_psprintf(r->pool, "%s://%s%s",
+ req->scheme, req->authority,
+ req->path ? req->path : "");
+ }
+ else if (req->scheme && ap_cstr_casecmp(req->scheme, "http")
+ && ap_cstr_casecmp(req->scheme, "https")) {
/* Client sent a non-http ':scheme', use an absolute URI */
uri = apr_psprintf(r->pool, "%s://%s%s",
req->scheme, req->authority, req->path ? req->path : "");
@@ -397,6 +404,30 @@ request_rec *h2_create_request_rec(const h2_request *req, conn_rec *c,
goto die;
}
}
+ else if (req->protocol) {
+ ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, c, APLOGNO(10460)
+ "':protocol: %s' header present in %s request",
+ req->protocol, req->method);
+ access_status = HTTP_BAD_REQUEST;
+ goto die;
+ }
+ else if (h2_config_cgeti(c, H2_CONF_PROXY_REQUESTS)) {
+ if (!req->scheme) {
+ ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, c, APLOGNO()
+ "H2ProxyRequests on, but request misses :scheme");
+ access_status = HTTP_BAD_REQUEST;
+ goto die;
+ }
+ if (!req->authority) {
+ ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, c, APLOGNO()
+ "H2ProxyRequests on, but request misses :authority");
+ access_status = HTTP_BAD_REQUEST;
+ goto die;
+ }
+ r->the_request = apr_psprintf(r->pool, "%s %s://%s%s HTTP/2.0",
+ req->method, req->scheme, req->authority,
+ req->path ? req->path : "");
+ }
else if (req->scheme && ap_cstr_casecmp(req->scheme, "http")
&& ap_cstr_casecmp(req->scheme, "https")) {
/* Client sent a ':scheme' pseudo header for something else