mirror of
https://github.com/curl/curl.git
synced 2026-07-22 04:37:17 +03:00
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:
parent
f65253056a
commit
b41c28e70a
8 changed files with 138 additions and 173 deletions
45
lib/cw-out.c
45
lib/cw-out.c
|
|
@ -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;
|
||||
|
|
|
|||
10
lib/cw-out.h
10
lib/cw-out.h
|
|
@ -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.
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
175
lib/sendf.c
175
lib/sendf.c
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
24
lib/sendf.h
24
lib/sendf.h
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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',
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue