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 *****************************************************************************/
30 #include <sys/types.h>
32 #ifdef HAVE_SYS_SOCKET_H
33 #include <sys/socket.h>
36 #include <vlc_common.h>
37 #include <vlc_block.h>
43 #if defined(PF_UNIX) && !defined(PF_LOCAL)
44 # define PF_LOCAL PF_UNIX
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
)
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
);
63 DATA
, HEADERS
, PRIORITY
, RST_STREAM
, SETTINGS
, PUSH_PROMISE
, PING
, GOAWAY
,
64 WINDOW_UPDATE
, CONTINUATION
,
67 static void conn_expect(uint_fast8_t wanted
)
75 val
= vlc_tls_Read(external_tls
, hdr
, 9, true);
79 /* Check type. We do not currently validate WINDOW_UPDATE. */
81 assert(wanted
== got
|| WINDOW_UPDATE
== got
);
83 len
= (hdr
[1] << 8) | hdr
[2];
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)
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);
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", "/");
131 struct vlc_http_stream
*s
= vlc_http_stream_open(conn
, m
, has_data
);
132 vlc_http_msg_destroy(m
);
136 static void stream_reply(uint_fast32_t id
, bool nodata
)
138 struct vlc_http_msg
*m
= vlc_http_resp_create(200);
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 */
164 struct vlc_http_stream
*s
, *s2
;
165 struct vlc_http_msg
*m
;
167 uint_fast32_t sid
= -1; /* Second guessed stream IDs :-/ */
173 conn_send(vlc_h2_frame_ping(42));
176 /* Test rejected stream */
178 s
= stream_open(false);
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
);
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 */
191 s
= stream_open(false);
193 stream_reply(sid
, false);
194 m
= vlc_http_msg_get_initial(s
);
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 */
208 s
= stream_open(false);
210 stream_continuation(sid
);
211 m
= vlc_http_msg_get_initial(s
);
213 assert(vlc_http_msg_get_status(m
) == 100);
214 stream_reply(sid
, false);
215 m
= vlc_http_msg_iterate(m
);
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
);
223 b
= vlc_http_msg_read(m
);
226 b
= vlc_http_msg_read(m
);
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 */
236 s
= stream_open(false);
238 stream_continuation(sid
);
239 stream_reply(sid
, true);
241 s2
= stream_open(false); /* 2nd stream to enforce test timing/ordering */
243 stream_reply(sid
, true);
244 m
= vlc_http_msg_get_initial(s2
);
246 vlc_http_msg_destroy(m
);
247 m
= vlc_http_msg_get_initial(s
);
249 assert(vlc_http_msg_get_status(m
) == 200);
250 b
= vlc_http_msg_read(m
);
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 */
261 s
= stream_open(true);
263 stream_continuation(sid
);
264 m
= vlc_http_msg_get_initial(s
);
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
);
274 vlc_http_msg_destroy(m
);
276 conn_expect(HEADERS
);
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 */
286 s
= stream_open(false);
289 s2
= stream_open(false);
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
);
296 vlc_http_msg_destroy(m
);
297 m
= vlc_http_msg_get_initial(s2
);
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 */
309 s
= stream_open(false);
311 conn_send(vlc_h2_frame_goaway(sid
- 2, VLC_H2_NO_ERROR
));
312 m
= vlc_http_stream_read_headers(s
);
315 /* Test stream after connection shut down */
316 assert(stream_open(false) == NULL
);
318 /* Test releasing connection before stream */
320 vlc_http_stream_close(s
, false);