qt: playlist: use item title if available
[vlc.git] / modules / access / http / h2conn_test.c
blob74d5cc15ac4376e8a5544d276ba3bdeebec12351
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 #ifdef HAVE_SYS_SOCKET_H
33 #include <sys/socket.h>
34 #endif
36 #include <vlc_common.h>
37 #include <vlc_block.h>
38 #include <vlc_tls.h>
39 #include "h2frame.h"
40 #include "conn.h"
41 #include "message.h"
43 #if defined(PF_UNIX) && !defined(PF_LOCAL)
44 # define PF_LOCAL PF_UNIX
45 #endif
47 const char vlc_module_name[] = "test_h2conn";
49 static struct vlc_http_conn *conn;
50 static struct vlc_tls *external_tls;
52 static void conn_send(struct vlc_h2_frame *f)
54 assert(f != NULL);
56 size_t len = vlc_h2_frame_size(f);
57 ssize_t val = vlc_tls_Write(external_tls, f->data, len);
58 assert((size_t)val == len);
59 free(f);
62 enum {
63 DATA, HEADERS, PRIORITY, RST_STREAM, SETTINGS, PUSH_PROMISE, PING, GOAWAY,
64 WINDOW_UPDATE, CONTINUATION,
67 static void conn_expect(uint_fast8_t wanted)
69 size_t len;
70 ssize_t val;
71 uint8_t hdr[9];
72 uint8_t got;
74 do {
75 val = vlc_tls_Read(external_tls, hdr, 9, true);
76 assert(val == 9);
77 assert(hdr[0] == 0);
79 /* Check type. We do not currently validate WINDOW_UPDATE. */
80 got = hdr[3];
81 assert(wanted == got || WINDOW_UPDATE == got);
83 len = (hdr[1] << 8) | hdr[2];
84 if (len > 0)
86 char buf[len];
88 val = vlc_tls_Read(external_tls, buf, len, true);
89 assert(val == (ssize_t)len);
92 while (got != wanted);
95 static void conn_create(void)
97 ssize_t val;
98 vlc_tls_t *tlsv[2];
99 char hello[24];
101 if (vlc_tls_SocketPair(PF_LOCAL, 0, tlsv))
102 assert(!"socketpair");
104 external_tls = tlsv[0];
106 conn = vlc_h2_conn_create(NULL, tlsv[1]);
107 assert(conn != NULL);
108 conn_send(vlc_h2_frame_settings());
110 val = vlc_tls_Read(external_tls, hello, 24, true);
111 assert(val == 24);
112 assert(!memcmp(hello, "PRI * HTTP/2.0\r\n", 16));
113 conn_expect(SETTINGS);
114 conn_expect(SETTINGS);
117 static void conn_destroy(void)
119 vlc_tls_Shutdown(external_tls, false);
120 vlc_http_conn_release(conn);
121 vlc_tls_SessionDelete(external_tls);
124 static struct vlc_http_stream *stream_open(bool has_data)
126 const char *verb = has_data ? "POST" : "GET";
127 struct vlc_http_msg *m = vlc_http_req_create(verb, "https",
128 "www.example.com", "/");
129 assert(m != NULL);
131 struct vlc_http_stream *s = vlc_http_stream_open(conn, m, has_data);
132 vlc_http_msg_destroy(m);
133 return s;
136 static void stream_reply(uint_fast32_t id, bool nodata)
138 struct vlc_http_msg *m = vlc_http_resp_create(200);
139 assert(m != NULL);
140 vlc_http_msg_add_agent(m, "VLC-h2-tester");
142 conn_send(vlc_http_msg_h2_frame(m, id, nodata));
143 vlc_http_msg_destroy(m);
146 static void stream_continuation(uint_fast32_t id)
148 const char *h[][2] = {
149 { ":status", "100" },
152 conn_send(vlc_h2_frame_headers(id, VLC_H2_DEFAULT_MAX_FRAME, false, 1, h));
155 static void stream_data(uint_fast32_t id, const char *str, bool eos)
157 conn_send(vlc_h2_frame_data(id, str, strlen(str), eos));
160 /* TODO: check messages coming from the connection under test */
162 int main(void)
164 struct vlc_http_stream *s, *s2;
165 struct vlc_http_msg *m;
166 struct block_t *b;
167 uint_fast32_t sid = -1; /* Second guessed stream IDs :-/ */
169 conn_create();
170 conn_destroy();
172 conn_create();
173 conn_send(vlc_h2_frame_ping(42));
174 conn_expect(PING);
176 /* Test rejected stream */
177 sid += 2;
178 s = stream_open(false);
179 assert(s != NULL);
180 conn_expect(HEADERS);
181 conn_send(vlc_h2_frame_rst_stream(sid, VLC_H2_REFUSED_STREAM));
182 m = vlc_http_stream_read_headers(s);
183 assert(m == NULL);
184 b = vlc_http_stream_read(s);
185 assert(b == vlc_http_error);
186 vlc_http_stream_close(s, false);
187 conn_expect(RST_STREAM);
189 /* Test accepted stream */
190 sid += 2;
191 s = stream_open(false);
192 assert(s != NULL);
193 stream_reply(sid, false);
194 m = vlc_http_msg_get_initial(s);
195 assert(m != NULL);
196 vlc_http_msg_destroy(m);
198 stream_data(3, "Hello ", false); /* late data */
199 stream_data(3, "world!", true);
201 conn_expect(HEADERS);
202 conn_expect(RST_STREAM);
203 conn_expect(RST_STREAM);
204 conn_expect(RST_STREAM);
206 /* Test continuation then accepted stream */
207 sid += 2;
208 s = stream_open(false);
209 assert(s != NULL);
210 stream_continuation(sid);
211 m = vlc_http_msg_get_initial(s);
212 assert(m != NULL);
213 assert(vlc_http_msg_get_status(m) == 100);
214 stream_reply(sid, false);
215 m = vlc_http_msg_iterate(m);
216 assert(m != NULL);
217 stream_data(sid, "Hello ", false);
218 stream_data(sid, "world!", true);
219 stream_data(sid, "Stray message", false); /* data after EOS */
220 b = vlc_http_msg_read(m);
221 assert(b != NULL);
222 block_Release(b);
223 b = vlc_http_msg_read(m);
224 assert(b != NULL);
225 block_Release(b);
226 b = vlc_http_msg_read(m);
227 assert(b == NULL);
228 vlc_http_msg_destroy(m);
230 conn_expect(HEADERS);
231 conn_expect(RST_STREAM);
232 conn_expect(RST_STREAM);
234 /* Test accepted stream after continuation */
235 sid += 2;
236 s = stream_open(false);
237 assert(s != NULL);
238 stream_continuation(sid);
239 stream_reply(sid, true);
240 sid += 2;
241 s2 = stream_open(false); /* 2nd stream to enforce test timing/ordering */
242 assert(s2 != NULL);
243 stream_reply(sid, true);
244 m = vlc_http_msg_get_initial(s2);
245 assert(m != NULL);
246 vlc_http_msg_destroy(m);
247 m = vlc_http_msg_get_initial(s);
248 assert(m != NULL);
249 assert(vlc_http_msg_get_status(m) == 200);
250 b = vlc_http_msg_read(m);
251 assert(b == NULL);
252 vlc_http_msg_destroy(m);
254 conn_expect(HEADERS);
255 conn_expect(HEADERS);
256 conn_expect(RST_STREAM);
257 conn_expect(RST_STREAM);
259 /* Test stream with request payload */
260 sid += 2;
261 s = stream_open(true);
262 assert(s != NULL);
263 stream_continuation(sid);
264 m = vlc_http_msg_get_initial(s);
265 assert(m != NULL);
266 b = block_Alloc(12);
267 assert(b != NULL);
268 memcpy(b->p_buffer, "Hello world!", 12);
269 assert(vlc_http_msg_write(m, b, false) == 0);
270 assert(vlc_http_msg_write(m, NULL, true) == 0);
271 stream_reply(sid, false);
272 m = vlc_http_msg_iterate(m);
273 assert(m != NULL);
274 vlc_http_msg_destroy(m);
276 conn_expect(HEADERS);
277 conn_expect(DATA);
278 conn_expect(DATA);
279 conn_expect(RST_STREAM);
281 /* Test nonexistent stream reset */
282 conn_send(vlc_h2_frame_rst_stream(sid + 100, VLC_H2_REFUSED_STREAM));
284 /* Test multiple streams in non-LIFO order */
285 sid += 2;
286 s = stream_open(false);
287 assert(s != NULL);
288 sid += 2;
289 s2 = stream_open(false);
290 assert(s2 != NULL);
291 stream_reply(sid, false);
292 stream_reply(sid - 2, true);
293 stream_data(sid, "Discarded", false); /* not read data */
294 m = vlc_http_msg_get_initial(s);
295 assert(m != NULL);
296 vlc_http_msg_destroy(m);
297 m = vlc_http_msg_get_initial(s2);
298 assert(m != NULL);
299 vlc_http_msg_destroy(m);
301 conn_expect(HEADERS);
302 conn_expect(HEADERS);
303 conn_expect(RST_STREAM);
304 conn_expect(RST_STREAM);
305 /* might or might not seen one or two extra RST_STREAM now */
307 /* Test graceful connection termination */
308 sid += 2;
309 s = stream_open(false);
310 assert(s != NULL);
311 conn_send(vlc_h2_frame_goaway(sid - 2, VLC_H2_NO_ERROR));
312 m = vlc_http_stream_read_headers(s);
313 assert(m == NULL);
315 /* Test stream after connection shut down */
316 assert(stream_open(false) == NULL);
318 /* Test releasing connection before stream */
319 conn_destroy();
320 vlc_http_stream_close(s, false);
322 return 0;