diff --git a/src/event/quic/ngx_event_quic.h b/src/event/quic/ngx_event_quic.h index 8ae7bf643..9481fef62 100644 --- a/src/event/quic/ngx_event_quic.h +++ b/src/event/quic/ngx_event_quic.h @@ -63,6 +63,7 @@ struct ngx_quic_stream_s { uint64_t recv_last; uint64_t final_size; ngx_chain_t *in; + ngx_chain_t *out; ngx_uint_t cancelable; /* unsigned cancelable:1; */ }; diff --git a/src/event/quic/ngx_event_quic_frames.c b/src/event/quic/ngx_event_quic_frames.c index 4a3902f7f..71ed981e6 100644 --- a/src/event/quic/ngx_event_quic_frames.c +++ b/src/event/quic/ngx_event_quic_frames.c @@ -482,14 +482,14 @@ done: ngx_int_t ngx_quic_order_bufs(ngx_connection_t *c, ngx_chain_t **out, ngx_chain_t *in, - size_t offset) + off_t limit, off_t offset) { + off_t n; u_char *p; - size_t n; ngx_buf_t *b; ngx_chain_t *cl, *sl; - while (in) { + while (in && limit) { cl = *out; if (cl == NULL) { @@ -523,8 +523,9 @@ ngx_quic_order_bufs(ngx_connection_t *c, ngx_chain_t **out, ngx_chain_t *in, continue; } - for (p = b->pos + offset; p != b->last && in; /* void */ ) { + for (p = b->pos + offset; p != b->last && in && limit; /* void */ ) { n = ngx_min(b->last - p, in->buf->last - in->buf->pos); + n = ngx_min(n, limit); if (b->sync) { ngx_memcpy(p, in->buf->pos, n); @@ -533,6 +534,7 @@ ngx_quic_order_bufs(ngx_connection_t *c, ngx_chain_t **out, ngx_chain_t *in, p += n; in->buf->pos += n; offset += n; + limit -= n; if (in->buf->pos == in->buf->last) { in = in->next; diff --git a/src/event/quic/ngx_event_quic_frames.h b/src/event/quic/ngx_event_quic_frames.h index f4c147682..1310f6dfd 100644 --- a/src/event/quic/ngx_event_quic_frames.h +++ b/src/event/quic/ngx_event_quic_frames.h @@ -31,7 +31,7 @@ ngx_chain_t *ngx_quic_copy_chain(ngx_connection_t *c, ngx_chain_t *in, void ngx_quic_trim_bufs(ngx_chain_t *in, size_t size); void ngx_quic_free_bufs(ngx_connection_t *c, ngx_chain_t *in); ngx_int_t ngx_quic_order_bufs(ngx_connection_t *c, ngx_chain_t **out, - ngx_chain_t *in, size_t offset); + ngx_chain_t *in, off_t limit, off_t offset); #if (NGX_DEBUG) void ngx_quic_log_frame(ngx_log_t *log, ngx_quic_frame_t *f, ngx_uint_t tx); diff --git a/src/event/quic/ngx_event_quic_ssl.c b/src/event/quic/ngx_event_quic_ssl.c index fb4b1af85..d2f1237a5 100644 --- a/src/event/quic/ngx_event_quic_ssl.c +++ b/src/event/quic/ngx_event_quic_ssl.c @@ -369,7 +369,7 @@ ngx_quic_handle_crypto_frame(ngx_connection_t *c, ngx_quic_header_t *pkt, } if (f->offset > ctx->crypto_received) { - return ngx_quic_order_bufs(c, &ctx->crypto, frame->data, + return ngx_quic_order_bufs(c, &ctx->crypto, frame->data, f->length, f->offset - ctx->crypto_received); } diff --git a/src/event/quic/ngx_event_quic_streams.c b/src/event/quic/ngx_event_quic_streams.c index 295aa54aa..d5facc270 100644 --- a/src/event/quic/ngx_event_quic_streams.c +++ b/src/event/quic/ngx_event_quic_streams.c @@ -838,8 +838,9 @@ static ngx_chain_t * ngx_quic_stream_send_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit) { size_t n, flow; + ngx_buf_t *b; ngx_event_t *wev; - ngx_chain_t *cl; + ngx_chain_t *out, **ll; ngx_connection_t *pc; ngx_quic_frame_t *frame; ngx_quic_stream_t *qs; @@ -862,26 +863,39 @@ ngx_quic_stream_send_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit) n = (limit && (size_t) limit < flow) ? (size_t) limit : flow; + if (ngx_quic_order_bufs(pc, &qs->out, in, n, 0) != NGX_OK) { + return NGX_CHAIN_ERROR; + } + + n = 0; + out = qs->out; + + for (ll = &out; *ll; ll = &(*ll)->next) { + b = (*ll)->buf; + + if (b->sync) { + /* hole */ + break; + } + + n += b->last - b->pos; + } + + qs->out = *ll; + *ll = NULL; + frame = ngx_quic_alloc_frame(pc); if (frame == NULL) { return NGX_CHAIN_ERROR; } - frame->data = ngx_quic_copy_chain(pc, in, n); - if (frame->data == NGX_CHAIN_ERROR) { - return NGX_CHAIN_ERROR; - } - - for (n = 0, cl = frame->data; cl; cl = cl->next) { - n += ngx_buf_size(cl->buf); - } - while (in && ngx_buf_size(in->buf) == 0) { in = in->next; } frame->level = ssl_encryption_application; frame->type = NGX_QUIC_FT_STREAM; + frame->data = out; frame->u.stream.off = 1; frame->u.stream.len = 1; frame->u.stream.fin = 0; @@ -977,6 +991,7 @@ ngx_quic_stream_cleanup_handler(void *data) ngx_rbtree_delete(&qc->streams.tree, &qs->node); ngx_quic_free_bufs(pc, qs->in); + ngx_quic_free_bufs(pc, qs->out); if (qc->closing) { /* schedule handler call to continue ngx_quic_close_connection() */ @@ -1098,7 +1113,7 @@ ngx_quic_handle_stream_frame(ngx_connection_t *c, ngx_quic_header_t *pkt, qs->final_size = last; } - if (ngx_quic_order_bufs(c, &qs->in, frame->data, + if (ngx_quic_order_bufs(c, &qs->in, frame->data, f->length, f->offset - qs->recv_offset) != NGX_OK) {