mirror of
https://github.com/apache/httpd.git
synced 2025-08-08 15:02:10 +03:00
*) mod_http2: adding checks for websocket support on platform and
server versions. Give error message accordingly when trying to enable websockets in unsupported configurations. Add test and code to check the, finally selected, server of a request_rec for websocket support or 501 the request. git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@1910535 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
@@ -33,6 +33,18 @@ struct h2_stream;
|
|||||||
#define H2_USE_PIPES (APR_FILES_AS_SOCKETS && APR_VERSION_AT_LEAST(1,6,0))
|
#define H2_USE_PIPES (APR_FILES_AS_SOCKETS && APR_VERSION_AT_LEAST(1,6,0))
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if AP_MODULE_MAGIC_AT_LEAST(20211221, 15)
|
||||||
|
#define H2_USE_POLLFD_FROM_CONN 1
|
||||||
|
#else
|
||||||
|
#define H2_USE_POLLFD_FROM_CONN 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if H2_USE_POLLFD_FROM_CONN && H2_USE_PIPES
|
||||||
|
#define H2_USE_WEBSOCKETS 1
|
||||||
|
#else
|
||||||
|
#define H2_USE_WEBSOCKETS 0
|
||||||
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The magic PRIamble of RFC 7540 that is always sent when starting
|
* The magic PRIamble of RFC 7540 that is always sent when starting
|
||||||
* a h2 communication.
|
* a h2 communication.
|
||||||
|
@@ -559,6 +559,7 @@ static int c2_hook_pre_connection(conn_rec *c2, void *csd)
|
|||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if H2_USE_POLLFD_FROM_CONN
|
||||||
static apr_status_t c2_get_pollfd_from_conn(conn_rec *c,
|
static apr_status_t c2_get_pollfd_from_conn(conn_rec *c,
|
||||||
struct apr_pollfd_t *pfd,
|
struct apr_pollfd_t *pfd,
|
||||||
apr_interval_time_t *ptimeout)
|
apr_interval_time_t *ptimeout)
|
||||||
@@ -583,6 +584,7 @@ static apr_status_t c2_get_pollfd_from_conn(conn_rec *c,
|
|||||||
}
|
}
|
||||||
return APR_ENOTIMPL;
|
return APR_ENOTIMPL;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
void h2_c2_register_hooks(void)
|
void h2_c2_register_hooks(void)
|
||||||
{
|
{
|
||||||
@@ -598,12 +600,11 @@ void h2_c2_register_hooks(void)
|
|||||||
ap_hook_post_read_request(c2_post_read_request, NULL, NULL,
|
ap_hook_post_read_request(c2_post_read_request, NULL, NULL,
|
||||||
APR_HOOK_REALLY_FIRST);
|
APR_HOOK_REALLY_FIRST);
|
||||||
ap_hook_fixups(c2_hook_fixups, NULL, NULL, APR_HOOK_LAST);
|
ap_hook_fixups(c2_hook_fixups, NULL, NULL, APR_HOOK_LAST);
|
||||||
#if AP_MODULE_MAGIC_AT_LEAST(20211221, 15)
|
#if H2_USE_POLLFD_FROM_CONN
|
||||||
ap_hook_get_pollfd_from_conn(c2_get_pollfd_from_conn, NULL, NULL,
|
ap_hook_get_pollfd_from_conn(c2_get_pollfd_from_conn, NULL, NULL,
|
||||||
APR_HOOK_MIDDLE);
|
APR_HOOK_MIDDLE);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
c2_net_in_filter_handle =
|
c2_net_in_filter_handle =
|
||||||
ap_register_input_filter("H2_C2_NET_IN", h2_c2_filter_in,
|
ap_register_input_filter("H2_C2_NET_IN", h2_c2_filter_in,
|
||||||
NULL, AP_FTYPE_NETWORK);
|
NULL, AP_FTYPE_NETWORK);
|
||||||
@@ -788,7 +789,7 @@ static apr_status_t c2_process(h2_conn_ctx_t *conn_ctx, conn_rec *c)
|
|||||||
cs->state = CONN_STATE_WRITE_COMPLETION;
|
cs->state = CONN_STATE_WRITE_COMPLETION;
|
||||||
|
|
||||||
cleanup:
|
cleanup:
|
||||||
return APR_SUCCESS;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
conn_rec *h2_c2_create(conn_rec *c1, apr_pool_t *parent,
|
conn_rec *h2_c2_create(conn_rec *c1, apr_pool_t *parent,
|
||||||
|
@@ -120,20 +120,28 @@ apr_status_t h2_c2_filter_request_in(ap_filter_t *f,
|
|||||||
return APR_EGENERAL;
|
return APR_EGENERAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ap_log_cerror(APLOG_MARK, APLOG_TRACE2, 0, f->c,
|
||||||
|
"h2_c2_filter_request_in(%s): adding request bucket",
|
||||||
|
conn_ctx->id);
|
||||||
|
b = h2_request_create_bucket(req, f->r);
|
||||||
|
APR_BRIGADE_INSERT_TAIL(bb, b);
|
||||||
|
|
||||||
if (req->http_status != H2_HTTP_STATUS_UNSET) {
|
if (req->http_status != H2_HTTP_STATUS_UNSET) {
|
||||||
/* error was encountered preparing this request */
|
/* error was encountered preparing this request */
|
||||||
|
ap_log_cerror(APLOG_MARK, APLOG_TRACE2, 0, f->c,
|
||||||
|
"h2_c2_filter_request_in(%s): adding error bucket %d",
|
||||||
|
conn_ctx->id, req->http_status);
|
||||||
b = ap_bucket_error_create(req->http_status, NULL, f->r->pool,
|
b = ap_bucket_error_create(req->http_status, NULL, f->r->pool,
|
||||||
f->c->bucket_alloc);
|
f->c->bucket_alloc);
|
||||||
APR_BRIGADE_INSERT_TAIL(bb, b);
|
APR_BRIGADE_INSERT_TAIL(bb, b);
|
||||||
return APR_SUCCESS;
|
return APR_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
b = h2_request_create_bucket(req, f->r);
|
|
||||||
APR_BRIGADE_INSERT_TAIL(bb, b);
|
|
||||||
if (!conn_ctx->beam_in) {
|
if (!conn_ctx->beam_in) {
|
||||||
b = apr_bucket_eos_create(f->c->bucket_alloc);
|
b = apr_bucket_eos_create(f->c->bucket_alloc);
|
||||||
APR_BRIGADE_INSERT_TAIL(bb, b);
|
APR_BRIGADE_INSERT_TAIL(bb, b);
|
||||||
}
|
}
|
||||||
|
|
||||||
return APR_SUCCESS;
|
return APR_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -694,11 +694,13 @@ static const char *h2_conf_set_websockets(cmd_parms *cmd,
|
|||||||
void *dirconf, const char *value)
|
void *dirconf, const char *value)
|
||||||
{
|
{
|
||||||
if (!strcasecmp(value, "On")) {
|
if (!strcasecmp(value, "On")) {
|
||||||
#if H2_USE_PIPES
|
#if H2_USE_WEBSOCKETS
|
||||||
CONFIG_CMD_SET(cmd, dirconf, H2_CONF_WEBSOCKETS, 1);
|
CONFIG_CMD_SET(cmd, dirconf, H2_CONF_WEBSOCKETS, 1);
|
||||||
return NULL;
|
return NULL;
|
||||||
#else
|
#elif !H2_USE_PIPES
|
||||||
return "HTTP/2 WebSockets are not supported on this platform";
|
return "HTTP/2 WebSockets are not supported on this platform";
|
||||||
|
#else
|
||||||
|
return "HTTP/2 WebSockets are not supported in this server version";
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
else if (!strcasecmp(value, "Off")) {
|
else if (!strcasecmp(value, "Off")) {
|
||||||
|
@@ -287,13 +287,14 @@ apr_bucket *h2_request_create_bucket(const h2_request *req, request_rec *r)
|
|||||||
apr_table_t *headers = apr_table_clone(r->pool, req->headers);
|
apr_table_t *headers = apr_table_clone(r->pool, req->headers);
|
||||||
const char *uri = req->path;
|
const char *uri = req->path;
|
||||||
|
|
||||||
|
AP_DEBUG_ASSERT(req->method);
|
||||||
AP_DEBUG_ASSERT(req->authority);
|
AP_DEBUG_ASSERT(req->authority);
|
||||||
if (req->scheme && (ap_cstr_casecmp(req->scheme,
|
if (!ap_cstr_casecmp("CONNECT", req->method)) {
|
||||||
ap_ssl_conn_is_ssl(c->master? c->master : c)? "https" : "http")
|
uri = req->authority;
|
||||||
|| !ap_cstr_casecmp("CONNECT", req->method))) {
|
}
|
||||||
/* Client sent a non-matching ':scheme' pseudo header or CONNECT.
|
else if (req->scheme && (ap_cstr_casecmp(req->scheme, "http") &&
|
||||||
* In this case, we use an absolute URI.
|
ap_cstr_casecmp(req->scheme, "https"))) {
|
||||||
*/
|
/* Client sent a non-http ':scheme', use an absolute URI */
|
||||||
uri = apr_psprintf(r->pool, "%s://%s%s",
|
uri = apr_psprintf(r->pool, "%s://%s%s",
|
||||||
req->scheme, req->authority, req->path ? req->path : "");
|
req->scheme, req->authority, req->path ? req->path : "");
|
||||||
}
|
}
|
||||||
@@ -379,33 +380,25 @@ request_rec *h2_create_request_rec(const h2_request *req, conn_rec *c,
|
|||||||
AP_DEBUG_ASSERT(req->authority);
|
AP_DEBUG_ASSERT(req->authority);
|
||||||
if (is_connect) {
|
if (is_connect) {
|
||||||
/* CONNECT MUST NOT have scheme or path */
|
/* CONNECT MUST NOT have scheme or path */
|
||||||
if (req->scheme) {
|
r->the_request = apr_psprintf(r->pool, "%s %s HTTP/2.0",
|
||||||
ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, c, APLOGNO(10458)
|
req->method, req->authority);
|
||||||
"':scheme: %s' header present in CONNECT request",
|
if (req->scheme) {
|
||||||
req->scheme);
|
ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, c, APLOGNO(10458)
|
||||||
access_status = HTTP_BAD_REQUEST;
|
"':scheme: %s' header present in CONNECT request",
|
||||||
goto die;
|
req->scheme);
|
||||||
}
|
access_status = HTTP_BAD_REQUEST;
|
||||||
if (req->path) {
|
goto die;
|
||||||
ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, c, APLOGNO(10459)
|
}
|
||||||
"':path: %s' header present in CONNECT request",
|
else if (req->path) {
|
||||||
req->path);
|
ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, c, APLOGNO(10459)
|
||||||
access_status = HTTP_BAD_REQUEST;
|
"':path: %s' header present in CONNECT request",
|
||||||
goto die;
|
req->path);
|
||||||
}
|
access_status = HTTP_BAD_REQUEST;
|
||||||
r->the_request = apr_psprintf(r->pool, "%s %s HTTP/2.0",
|
goto die;
|
||||||
req->method, req->authority);
|
}
|
||||||
}
|
}
|
||||||
else if (req->protocol) {
|
else if (req->scheme && ap_cstr_casecmp(req->scheme, "http")
|
||||||
ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, c, APLOGNO(10460)
|
&& ap_cstr_casecmp(req->scheme, "https")) {
|
||||||
"':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
|
/* Client sent a ':scheme' pseudo header for something else
|
||||||
* than what we have on this connection. 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",
|
r->the_request = apr_psprintf(r->pool, "%s %s://%s%s HTTP/2.0",
|
||||||
|
@@ -900,11 +900,23 @@ apr_status_t h2_stream_end_headers(h2_stream *stream, int eos, size_t raw_bytes)
|
|||||||
* of CONNECT requests (see [RFC7230], Section 5.3)).
|
* of CONNECT requests (see [RFC7230], Section 5.3)).
|
||||||
*/
|
*/
|
||||||
if (!ap_cstr_casecmp(req->method, "CONNECT")) {
|
if (!ap_cstr_casecmp(req->method, "CONNECT")) {
|
||||||
if (req->protocol && !strcmp("websocket", req->protocol)) {
|
if (req->protocol) {
|
||||||
if (!req->scheme || !req->path) {
|
if (!strcmp("websocket", req->protocol)) {
|
||||||
ap_log_cerror(APLOG_MARK, APLOG_INFO, 0, stream->session->c1,
|
if (!req->scheme || !req->path) {
|
||||||
H2_STRM_LOG(APLOGNO(10457), stream, "Request to websocket CONNECT "
|
ap_log_cerror(APLOG_MARK, APLOG_INFO, 0, stream->session->c1,
|
||||||
"without :scheme or :path, sending 400 answer"));
|
H2_STRM_LOG(APLOGNO(10457), stream, "Request to websocket CONNECT "
|
||||||
|
"without :scheme or :path, sending 400 answer"));
|
||||||
|
set_error_response(stream, HTTP_BAD_REQUEST);
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
/* do not know that protocol */
|
||||||
|
ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, stream->session->c1, APLOGNO(10460)
|
||||||
|
"':protocol: %s' header present in %s request",
|
||||||
|
req->protocol, req->method);
|
||||||
|
set_error_response(stream, HTTP_NOT_IMPLEMENTED);
|
||||||
|
goto cleanup;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (req->scheme || req->path) {
|
else if (req->scheme || req->path) {
|
||||||
|
@@ -43,6 +43,8 @@
|
|||||||
#include "h2_request.h"
|
#include "h2_request.h"
|
||||||
#include "h2_ws.h"
|
#include "h2_ws.h"
|
||||||
|
|
||||||
|
#if H2_USE_WEBSOCKETS
|
||||||
|
|
||||||
static ap_filter_rec_t *c2_ws_out_filter_handle;
|
static ap_filter_rec_t *c2_ws_out_filter_handle;
|
||||||
|
|
||||||
struct ws_filter_ctx {
|
struct ws_filter_ctx {
|
||||||
@@ -318,9 +320,41 @@ static apr_status_t h2_c2_ws_filter_out(ap_filter_t* f, apr_bucket_brigade* bb)
|
|||||||
return ap_pass_brigade(f->next, bb);
|
return ap_pass_brigade(f->next, bb);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int ws_post_read(request_rec *r)
|
||||||
|
{
|
||||||
|
|
||||||
|
if (r->connection->master) {
|
||||||
|
h2_conn_ctx_t *conn_ctx = h2_conn_ctx_get(r->connection);
|
||||||
|
if (conn_ctx && conn_ctx->is_upgrade &&
|
||||||
|
!h2_config_sgeti(r->server, H2_CONF_WEBSOCKETS)) {
|
||||||
|
return HTTP_NOT_IMPLEMENTED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return DECLINED;
|
||||||
|
}
|
||||||
|
|
||||||
void h2_ws_register_hooks(void)
|
void h2_ws_register_hooks(void)
|
||||||
{
|
{
|
||||||
|
ap_hook_post_read_request(ws_post_read, NULL, NULL, APR_HOOK_MIDDLE);
|
||||||
c2_ws_out_filter_handle =
|
c2_ws_out_filter_handle =
|
||||||
ap_register_output_filter("H2_C2_WS_OUT", h2_c2_ws_filter_out,
|
ap_register_output_filter("H2_C2_WS_OUT", h2_c2_ws_filter_out,
|
||||||
NULL, AP_FTYPE_NETWORK);
|
NULL, AP_FTYPE_NETWORK);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#else /* H2_USE_WEBSOCKETS */
|
||||||
|
|
||||||
|
const h2_request *h2_ws_rewrite_request(const h2_request *req,
|
||||||
|
conn_rec *c2, int no_body)
|
||||||
|
{
|
||||||
|
(void)c2;
|
||||||
|
(void)no_body;
|
||||||
|
/* no rewriting */
|
||||||
|
return req;
|
||||||
|
}
|
||||||
|
|
||||||
|
void h2_ws_register_hooks(void)
|
||||||
|
{
|
||||||
|
/* NOP */
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* H2_USE_WEBSOCKETS (else part) */
|
||||||
|
@@ -5,11 +5,8 @@ import shutil
|
|||||||
import subprocess
|
import subprocess
|
||||||
import time
|
import time
|
||||||
from datetime import timedelta, datetime
|
from datetime import timedelta, datetime
|
||||||
from typing import Tuple, Union, List
|
|
||||||
import packaging.version
|
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
import websockets
|
|
||||||
from pyhttpd.result import ExecResult
|
from pyhttpd.result import ExecResult
|
||||||
from pyhttpd.ws_util import WsFrameReader, WsFrame
|
from pyhttpd.ws_util import WsFrameReader, WsFrame
|
||||||
|
|
||||||
@@ -18,18 +15,15 @@ from .env import H2Conf, H2TestEnv
|
|||||||
|
|
||||||
log = logging.getLogger(__name__)
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
ws_version = packaging.version.parse(websockets.version.version)
|
|
||||||
ws_version_min = packaging.version.Version('10.4')
|
|
||||||
|
|
||||||
|
def ws_run(env: H2TestEnv, path, authority=None, do_input=None, inbytes=None,
|
||||||
def ws_run(env: H2TestEnv, path, do_input=None,
|
send_close=True, timeout=5, scenario='ws-stdin',
|
||||||
inbytes=None, send_close=True,
|
wait_close: float = 0.0):
|
||||||
timeout=5, scenario='ws-stdin',
|
|
||||||
wait_close: float = 0.0) -> Tuple[ExecResult, List[str], Union[List[WsFrame], bytes]]:
|
|
||||||
""" Run the h2ws test client in various scenarios with given input and
|
""" Run the h2ws test client in various scenarios with given input and
|
||||||
timings.
|
timings.
|
||||||
:param env: the test environment
|
:param env: the test environment
|
||||||
:param path: the path on the Apache server to CONNECt to
|
:param path: the path on the Apache server to CONNECt to
|
||||||
|
:param authority: the host:port to use as
|
||||||
:param do_input: a Callable for sending input to h2ws
|
:param do_input: a Callable for sending input to h2ws
|
||||||
:param inbytes: fixed bytes to send to h2ws, unless do_input is given
|
:param inbytes: fixed bytes to send to h2ws, unless do_input is given
|
||||||
:param send_close: send a CLOSE WebSockets frame at the end
|
:param send_close: send a CLOSE WebSockets frame at the end
|
||||||
@@ -41,9 +35,11 @@ def ws_run(env: H2TestEnv, path, do_input=None,
|
|||||||
h2ws = os.path.join(env.clients_dir, 'h2ws')
|
h2ws = os.path.join(env.clients_dir, 'h2ws')
|
||||||
if not os.path.exists(h2ws):
|
if not os.path.exists(h2ws):
|
||||||
pytest.fail(f'test client not build: {h2ws}')
|
pytest.fail(f'test client not build: {h2ws}')
|
||||||
|
if authority is None:
|
||||||
|
authority = f'cgi.{env.http_tld}:{env.http_port}'
|
||||||
args = [
|
args = [
|
||||||
h2ws, '-vv', '-c', f'localhost:{env.http_port}',
|
h2ws, '-vv', '-c', f'localhost:{env.http_port}',
|
||||||
f'ws://cgi.{env.http_tld}:{env.http_port}{path}',
|
f'ws://{authority}{path}',
|
||||||
scenario
|
scenario
|
||||||
]
|
]
|
||||||
# we write all output to files, because we manipulate input timings
|
# we write all output to files, because we manipulate input timings
|
||||||
@@ -80,8 +76,8 @@ def ws_run(env: H2TestEnv, path, do_input=None,
|
|||||||
|
|
||||||
|
|
||||||
@pytest.mark.skipif(condition=H2TestEnv.is_unsupported, reason="mod_http2 not supported here")
|
@pytest.mark.skipif(condition=H2TestEnv.is_unsupported, reason="mod_http2 not supported here")
|
||||||
@pytest.mark.skipif(condition=ws_version < ws_version_min,
|
@pytest.mark.skipif(condition=not H2TestEnv().httpd_is_at_least("2.5.0"),
|
||||||
reason=f'websockets is {ws_version}, need at least {ws_version_min}')
|
reason=f'need at least httpd 2.5.0 for this')
|
||||||
class TestWebSockets:
|
class TestWebSockets:
|
||||||
|
|
||||||
@pytest.fixture(autouse=True, scope='class')
|
@pytest.fixture(autouse=True, scope='class')
|
||||||
@@ -97,6 +93,7 @@ class TestWebSockets:
|
|||||||
]
|
]
|
||||||
})
|
})
|
||||||
conf.add_vhost_cgi(proxy_self=True, h2proxy_self=True).install()
|
conf.add_vhost_cgi(proxy_self=True, h2proxy_self=True).install()
|
||||||
|
conf.add_vhost_test1(proxy_self=True, h2proxy_self=True).install()
|
||||||
assert env.apache_restart() == 0
|
assert env.apache_restart() == 0
|
||||||
|
|
||||||
def ws_check_alive(self, env, timeout=5):
|
def ws_check_alive(self, env, timeout=5):
|
||||||
@@ -150,7 +147,7 @@ class TestWebSockets:
|
|||||||
def test_h2_800_02_fail_proto(self, env: H2TestEnv, ws_server):
|
def test_h2_800_02_fail_proto(self, env: H2TestEnv, ws_server):
|
||||||
r, infos, frames = ws_run(env, path='/ws/echo/', scenario='fail-proto')
|
r, infos, frames = ws_run(env, path='/ws/echo/', scenario='fail-proto')
|
||||||
assert r.exit_code == 0, f'{r}'
|
assert r.exit_code == 0, f'{r}'
|
||||||
assert infos == ['[1] :status: 400', '[1] EOF'], f'{r}'
|
assert infos == ['[1] :status: 501', '[1] EOF'], f'{r}'
|
||||||
|
|
||||||
# CONNECT to a URL path that does not exist on the server
|
# CONNECT to a URL path that does not exist on the server
|
||||||
def test_h2_800_03_not_found(self, env: H2TestEnv, ws_server):
|
def test_h2_800_03_not_found(self, env: H2TestEnv, ws_server):
|
||||||
@@ -193,11 +190,18 @@ class TestWebSockets:
|
|||||||
assert infos == ['[1] RST'], f'{r}'
|
assert infos == ['[1] RST'], f'{r}'
|
||||||
|
|
||||||
# CONNECT missing the :authority header
|
# CONNECT missing the :authority header
|
||||||
def test_h2_800_09_miss_authority(self, env: H2TestEnv, ws_server):
|
def test_h2_800_09a_miss_authority(self, env: H2TestEnv, ws_server):
|
||||||
r, infos, frames = ws_run(env, path='/ws/echo/', scenario='miss-authority')
|
r, infos, frames = ws_run(env, path='/ws/echo/', scenario='miss-authority')
|
||||||
assert r.exit_code == 0, f'{r}'
|
assert r.exit_code == 0, f'{r}'
|
||||||
assert infos == ['[1] RST'], f'{r}'
|
assert infos == ['[1] RST'], f'{r}'
|
||||||
|
|
||||||
|
# CONNECT to authority with disabled websockets
|
||||||
|
def test_h2_800_09b_unsupported(self, env: H2TestEnv, ws_server):
|
||||||
|
r, infos, frames = ws_run(env, path='/ws/echo/',
|
||||||
|
authority=f'test1.{env.http_tld}:{env.http_port}')
|
||||||
|
assert r.exit_code == 0, f'{r}'
|
||||||
|
assert infos == ['[1] :status: 501', '[1] EOF'], f'{r}'
|
||||||
|
|
||||||
# CONNECT and exchange a PING
|
# CONNECT and exchange a PING
|
||||||
def test_h2_800_10_ws_ping(self, env: H2TestEnv, ws_server):
|
def test_h2_800_10_ws_ping(self, env: H2TestEnv, ws_server):
|
||||||
ping = WsFrame.client_ping(b'12345')
|
ping = WsFrame.client_ping(b'12345')
|
||||||
|
Reference in New Issue
Block a user