summaryrefslogtreecommitdiffstats
path: root/src/hq_interop.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/hq_interop.c')
-rw-r--r--src/hq_interop.c117
1 files changed, 91 insertions, 26 deletions
diff --git a/src/hq_interop.c b/src/hq_interop.c
index 31c2101..c88f888 100644
--- a/src/hq_interop.c
+++ b/src/hq_interop.c
@@ -8,8 +8,10 @@
#include <haproxy/http.h>
#include <haproxy/mux_quic.h>
#include <haproxy/qmux_http.h>
+#include <haproxy/qmux_trace.h>
+#include <haproxy/trace.h>
-static ssize_t hq_interop_decode_qcs(struct qcs *qcs, struct buffer *b, int fin)
+static ssize_t hq_interop_rcv_buf(struct qcs *qcs, struct buffer *b, int fin)
{
struct htx *htx;
struct htx_sl *sl;
@@ -25,7 +27,7 @@ static ssize_t hq_interop_decode_qcs(struct qcs *qcs, struct buffer *b, int fin)
if (!fin)
return 0;
- b_alloc(&htx_buf);
+ b_alloc(&htx_buf, DB_MUX_RX);
htx = htx_from_buf(&htx_buf);
/* skip method */
@@ -83,34 +85,21 @@ static ssize_t hq_interop_decode_qcs(struct qcs *qcs, struct buffer *b, int fin)
return b_data(b);
}
-static struct buffer *mux_get_buf(struct qcs *qcs)
-{
- if (!b_size(&qcs->tx.buf))
- b_alloc(&qcs->tx.buf);
-
- return &qcs->tx.buf;
-}
-
static size_t hq_interop_snd_buf(struct qcs *qcs, struct buffer *buf,
size_t count)
{
enum htx_blk_type btype;
- struct htx *htx;
+ struct htx *htx = NULL;
struct htx_blk *blk;
int32_t idx;
uint32_t bsize, fsize;
- struct buffer *res, outbuf;
+ struct buffer *res = NULL;
size_t total = 0;
-
- res = mux_get_buf(qcs);
- outbuf = b_make(b_tail(res), b_contig_space(res), 0, 0);
+ int err;
htx = htx_from_buf(buf);
- if (htx->extra && htx->extra == HTX_UNKOWN_PAYLOAD_LENGTH)
- qcs->flags |= QC_SF_UNKNOWN_PL_LENGTH;
-
- while (count && !htx_is_empty(htx) && !(qcs->flags & QC_SF_BLK_MROOM)) {
+ while (count && !htx_is_empty(htx) && qcc_stream_can_send(qcs)) {
/* Not implemented : QUIC on backend side */
idx = htx_get_head(htx);
blk = htx_get_blk(htx, idx);
@@ -121,18 +110,48 @@ static size_t hq_interop_snd_buf(struct qcs *qcs, struct buffer *buf,
switch (btype) {
case HTX_BLK_DATA:
+ res = qcc_get_stream_txbuf(qcs, &err);
+ if (!res) {
+ if (err)
+ ABORT_NOW();
+ goto end;
+ }
+
+ if (unlikely(fsize == count &&
+ !b_data(res) &&
+ htx_nbblks(htx) == 1 && btype == HTX_BLK_DATA)) {
+ void *old_area = res->area;
+
+ TRACE_DATA("perform zero-copy DATA transfer", QMUX_EV_STRM_SEND,
+ qcs->qcc->conn, qcs);
+
+ /* remap MUX buffer to HTX area */
+ *res = b_make(buf->area, buf->size,
+ sizeof(struct htx) + blk->addr, fsize);
+
+ /* assign old MUX area to HTX buffer. */
+ buf->area = old_area;
+ buf->data = buf->head = 0;
+ total += fsize;
+
+ /* reload HTX with empty buffer. */
+ *htx = *htx_from_buf(buf);
+ goto end;
+ }
+
if (fsize > count)
fsize = count;
- if (b_room(&outbuf) < fsize)
- fsize = b_room(&outbuf);
+ if (b_contig_space(res) < fsize)
+ fsize = b_contig_space(res);
if (!fsize) {
- qcs->flags |= QC_SF_BLK_MROOM;
- goto end;
+ /* Release buf and restart parsing if sending still possible. */
+ qcc_release_stream_txbuf(qcs);
+ continue;
}
- b_putblk(&outbuf, htx_get_blk_ptr(htx, blk), fsize);
+ b_putblk(res, htx_get_blk_ptr(htx, blk), fsize);
total += fsize;
count -= fsize;
@@ -155,12 +174,56 @@ static size_t hq_interop_snd_buf(struct qcs *qcs, struct buffer *buf,
}
end:
- b_add(res, b_data(&outbuf));
htx_to_buf(htx, buf);
return total;
}
+static size_t hq_interop_nego_ff(struct qcs *qcs, size_t count)
+{
+ int err, ret = 0;
+ struct buffer *res;
+
+ start:
+ res = qcc_get_stream_txbuf(qcs, &err);
+ if (!res) {
+ if (err)
+ ABORT_NOW();
+ qcs->sd->iobuf.flags |= IOBUF_FL_FF_BLOCKED;
+ goto end;
+ }
+
+ if (!b_room(res)) {
+ if (qcc_release_stream_txbuf(qcs)) {
+ qcs->sd->iobuf.flags |= IOBUF_FL_FF_BLOCKED;
+ goto end;
+ }
+
+ goto start;
+ }
+
+ /* No header required for HTTP/0.9, no need to reserve an offset. */
+ qcs->sd->iobuf.buf = res;
+ qcs->sd->iobuf.offset = 0;
+ qcs->sd->iobuf.data = 0;
+
+ ret = MIN(count, b_contig_space(res));
+ end:
+ return ret;
+}
+
+static size_t hq_interop_done_ff(struct qcs *qcs)
+{
+ const size_t ret = qcs->sd->iobuf.data;
+
+ /* No header required for HTTP/0.9, simply mark ff as done. */
+ qcs->sd->iobuf.buf = NULL;
+ qcs->sd->iobuf.offset = 0;
+ qcs->sd->iobuf.data = 0;
+
+ return ret;
+}
+
static int hq_interop_attach(struct qcs *qcs, void *conn_ctx)
{
qcs_wait_http_req(qcs);
@@ -168,7 +231,9 @@ static int hq_interop_attach(struct qcs *qcs, void *conn_ctx)
}
const struct qcc_app_ops hq_interop_ops = {
- .decode_qcs = hq_interop_decode_qcs,
+ .rcv_buf = hq_interop_rcv_buf,
.snd_buf = hq_interop_snd_buf,
+ .nego_ff = hq_interop_nego_ff,
+ .done_ff = hq_interop_done_ff,
.attach = hq_interop_attach,
};