]> git.proxmox.com Git - ceph.git/blame - ceph/src/boost/libs/beast/test/beast/websocket/handshake.cpp
update ceph source to reef 18.1.2
[ceph.git] / ceph / src / boost / libs / beast / test / beast / websocket / handshake.cpp
CommitLineData
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
25namespace boost {
26namespace beast {
27namespace websocket {
28
29class handshake_test : public websocket_test_suite
30{
31public:
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
835BEAST_DEFINE_TESTSUITE(beast,websocket,handshake);
836
837} // websocket
838} // beast
839} // boost