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 #include <sys/socket.h>
34 #include <vlc_common.h>
35 #include <vlc_block.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
)
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
);
55 DATA
, HEADERS
, PRIORITY
, RST_STREAM
, SETTINGS
, PUSH_PROMISE
, PING
, GOAWAY
,
56 WINDOW_UPDATE
, CONTINUATION
,
59 static void conn_expect(uint_fast8_t wanted
)
67 val
= vlc_tls_Read(external_tls
, hdr
, 9, true);
71 /* Check type. We do not currently validate WINDOW_UPDATE. */
73 assert(wanted
== got
|| WINDOW_UPDATE
== got
);
75 len
= (hdr
[1] << 8) | hdr
[2];
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)
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]);
100 conn_send(vlc_h2_frame_settings());
102 val
= vlc_tls_Read(external_tls
, hello
, 24, true);
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", "/");
122 struct vlc_http_stream
*s
= vlc_http_stream_open(conn
, m
);
123 vlc_http_msg_destroy(m
);
127 static void stream_reply(uint_fast32_t id
, bool nodata
)
129 struct vlc_http_msg
*m
= vlc_http_resp_create(200);
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 */
155 struct vlc_http_stream
*s
, *s2
;
156 struct vlc_http_msg
*m
;
158 uint_fast32_t sid
= -1; /* Second guessed stream IDs :-/ */
164 conn_send(vlc_h2_frame_ping(42));
167 /* Test rejected stream */
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
);
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 */
184 stream_reply(sid
, false);
185 m
= vlc_http_msg_get_initial(s
);
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 */
201 stream_continuation(sid
);
202 m
= vlc_http_msg_get_initial(s
);
204 assert(vlc_http_msg_get_status(m
) == 100);
205 stream_reply(sid
, false);
206 m
= vlc_http_msg_iterate(m
);
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
);
214 b
= vlc_http_msg_read(m
);
217 b
= vlc_http_msg_read(m
);
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 */
229 stream_continuation(sid
);
230 stream_reply(sid
, true);
232 s2
= stream_open(); /* second stream to enforce test timing/ordering */
234 stream_reply(sid
, true);
235 m
= vlc_http_msg_get_initial(s2
);
237 vlc_http_msg_destroy(m
);
238 m
= vlc_http_msg_get_initial(s
);
240 assert(vlc_http_msg_get_status(m
) == 200);
241 b
= vlc_http_msg_read(m
);
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 */
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
);
265 vlc_http_msg_destroy(m
);
266 m
= vlc_http_msg_get_initial(s2
);
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 */
280 conn_send(vlc_h2_frame_goaway(sid
- 2, VLC_H2_NO_ERROR
));
281 m
= vlc_http_stream_read_headers(s
);
284 /* Test stream after connection shut down */
285 assert(stream_open() == NULL
);
287 /* Test releasing connection before stream */
289 vlc_http_stream_close(s
, false);