Files
haproxy/src/hq_interop.c
Christopher Faulet db90f2aa9f MEDIUM: conn-stream: Add an endpoint structure in the conn-stream
Group the endpoint target of a conn-stream, its context and the associated
flags in a dedicated structure in the conn-stream. It is not inlined in the
conn-stream structure. There is a dedicated pool.

For now, there is no complexity. It is just an indirection to get the
endpoint or its context. But the purpose of this structure is to be able to
share a refcounted context between the mux and the conn-stream. This way, it
will be possible to preserve it when the mux is detached from the
conn-stream.
2022-04-13 15:10:14 +02:00

183 lines
3.6 KiB
C

#include <haproxy/hq_interop.h>
#include <import/ist.h>
#include <haproxy/buf.h>
#include <haproxy/connection.h>
#include <haproxy/dynbuf.h>
#include <haproxy/htx.h>
#include <haproxy/http.h>
#include <haproxy/mux_quic.h>
static int hq_interop_decode_qcs(struct qcs *qcs, int fin, void *ctx)
{
struct buffer *rxbuf = &qcs->rx.buf;
struct htx *htx;
struct htx_sl *sl;
struct conn_stream *cs;
struct buffer htx_buf = BUF_NULL;
struct ist path;
char *ptr = b_head(rxbuf);
char *end = b_wrap(rxbuf);
size_t size = b_size(rxbuf);
size_t data = b_data(rxbuf);
b_alloc(&htx_buf);
htx = htx_from_buf(&htx_buf);
/* skip method */
while (data && HTTP_IS_TOKEN(*ptr)) {
if (++ptr == end)
ptr -= size;
data--;
}
if (!data || !HTTP_IS_SPHT(*ptr)) {
fprintf(stderr, "truncated stream\n");
return 0;
}
if (++ptr == end)
ptr -= size;
if (!--data) {
fprintf(stderr, "truncated stream\n");
return 0;
}
/* extract path */
BUG_ON(HTTP_IS_LWS(*ptr));
path.ptr = ptr;
while (data && !HTTP_IS_LWS(*ptr)) {
if (++ptr == end)
ptr -= size;
data--;
}
if (!data) {
fprintf(stderr, "truncated stream\n");
return 0;
}
BUG_ON(!HTTP_IS_LWS(*ptr));
path.len = ptr - path.ptr;
sl = htx_add_stline(htx, HTX_BLK_REQ_SL, 0, ist("GET"), path, ist("HTTP/1.0"));
if (!sl)
return -1;
sl->flags |= HTX_SL_F_BODYLESS;
sl->info.req.meth = find_http_meth("GET", 3);
htx_add_endof(htx, HTX_BLK_EOH);
htx_to_buf(htx, &htx_buf);
cs = qc_attach_cs(qcs, &htx_buf);
if (!cs)
return -1;
b_del(rxbuf, b_data(rxbuf));
b_free(&htx_buf);
if (fin)
htx->flags |= HTX_FL_EOM;
return 0;
}
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 conn_stream *cs, struct buffer *buf,
size_t count, int flags)
{
struct qcs *qcs = __cs_mux(cs);
struct htx *htx;
enum htx_blk_type btype;
struct htx_blk *blk;
int32_t idx;
uint32_t bsize, fsize;
struct buffer *res, outbuf;
size_t total = 0;
htx = htx_from_buf(buf);
res = mux_get_buf(qcs);
outbuf = b_make(b_tail(res), b_contig_space(res), 0, 0);
while (count && !htx_is_empty(htx) && !(qcs->flags & QC_SF_BLK_MROOM)) {
/* Not implemented : QUIC on backend side */
idx = htx_get_head(htx);
blk = htx_get_blk(htx, idx);
btype = htx_get_blk_type(blk);
fsize = bsize = htx_get_blksz(blk);
BUG_ON(btype == HTX_BLK_REQ_SL);
switch (btype) {
case HTX_BLK_DATA:
if (fsize > count)
fsize = count;
if (b_room(&outbuf) < fsize)
fsize = b_room(&outbuf);
if (!fsize) {
qcs->flags |= QC_SF_BLK_MROOM;
goto end;
}
b_putblk(&outbuf, htx_get_blk_ptr(htx, blk), fsize);
total += fsize;
count -= fsize;
if (fsize == bsize)
htx_remove_blk(htx, blk);
else
htx_cut_data_blk(htx, blk, fsize);
break;
/* only body is transferred on HTTP/0.9 */
case HTX_BLK_RES_SL:
case HTX_BLK_TLR:
case HTX_BLK_EOT:
default:
htx_remove_blk(htx, blk);
total += bsize;
count -= bsize;
break;
}
}
end:
if ((htx->flags & HTX_FL_EOM) && htx_is_empty(htx))
qcs->flags |= QC_SF_FIN_STREAM;
b_add(res, b_data(&outbuf));
if (total) {
if (!(qcs->qcc->wait_event.events & SUB_RETRY_SEND))
tasklet_wakeup(qcs->qcc->wait_event.tasklet);
}
return total;
}
static int hq_is_active(const struct qcc *qcc, void *ctx)
{
if (!eb_is_empty(&qcc->streams_by_id))
return 1;
return 0;
}
const struct qcc_app_ops hq_interop_ops = {
.decode_qcs = hq_interop_decode_qcs,
.snd_buf = hq_interop_snd_buf,
.is_active = hq_is_active,
};