1
0
mirror of https://github.com/apache/httpd.git synced 2025-08-07 04:02:58 +03:00

*) mod_http2: added support for bootstrapping WebSockets via HTTP/2, as

described in RFC 8441. A new directive 'H2WebSockets on|off' has been
     added. The feature is by default not enabled.
     As also discussed in the manual, this feature should work for setups
     using "ProxyPass backend-url upgrade=websocket" without further changes.
     Special server modules for WebSockets will have to be adapted,
     most likely, as the handling if IO events is different with HTTP/2.
     HTTP/2 WebSockets are supported on platforms with native pipes. This
     excludes Windows.



git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@1910507 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Stefan Eissing
2023-06-20 12:01:09 +00:00
parent 93b072e61c
commit 3ed9d65b05
41 changed files with 2530 additions and 95 deletions

View File

@@ -166,6 +166,10 @@ apr_status_t h2_request_add_header(h2_request *req, apr_pool_t *pool,
&& !strncmp(H2_HEADER_AUTH, name, nlen)) {
req->authority = apr_pstrndup(pool, value, vlen);
}
else if (H2_HEADER_PROTO_LEN == nlen
&& !strncmp(H2_HEADER_PROTO, name, nlen)) {
req->protocol = apr_pstrndup(pool, value, vlen);
}
else {
char buffer[32];
memset(buffer, 0, 32);
@@ -214,6 +218,7 @@ h2_request *h2_request_clone(apr_pool_t *p, const h2_request *src)
dst->scheme = apr_pstrdup(p, src->scheme);
dst->authority = apr_pstrdup(p, src->authority);
dst->path = apr_pstrdup(p, src->path);
dst->protocol = apr_pstrdup(p, src->protocol);
dst->headers = apr_table_clone(p, src->headers);
return dst;
}
@@ -299,13 +304,13 @@ apr_bucket *h2_request_create_bucket(const h2_request *req, request_rec *r)
#endif
static void assign_headers(request_rec *r, const h2_request *req,
int no_body)
int no_body, int is_connect)
{
const char *cl;
r->headers_in = apr_table_clone(r->pool, req->headers);
if (req->authority) {
if (req->authority && !is_connect) {
/* for internal handling, we have to simulate that :authority
* came in as Host:, RFC 9113 ch. says that mismatches between
* :authority and Host: SHOULD be rejected as malformed. However,
@@ -324,36 +329,40 @@ static void assign_headers(request_rec *r, const h2_request *req,
"set 'Host: %s' from :authority", req->authority);
}
cl = apr_table_get(req->headers, "Content-Length");
if (no_body) {
if (!cl && apr_table_get(req->headers, "Content-Type")) {
/* If we have a content-type, but already seen eos, no more
* data will come. Signal a zero content length explicitly.
*/
apr_table_setn(req->headers, "Content-Length", "0");
/* Unless we open a byte stream via CONNECT, apply content-length guards. */
if (!is_connect) {
cl = apr_table_get(req->headers, "Content-Length");
if (no_body) {
if (!cl && apr_table_get(req->headers, "Content-Type")) {
/* If we have a content-type, but already seen eos, no more
* data will come. Signal a zero content length explicitly.
*/
apr_table_setn(req->headers, "Content-Length", "0");
}
}
}
#if !AP_HAS_RESPONSE_BUCKETS
else if (!cl) {
/* there may be a body and we have internal HTTP/1.1 processing.
* If the Content-Length is unspecified, we MUST simulate
* chunked Transfer-Encoding.
*
* HTTP/2 does not need a Content-Length for framing. Ideally
* all clients set the EOS flag on the header frame if they
* do not intent to send a body. However, forwarding proxies
* might just no know at the time and send an empty DATA
* frame with EOS much later.
*/
apr_table_mergen(r->headers_in, "Transfer-Encoding", "chunked");
}
else if (!cl) {
/* there may be a body and we have internal HTTP/1.1 processing.
* If the Content-Length is unspecified, we MUST simulate
* chunked Transfer-Encoding.
*
* HTTP/2 does not need a Content-Length for framing. Ideally
* all clients set the EOS flag on the header frame if they
* do not intent to send a body. However, forwarding proxies
* might just no know at the time and send an empty DATA
* frame with EOS much later.
*/
apr_table_mergen(r->headers_in, "Transfer-Encoding", "chunked");
}
#endif /* else AP_HAS_RESPONSE_BUCKETS */
}
}
request_rec *h2_create_request_rec(const h2_request *req, conn_rec *c,
int no_body)
{
int access_status = HTTP_OK;
int is_connect = !ap_cstr_casecmp("CONNECT", req->method);
#if AP_MODULE_MAGIC_AT_LEAST(20120211, 106)
request_rec *r = ap_create_request(c);
@@ -362,24 +371,43 @@ request_rec *h2_create_request_rec(const h2_request *req, conn_rec *c,
#endif
#if AP_MODULE_MAGIC_AT_LEAST(20120211, 107)
assign_headers(r, req, no_body);
assign_headers(r, req, no_body, is_connect);
ap_run_pre_read_request(r, c);
/* Time to populate r with the data we have. */
r->request_time = req->request_time;
AP_DEBUG_ASSERT(req->authority);
if (!apr_strnatcasecmp("CONNECT", req->method)) {
if (is_connect) {
/* CONNECT MUST NOT have scheme or path */
if (req->scheme) {
ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, c, APLOGNO(10458)
"':scheme: %s' header present in CONNECT request",
req->scheme);
access_status = HTTP_BAD_REQUEST;
goto die;
}
if (req->path) {
ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, c, APLOGNO(10459)
"':path: %s' header present in CONNECT request",
req->path);
access_status = HTTP_BAD_REQUEST;
goto die;
}
r->the_request = apr_psprintf(r->pool, "%s %s HTTP/2.0",
req->method, req->authority);
}
else if (req->scheme && ap_cstr_casecmp(req->scheme, "http")
&& ap_cstr_casecmp(req->scheme, "https")) {
/* FIXME: we also need to create absolute uris when we are
* in a forward proxy configuration! But there is currently
* no way to detect that. */
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 (req->scheme &&
ap_cstr_casecmp(req->scheme, ap_ssl_conn_is_ssl(c->master? c->master : c)?
"https" : "http")) {
/* Client sent a ':scheme' pseudo header for something else
* than what we handle by default. Make an absolute URI. */
* than what we have on this connection. Make an absolute URI. */
r->the_request = apr_psprintf(r->pool, "%s %s://%s%s HTTP/2.0",
req->method, req->scheme, req->authority,
req->path ? req->path : "");
@@ -420,7 +448,7 @@ request_rec *h2_create_request_rec(const h2_request *req, conn_rec *c,
{
const char *s;
assign_headers(r, req, no_body);
assign_headers(r, req, no_body, is_connect);
ap_run_pre_read_request(r, c);
/* Time to populate r with the data we have. */