]>
Commit | Line | Data |
---|---|---|
b32b8144 | 1 | // |
92f5a8d4 | 2 | // Copyright (c) 2016-2019 Vinnie Falco (vinnie dot falco at gmail dot com) |
b32b8144 FG |
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 | ||
92f5a8d4 TL |
13 | #include <boost/beast/_experimental/test/stream.hpp> |
14 | #include <boost/beast/_experimental/test/tcp.hpp> | |
15 | ||
b32b8144 FG |
16 | #include "test.hpp" |
17 | ||
92f5a8d4 | 18 | #include <boost/asio/io_context.hpp> |
11fdf7f2 | 19 | #include <boost/asio/strand.hpp> |
92f5a8d4 | 20 | #include <thread> |
20effc67 TL |
21 | #if BOOST_ASIO_HAS_CO_AWAIT |
22 | #include <boost/asio/use_awaitable.hpp> | |
23 | #endif | |
11fdf7f2 | 24 | |
b32b8144 FG |
25 | namespace boost { |
26 | namespace beast { | |
27 | namespace websocket { | |
28 | ||
29 | class handshake_test : public websocket_test_suite | |
30 | { | |
31 | public: | |
32 | template<class Wrap> | |
33 | void | |
34 | doTestHandshake(Wrap const& w) | |
35 | { | |
36 | class req_decorator | |
37 | { | |
38 | bool& b_; | |
39 | ||
40 | public: | |
41 | req_decorator(req_decorator const&) = default; | |
42 | ||
43 | explicit | |
44 | req_decorator(bool& b) | |
45 | : b_(b) | |
46 | { | |
47 | } | |
48 | ||
49 | void | |
50 | operator()(request_type&) const | |
51 | { | |
52 | b_ = true; | |
53 | } | |
54 | }; | |
55 | ||
56 | // handshake | |
57 | doStreamLoop([&](test::stream& ts) | |
58 | { | |
59 | echo_server es{log}; | |
60 | ws_type ws{ts}; | |
61 | ws.next_layer().connect(es.stream()); | |
62 | try | |
63 | { | |
64 | w.handshake(ws, "localhost", "/"); | |
65 | } | |
66 | catch(...) | |
67 | { | |
68 | ts.close(); | |
69 | throw; | |
70 | } | |
71 | ts.close(); | |
72 | }); | |
73 | ||
74 | // handshake, response | |
75 | doStreamLoop([&](test::stream& ts) | |
76 | { | |
77 | echo_server es{log}; | |
78 | ws_type ws{ts}; | |
79 | ws.next_layer().connect(es.stream()); | |
80 | response_type res; | |
81 | try | |
82 | { | |
83 | w.handshake(ws, res, "localhost", "/"); | |
84 | // VFALCO validate res? | |
85 | } | |
86 | catch(...) | |
87 | { | |
88 | ts.close(); | |
89 | throw; | |
90 | } | |
91 | ts.close(); | |
92 | }); | |
93 | ||
94 | // handshake, decorator | |
95 | doStreamLoop([&](test::stream& ts) | |
96 | { | |
97 | echo_server es{log}; | |
98 | ws_type ws{ts}; | |
99 | ws.next_layer().connect(es.stream()); | |
100 | bool called = false; | |
101 | try | |
102 | { | |
92f5a8d4 TL |
103 | ws.set_option(stream_base::decorator( |
104 | req_decorator{called})); | |
105 | w.handshake(ws, "localhost", "/"); | |
b32b8144 FG |
106 | BEAST_EXPECT(called); |
107 | } | |
108 | catch(...) | |
109 | { | |
110 | ts.close(); | |
111 | throw; | |
112 | } | |
113 | ts.close(); | |
114 | }); | |
115 | ||
116 | // handshake, response, decorator | |
117 | doStreamLoop([&](test::stream& ts) | |
118 | { | |
119 | echo_server es{log}; | |
120 | ws_type ws{ts}; | |
121 | ws.next_layer().connect(es.stream()); | |
122 | bool called = false; | |
123 | response_type res; | |
124 | try | |
125 | { | |
92f5a8d4 TL |
126 | ws.set_option(stream_base::decorator( |
127 | req_decorator{called})); | |
128 | w.handshake(ws, res, "localhost", "/"); | |
b32b8144 FG |
129 | // VFALCO validate res? |
130 | BEAST_EXPECT(called); | |
131 | } | |
132 | catch(...) | |
133 | { | |
134 | ts.close(); | |
135 | throw; | |
136 | } | |
137 | ts.close(); | |
138 | }); | |
139 | } | |
140 | ||
141 | void | |
142 | testHandshake() | |
143 | { | |
144 | doTestHandshake(SyncClient{}); | |
145 | ||
146 | yield_to([&](yield_context yield) | |
147 | { | |
148 | doTestHandshake(AsyncClient{yield}); | |
149 | }); | |
150 | ||
151 | auto const check = | |
11fdf7f2 | 152 | [&](error e, std::string const& s) |
b32b8144 FG |
153 | { |
154 | stream<test::stream> ws{ioc_}; | |
155 | auto tr = connect(ws.next_layer()); | |
156 | ws.next_layer().append(s); | |
157 | tr.close(); | |
158 | try | |
159 | { | |
160 | ws.handshake("localhost:80", "/"); | |
161 | fail(); | |
162 | } | |
163 | catch(system_error const& se) | |
164 | { | |
11fdf7f2 | 165 | BEAST_EXPECTS(se.code() == e, se.what()); |
b32b8144 FG |
166 | } |
167 | }; | |
11fdf7f2 TL |
168 | // bad HTTP version |
169 | check(error::bad_http_version, | |
b32b8144 FG |
170 | "HTTP/1.0 101 Switching Protocols\r\n" |
171 | "Server: beast\r\n" | |
172 | "Upgrade: WebSocket\r\n" | |
173 | "Connection: upgrade\r\n" | |
174 | "Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\n" | |
175 | "Sec-WebSocket-Version: 13\r\n" | |
176 | "\r\n" | |
177 | ); | |
11fdf7f2 TL |
178 | // no Connection |
179 | check(error::no_connection, | |
180 | "HTTP/1.1 101 Switching Protocols\r\n" | |
b32b8144 FG |
181 | "Server: beast\r\n" |
182 | "Upgrade: WebSocket\r\n" | |
b32b8144 FG |
183 | "Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\n" |
184 | "Sec-WebSocket-Version: 13\r\n" | |
185 | "\r\n" | |
186 | ); | |
11fdf7f2 TL |
187 | // no Connection upgrade |
188 | check(error::no_connection_upgrade, | |
189 | "HTTP/1.1 101 Switching Protocols\r\n" | |
190 | "Server: beast\r\n" | |
191 | "Upgrade: WebSocket\r\n" | |
192 | "Connection: keep-alive\r\n" | |
193 | "Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\n" | |
194 | "Sec-WebSocket-Version: 13\r\n" | |
195 | "\r\n" | |
196 | ); | |
197 | // no Upgrade | |
198 | check(error::no_upgrade, | |
b32b8144 FG |
199 | "HTTP/1.1 101 Switching Protocols\r\n" |
200 | "Server: beast\r\n" | |
b32b8144 FG |
201 | "Connection: upgrade\r\n" |
202 | "Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\n" | |
203 | "Sec-WebSocket-Version: 13\r\n" | |
204 | "\r\n" | |
205 | ); | |
11fdf7f2 TL |
206 | // no Upgrade websocket |
207 | check(error::no_upgrade_websocket, | |
b32b8144 FG |
208 | "HTTP/1.1 101 Switching Protocols\r\n" |
209 | "Server: beast\r\n" | |
11fdf7f2 TL |
210 | "Upgrade: HTTP/2\r\n" |
211 | "Connection: upgrade\r\n" | |
b32b8144 FG |
212 | "Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\n" |
213 | "Sec-WebSocket-Version: 13\r\n" | |
214 | "\r\n" | |
215 | ); | |
11fdf7f2 TL |
216 | // no Sec-WebSocket-Accept |
217 | check(error::no_sec_accept, | |
b32b8144 FG |
218 | "HTTP/1.1 101 Switching Protocols\r\n" |
219 | "Server: beast\r\n" | |
220 | "Upgrade: WebSocket\r\n" | |
221 | "Connection: upgrade\r\n" | |
222 | "Sec-WebSocket-Version: 13\r\n" | |
223 | "\r\n" | |
224 | ); | |
11fdf7f2 TL |
225 | // bad Sec-WebSocket-Accept |
226 | check(error::bad_sec_accept, | |
b32b8144 FG |
227 | "HTTP/1.1 101 Switching Protocols\r\n" |
228 | "Server: beast\r\n" | |
229 | "Upgrade: WebSocket\r\n" | |
230 | "Connection: upgrade\r\n" | |
231 | "Sec-WebSocket-Accept: *\r\n" | |
232 | "Sec-WebSocket-Version: 13\r\n" | |
233 | "\r\n" | |
234 | ); | |
11fdf7f2 TL |
235 | // declined |
236 | check(error::upgrade_declined, | |
237 | "HTTP/1.1 200 OK\r\n" | |
238 | "Server: beast\r\n" | |
239 | "Upgrade: WebSocket\r\n" | |
240 | "Connection: upgrade\r\n" | |
241 | "Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\n" | |
242 | "Sec-WebSocket-Version: 13\r\n" | |
243 | "\r\n" | |
244 | ); | |
b32b8144 FG |
245 | } |
246 | ||
247 | // Compression Extensions for WebSocket | |
248 | // | |
249 | // https://tools.ietf.org/html/rfc7692 | |
250 | // | |
251 | void | |
252 | testExtRead() | |
253 | { | |
254 | detail::pmd_offer po; | |
255 | ||
256 | auto const accept = | |
257 | [&](string_view s) | |
258 | { | |
259 | http::fields f; | |
260 | f.set(http::field::sec_websocket_extensions, s); | |
261 | po = detail::pmd_offer(); | |
262 | detail::pmd_read(po, f); | |
263 | BEAST_EXPECT(po.accept); | |
264 | }; | |
265 | ||
266 | auto const reject = | |
267 | [&](string_view s) | |
268 | { | |
269 | http::fields f; | |
270 | f.set(http::field::sec_websocket_extensions, s); | |
271 | po = detail::pmd_offer(); | |
272 | detail::pmd_read(po, f); | |
273 | BEAST_EXPECT(! po.accept); | |
274 | }; | |
275 | ||
276 | // duplicate parameters | |
277 | reject("permessage-deflate; server_max_window_bits=8; server_max_window_bits=8"); | |
278 | ||
279 | // missing value | |
280 | reject("permessage-deflate; server_max_window_bits"); | |
281 | reject("permessage-deflate; server_max_window_bits="); | |
282 | ||
283 | // invalid value | |
284 | reject("permessage-deflate; server_max_window_bits=-1"); | |
285 | reject("permessage-deflate; server_max_window_bits=7"); | |
286 | reject("permessage-deflate; server_max_window_bits=16"); | |
287 | reject("permessage-deflate; server_max_window_bits=999999999999999999999999"); | |
288 | reject("permessage-deflate; server_max_window_bits=9a"); | |
289 | ||
290 | // duplicate parameters | |
291 | reject("permessage-deflate; client_max_window_bits=8; client_max_window_bits=8"); | |
292 | ||
293 | // optional value excluded | |
294 | accept("permessage-deflate; client_max_window_bits"); | |
295 | BEAST_EXPECT(po.client_max_window_bits == -1); | |
296 | accept("permessage-deflate; client_max_window_bits="); | |
297 | BEAST_EXPECT(po.client_max_window_bits == -1); | |
298 | ||
299 | // invalid value | |
300 | reject("permessage-deflate; client_max_window_bits=-1"); | |
301 | reject("permessage-deflate; client_max_window_bits=7"); | |
302 | reject("permessage-deflate; client_max_window_bits=16"); | |
303 | reject("permessage-deflate; client_max_window_bits=999999999999999999999999"); | |
304 | ||
305 | // duplicate parameters | |
306 | reject("permessage-deflate; server_no_context_takeover; server_no_context_takeover"); | |
307 | ||
308 | // valueless parameter | |
309 | accept("permessage-deflate; server_no_context_takeover"); | |
310 | BEAST_EXPECT(po.server_no_context_takeover); | |
311 | accept("permessage-deflate; server_no_context_takeover="); | |
312 | BEAST_EXPECT(po.server_no_context_takeover); | |
313 | ||
314 | // disallowed value | |
315 | reject("permessage-deflate; server_no_context_takeover=-1"); | |
316 | reject("permessage-deflate; server_no_context_takeover=x"); | |
317 | reject("permessage-deflate; server_no_context_takeover=\"yz\""); | |
318 | reject("permessage-deflate; server_no_context_takeover=999999999999999999999999"); | |
319 | ||
320 | // duplicate parameters | |
321 | reject("permessage-deflate; client_no_context_takeover; client_no_context_takeover"); | |
322 | ||
323 | // valueless parameter | |
324 | accept("permessage-deflate; client_no_context_takeover"); | |
325 | BEAST_EXPECT(po.client_no_context_takeover); | |
326 | accept("permessage-deflate; client_no_context_takeover="); | |
327 | BEAST_EXPECT(po.client_no_context_takeover); | |
328 | ||
329 | // disallowed value | |
330 | reject("permessage-deflate; client_no_context_takeover=-1"); | |
331 | reject("permessage-deflate; client_no_context_takeover=x"); | |
332 | reject("permessage-deflate; client_no_context_takeover=\"yz\""); | |
333 | reject("permessage-deflate; client_no_context_takeover=999999999999999999999999"); | |
334 | ||
335 | // unknown extension parameter | |
336 | reject("permessage-deflate; unknown"); | |
337 | reject("permessage-deflate; unknown="); | |
338 | reject("permessage-deflate; unknown=1"); | |
339 | reject("permessage-deflate; unknown=x"); | |
340 | reject("permessage-deflate; unknown=\"xy\""); | |
341 | } | |
342 | ||
343 | void | |
344 | testExtWrite() | |
345 | { | |
346 | detail::pmd_offer po; | |
347 | ||
348 | auto const check = | |
349 | [&](string_view match) | |
350 | { | |
351 | http::fields f; | |
352 | detail::pmd_write(f, po); | |
353 | BEAST_EXPECT( | |
354 | f[http::field::sec_websocket_extensions] | |
355 | == match); | |
356 | }; | |
357 | ||
358 | po.accept = true; | |
359 | po.server_max_window_bits = 0; | |
360 | po.client_max_window_bits = 0; | |
361 | po.server_no_context_takeover = false; | |
362 | po.client_no_context_takeover = false; | |
92f5a8d4 | 363 | |
b32b8144 FG |
364 | check("permessage-deflate"); |
365 | ||
366 | po.server_max_window_bits = 10; | |
367 | check("permessage-deflate; server_max_window_bits=10"); | |
368 | ||
369 | po.server_max_window_bits = -1; | |
370 | check("permessage-deflate; server_max_window_bits"); | |
371 | ||
372 | po.server_max_window_bits = 0; | |
373 | po.client_max_window_bits = 10; | |
374 | check("permessage-deflate; client_max_window_bits=10"); | |
375 | ||
376 | po.client_max_window_bits = -1; | |
377 | check("permessage-deflate; client_max_window_bits"); | |
378 | ||
379 | po.client_max_window_bits = 0; | |
380 | po.server_no_context_takeover = true; | |
381 | check("permessage-deflate; server_no_context_takeover"); | |
382 | ||
383 | po.server_no_context_takeover = false; | |
384 | po.client_no_context_takeover = true; | |
385 | check("permessage-deflate; client_no_context_takeover"); | |
386 | } | |
387 | ||
388 | void | |
389 | testExtNegotiate() | |
390 | { | |
391 | permessage_deflate pmd; | |
392 | ||
393 | auto const reject = | |
394 | [&]( | |
395 | string_view offer) | |
396 | { | |
397 | detail::pmd_offer po; | |
398 | { | |
399 | http::fields f; | |
400 | f.set(http::field::sec_websocket_extensions, offer); | |
401 | detail::pmd_read(po, f); | |
402 | } | |
403 | http::fields f; | |
404 | detail::pmd_offer config; | |
405 | detail::pmd_negotiate(f, config, po, pmd); | |
406 | BEAST_EXPECT(! config.accept); | |
407 | }; | |
408 | ||
409 | auto const accept = | |
410 | [&]( | |
411 | string_view offer, | |
412 | string_view result) | |
413 | { | |
414 | detail::pmd_offer po; | |
415 | { | |
416 | http::fields f; | |
417 | f.set(http::field::sec_websocket_extensions, offer); | |
418 | detail::pmd_read(po, f); | |
419 | } | |
420 | http::fields f; | |
421 | detail::pmd_offer config; | |
422 | detail::pmd_negotiate(f, config, po, pmd); | |
423 | auto const got = | |
424 | f[http::field::sec_websocket_extensions]; | |
425 | BEAST_EXPECTS(got == result, got); | |
426 | { | |
427 | detail::pmd_offer poc; | |
428 | detail::pmd_read(poc, f); | |
429 | detail::pmd_normalize(poc); | |
430 | BEAST_EXPECT(poc.accept); | |
431 | } | |
432 | BEAST_EXPECT(config.server_max_window_bits != 0); | |
433 | BEAST_EXPECT(config.client_max_window_bits != 0); | |
434 | }; | |
435 | ||
436 | pmd.server_enable = true; | |
437 | pmd.server_max_window_bits = 15; | |
438 | pmd.client_max_window_bits = 15; | |
439 | pmd.server_no_context_takeover = false; | |
440 | pmd.client_no_context_takeover = false; | |
441 | ||
442 | // default | |
443 | accept( | |
444 | "permessage-deflate", | |
445 | "permessage-deflate"); | |
446 | ||
447 | // non-default server_max_window_bits | |
448 | accept( | |
449 | "permessage-deflate; server_max_window_bits=14", | |
450 | "permessage-deflate; server_max_window_bits=14"); | |
451 | ||
452 | // explicit default server_max_window_bits | |
453 | accept( | |
454 | "permessage-deflate; server_max_window_bits=15", | |
455 | "permessage-deflate"); | |
456 | ||
457 | // minimum window size of 8 bits (a zlib bug) | |
458 | accept( | |
459 | "permessage-deflate; server_max_window_bits=8", | |
460 | "permessage-deflate; server_max_window_bits=9"); | |
461 | ||
462 | // non-default server_max_window_bits setting | |
463 | pmd.server_max_window_bits = 10; | |
464 | accept( | |
465 | "permessage-deflate", | |
466 | "permessage-deflate; server_max_window_bits=10"); | |
467 | ||
468 | // clamped server_max_window_bits setting #1 | |
469 | pmd.server_max_window_bits = 10; | |
470 | accept( | |
471 | "permessage-deflate; server_max_window_bits=14", | |
472 | "permessage-deflate; server_max_window_bits=10"); | |
473 | ||
474 | // clamped server_max_window_bits setting #2 | |
475 | pmd.server_max_window_bits=8; | |
476 | accept( | |
477 | "permessage-deflate; server_max_window_bits=14", | |
478 | "permessage-deflate; server_max_window_bits=9"); | |
479 | ||
480 | pmd.server_max_window_bits = 15; | |
481 | ||
482 | // present with no value | |
483 | accept( | |
484 | "permessage-deflate; client_max_window_bits", | |
485 | "permessage-deflate"); | |
486 | ||
487 | // present with no value, non-default setting | |
488 | pmd.client_max_window_bits = 10; | |
489 | accept( | |
490 | "permessage-deflate; client_max_window_bits", | |
491 | "permessage-deflate; client_max_window_bits=10"); | |
492 | ||
493 | // absent, non-default setting | |
494 | pmd.client_max_window_bits = 10; | |
495 | reject( | |
496 | "permessage-deflate"); | |
497 | } | |
498 | ||
11fdf7f2 TL |
499 | void |
500 | testMoveOnly() | |
501 | { | |
92f5a8d4 | 502 | net::io_context ioc; |
11fdf7f2 TL |
503 | stream<test::stream> ws{ioc}; |
504 | ws.async_handshake("", "", move_only_handler{}); | |
505 | } | |
506 | ||
507 | struct copyable_handler | |
508 | { | |
509 | template<class... Args> | |
510 | void | |
511 | operator()(Args&&...) const | |
512 | { | |
513 | } | |
514 | }; | |
515 | ||
516 | void | |
92f5a8d4 | 517 | testAsync() |
11fdf7f2 | 518 | { |
92f5a8d4 TL |
519 | using tcp = net::ip::tcp; |
520 | ||
521 | net::io_context ioc; | |
522 | ||
523 | // success, no timeout | |
524 | ||
525 | { | |
526 | stream<tcp::socket> ws1(ioc); | |
527 | stream<tcp::socket> ws2(ioc); | |
528 | test::connect(ws1.next_layer(), ws2.next_layer()); | |
529 | ||
530 | ws1.async_handshake("test", "/", test::success_handler()); | |
531 | ws2.async_accept(test::success_handler()); | |
532 | test::run_for(ioc, std::chrono::seconds(1)); | |
533 | } | |
534 | ||
535 | { | |
536 | stream<test::stream> ws1(ioc); | |
537 | stream<test::stream> ws2(ioc); | |
538 | test::connect(ws1.next_layer(), ws2.next_layer()); | |
539 | ||
540 | ws1.async_handshake("test", "/", test::success_handler()); | |
541 | ws2.async_accept(test::success_handler()); | |
542 | test::run_for(ioc, std::chrono::seconds(1)); | |
543 | } | |
544 | ||
545 | // success, timeout enabled | |
546 | ||
547 | { | |
548 | stream<tcp::socket> ws1(ioc); | |
549 | stream<tcp::socket> ws2(ioc); | |
550 | test::connect(ws1.next_layer(), ws2.next_layer()); | |
551 | ||
552 | ws1.set_option(stream_base::timeout{ | |
553 | std::chrono::milliseconds(50), | |
554 | stream_base::none(), | |
555 | false}); | |
556 | ws1.async_handshake("test", "/", test::success_handler()); | |
557 | ws2.async_accept(test::success_handler()); | |
558 | test::run_for(ioc, std::chrono::seconds(1)); | |
559 | } | |
560 | ||
561 | { | |
562 | stream<test::stream> ws1(ioc); | |
563 | stream<test::stream> ws2(ioc); | |
564 | test::connect(ws1.next_layer(), ws2.next_layer()); | |
565 | ||
566 | ws1.set_option(stream_base::timeout{ | |
567 | std::chrono::milliseconds(50), | |
568 | stream_base::none(), | |
569 | false}); | |
570 | ws1.async_handshake("test", "/", test::success_handler()); | |
571 | ws2.async_accept(test::success_handler()); | |
572 | test::run_for(ioc, std::chrono::seconds(1)); | |
573 | } | |
574 | ||
575 | // timeout | |
576 | ||
577 | { | |
578 | stream<tcp::socket> ws1(ioc); | |
579 | stream<tcp::socket> ws2(ioc); | |
580 | test::connect(ws1.next_layer(), ws2.next_layer()); | |
581 | ||
582 | ws1.set_option(stream_base::timeout{ | |
583 | std::chrono::milliseconds(50), | |
584 | stream_base::none(), | |
585 | false}); | |
586 | ws1.async_handshake("test", "/", | |
587 | test::fail_handler(beast::error::timeout)); | |
588 | test::run_for(ioc, std::chrono::seconds(1)); | |
589 | } | |
590 | ||
591 | { | |
592 | stream<test::stream> ws1(ioc); | |
593 | stream<test::stream> ws2(ioc); | |
594 | test::connect(ws1.next_layer(), ws2.next_layer()); | |
595 | ||
596 | ws1.set_option(stream_base::timeout{ | |
597 | std::chrono::milliseconds(50), | |
598 | stream_base::none(), | |
599 | false}); | |
600 | ws1.async_handshake("test", "/", | |
601 | test::fail_handler(beast::error::timeout)); | |
602 | test::run_for(ioc, std::chrono::seconds(1)); | |
603 | } | |
604 | ||
605 | // abandoned operation | |
606 | ||
607 | { | |
608 | { | |
609 | stream<tcp::socket> ws1(ioc); | |
610 | ws1.async_handshake("test", "/", | |
611 | test::fail_handler( | |
612 | net::error::operation_aborted)); | |
613 | } | |
614 | test::run(ioc); | |
615 | } | |
616 | } | |
617 | ||
618 | // https://github.com/boostorg/beast/issues/1460 | |
619 | void | |
620 | testIssue1460() | |
621 | { | |
622 | net::io_context ioc; | |
623 | auto const make_big = [](response_type& res) | |
624 | { | |
625 | res.insert("Date", "Mon, 18 Feb 2019 12:48:36 GMT"); | |
626 | res.insert("Set-Cookie", | |
627 | "__cfduid=de1e209833e7f05aaa1044c6d448994761550494116; " | |
628 | "expires=Tue, 18-Feb-20 12:48:36 GMT; path=/; domain=.cryptofacilities.com; HttpOnly; Secure"); | |
629 | res.insert("Feature-Policy", | |
630 | "accelerometer 'none'; ambient-light-sensor 'none'; " | |
631 | "animations 'none'; autoplay 'none'; camera 'none'; document-write 'none'; " | |
632 | "encrypted-media 'none'; geolocation 'none'; gyroscope 'none'; legacy-image-formats 'none'; " | |
633 | "magnetometer 'none'; max-downscaling-image 'none'; microphone 'none'; midi 'none'; " | |
634 | "payment 'none'; picture-in-picture 'none'; unsized-media 'none'; usb 'none'; vr 'none'"); | |
635 | res.insert("Referrer-Policy", "origin"); | |
636 | res.insert("Strict-Transport-Security", "max-age=15552000; includeSubDomains; preload"); | |
637 | res.insert("X-Content-Type-Options", "nosniff"); | |
638 | res.insert("Content-Security-Policy", | |
639 | "default-src 'none'; manifest-src 'self'; object-src 'self'; " | |
640 | "child-src 'self' https://www.google.com; " | |
641 | "font-src 'self' https://use.typekit.net https://maxcdn.bootstrapcdn.com https://fonts.gstatic.com data:; " | |
642 | "script-src 'self' 'unsafe-inline' 'unsafe-eval' https://ajax.cloudflare.com https://use.typekit.net " | |
643 | "https://www.googletagmanager.com https://www.google-analytics.com https://www.google.com https://www.googleadservices.com " | |
644 | "https://googleads.g.doubleclick.net https://www.gstatic.com; connect-src 'self' wss://*.cryptofacilities.com/ws/v1 wss://*.cryptofacilities.com/ws/indices " | |
645 | "https://uat.cryptofacilities.com https://uat.cf0.io wss://*.cf0.io https://www.googletagmanager.com https://www.google-analytics.com https://www.google.com " | |
646 | "https://fonts.googleapis.com https://google-analytics.com https://use.typekit.net https://p.typekit.net https://fonts.gstatic.com https://www.gstatic.com " | |
647 | "https://chart.googleapis.com; worker-src 'self'; img-src 'self' https://chart.googleapis.com https://p.typekit.net https://www.google.co.uk https://www.google.com " | |
648 | "https://www.google-analytics.com https://stats.g.doubleclick.net data:; style-src 'self' 'unsafe-inline' https://use.typekit.net https://p.typekit.net " | |
649 | "https://fonts.googleapis.com https://maxcdn.bootstrapcdn.com"); | |
650 | res.insert("X-Frame-Options", "SAMEORIGIN"); | |
651 | res.insert("X-Xss-Protection", "1; mode=block"); | |
652 | res.insert("Expect-CT", "max-age=604800, report-uri=\"https://report-uri.cloudflare.com/cdn-cgi/beacon/expect-ct\""); | |
653 | res.insert("Server", "cloudflare"); | |
654 | res.insert("CF-RAY", "4ab09be1a9d0cb06-ARN"); | |
655 | res.insert("Bulk", | |
656 | "****************************************************************************************************" | |
657 | "****************************************************************************************************" | |
658 | "****************************************************************************************************" | |
659 | "****************************************************************************************************" | |
660 | "****************************************************************************************************" | |
661 | "****************************************************************************************************" | |
662 | "****************************************************************************************************" | |
663 | "****************************************************************************************************" | |
664 | "****************************************************************************************************" | |
665 | "****************************************************************************************************" | |
666 | "****************************************************************************************************" | |
667 | "****************************************************************************************************" | |
668 | "****************************************************************************************************" | |
669 | "****************************************************************************************************" | |
670 | "****************************************************************************************************" | |
671 | "****************************************************************************************************" | |
672 | "****************************************************************************************************" | |
673 | "****************************************************************************************************" | |
674 | "****************************************************************************************************" | |
675 | "****************************************************************************************************"); | |
676 | }; | |
677 | ||
678 | { | |
679 | stream<test::stream> ws1(ioc); | |
680 | stream<test::stream> ws2(ioc); | |
681 | test::connect(ws1.next_layer(), ws2.next_layer()); | |
682 | ||
683 | ws2.set_option(stream_base::decorator(make_big)); | |
684 | error_code ec; | |
685 | ws2.async_accept(test::success_handler()); | |
686 | std::thread t( | |
687 | [&ioc] | |
688 | { | |
689 | ioc.run(); | |
690 | ioc.restart(); | |
691 | }); | |
692 | ws1.handshake("test", "/", ec); | |
693 | BEAST_EXPECTS(! ec, ec.message()); | |
694 | t.join(); | |
695 | } | |
696 | ||
697 | { | |
698 | stream<test::stream> ws1(ioc); | |
699 | stream<test::stream> ws2(ioc); | |
700 | test::connect(ws1.next_layer(), ws2.next_layer()); | |
701 | ||
702 | ws2.set_option(stream_base::decorator(make_big)); | |
703 | ws2.async_accept(test::success_handler()); | |
704 | ws1.async_handshake("test", "/", test::success_handler()); | |
705 | ioc.run(); | |
706 | ioc.restart(); | |
707 | } | |
11fdf7f2 TL |
708 | } |
709 | ||
20effc67 TL |
710 | #if BOOST_ASIO_HAS_CO_AWAIT |
711 | void testAwaitableCompiles( | |
712 | stream<test::stream>& s, | |
713 | std::string host, | |
714 | std::string port, | |
715 | response_type& resp) | |
716 | { | |
717 | static_assert(std::is_same_v< | |
718 | net::awaitable<void>, decltype( | |
719 | s.async_handshake(host, port, net::use_awaitable))>); | |
720 | ||
721 | static_assert(std::is_same_v< | |
722 | net::awaitable<void>, decltype( | |
723 | s.async_handshake(resp, host, port, net::use_awaitable))>); | |
724 | } | |
725 | #endif | |
726 | ||
1e59de90 TL |
727 | void |
728 | testIssue2364() | |
729 | { | |
730 | { // sync unauthorized | |
731 | net::io_context ioc; | |
732 | stream<test::stream> ws{ioc}; | |
733 | auto tr = connect(ws.next_layer()); | |
734 | std::string const reply = | |
735 | "HTTP/1.1 401 Unauthorized\r\n" | |
736 | "\r\n"; | |
737 | ws.next_layer().append(reply); | |
738 | tr.close(); | |
739 | try | |
740 | { | |
741 | websocket::response_type response; | |
742 | error_code ec; | |
743 | ws.handshake(response, "localhost:80", "/", ec); | |
744 | BEAST_EXPECT(ec); | |
745 | BEAST_EXPECTS(response.result() == http::status::unauthorized, | |
746 | std::to_string(response.result_int())); | |
747 | } | |
748 | catch(system_error const&) | |
749 | { | |
750 | fail(); | |
751 | } | |
752 | } | |
753 | ||
754 | { // sync invalid response | |
755 | net::io_context ioc; | |
756 | stream<test::stream> ws{ioc}; | |
757 | auto tr = connect(ws.next_layer()); | |
758 | std::string const reply = | |
759 | "zzzzzzzzzzzzzzzzzzzzz"; | |
760 | ws.next_layer().append(reply); | |
761 | tr.close(); | |
762 | try | |
763 | { | |
764 | websocket::response_type response; | |
765 | error_code ec; | |
766 | ws.handshake(response, "localhost:80", "/", ec); | |
767 | BEAST_EXPECT(ec); | |
768 | BEAST_EXPECTS(response.result() == http::status::internal_server_error, | |
769 | std::to_string(response.result_int())); | |
770 | } | |
771 | catch(system_error const&) | |
772 | { | |
773 | fail(); | |
774 | } | |
775 | } | |
776 | ||
777 | { // async unauthorized | |
778 | net::io_context ioc; | |
779 | stream<test::stream> ws{ioc}; | |
780 | auto tr = connect(ws.next_layer()); | |
781 | std::string const reply = | |
782 | "HTTP/1.1 401 Unauthorized\r\n" | |
783 | "\r\n"; | |
784 | ws.next_layer().append(reply); | |
785 | tr.close(); | |
786 | websocket::response_type response; | |
787 | auto handler = [&](error_code ec) | |
788 | { | |
789 | BEAST_EXPECT(ec); | |
790 | BEAST_EXPECTS(response.result() == http::status::unauthorized, | |
791 | std::to_string(response.result_int())); | |
792 | }; | |
793 | ws.async_handshake(response, "localhost:80", "/", handler); | |
794 | ioc.run(); | |
795 | } | |
796 | ||
797 | { // async invalid response | |
798 | net::io_context ioc; | |
799 | stream<test::stream> ws{ioc}; | |
800 | auto tr = connect(ws.next_layer()); | |
801 | std::string const reply = | |
802 | "zzzzzzzzzzzzzzzz"; | |
803 | ws.next_layer().append(reply); | |
804 | tr.close(); | |
805 | websocket::response_type response; | |
806 | auto handler = [&](error_code ec) | |
807 | { | |
808 | BEAST_EXPECT(ec); | |
809 | BEAST_EXPECTS(response.result() == http::status::internal_server_error, | |
810 | std::to_string(response.result_int())); | |
811 | }; | |
812 | ws.async_handshake(response, "localhost:80", "/", handler); | |
813 | ioc.run(); | |
814 | } | |
815 | } | |
816 | ||
817 | ||
b32b8144 FG |
818 | void |
819 | run() override | |
820 | { | |
821 | testHandshake(); | |
822 | testExtRead(); | |
823 | testExtWrite(); | |
824 | testExtNegotiate(); | |
11fdf7f2 | 825 | testMoveOnly(); |
92f5a8d4 TL |
826 | testAsync(); |
827 | testIssue1460(); | |
20effc67 TL |
828 | #if BOOST_ASIO_HAS_CO_AWAIT |
829 | boost::ignore_unused(&handshake_test::testAwaitableCompiles); | |
830 | #endif | |
1e59de90 | 831 | testIssue2364(); |
b32b8144 FG |
832 | } |
833 | }; | |
834 | ||
835 | BEAST_DEFINE_TESTSUITE(beast,websocket,handshake); | |
836 | ||
837 | } // websocket | |
838 | } // beast | |
839 | } // boost |