const char *host, uint16_t port)
{
nghttp2_session_callbacks *cbs = NULL;
+ nghttp2_settings_entry settings[2];
int rv = -1;
memset(session, 0, sizeof(*session));
goto leave;
}
/* submit initial settings */
- rv = nghttp2_submit_settings(session->ngh2, NGHTTP2_FLAG_NONE, NULL, 0);
+ settings[0].settings_id = NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS;
+ settings[0].value = 100;
+ settings[1].settings_id = NGHTTP2_SETTINGS_INITIAL_WINDOW_SIZE;
+ settings[1].value = 10 * 1024 * 1024;
+
+ rv = nghttp2_submit_settings(session->ngh2, NGHTTP2_FLAG_NONE, settings, 2);
if (rv) {
log_errf("submit settings", "error_code=%d, msg=%s\n", rv,
nghttp2_strerror(rv));
rv = -1;
goto leave;
}
+ rv = nghttp2_session_set_local_window_size(session->ngh2, NGHTTP2_FLAG_NONE,
+ 0, 10 * 1024 * 1024);
+ if (rv) {
+ log_errf("set connection window size", "error_code=%d, msg=%s\n", rv,
+ nghttp2_strerror(rv));
+ rv = -1;
+ goto leave;
+ }
rv = 0;
leave:
# we write all output to files, because we manipulate input timings
# and would run in deadlock situations with h2ws blocking operations
# because its output is not consumed
+ start = datetime.now()
with open(f'{env.gen_dir}/h2ws.stdout', 'w') as fdout:
with open(f'{env.gen_dir}/h2ws.stderr', 'w') as fderr:
proc = subprocess.Popen(args=args, stdin=subprocess.PIPE,
log.error(f'ws_run: timeout expired')
proc.kill()
proc.communicate(timeout=timeout)
+ end = datetime.now()
lines = open(f'{env.gen_dir}/h2ws.stdout').read().splitlines()
infos = [line for line in lines if line.startswith('[1] ')]
hex_content = ' '.join([line for line in lines if not line.startswith('[1] ')])
else:
frames = bytearray.fromhex(hex_content)
return ExecResult(args=args, exit_code=proc.returncode,
- stdout=b'', stderr=b''), infos, frames
+ stdout=b'', stderr=b'', duration=end - start), infos, frames
@pytest.mark.skipif(condition=H2TestEnv.is_unsupported, reason="mod_http2 not supported here")
f' H2WebSockets on',
f' ProxyPass /ws/ http://127.0.0.1:{env.ws_port}/ \\',
f' upgrade=websocket timeout=10',
+ f' ReadBufferSize 65535'
]
})
conf.add_vhost_cgi(proxy_self=True, h2proxy_self=True).install()
assert len(frames) > 0
total_len = sum([f.data_len for f in frames if f.opcode == WsFrame.BINARY])
assert total_len == flen, f'{frames}\n{r}'
+
+ # CONNECT to path with 1MB file and trigger delays between BINARY frame writes
+ @pytest.mark.parametrize("frame_len", [
+ 64 * 1024,
+ 16 * 1024,
+ 1 * 1024,
+ ])
+ def test_h2_800_17_ws_throughput(self, env: H2TestEnv, ws_server, frame_len):
+ fname = "data-1m"
+ flen = 1000*1000
+ ncount = 5
+ r, infos, frames = ws_run(env, path=f'/ws/file/{fname}/{frame_len}/0/{ncount}',
+ wait_close=0.1, send_close=False, timeout=30)
+ assert r.exit_code == 0, f'{r}'
+ assert infos == ['[1] :status: 200', '[1] EOF'], f'{r}'
+ assert len(frames) > 0
+ total_len = sum([f.data_len for f in frames if f.opcode == WsFrame.BINARY])
+ assert total_len == ncount * flen, f'{frames}\n{r}'
+ # to see these logged, invoke: `pytest -o log_cli=true`
+ log.info(f'throughput (frame-len={frame_len}): {(total_len / (1024*1024)) / r.duration.total_seconds():0.2f} MB/s')
delay_ms = 0
if len(pcomps) > 3:
delay_ms = int(pcomps[3])
- with open(fpath, 'r+b') as fd:
- while True:
- buf = fd.read(bufsize)
- if buf is None or len(buf) == 0:
- break
- await conn.send(buf)
- if delay_ms > 0:
- time.sleep(delay_ms/1000)
+ n = 1
+ if len(pcomps) > 4:
+ n = int(pcomps[4])
+ for _ in range(n):
+ with open(fpath, 'r+b') as fd:
+ while True:
+ buf = fd.read(bufsize)
+ if buf is None or len(buf) == 0:
+ break
+ await conn.send(buf)
+ if delay_ms > 0:
+ time.sleep(delay_ms/1000)
else:
log.info(f'unknown endpoint: {rpath}')
await conn.close(code=4999, reason='path unknown')