blob: 5000a7e2ef716b3b404cd941a5bc7a447bf7dd36 [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 Denoyelle1f21ebd2022-06-07 17:30:55 +020011static ssize_t hq_interop_decode_qcs(struct qcs *qcs, struct buffer *b, int fin)
Amaury Denoyelle154bc7f2021-11-12 16:09:54 +010012{
Amaury Denoyelle154bc7f2021-11-12 16:09:54 +010013 struct htx *htx;
14 struct htx_sl *sl;
Willy Tarreau3215e732022-05-27 10:09:11 +020015 struct stconn *sc;
Amaury Denoyelle154bc7f2021-11-12 16:09:54 +010016 struct buffer htx_buf = BUF_NULL;
17 struct ist path;
Amaury Denoyelle62eef852022-06-03 16:40:34 +020018 char *ptr = b_head(b);
19 char *end = b_wrap(b);
20 size_t size = b_size(b);
21 size_t data = b_data(b);
Amaury Denoyelle154bc7f2021-11-12 16:09:54 +010022
23 b_alloc(&htx_buf);
24 htx = htx_from_buf(&htx_buf);
25
26 /* skip method */
Frédéric Lécailleafd373c2021-12-15 22:38:48 +010027 while (data && HTTP_IS_TOKEN(*ptr)) {
28 if (++ptr == end)
29 ptr -= size;
30 data--;
31 }
32
33 if (!data || !HTTP_IS_SPHT(*ptr)) {
34 fprintf(stderr, "truncated stream\n");
35 return 0;
36 }
37
38 if (++ptr == end)
39 ptr -= size;
40
41 if (!--data) {
42 fprintf(stderr, "truncated stream\n");
43 return 0;
44 }
Amaury Denoyelle154bc7f2021-11-12 16:09:54 +010045
46 /* extract path */
47 BUG_ON(HTTP_IS_LWS(*ptr));
48 path.ptr = ptr;
Frédéric Lécailleafd373c2021-12-15 22:38:48 +010049 while (data && !HTTP_IS_LWS(*ptr)) {
50 if (++ptr == end)
51 ptr -= size;
52 data--;
53 }
54
55 if (!data) {
56 fprintf(stderr, "truncated stream\n");
57 return 0;
58 }
59
Amaury Denoyelle154bc7f2021-11-12 16:09:54 +010060 BUG_ON(!HTTP_IS_LWS(*ptr));
61 path.len = ptr - path.ptr;
62
63 sl = htx_add_stline(htx, HTX_BLK_REQ_SL, 0, ist("GET"), path, ist("HTTP/1.0"));
Amaury Denoyelleb48c59a2021-11-18 14:40:26 +010064 if (!sl)
Amaury Denoyelle1f21ebd2022-06-07 17:30:55 +020065 return -1;
Amaury Denoyelleb48c59a2021-11-18 14:40:26 +010066
Amaury Denoyelle154bc7f2021-11-12 16:09:54 +010067 sl->flags |= HTX_SL_F_BODYLESS;
68 sl->info.req.meth = find_http_meth("GET", 3);
69
70 htx_add_endof(htx, HTX_BLK_EOH);
71 htx_to_buf(htx, &htx_buf);
72
Willy Tarreau3215e732022-05-27 10:09:11 +020073 sc = qc_attach_sc(qcs, &htx_buf);
74 if (!sc)
Amaury Denoyelle1f21ebd2022-06-07 17:30:55 +020075 return -1;
Amaury Denoyelle154bc7f2021-11-12 16:09:54 +010076
Amaury Denoyelle154bc7f2021-11-12 16:09:54 +010077 b_free(&htx_buf);
78
Amaury Denoyelledb443382021-11-30 11:23:29 +010079 if (fin)
80 htx->flags |= HTX_FL_EOM;
81
Amaury Denoyelle1f21ebd2022-06-07 17:30:55 +020082 return b_data(b);
Amaury Denoyelle154bc7f2021-11-12 16:09:54 +010083}
84
85static struct buffer *mux_get_buf(struct qcs *qcs)
86{
87 if (!b_size(&qcs->tx.buf))
88 b_alloc(&qcs->tx.buf);
89
90 return &qcs->tx.buf;
91}
92
Willy Tarreau3215e732022-05-27 10:09:11 +020093static size_t hq_interop_snd_buf(struct stconn *sc, struct buffer *buf,
Amaury Denoyelle154bc7f2021-11-12 16:09:54 +010094 size_t count, int flags)
95{
Willy Tarreau3215e732022-05-27 10:09:11 +020096 struct qcs *qcs = __sc_mux_strm(sc);
Amaury Denoyelle154bc7f2021-11-12 16:09:54 +010097 struct htx *htx;
98 enum htx_blk_type btype;
99 struct htx_blk *blk;
100 int32_t idx;
101 uint32_t bsize, fsize;
102 struct buffer *res, outbuf;
103 size_t total = 0;
104
105 htx = htx_from_buf(buf);
106 res = mux_get_buf(qcs);
107 outbuf = b_make(b_tail(res), b_contig_space(res), 0, 0);
108
Amaury Denoyelle84ea8dc2021-12-03 14:40:01 +0100109 while (count && !htx_is_empty(htx) && !(qcs->flags & QC_SF_BLK_MROOM)) {
Amaury Denoyelle154bc7f2021-11-12 16:09:54 +0100110 /* Not implemented : QUIC on backend side */
111 idx = htx_get_head(htx);
112 blk = htx_get_blk(htx, idx);
113 btype = htx_get_blk_type(blk);
114 fsize = bsize = htx_get_blksz(blk);
115
116 BUG_ON(btype == HTX_BLK_REQ_SL);
117
118 switch (btype) {
119 case HTX_BLK_DATA:
120 if (fsize > count)
121 fsize = count;
Amaury Denoyelle5ede40b2021-12-07 16:19:03 +0100122
Amaury Denoyelle1ac95442021-12-09 10:07:23 +0100123 if (b_room(&outbuf) < fsize)
124 fsize = b_room(&outbuf);
Amaury Denoyelle5ede40b2021-12-07 16:19:03 +0100125
126 if (!fsize) {
127 qcs->flags |= QC_SF_BLK_MROOM;
128 goto end;
129 }
130
Amaury Denoyelle154bc7f2021-11-12 16:09:54 +0100131 b_putblk(&outbuf, htx_get_blk_ptr(htx, blk), fsize);
132 total += fsize;
133 count -= fsize;
134
135 if (fsize == bsize)
136 htx_remove_blk(htx, blk);
137 else
138 htx_cut_data_blk(htx, blk, fsize);
139 break;
140
Ilya Shipitsin5e87bcf2021-12-25 11:45:52 +0500141 /* only body is transferred on HTTP/0.9 */
Amaury Denoyelle154bc7f2021-11-12 16:09:54 +0100142 case HTX_BLK_RES_SL:
143 case HTX_BLK_TLR:
144 case HTX_BLK_EOT:
145 default:
146 htx_remove_blk(htx, blk);
147 total += bsize;
148 count -= bsize;
149 break;
150 }
151 }
152
Amaury Denoyelle5ede40b2021-12-07 16:19:03 +0100153 end:
Amaury Denoyellec2025c12021-12-03 15:03:36 +0100154 if ((htx->flags & HTX_FL_EOM) && htx_is_empty(htx))
155 qcs->flags |= QC_SF_FIN_STREAM;
156
Amaury Denoyelle154bc7f2021-11-12 16:09:54 +0100157 b_add(res, b_data(&outbuf));
158
159 if (total) {
160 if (!(qcs->qcc->wait_event.events & SUB_RETRY_SEND))
161 tasklet_wakeup(qcs->qcc->wait_event.tasklet);
162 }
163
164 return total;
165}
166
Amaury Denoyelle198d35f2022-04-01 17:56:58 +0200167static int hq_is_active(const struct qcc *qcc, void *ctx)
168{
169 if (!eb_is_empty(&qcc->streams_by_id))
170 return 1;
171
172 return 0;
173}
174
Amaury Denoyelle154bc7f2021-11-12 16:09:54 +0100175const struct qcc_app_ops hq_interop_ops = {
176 .decode_qcs = hq_interop_decode_qcs,
177 .snd_buf = hq_interop_snd_buf,
Amaury Denoyelle198d35f2022-04-01 17:56:58 +0200178 .is_active = hq_is_active,
Amaury Denoyelle154bc7f2021-11-12 16:09:54 +0100179};