blob: dcaba8ef94ada928b6193d03066e6f4cbf06f6a0 [file] [log] [blame]
Amaury Denoyelle154bc7f2021-11-12 16:09:54 +01001#include <haproxy/hq_interop.h>
2
3#include <import/ist.h>
4#include <haproxy/buf.h>
5#include <haproxy/connection.h>
6#include <haproxy/dynbuf.h>
7#include <haproxy/htx.h>
8#include <haproxy/http.h>
Amaury Denoyelle846cc042022-04-04 16:13:44 +02009#include <haproxy/mux_quic.h>
Amaury Denoyelle154bc7f2021-11-12 16:09:54 +010010
Amaury Denoyelledb443382021-11-30 11:23:29 +010011static int hq_interop_decode_qcs(struct qcs *qcs, int fin, void *ctx)
Amaury Denoyelle154bc7f2021-11-12 16:09:54 +010012{
13 struct buffer *rxbuf = &qcs->rx.buf;
14 struct htx *htx;
15 struct htx_sl *sl;
16 struct conn_stream *cs;
17 struct buffer htx_buf = BUF_NULL;
18 struct ist path;
Frédéric Lécailleafd373c2021-12-15 22:38:48 +010019 char *ptr = b_head(rxbuf);
20 char *end = b_wrap(rxbuf);
21 size_t size = b_size(rxbuf);
22 size_t data = b_data(rxbuf);
Amaury Denoyelle154bc7f2021-11-12 16:09:54 +010023
24 b_alloc(&htx_buf);
25 htx = htx_from_buf(&htx_buf);
26
27 /* skip method */
Frédéric Lécailleafd373c2021-12-15 22:38:48 +010028 while (data && HTTP_IS_TOKEN(*ptr)) {
29 if (++ptr == end)
30 ptr -= size;
31 data--;
32 }
33
34 if (!data || !HTTP_IS_SPHT(*ptr)) {
35 fprintf(stderr, "truncated stream\n");
36 return 0;
37 }
38
39 if (++ptr == end)
40 ptr -= size;
41
42 if (!--data) {
43 fprintf(stderr, "truncated stream\n");
44 return 0;
45 }
Amaury Denoyelle154bc7f2021-11-12 16:09:54 +010046
47 /* extract path */
48 BUG_ON(HTTP_IS_LWS(*ptr));
49 path.ptr = ptr;
Frédéric Lécailleafd373c2021-12-15 22:38:48 +010050 while (data && !HTTP_IS_LWS(*ptr)) {
51 if (++ptr == end)
52 ptr -= size;
53 data--;
54 }
55
56 if (!data) {
57 fprintf(stderr, "truncated stream\n");
58 return 0;
59 }
60
Amaury Denoyelle154bc7f2021-11-12 16:09:54 +010061 BUG_ON(!HTTP_IS_LWS(*ptr));
62 path.len = ptr - path.ptr;
63
64 sl = htx_add_stline(htx, HTX_BLK_REQ_SL, 0, ist("GET"), path, ist("HTTP/1.0"));
Amaury Denoyelleb48c59a2021-11-18 14:40:26 +010065 if (!sl)
66 return -1;
67
Amaury Denoyelle154bc7f2021-11-12 16:09:54 +010068 sl->flags |= HTX_SL_F_BODYLESS;
69 sl->info.req.meth = find_http_meth("GET", 3);
70
71 htx_add_endof(htx, HTX_BLK_EOH);
72 htx_to_buf(htx, &htx_buf);
73
Amaury Denoyelle846cc042022-04-04 16:13:44 +020074 cs = qc_attach_cs(qcs, &htx_buf);
Frédéric Lécaille1e1fb5d2022-02-15 09:13:05 +010075 if (!cs)
76 return -1;
Amaury Denoyelle154bc7f2021-11-12 16:09:54 +010077
Christopher Faulet93882042022-01-19 14:56:50 +010078
Amaury Denoyelle154bc7f2021-11-12 16:09:54 +010079 b_del(rxbuf, b_data(rxbuf));
80 b_free(&htx_buf);
81
Amaury Denoyelledb443382021-11-30 11:23:29 +010082 if (fin)
83 htx->flags |= HTX_FL_EOM;
84
Amaury Denoyelle154bc7f2021-11-12 16:09:54 +010085 return 0;
86}
87
88static struct buffer *mux_get_buf(struct qcs *qcs)
89{
90 if (!b_size(&qcs->tx.buf))
91 b_alloc(&qcs->tx.buf);
92
93 return &qcs->tx.buf;
94}
95
96static size_t hq_interop_snd_buf(struct conn_stream *cs, struct buffer *buf,
97 size_t count, int flags)
98{
Christopher Fauletdb90f2a2022-03-22 16:06:25 +010099 struct qcs *qcs = __cs_mux(cs);
Amaury Denoyelle154bc7f2021-11-12 16:09:54 +0100100 struct htx *htx;
101 enum htx_blk_type btype;
102 struct htx_blk *blk;
103 int32_t idx;
104 uint32_t bsize, fsize;
105 struct buffer *res, outbuf;
106 size_t total = 0;
107
108 htx = htx_from_buf(buf);
109 res = mux_get_buf(qcs);
110 outbuf = b_make(b_tail(res), b_contig_space(res), 0, 0);
111
Amaury Denoyelle84ea8dc2021-12-03 14:40:01 +0100112 while (count && !htx_is_empty(htx) && !(qcs->flags & QC_SF_BLK_MROOM)) {
Amaury Denoyelle154bc7f2021-11-12 16:09:54 +0100113 /* Not implemented : QUIC on backend side */
114 idx = htx_get_head(htx);
115 blk = htx_get_blk(htx, idx);
116 btype = htx_get_blk_type(blk);
117 fsize = bsize = htx_get_blksz(blk);
118
119 BUG_ON(btype == HTX_BLK_REQ_SL);
120
121 switch (btype) {
122 case HTX_BLK_DATA:
123 if (fsize > count)
124 fsize = count;
Amaury Denoyelle5ede40b2021-12-07 16:19:03 +0100125
Amaury Denoyelle1ac95442021-12-09 10:07:23 +0100126 if (b_room(&outbuf) < fsize)
127 fsize = b_room(&outbuf);
Amaury Denoyelle5ede40b2021-12-07 16:19:03 +0100128
129 if (!fsize) {
130 qcs->flags |= QC_SF_BLK_MROOM;
131 goto end;
132 }
133
Amaury Denoyelle154bc7f2021-11-12 16:09:54 +0100134 b_putblk(&outbuf, htx_get_blk_ptr(htx, blk), fsize);
135 total += fsize;
136 count -= fsize;
137
138 if (fsize == bsize)
139 htx_remove_blk(htx, blk);
140 else
141 htx_cut_data_blk(htx, blk, fsize);
142 break;
143
Ilya Shipitsin5e87bcf2021-12-25 11:45:52 +0500144 /* only body is transferred on HTTP/0.9 */
Amaury Denoyelle154bc7f2021-11-12 16:09:54 +0100145 case HTX_BLK_RES_SL:
146 case HTX_BLK_TLR:
147 case HTX_BLK_EOT:
148 default:
149 htx_remove_blk(htx, blk);
150 total += bsize;
151 count -= bsize;
152 break;
153 }
154 }
155
Amaury Denoyelle5ede40b2021-12-07 16:19:03 +0100156 end:
Amaury Denoyellec2025c12021-12-03 15:03:36 +0100157 if ((htx->flags & HTX_FL_EOM) && htx_is_empty(htx))
158 qcs->flags |= QC_SF_FIN_STREAM;
159
Amaury Denoyelle154bc7f2021-11-12 16:09:54 +0100160 b_add(res, b_data(&outbuf));
161
162 if (total) {
163 if (!(qcs->qcc->wait_event.events & SUB_RETRY_SEND))
164 tasklet_wakeup(qcs->qcc->wait_event.tasklet);
165 }
166
167 return total;
168}
169
Amaury Denoyelle198d35f2022-04-01 17:56:58 +0200170static int hq_is_active(const struct qcc *qcc, void *ctx)
171{
172 if (!eb_is_empty(&qcc->streams_by_id))
173 return 1;
174
175 return 0;
176}
177
Amaury Denoyelle154bc7f2021-11-12 16:09:54 +0100178const struct qcc_app_ops hq_interop_ops = {
179 .decode_qcs = hq_interop_decode_qcs,
180 .snd_buf = hq_interop_snd_buf,
Amaury Denoyelle198d35f2022-04-01 17:56:58 +0200181 .is_active = hq_is_active,
Amaury Denoyelle154bc7f2021-11-12 16:09:54 +0100182};