contrib: soxr: enable by default
[vlc.git] / modules / access / http / h2conn_test.c
blob109e6c0cf0c4a0a86b9f582cf64539620fcd9f73
1 /*****************************************************************************
2 * h2conn_test.c: HTTP/2 connection tests
3 *****************************************************************************
4 * Copyright (C) 2015 RĂ©mi Denis-Courmont
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU Lesser General Public License as published by
8 * the Free Software Foundation; either version 2.1 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public License
17 * along with this program; if not, write to the Free Software Foundation,
18 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
19 *****************************************************************************/
21 #ifdef HAVE_CONFIG_H
22 # include <config.h>
23 #endif
25 #undef NDEBUG
27 #include <assert.h>
28 #include <stdint.h>
29 #include <string.h>
30 #include <sys/types.h>
31 #include <unistd.h>
32 #include <sys/socket.h>
34 #include <vlc_common.h>
35 #include <vlc_block.h>
36 #include <vlc_tls.h>
37 #include "h2frame.h"
38 #include "conn.h"
39 #include "message.h"
41 static struct vlc_http_conn *conn;
42 static struct vlc_tls *external_tls;
44 static void conn_send(struct vlc_h2_frame *f)
46 assert(f != NULL);
48 size_t len = vlc_h2_frame_size(f);
49 ssize_t val = vlc_tls_Write(external_tls, f->data, len);
50 assert((size_t)val == len);
51 free(f);
54 enum {
55 DATA, HEADERS, PRIORITY, RST_STREAM, SETTINGS, PUSH_PROMISE, PING, GOAWAY,
56 WINDOW_UPDATE, CONTINUATION,
59 static void conn_expect(uint_fast8_t wanted)
61 size_t len;
62 ssize_t val;
63 uint8_t hdr[9];
64 uint8_t got;
66 do {
67 val = vlc_tls_Read(external_tls, hdr, 9, true);
68 assert(val == 9);
69 assert(hdr[0] == 0);
71 /* Check type. We do not currently validate WINDOW_UPDATE. */
72 got = hdr[3];
73 assert(wanted == got || WINDOW_UPDATE == got);
75 len = (hdr[1] << 8) | hdr[2];
76 if (len > 0)
78 char buf[len];
80 val = vlc_tls_Read(external_tls, buf, len, true);
81 assert(val == (ssize_t)len);
84 while (got != wanted);
87 static void conn_create(void)
89 ssize_t val;
90 vlc_tls_t *tlsv[2];
91 char hello[24];
93 if (vlc_tls_SocketPair(PF_LOCAL, 0, tlsv))
94 assert(!"socketpair");
96 external_tls = tlsv[0];
98 conn = vlc_h2_conn_create(NULL, tlsv[1]);
99 assert(conn != NULL);
100 conn_send(vlc_h2_frame_settings());
102 val = vlc_tls_Read(external_tls, hello, 24, true);
103 assert(val == 24);
104 assert(!memcmp(hello, "PRI * HTTP/2.0\r\n", 16));
105 conn_expect(SETTINGS);
106 conn_expect(SETTINGS);
109 static void conn_destroy(void)
111 vlc_tls_Shutdown(external_tls, false);
112 vlc_http_conn_release(conn);
113 vlc_tls_SessionDelete(external_tls);
116 static struct vlc_http_stream *stream_open(void)
118 struct vlc_http_msg *m = vlc_http_req_create("GET", "https",
119 "www.example.com", "/");
120 assert(m != NULL);
122 struct vlc_http_stream *s = vlc_http_stream_open(conn, m);
123 vlc_http_msg_destroy(m);
124 return s;
127 static void stream_reply(uint_fast32_t id, bool nodata)
129 struct vlc_http_msg *m = vlc_http_resp_create(200);
130 assert(m != NULL);
131 vlc_http_msg_add_agent(m, "VLC-h2-tester");
133 conn_send(vlc_http_msg_h2_frame(m, id, nodata));
134 vlc_http_msg_destroy(m);
137 static void stream_continuation(uint_fast32_t id)
139 const char *h[][2] = {
140 { ":status", "100" },
143 conn_send(vlc_h2_frame_headers(id, VLC_H2_DEFAULT_MAX_FRAME, false, 1, h));
146 static void stream_data(uint_fast32_t id, const char *str, bool eos)
148 conn_send(vlc_h2_frame_data(id, str, strlen(str), eos));
151 /* TODO: check messages coming from the connection under test */
153 int main(void)
155 struct vlc_http_stream *s, *s2;
156 struct vlc_http_msg *m;
157 struct block_t *b;
158 uint_fast32_t sid = -1; /* Second guessed stream IDs :-/ */
160 conn_create();
161 conn_destroy();
163 conn_create();
164 conn_send(vlc_h2_frame_ping(42));
165 conn_expect(PING);
167 /* Test rejected stream */
168 sid += 2;
169 s = stream_open();
170 assert(s != NULL);
171 conn_expect(HEADERS);
172 conn_send(vlc_h2_frame_rst_stream(sid, VLC_H2_REFUSED_STREAM));
173 m = vlc_http_stream_read_headers(s);
174 assert(m == NULL);
175 b = vlc_http_stream_read(s);
176 assert(b == vlc_http_error);
177 vlc_http_stream_close(s, false);
178 conn_expect(RST_STREAM);
180 /* Test accepted stream */
181 sid += 2;
182 s = stream_open();
183 assert(s != NULL);
184 stream_reply(sid, false);
185 m = vlc_http_msg_get_initial(s);
186 assert(m != NULL);
187 vlc_http_msg_destroy(m);
189 stream_data(3, "Hello ", false); /* late data */
190 stream_data(3, "world!", true);
192 conn_expect(HEADERS);
193 conn_expect(RST_STREAM);
194 conn_expect(RST_STREAM);
195 conn_expect(RST_STREAM);
197 /* Test continuation then accepted stream */
198 sid += 2;
199 s = stream_open();
200 assert(s != NULL);
201 stream_continuation(sid);
202 m = vlc_http_msg_get_initial(s);
203 assert(m != NULL);
204 assert(vlc_http_msg_get_status(m) == 100);
205 stream_reply(sid, false);
206 m = vlc_http_msg_iterate(m);
207 assert(m != NULL);
208 stream_data(sid, "Hello ", false);
209 stream_data(sid, "world!", true);
210 stream_data(sid, "Stray message", false); /* data after EOS */
211 b = vlc_http_msg_read(m);
212 assert(b != NULL);
213 block_Release(b);
214 b = vlc_http_msg_read(m);
215 assert(b != NULL);
216 block_Release(b);
217 b = vlc_http_msg_read(m);
218 assert(b == NULL);
219 vlc_http_msg_destroy(m);
221 conn_expect(HEADERS);
222 conn_expect(RST_STREAM);
223 conn_expect(RST_STREAM);
225 /* Test accepted stream after continuation */
226 sid += 2;
227 s = stream_open();
228 assert(s != NULL);
229 stream_continuation(sid);
230 stream_reply(sid, true);
231 sid += 2;
232 s2 = stream_open(); /* second stream to enforce test timing/ordering */
233 assert(s2 != NULL);
234 stream_reply(sid, true);
235 m = vlc_http_msg_get_initial(s2);
236 assert(m != NULL);
237 vlc_http_msg_destroy(m);
238 m = vlc_http_msg_get_initial(s);
239 assert(m != NULL);
240 assert(vlc_http_msg_get_status(m) == 200);
241 b = vlc_http_msg_read(m);
242 assert(b == NULL);
243 vlc_http_msg_destroy(m);
245 conn_expect(HEADERS);
246 conn_expect(HEADERS);
247 conn_expect(RST_STREAM);
248 conn_expect(RST_STREAM);
250 /* Test nonexistent stream reset */
251 conn_send(vlc_h2_frame_rst_stream(sid + 100, VLC_H2_REFUSED_STREAM));
253 /* Test multiple streams in non-LIFO order */
254 sid += 2;
255 s = stream_open();
256 assert(s != NULL);
257 sid += 2;
258 s2 = stream_open();
259 assert(s2 != NULL);
260 stream_reply(sid, false);
261 stream_reply(sid - 2, true);
262 stream_data(sid, "Discarded", false); /* not read data */
263 m = vlc_http_msg_get_initial(s);
264 assert(m != NULL);
265 vlc_http_msg_destroy(m);
266 m = vlc_http_msg_get_initial(s2);
267 assert(m != NULL);
268 vlc_http_msg_destroy(m);
270 conn_expect(HEADERS);
271 conn_expect(HEADERS);
272 conn_expect(RST_STREAM);
273 conn_expect(RST_STREAM);
274 /* might or might not seen one or two extra RST_STREAM now */
276 /* Test graceful connection termination */
277 sid += 2;
278 s = stream_open();
279 assert(s != NULL);
280 conn_send(vlc_h2_frame_goaway(sid - 2, VLC_H2_NO_ERROR));
281 m = vlc_http_stream_read_headers(s);
282 assert(m == NULL);
284 /* Test stream after connection shut down */
285 assert(stream_open() == NULL);
287 /* Test releasing connection before stream */
288 conn_destroy();
289 vlc_http_stream_close(s, false);
291 return 0;