]>
Commit | Line | Data |
---|---|---|
b32b8144 FG |
1 | // |
2 | // Copyright (w) 2016-2017 Vinnie Falco (vinnie dot falco at gmail dot com) | |
3 | // | |
4 | // Distributed under the Boost Software License, Version 1.0. (See accompanying | |
5 | // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) | |
6 | // | |
7 | // Official repository: https://github.com/boostorg/beast | |
8 | // | |
9 | ||
10 | // Test that header file is self-contained. | |
11 | #include <boost/beast/websocket/stream.hpp> | |
12 | ||
13 | #include "test.hpp" | |
14 | ||
15 | namespace boost { | |
16 | namespace beast { | |
17 | namespace websocket { | |
18 | ||
19 | class ping_test : public websocket_test_suite | |
20 | { | |
21 | public: | |
22 | template<class Wrap> | |
23 | void | |
24 | doTestPing(Wrap const& w) | |
25 | { | |
26 | permessage_deflate pmd; | |
27 | pmd.client_enable = false; | |
28 | pmd.server_enable = false; | |
29 | ||
30 | // ping | |
31 | doTest(pmd, [&](ws_type& ws) | |
32 | { | |
33 | w.ping(ws, {}); | |
34 | }); | |
35 | ||
36 | // pong | |
37 | doTest(pmd, [&](ws_type& ws) | |
38 | { | |
39 | w.pong(ws, {}); | |
40 | }); | |
41 | ||
42 | // ping, already closed | |
43 | { | |
44 | echo_server es{log}; | |
45 | stream<test::stream> ws{ioc_}; | |
46 | ws.next_layer().connect(es.stream()); | |
47 | ws.handshake("localhost", "/"); | |
48 | ws.close({}); | |
49 | try | |
50 | { | |
51 | w.ping(ws, {}); | |
52 | fail("", __FILE__, __LINE__); | |
53 | } | |
54 | catch(system_error const& se) | |
55 | { | |
56 | BEAST_EXPECTS( | |
57 | se.code() == boost::asio::error::operation_aborted, | |
58 | se.code().message()); | |
59 | } | |
60 | } | |
61 | ||
62 | // pong, already closed | |
63 | { | |
64 | echo_server es{log}; | |
65 | stream<test::stream> ws{ioc_}; | |
66 | ws.next_layer().connect(es.stream()); | |
67 | ws.handshake("localhost", "/"); | |
68 | ws.close({}); | |
69 | try | |
70 | { | |
71 | w.pong(ws, {}); | |
72 | fail("", __FILE__, __LINE__); | |
73 | } | |
74 | catch(system_error const& se) | |
75 | { | |
76 | BEAST_EXPECTS( | |
77 | se.code() == boost::asio::error::operation_aborted, | |
78 | se.code().message()); | |
79 | } | |
80 | } | |
81 | } | |
82 | ||
83 | void | |
84 | testPing() | |
85 | { | |
86 | doTestPing(SyncClient{}); | |
87 | ||
88 | yield_to([&](yield_context yield) | |
89 | { | |
90 | doTestPing(AsyncClient{yield}); | |
91 | }); | |
92 | } | |
93 | ||
94 | void | |
95 | testSuspend() | |
96 | { | |
97 | // suspend on write | |
98 | doFailLoop([&](test::fail_counter& fc) | |
99 | { | |
100 | echo_server es{log}; | |
101 | boost::asio::io_context ioc; | |
102 | stream<test::stream> ws{ioc, fc}; | |
103 | ws.next_layer().connect(es.stream()); | |
104 | ws.handshake("localhost", "/"); | |
105 | std::size_t count = 0; | |
106 | ws.async_write(sbuf("Hello, world"), | |
107 | [&](error_code ec, std::size_t n) | |
108 | { | |
109 | ++count; | |
110 | if(ec) | |
111 | BOOST_THROW_EXCEPTION( | |
112 | system_error{ec}); | |
113 | BEAST_EXPECT(n == 12); | |
114 | }); | |
115 | BEAST_EXPECT(ws.wr_block_); | |
116 | BEAST_EXPECT(count == 0); | |
117 | ws.async_ping({}, | |
118 | [&](error_code ec) | |
119 | { | |
120 | ++count; | |
121 | if(ec) | |
122 | BOOST_THROW_EXCEPTION( | |
123 | system_error{ec}); | |
124 | }); | |
125 | BEAST_EXPECT(count == 0); | |
126 | ioc.run(); | |
127 | BEAST_EXPECT(count == 2); | |
128 | }); | |
129 | ||
130 | // suspend on close | |
131 | doFailLoop([&](test::fail_counter& fc) | |
132 | { | |
133 | echo_server es{log}; | |
134 | boost::asio::io_context ioc; | |
135 | stream<test::stream> ws{ioc, fc}; | |
136 | ws.next_layer().connect(es.stream()); | |
137 | ws.handshake("localhost", "/"); | |
138 | std::size_t count = 0; | |
139 | ws.async_close({}, | |
140 | [&](error_code ec) | |
141 | { | |
142 | ++count; | |
143 | if(ec) | |
144 | BOOST_THROW_EXCEPTION( | |
145 | system_error{ec}); | |
146 | }); | |
147 | BEAST_EXPECT(ws.wr_block_); | |
148 | BEAST_EXPECT(count == 0); | |
149 | ws.async_ping({}, | |
150 | [&](error_code ec) | |
151 | { | |
152 | ++count; | |
153 | if(ec != boost::asio::error::operation_aborted) | |
154 | BOOST_THROW_EXCEPTION( | |
155 | system_error{ec}); | |
156 | }); | |
157 | BEAST_EXPECT(count == 0); | |
158 | ioc.run(); | |
159 | BEAST_EXPECT(count == 2); | |
160 | }); | |
161 | ||
162 | // suspend on read ping + message | |
163 | doFailLoop([&](test::fail_counter& fc) | |
164 | { | |
165 | echo_server es{log}; | |
166 | boost::asio::io_context ioc; | |
167 | stream<test::stream> ws{ioc, fc}; | |
168 | ws.next_layer().connect(es.stream()); | |
169 | ws.handshake("localhost", "/"); | |
170 | // add a ping and message to the input | |
171 | ws.next_layer().append(string_view{ | |
172 | "\x89\x00" "\x81\x01*", 5}); | |
173 | std::size_t count = 0; | |
174 | multi_buffer b; | |
175 | ws.async_read(b, | |
176 | [&](error_code ec, std::size_t) | |
177 | { | |
178 | ++count; | |
179 | if(ec) | |
180 | BOOST_THROW_EXCEPTION( | |
181 | system_error{ec}); | |
182 | }); | |
183 | while(! ws.wr_block_) | |
184 | { | |
185 | ioc.run_one(); | |
186 | if(! BEAST_EXPECT(! ioc.stopped())) | |
187 | break; | |
188 | } | |
189 | BEAST_EXPECT(count == 0); | |
190 | ws.async_ping({}, | |
191 | [&](error_code ec) | |
192 | { | |
193 | ++count; | |
194 | if(ec) | |
195 | BOOST_THROW_EXCEPTION( | |
196 | system_error{ec}); | |
197 | }); | |
198 | BEAST_EXPECT(count == 0); | |
199 | ioc.run(); | |
200 | BEAST_EXPECT(count == 2); | |
201 | }); | |
202 | ||
203 | // suspend on read bad message | |
204 | doFailLoop([&](test::fail_counter& fc) | |
205 | { | |
206 | echo_server es{log}; | |
207 | boost::asio::io_context ioc; | |
208 | stream<test::stream> ws{ioc, fc}; | |
209 | ws.next_layer().connect(es.stream()); | |
210 | ws.handshake("localhost", "/"); | |
211 | // add an invalid frame to the input | |
212 | ws.next_layer().append(string_view{ | |
213 | "\x09\x00", 2}); | |
214 | ||
215 | std::size_t count = 0; | |
216 | multi_buffer b; | |
217 | ws.async_read(b, | |
218 | [&](error_code ec, std::size_t) | |
219 | { | |
220 | ++count; | |
221 | if(ec != error::failed) | |
222 | BOOST_THROW_EXCEPTION( | |
223 | system_error{ec}); | |
224 | }); | |
225 | while(! ws.wr_block_) | |
226 | { | |
227 | ioc.run_one(); | |
228 | if(! BEAST_EXPECT(! ioc.stopped())) | |
229 | break; | |
230 | } | |
231 | BEAST_EXPECT(count == 0); | |
232 | ws.async_ping({}, | |
233 | [&](error_code ec) | |
234 | { | |
235 | ++count; | |
236 | if(ec != boost::asio::error::operation_aborted) | |
237 | BOOST_THROW_EXCEPTION( | |
238 | system_error{ec}); | |
239 | }); | |
240 | BEAST_EXPECT(count == 0); | |
241 | ioc.run(); | |
242 | BEAST_EXPECT(count == 2); | |
243 | }); | |
244 | ||
245 | // suspend on read close #1 | |
246 | doFailLoop([&](test::fail_counter& fc) | |
247 | { | |
248 | echo_server es{log}; | |
249 | boost::asio::io_context ioc; | |
250 | stream<test::stream> ws{ioc, fc}; | |
251 | ws.next_layer().connect(es.stream()); | |
252 | ws.handshake("localhost", "/"); | |
253 | // add a close frame to the input | |
254 | ws.next_layer().append(string_view{ | |
255 | "\x88\x00", 2}); | |
256 | std::size_t count = 0; | |
257 | multi_buffer b; | |
258 | ws.async_read(b, | |
259 | [&](error_code ec, std::size_t) | |
260 | { | |
261 | ++count; | |
262 | if(ec != error::closed) | |
263 | BOOST_THROW_EXCEPTION( | |
264 | system_error{ec}); | |
265 | }); | |
266 | while(! ws.wr_block_) | |
267 | { | |
268 | ioc.run_one(); | |
269 | if(! BEAST_EXPECT(! ioc.stopped())) | |
270 | break; | |
271 | } | |
272 | BEAST_EXPECT(count == 0); | |
273 | ws.async_ping({}, | |
274 | [&](error_code ec) | |
275 | { | |
276 | ++count; | |
277 | if(ec != boost::asio::error::operation_aborted) | |
278 | BOOST_THROW_EXCEPTION( | |
279 | system_error{ec}); | |
280 | }); | |
281 | BEAST_EXPECT(count == 0); | |
282 | ioc.run(); | |
283 | BEAST_EXPECT(count == 2); | |
284 | }); | |
285 | ||
286 | // suspend on read close #2 | |
287 | doFailLoop([&](test::fail_counter& fc) | |
288 | { | |
289 | echo_server es{log, kind::async}; | |
290 | boost::asio::io_context ioc; | |
291 | stream<test::stream> ws{ioc, fc}; | |
292 | ws.next_layer().connect(es.stream()); | |
293 | ws.handshake("localhost", "/"); | |
294 | // Cause close to be received | |
295 | es.async_close(); | |
296 | std::size_t count = 0; | |
297 | multi_buffer b; | |
298 | ws.async_read(b, | |
299 | [&](error_code ec, std::size_t) | |
300 | { | |
301 | ++count; | |
302 | if(ec != error::closed) | |
303 | BOOST_THROW_EXCEPTION( | |
304 | system_error{ec}); | |
305 | }); | |
306 | while(! ws.wr_block_) | |
307 | { | |
308 | ioc.run_one(); | |
309 | if(! BEAST_EXPECT(! ioc.stopped())) | |
310 | break; | |
311 | } | |
312 | BEAST_EXPECT(count == 0); | |
313 | ws.async_ping({}, | |
314 | [&](error_code ec) | |
315 | { | |
316 | ++count; | |
317 | if(ec != boost::asio::error::operation_aborted) | |
318 | BOOST_THROW_EXCEPTION( | |
319 | system_error{ec}); | |
320 | }); | |
321 | BEAST_EXPECT(count == 0); | |
322 | ioc.run(); | |
323 | BEAST_EXPECT(count == 2); | |
324 | }); | |
325 | ||
326 | // don't ping on close | |
327 | doFailLoop([&](test::fail_counter& fc) | |
328 | { | |
329 | echo_server es{log}; | |
330 | error_code ec; | |
331 | boost::asio::io_context ioc; | |
332 | stream<test::stream> ws{ioc, fc}; | |
333 | ws.next_layer().connect(es.stream()); | |
334 | ws.handshake("localhost", "/"); | |
335 | std::size_t count = 0; | |
336 | ws.async_write(sbuf("*"), | |
337 | [&](error_code ec, std::size_t n) | |
338 | { | |
339 | ++count; | |
340 | if(ec) | |
341 | BOOST_THROW_EXCEPTION( | |
342 | system_error{ec}); | |
343 | BEAST_EXPECT(n == 1); | |
344 | }); | |
345 | BEAST_EXPECT(ws.wr_block_); | |
346 | ws.async_ping("", | |
347 | [&](error_code ec) | |
348 | { | |
349 | ++count; | |
350 | if(ec != boost::asio::error::operation_aborted) | |
351 | BOOST_THROW_EXCEPTION( | |
352 | system_error{ec}); | |
353 | }); | |
354 | ws.async_close({}, | |
355 | [&](error_code) | |
356 | { | |
357 | ++count; | |
358 | if(ec) | |
359 | BOOST_THROW_EXCEPTION( | |
360 | system_error{ec}); | |
361 | }); | |
362 | ioc.run(); | |
363 | BEAST_EXPECT(count == 3); | |
364 | }); | |
365 | ||
366 | { | |
367 | echo_server es{log, kind::async}; | |
368 | boost::asio::io_context ioc; | |
369 | stream<test::stream> ws{ioc}; | |
370 | ws.next_layer().connect(es.stream()); | |
371 | ws.handshake("localhost", "/"); | |
372 | ||
373 | // Cause close to be received | |
374 | es.async_close(); | |
375 | ||
376 | multi_buffer b; | |
377 | std::size_t count = 0; | |
378 | // Read a close frame. | |
379 | // Sends a close frame, blocking writes. | |
380 | ws.async_read(b, | |
381 | [&](error_code ec, std::size_t) | |
382 | { | |
383 | // Read should complete with error::closed | |
384 | ++count; | |
385 | BEAST_EXPECTS(ec == error::closed, | |
386 | ec.message()); | |
387 | // Pings after a close are aborted | |
388 | ws.async_ping("", | |
389 | [&](error_code ec) | |
390 | { | |
391 | ++count; | |
392 | BEAST_EXPECTS(ec == boost::asio:: | |
393 | error::operation_aborted, | |
394 | ec.message()); | |
395 | }); | |
396 | }); | |
397 | if(! BEAST_EXPECT(run_until(ioc, 100, | |
398 | [&]{ return ws.wr_close_; }))) | |
399 | return; | |
400 | // Try to ping | |
401 | ws.async_ping("payload", | |
402 | [&](error_code ec) | |
403 | { | |
404 | // Pings after a close are aborted | |
405 | ++count; | |
406 | BEAST_EXPECTS(ec == boost::asio:: | |
407 | error::operation_aborted, | |
408 | ec.message()); | |
409 | // Subsequent calls to close are aborted | |
410 | ws.async_close({}, | |
411 | [&](error_code ec) | |
412 | { | |
413 | ++count; | |
414 | BEAST_EXPECTS(ec == boost::asio:: | |
415 | error::operation_aborted, | |
416 | ec.message()); | |
417 | }); | |
418 | }); | |
419 | static std::size_t constexpr limit = 100; | |
420 | std::size_t n; | |
421 | for(n = 0; n < limit; ++n) | |
422 | { | |
423 | if(count >= 4) | |
424 | break; | |
425 | ioc.run_one(); | |
426 | } | |
427 | BEAST_EXPECT(n < limit); | |
428 | ioc.run(); | |
429 | } | |
430 | } | |
431 | ||
432 | void | |
433 | testContHook() | |
434 | { | |
435 | struct handler | |
436 | { | |
437 | void operator()(error_code) {} | |
438 | }; | |
439 | ||
440 | stream<test::stream> ws{ioc_}; | |
441 | stream<test::stream>::ping_op<handler> op{ | |
442 | handler{}, ws, detail::opcode::ping, {}}; | |
443 | using boost::asio::asio_handler_is_continuation; | |
444 | asio_handler_is_continuation(&op); | |
445 | } | |
446 | ||
447 | void | |
448 | run() override | |
449 | { | |
450 | testPing(); | |
451 | testSuspend(); | |
452 | testContHook(); | |
453 | } | |
454 | }; | |
455 | ||
456 | BEAST_DEFINE_TESTSUITE(beast,websocket,ping); | |
457 | ||
458 | } // websocket | |
459 | } // beast | |
460 | } // boost |