lib: client writer tweaks

- keep pause state at request
- keep presense of content decoding writers at request
- only add cw-pause writer when content decoding happens
- define macro for passing data down the writer chain

scorecard: add option to test with h2o server

Closes #22335
This commit is contained in:
Stefan Eissing 2026-07-16 11:26:33 +02:00 committed by Daniel Stenberg
parent f65253056a
commit b41c28e70a
No known key found for this signature in database
GPG key ID: 5CC908FDB71E12C2
8 changed files with 138 additions and 173 deletions

View file

@ -97,7 +97,6 @@ static void cw_out_buf_free(struct cw_out_buf *cwbuf)
struct cw_out_ctx {
struct Curl_cwriter super;
struct cw_out_buf *buf;
BIT(paused);
BIT(errored);
};
@ -171,8 +170,7 @@ static void cw_get_writefunc(struct Curl_easy *data, cw_out_type otype,
}
}
static CURLcode cw_out_cb_write(struct cw_out_ctx *ctx,
struct Curl_easy *data,
static CURLcode cw_out_cb_write(struct Curl_easy *data,
curl_write_callback wcb,
void *wcb_data,
cw_out_type otype,
@ -200,7 +198,7 @@ static CURLcode cw_out_cb_write(struct cw_out_ctx *ctx,
failf(data, "Write callback asked for PAUSE when not supported");
return CURLE_WRITE_ERROR;
}
ctx->paused = TRUE;
data->req.writer.paused = TRUE;
CURL_TRC_WRITE(data, "[OUT] PAUSE requested by client");
result = Curl_xfer_pause_recv(data, TRUE);
return result ? result : CURLE_AGAIN;
@ -245,18 +243,18 @@ static CURLcode cw_out_ptr_flush(struct cw_out_ctx *ctx,
*pconsumed = 0;
if(otype == CW_OUT_BODY_0LEN) {
DEBUGASSERT(!blen);
return cw_out_cb_write(ctx, data, wcb, wcb_data, otype,
return cw_out_cb_write(data, wcb, wcb_data, otype,
buf, blen, &nwritten);
}
else {
while(blen && !ctx->paused) {
while(blen && !data->req.writer.paused) {
if(!flush_all && blen < min_write)
break;
wlen = max_write ? CURLMIN(blen, max_write) : blen;
if(otype == CW_OUT_BODY)
result = Curl_pgrs_deliver_check(data, wlen);
if(!result)
result = cw_out_cb_write(ctx, data, wcb, wcb_data, otype,
result = cw_out_cb_write(data, wcb, wcb_data, otype,
buf, wlen, &nwritten);
if(result)
return result;
@ -314,7 +312,7 @@ static CURLcode cw_out_flush_chain(struct cw_out_ctx *ctx,
if(!cwbuf)
return CURLE_OK;
if(ctx->paused)
if(data->req.writer.paused)
return CURLE_OK;
/* write the end of the chain until it blocks or gets empty */
@ -327,7 +325,7 @@ static CURLcode cw_out_flush_chain(struct cw_out_ctx *ctx,
return result;
if(*plast) {
/* could not write last, paused again? */
DEBUGASSERT(ctx->paused);
DEBUGASSERT(data->req.writer.paused);
return CURLE_OK;
}
}
@ -457,7 +455,7 @@ static CURLcode cw_out_do_flush(struct Curl_easy *data,
if(ctx->errored)
return CURLE_WRITE_ERROR;
if(ctx->paused)
if(data->req.writer.paused)
return CURLE_OK; /* not doing it */
result = cw_out_flush_chain(ctx, data, &ctx->buf, flush_all);
@ -486,33 +484,6 @@ const struct Curl_cwtype Curl_cwt_out = {
sizeof(struct cw_out_ctx)
};
bool Curl_cw_out_is_paused(struct Curl_easy *data)
{
struct Curl_cwriter *cw_out;
struct cw_out_ctx *ctx;
cw_out = Curl_cwriter_get_by_type(data, &Curl_cwt_out);
if(!cw_out)
return FALSE;
ctx = (struct cw_out_ctx *)cw_out;
return (bool)ctx->paused;
}
CURLcode Curl_cw_out_unpause(struct Curl_easy *data)
{
struct Curl_cwriter *cw_out;
CURLcode result = CURLE_OK;
cw_out = Curl_cwriter_get_by_type(data, &Curl_cwt_out);
if(cw_out) {
struct cw_out_ctx *ctx = (struct cw_out_ctx *)cw_out;
CURL_TRC_WRITE(data, "[OUT] unpause");
ctx->paused = FALSE;
}
return result;
}
CURLcode Curl_cw_out_done(struct Curl_easy *data)
{
struct Curl_cwriter *cw_out;

View file

@ -34,16 +34,6 @@ struct Curl_easy;
*/
extern const struct Curl_cwtype Curl_cwt_out;
/**
* Return TRUE iff 'cw-out' client write has paused data.
*/
bool Curl_cw_out_is_paused(struct Curl_easy *data);
/**
* Flush any buffered date to the client, chunk collation still applies.
*/
CURLcode Curl_cw_out_unpause(struct Curl_easy *data);
/**
* Mark EndOfStream reached and flush ALL data to the client.
*/

View file

@ -100,7 +100,6 @@ static CURLcode cw_pause_flush(struct Curl_easy *data,
struct Curl_cwriter *cw_pause)
{
struct cw_pause_ctx *ctx = (struct cw_pause_ctx *)cw_pause;
bool decoding = Curl_cwriter_is_content_decoding(data);
CURLcode result = CURLE_OK;
/* write the end of the chain until it blocks or gets empty */
@ -112,7 +111,7 @@ static CURLcode cw_pause_flush(struct Curl_easy *data,
while((*plast)->next) /* got to last in list */
plast = &(*plast)->next;
if(Curl_bufq_peek(&(*plast)->b, &buf, &blen)) {
wlen = (decoding && ((*plast)->type & CLIENTWRITE_BODY)) ?
wlen = ((*plast)->type & CLIENTWRITE_BODY) ?
CURLMIN(blen, CW_PAUSE_DEC_WRITE_CHUNK) : blen;
result = Curl_cwriter_write(data, cw_pause->next, (*plast)->type,
(const char *)buf, wlen);
@ -151,7 +150,6 @@ static CURLcode cw_pause_write(struct Curl_easy *data,
struct cw_pause_ctx *ctx = writer->ctx;
CURLcode result = CURLE_OK;
size_t wlen = 0;
bool decoding = Curl_cwriter_is_content_decoding(data);
if(ctx->buf && !Curl_cwriter_is_paused(data)) {
result = cw_pause_flush(data, writer);
@ -164,7 +162,7 @@ static CURLcode cw_pause_write(struct Curl_easy *data,
DEBUGASSERT(!ctx->buf);
/* content decoding might blow up size considerably, write smaller
* chunks to make pausing need buffer less. */
wlen = (decoding && (type & CLIENTWRITE_BODY)) ?
wlen = (type & CLIENTWRITE_BODY) ?
CURLMIN(blen, CW_PAUSE_DEC_WRITE_CHUNK) : blen;
if(wlen < blen)
wtype &= ~CLIENTWRITE_EOS;

View file

@ -101,10 +101,16 @@ struct SingleRequest {
/* Client Writer stack, handles transfer- and content-encodings, protocol
* checks, pausing by client callbacks. */
struct Curl_cwriter *writer_stack;
struct {
struct Curl_cwriter *stack;
BIT(paused);
} writer;
/* Client Reader stack, handles transfer- and content-encodings, protocol
* checks, pausing by client callbacks. */
struct Curl_creader *reader_stack;
struct {
struct Curl_creader *stack;
BIT(paused);
} reader;
struct bufq sendbuf; /* data which needs to be send to the server */
size_t sendbuf_hds_len; /* amount of header bytes in sendbuf */
time_t timeofdoc;

View file

@ -46,24 +46,24 @@
static void cl_reset_writer(struct Curl_easy *data)
{
struct Curl_cwriter *writer = data->req.writer_stack;
struct Curl_cwriter *writer = data->req.writer.stack;
while(writer) {
data->req.writer_stack = writer->next;
data->req.writer.stack = writer->next;
writer->cwt->do_close(data, writer);
curlx_free(writer);
writer = data->req.writer_stack;
writer = data->req.writer.stack;
}
}
static void cl_reset_reader(struct Curl_easy *data)
{
struct Curl_creader *reader = data->req.reader_stack;
struct Curl_creader *reader = data->req.reader.stack;
data->req.reader_started = FALSE;
while(reader) {
data->req.reader_stack = reader->next;
data->req.reader.stack = reader->next;
reader->crt->do_close(data, reader);
curlx_free(reader);
reader = data->req.reader_stack;
reader = data->req.reader.stack;
}
}
@ -95,7 +95,7 @@ void Curl_client_reset(struct Curl_easy *data)
CURLcode Curl_client_start(struct Curl_easy *data)
{
if(data->req.rewind_read) {
struct Curl_creader *r = data->req.reader_stack;
struct Curl_creader *r = data->req.reader.stack;
CURLcode result = CURLE_OK;
CURL_TRC_READ(data, "client start, rewind readers");
@ -124,25 +124,6 @@ void Curl_creader_set_rewind(struct Curl_easy *data, bool enable)
data->req.rewind_read = !!enable;
}
/* Write data using an unencoding writer stack. */
CURLcode Curl_cwriter_write(struct Curl_easy *data,
struct Curl_cwriter *writer, int type,
const char *buf, size_t nbytes)
{
if(!writer)
return CURLE_WRITE_ERROR;
return writer->cwt->do_write(data, writer, type, buf, nbytes);
}
CURLcode Curl_cwriter_flush(struct Curl_easy *data,
struct Curl_cwriter *writer)
{
if(!writer) {
return CURLE_WRITE_ERROR;
}
return writer->cwt->do_flush(data, writer);
}
CURLcode Curl_cwriter_def_init(struct Curl_easy *data,
struct Curl_cwriter *writer)
{
@ -340,47 +321,39 @@ static const struct Curl_cwtype cw_raw = {
sizeof(struct Curl_cwriter)
};
static void cwriter_add(struct Curl_easy *data,
struct Curl_cwriter *writer)
{
struct Curl_cwriter **anchor = &data->req.writer.stack;
/* Insert the writer as first in its phase.
* Skip existing writers of lower phases. */
while(*anchor && (*anchor)->phase < writer->phase)
anchor = &((*anchor)->next);
writer->next = *anchor;
*anchor = writer;
}
static CURLcode do_init_writer_stack(struct Curl_easy *data)
{
struct Curl_cwriter *writer;
CURLcode result;
DEBUGASSERT(!data->req.writer_stack);
result = Curl_cwriter_create(&data->req.writer_stack,
DEBUGASSERT(!data->req.writer.stack);
result = Curl_cwriter_create(&data->req.writer.stack,
data, &Curl_cwt_out, CURL_CW_CLIENT);
if(result)
return result;
/* This places the "pause" writer behind the "download" writer that
* is added below. Meaning the "download" can do checks on content length
* and other things *before* write outs are buffered for paused transfers. */
result = Curl_cwriter_create(&writer, data, &Curl_cwt_pause,
CURL_CW_PROTOCOL);
if(!result) {
result = Curl_cwriter_add(data, writer);
if(result)
Curl_cwriter_free(data, writer);
}
if(result)
return result;
result = Curl_cwriter_create(&writer, data, &cw_download, CURL_CW_PROTOCOL);
if(!result) {
result = Curl_cwriter_add(data, writer);
if(result)
Curl_cwriter_free(data, writer);
}
if(result)
return result;
cwriter_add(data, writer);
result = Curl_cwriter_create(&writer, data, &cw_raw, CURL_CW_RAW);
if(!result) {
result = Curl_cwriter_add(data, writer);
if(result)
Curl_cwriter_free(data, writer);
}
if(result)
return result;
cwriter_add(data, writer);
return result;
}
@ -405,14 +378,14 @@ CURLcode Curl_client_write(struct Curl_easy *data, int type, const char *buf,
DEBUGASSERT(!(type & CLIENTWRITE_INFO) ||
((type & ~(CLIENTWRITE_INFO | CLIENTWRITE_EOS)) == 0));
if(!data->req.writer_stack) {
if(!data->req.writer.stack) {
result = do_init_writer_stack(data);
if(result)
return result;
DEBUGASSERT(data->req.writer_stack);
DEBUGASSERT(data->req.writer.stack);
}
result = Curl_cwriter_write(data, data->req.writer_stack, type, buf, len);
result = Curl_cwriter_write(data, data->req.writer.stack, type, buf, len);
CURL_TRC_WRITE(data, "client_write(type=%x, len=%zu) -> %d",
(unsigned int)type, len, (int)result);
return result;
@ -422,14 +395,14 @@ CURLcode Curl_client_flush(struct Curl_easy *data)
{
CURLcode result;
if(!data->req.writer_stack) {
if(!data->req.writer.stack) {
result = do_init_writer_stack(data);
if(result)
return result;
DEBUGASSERT(data->req.writer_stack);
DEBUGASSERT(data->req.writer.stack);
}
result = Curl_cwriter_flush(data, data->req.writer_stack);
result = Curl_cwriter_flush(data, data->req.writer.stack);
CURL_TRC_WRITE(data, "client_flush() -> %d", (int)result);
return result;
}
@ -476,18 +449,33 @@ size_t Curl_cwriter_count(struct Curl_easy *data, Curl_cwriter_phase phase)
struct Curl_cwriter *w;
size_t n = 0;
for(w = data->req.writer_stack; w; w = w->next) {
for(w = data->req.writer.stack; w; w = w->next) {
if(w->phase == phase)
++n;
}
return n;
}
static CURLcode cwriter_ensure_pause_writer(struct Curl_easy *data)
{
struct Curl_cwriter *writer =
Curl_cwriter_get_by_type(data, &Curl_cwt_pause);
CURLcode result = CURLE_OK;
if(!writer) {
result = Curl_cwriter_create(&writer, data, &Curl_cwt_pause,
CURL_CW_BEFORE_DECODE);
if(!result)
cwriter_add(data, writer);
}
return result;
}
CURLcode Curl_cwriter_add(struct Curl_easy *data,
struct Curl_cwriter *writer)
{
CURLcode result;
struct Curl_cwriter **anchor = &data->req.writer_stack;
struct Curl_cwriter **anchor = &data->req.writer.stack;
if(!*anchor) {
result = do_init_writer_stack(data);
@ -495,12 +483,16 @@ CURLcode Curl_cwriter_add(struct Curl_easy *data,
return result;
}
/* Insert the writer as first in its phase.
* Skip existing writers of lower phases. */
while(*anchor && (*anchor)->phase < writer->phase)
anchor = &((*anchor)->next);
writer->next = *anchor;
*anchor = writer;
if(writer->phase == CURL_CW_CONTENT_DECODE) {
/* On adding a content decoder, add the pause writer. Do this
* BEFORE the given writer as any failure will make the
* caller destroy the writer again. */
result = cwriter_ensure_pause_writer(data);
if(result)
return result;
}
cwriter_add(data, writer);
return CURLE_OK;
}
@ -508,7 +500,7 @@ struct Curl_cwriter *Curl_cwriter_get_by_name(struct Curl_easy *data,
const char *name)
{
struct Curl_cwriter *writer;
for(writer = data->req.writer_stack; writer; writer = writer->next) {
for(writer = data->req.writer.stack; writer; writer = writer->next) {
if(!strcmp(name, writer->cwt->name))
return writer;
}
@ -519,34 +511,17 @@ struct Curl_cwriter *Curl_cwriter_get_by_type(struct Curl_easy *data,
const struct Curl_cwtype *cwt)
{
struct Curl_cwriter *writer;
for(writer = data->req.writer_stack; writer; writer = writer->next) {
for(writer = data->req.writer.stack; writer; writer = writer->next) {
if(writer->cwt == cwt)
return writer;
}
return NULL;
}
bool Curl_cwriter_is_content_decoding(struct Curl_easy *data)
{
struct Curl_cwriter *writer;
for(writer = data->req.writer_stack; writer; writer = writer->next) {
if(writer->phase == CURL_CW_CONTENT_DECODE)
return TRUE;
}
return FALSE;
}
bool Curl_cwriter_is_paused(struct Curl_easy *data)
{
return Curl_cw_out_is_paused(data);
}
CURLcode Curl_cwriter_unpause(struct Curl_easy *data)
{
CURLcode result = Curl_cw_out_unpause(data);
if(!result)
result = Curl_cwriter_flush(data, data->req.writer_stack);
return result;
data->req.writer.paused = FALSE;
return Curl_cwriter_flush(data, data->req.writer.stack);
}
CURLcode Curl_creader_read(struct Curl_easy *data,
@ -1141,9 +1116,9 @@ static CURLcode do_init_reader_stack(struct Curl_easy *data,
DEBUGASSERT(r);
DEBUGASSERT(r->crt);
DEBUGASSERT(r->phase == CURL_CR_CLIENT);
DEBUGASSERT(!data->req.reader_stack);
DEBUGASSERT(!data->req.reader.stack);
data->req.reader_stack = r;
data->req.reader.stack = r;
clen = r->crt->total_length(data, r);
/* if we do not have 0 length init, and crlf conversion is wanted,
* add the reader for it */
@ -1184,7 +1159,7 @@ CURLcode Curl_creader_add(struct Curl_easy *data,
struct Curl_creader *reader)
{
CURLcode result;
struct Curl_creader **anchor = &data->req.reader_stack;
struct Curl_creader **anchor = &data->req.reader.stack;
if(!*anchor) {
result = Curl_creader_set_fread(data, data->state.infilesize);
@ -1227,11 +1202,11 @@ CURLcode Curl_client_read(struct Curl_easy *data, char *buf, size_t blen,
DEBUGASSERT(eos);
*nread = 0;
if(!data->req.reader_stack) {
if(!data->req.reader.stack) {
result = Curl_creader_set_fread(data, data->state.infilesize);
if(result)
return result;
DEBUGASSERT(data->req.reader_stack);
DEBUGASSERT(data->req.reader.stack);
}
if(!data->req.reader_started) {
Curl_rlimit_start(&data->progress.ul.rlimit, Curl_pgrs_now(data), -1);
@ -1248,7 +1223,7 @@ CURLcode Curl_client_read(struct Curl_easy *data, char *buf, size_t blen,
if(ul_avail < (curl_off_t)blen)
blen = (size_t)ul_avail;
}
result = Curl_creader_read(data, data->req.reader_stack, buf, blen,
result = Curl_creader_read(data, data->req.reader.stack, buf, blen,
nread, eos);
out:
@ -1259,7 +1234,7 @@ out:
bool Curl_creader_needs_rewind(struct Curl_easy *data)
{
struct Curl_creader *reader = data->req.reader_stack;
struct Curl_creader *reader = data->req.reader.stack;
while(reader) {
if(reader->crt->needs_rewind(data, reader)) {
CURL_TRC_READ(data, "client reader needs rewind before next request");
@ -1445,13 +1420,13 @@ out:
curl_off_t Curl_creader_total_length(struct Curl_easy *data)
{
struct Curl_creader *r = data->req.reader_stack;
struct Curl_creader *r = data->req.reader.stack;
return r ? r->crt->total_length(data, r) : -1;
}
curl_off_t Curl_creader_client_length(struct Curl_easy *data)
{
struct Curl_creader *r = data->req.reader_stack;
struct Curl_creader *r = data->req.reader.stack;
while(r && r->phase != CURL_CR_CLIENT)
r = r->next;
return r ? r->crt->total_length(data, r) : -1;
@ -1459,7 +1434,7 @@ curl_off_t Curl_creader_client_length(struct Curl_easy *data)
CURLcode Curl_creader_resume_from(struct Curl_easy *data, curl_off_t offset)
{
struct Curl_creader *r = data->req.reader_stack;
struct Curl_creader *r = data->req.reader.stack;
while(r && r->phase != CURL_CR_CLIENT)
r = r->next;
return r ? r->crt->resume_from(data, r, offset) : CURLE_READ_ERROR;
@ -1467,7 +1442,7 @@ CURLcode Curl_creader_resume_from(struct Curl_easy *data, curl_off_t offset)
CURLcode Curl_creader_unpause(struct Curl_easy *data)
{
struct Curl_creader *reader = data->req.reader_stack;
struct Curl_creader *reader = data->req.reader.stack;
CURLcode result = CURLE_OK;
while(reader) {
@ -1482,7 +1457,7 @@ CURLcode Curl_creader_unpause(struct Curl_easy *data)
bool Curl_creader_is_paused(struct Curl_easy *data)
{
struct Curl_creader *reader = data->req.reader_stack;
struct Curl_creader *reader = data->req.reader.stack;
while(reader) {
if(reader->crt->is_paused(data, reader))
@ -1494,7 +1469,7 @@ bool Curl_creader_is_paused(struct Curl_easy *data)
void Curl_creader_done(struct Curl_easy *data, int premature)
{
struct Curl_creader *reader = data->req.reader_stack;
struct Curl_creader *reader = data->req.reader.stack;
while(reader) {
reader->crt->done(data, reader, premature);
reader = reader->next;
@ -1505,7 +1480,7 @@ struct Curl_creader *Curl_creader_get_by_type(struct Curl_easy *data,
const struct Curl_crtype *crt)
{
struct Curl_creader *r;
for(r = data->req.reader_stack; r; r = r->next) {
for(r = data->req.reader.stack; r; r = r->next) {
if(r->crt == crt)
return r;
}

View file

@ -24,6 +24,7 @@
*
***************************************************************************/
#include "curl_setup.h"
#include "cw-out.h"
/**
* Type of data that is being written to the client (application)
@ -104,6 +105,7 @@ typedef enum {
CURL_CW_RAW, /* raw data written, before any decoding */
CURL_CW_TRANSFER_DECODE, /* remove transfer-encodings */
CURL_CW_PROTOCOL, /* after transfer, but before content decoding */
CURL_CW_BEFORE_DECODE, /* after protocol, but before content decoding */
CURL_CW_CONTENT_DECODE, /* remove content-encodings */
CURL_CW_CLIENT /* data written to client */
} Curl_cwriter_phase;
@ -176,22 +178,16 @@ struct Curl_cwriter *Curl_cwriter_get_by_type(struct Curl_easy *data,
struct Curl_cwriter *Curl_cwriter_get_by_name(struct Curl_easy *data,
const char *name);
/**
* Convenience method for calling `writer->do_write()` that
* checks for NULL writer.
*/
CURLcode Curl_cwriter_write(struct Curl_easy *data,
struct Curl_cwriter *writer, int type,
const char *buf, size_t nbytes);
CURLcode Curl_cwriter_flush(struct Curl_easy *data,
struct Curl_cwriter *writer);
/* Convenience method for calling `writer->do_write()` that
* checks for NULL writer. */
#define Curl_cwriter_write(d, w, t, b, n) \
((w) ? (w)->cwt->do_write((d), (w), (t), (b), (n)) : CURLE_WRITE_ERROR)
/**
* Return TRUE iff client writer is paused.
*/
bool Curl_cwriter_is_paused(struct Curl_easy *data);
#define Curl_cwriter_flush(d, w) \
((w) ? (w)->cwt->do_flush((d), (w)) : CURLE_WRITE_ERROR)
bool Curl_cwriter_is_content_decoding(struct Curl_easy *data);
/* TRUE if client writer is paused. */
#define Curl_cwriter_is_paused(d) ((bool)(d)->req.writer.paused)
/**
* Unpause client writer and flush any buffered date to the client.

View file

@ -40,6 +40,7 @@ from testenv import (
Dante,
Env,
ExecResult,
H2oServer,
Httpd,
NghttpxQuic,
RunProfile,
@ -776,17 +777,19 @@ def run_score(args, protocol):
uploads = None
requests = args.requests
test_httpd = protocol != 'h3'
test_caddy = protocol == 'h3'
if args.caddy or args.httpd:
test_caddy = args.caddy
test_httpd = args.httpd
rv = 0
env = Env()
env.setup()
env.test_timeout = None
test_httpd = protocol != 'h3'
test_h2o = protocol == 'h3' and env.have_h2o()
test_caddy = protocol == 'h3' and not test_h2o
if args.caddy or args.httpd or args.h2o:
test_caddy = args.caddy
test_httpd = args.httpd
test_h2o = args.h2o
sockd = None
socks_args = None
if args.socks4 and args.socks5:
@ -803,6 +806,7 @@ def run_score(args, protocol):
httpd = None
nghttpx = None
caddy = None
h2o = None
try:
cards = []
@ -859,6 +863,26 @@ def run_score(args, protocol):
card.setup_resources(server_docs, downloads)
cards.append(card)
if test_h2o:
h2o = H2oServer(env=env)
h2o.clear_logs()
assert h2o.initial_start()
server_descr = f'H2o/{env.h2o_version()}'
server_port = h2o.port
server_docs = h2o.docs_dir
card = ScoreRunner(env=env,
protocol=protocol,
server_descr=server_descr,
server_port=server_port,
verbose=args.verbose, curl_verbose=args.curl_verbose,
download_parallel=args.download_parallel,
upload_parallel=args.upload_parallel,
with_flame=args.flame,
socks_args=socks_args,
limit_rate=args.limit_rate)
card.setup_resources(server_docs, downloads)
cards.append(card)
if test_caddy and env.caddy:
backend = ''
if uploads and httpd is None:
@ -921,6 +945,8 @@ def run_score(args, protocol):
caddy.stop()
if nghttpx:
nghttpx.stop(wait_dead=False)
if h2o:
h2o.stop()
if httpd:
httpd.stop()
if sockd:
@ -951,6 +977,8 @@ def main():
default=1, help="how many sample runs to make")
parser.add_argument("--httpd", action='store_true', default=False,
help="evaluate httpd server only")
parser.add_argument("--h2o", action='store_true', default=False,
help="evaluate h2o server only")
parser.add_argument("--caddy", action='store_true', default=False,
help="evaluate caddy server only")
parser.add_argument("--curl-verbose", action='store_true',

View file

@ -38,6 +38,7 @@ from .client import LocalClient
from .dante import Dante
from .dnsd import Dnsd
from .env import Env
from .h2o import H2oServer, H2oProxy
from .httpd import Httpd
from .nghttpx import Nghttpx, NghttpxFwd, NghttpxQuic
from .sshd import Sshd