]>
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 | #include <boost/beast/_experimental/unit_test/suite.hpp> | |
b32b8144 | 16 | #include "test.hpp" |
20effc67 TL |
17 | #if BOOST_ASIO_HAS_CO_AWAIT |
18 | #include <boost/asio/use_awaitable.hpp> | |
19 | #endif | |
b32b8144 FG |
20 | namespace boost { |
21 | namespace beast { | |
22 | namespace websocket { | |
23 | ||
92f5a8d4 | 24 | class accept_test : public unit_test::suite //: public websocket_test_suite |
b32b8144 FG |
25 | { |
26 | public: | |
92f5a8d4 | 27 | class res_decorator |
b32b8144 | 28 | { |
92f5a8d4 TL |
29 | bool& b_; |
30 | ||
31 | public: | |
32 | res_decorator(res_decorator const&) = default; | |
33 | ||
34 | explicit | |
35 | res_decorator(bool& b) | |
36 | : b_(b) | |
b32b8144 | 37 | { |
92f5a8d4 | 38 | } |
b32b8144 | 39 | |
92f5a8d4 TL |
40 | void |
41 | operator()(response_type&) const | |
42 | { | |
43 | this->b_ = true; | |
44 | } | |
45 | }; | |
46 | ||
47 | template<std::size_t N> | |
48 | static | |
49 | net::const_buffer | |
50 | sbuf(const char (&s)[N]) | |
51 | { | |
52 | return net::const_buffer(&s[0], N-1); | |
53 | } | |
b32b8144 | 54 | |
92f5a8d4 TL |
55 | static |
56 | void | |
57 | fail_loop( | |
58 | std::function<void(stream<test::stream>&)> f, | |
59 | std::chrono::steady_clock::duration amount = | |
60 | std::chrono::seconds(5)) | |
61 | { | |
62 | using clock_type = std::chrono::steady_clock; | |
63 | auto const expires_at = | |
64 | clock_type::now() + amount; | |
65 | net::io_context ioc; | |
66 | for(std::size_t n = 0;;++n) | |
67 | { | |
68 | test::fail_count fc(n); | |
69 | try | |
b32b8144 | 70 | { |
92f5a8d4 TL |
71 | stream<test::stream> ws(ioc, fc); |
72 | auto tr = connect(ws.next_layer()); | |
73 | f(ws); | |
74 | break; | |
b32b8144 | 75 | } |
92f5a8d4 | 76 | catch(system_error const& se) |
b32b8144 | 77 | { |
92f5a8d4 TL |
78 | // VFALCO Commented this out after the short |
79 | // read change, because it converts test_failure | |
80 | // into http::partial_message | |
81 | // | |
82 | boost::ignore_unused(se); | |
83 | #if 0 | |
84 | if(! BEAST_EXPECTS( | |
85 | se.code() == test::error::test_failure, | |
86 | se.code().message())) | |
87 | throw; | |
88 | #endif | |
89 | if(! BEAST_EXPECTS( | |
90 | clock_type::now() < expires_at, | |
91 | "a test timeout occurred")) | |
92 | break; | |
b32b8144 | 93 | } |
92f5a8d4 TL |
94 | } |
95 | } | |
b32b8144 | 96 | |
92f5a8d4 TL |
97 | template<class Api> |
98 | void | |
99 | testMatrix(Api api) | |
100 | { | |
101 | net::io_context ioc; | |
b32b8144 FG |
102 | |
103 | // request in stream | |
92f5a8d4 | 104 | fail_loop([&](stream<test::stream>& ws) |
b32b8144 | 105 | { |
92f5a8d4 | 106 | ws.next_layer().append( |
b32b8144 FG |
107 | "GET / HTTP/1.1\r\n" |
108 | "Host: localhost\r\n" | |
109 | "Upgrade: websocket\r\n" | |
110 | "Connection: upgrade\r\n" | |
111 | "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n" | |
112 | "Sec-WebSocket-Version: 13\r\n" | |
113 | "\r\n"); | |
92f5a8d4 TL |
114 | ws.next_layer().read_size(20); |
115 | api.accept(ws); | |
b32b8144 FG |
116 | }); |
117 | ||
92f5a8d4 TL |
118 | // request in stream, decorator |
119 | fail_loop([&](stream<test::stream>& ws) | |
b32b8144 | 120 | { |
92f5a8d4 | 121 | ws.next_layer().append( |
b32b8144 FG |
122 | "GET / HTTP/1.1\r\n" |
123 | "Host: localhost\r\n" | |
124 | "Upgrade: websocket\r\n" | |
125 | "Connection: upgrade\r\n" | |
126 | "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n" | |
127 | "Sec-WebSocket-Version: 13\r\n" | |
92f5a8d4 TL |
128 | "\r\n"); |
129 | ws.next_layer().read_size(20); | |
130 | bool called = false; | |
131 | ws.set_option(stream_base::decorator( | |
132 | res_decorator{called})); | |
133 | api.accept(ws); | |
134 | BEAST_EXPECT(called); | |
135 | }); | |
b32b8144 | 136 | |
92f5a8d4 TL |
137 | // request in buffers |
138 | fail_loop([&](stream<test::stream>& ws) | |
b32b8144 | 139 | { |
92f5a8d4 TL |
140 | api.accept(ws, sbuf( |
141 | "GET / HTTP/1.1\r\n" | |
142 | "Host: localhost\r\n" | |
143 | "Upgrade: websocket\r\n" | |
144 | "Connection: upgrade\r\n" | |
145 | "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n" | |
146 | "Sec-WebSocket-Version: 13\r\n" | |
147 | "\r\n" | |
148 | )); | |
149 | }); | |
150 | ||
151 | // request in buffers, decorator | |
152 | fail_loop([&](stream<test::stream>& ws) | |
153 | { | |
154 | bool called = false; | |
155 | ws.set_option(stream_base::decorator( | |
156 | res_decorator{called})); | |
157 | api.accept(ws, sbuf( | |
158 | "GET / HTTP/1.1\r\n" | |
159 | "Host: localhost\r\n" | |
160 | "Upgrade: websocket\r\n" | |
161 | "Connection: upgrade\r\n" | |
162 | "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n" | |
163 | "Sec-WebSocket-Version: 13\r\n" | |
164 | "\r\n")); | |
165 | BEAST_EXPECT(called); | |
166 | }); | |
167 | ||
168 | // request in buffers and stream | |
169 | fail_loop([&](stream<test::stream>& ws) | |
170 | { | |
171 | ws.next_layer().append( | |
172 | "Connection: upgrade\r\n" | |
173 | "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n" | |
174 | "Sec-WebSocket-Version: 13\r\n" | |
175 | "\r\n"); | |
176 | ws.next_layer().read_size(16); | |
177 | api.accept(ws, sbuf( | |
b32b8144 FG |
178 | "GET / HTTP/1.1\r\n" |
179 | "Host: localhost\r\n" | |
180 | "Upgrade: websocket\r\n" | |
92f5a8d4 TL |
181 | )); |
182 | // VFALCO validate contents of ws.next_layer().str? | |
183 | }); | |
184 | ||
185 | // request in buffers and stream, decorator | |
186 | fail_loop([&](stream<test::stream>& ws) | |
187 | { | |
188 | ws.next_layer().append( | |
b32b8144 FG |
189 | "Connection: upgrade\r\n" |
190 | "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n" | |
191 | "Sec-WebSocket-Version: 13\r\n" | |
192 | "\r\n"); | |
92f5a8d4 | 193 | ws.next_layer().read_size(16); |
b32b8144 | 194 | bool called = false; |
92f5a8d4 TL |
195 | ws.set_option(stream_base::decorator( |
196 | res_decorator{called})); | |
197 | api.accept(ws, sbuf( | |
198 | "GET / HTTP/1.1\r\n" | |
199 | "Host: localhost\r\n" | |
200 | "Upgrade: websocket\r\n")); | |
b32b8144 FG |
201 | BEAST_EXPECT(called); |
202 | }); | |
203 | ||
92f5a8d4 TL |
204 | // request in message |
205 | { | |
206 | request_type req; | |
207 | req.method(http::verb::get); | |
208 | req.target("/"); | |
209 | req.version(11); | |
210 | req.insert(http::field::host, "localhost"); | |
211 | req.insert(http::field::upgrade, "websocket"); | |
212 | req.insert(http::field::connection, "upgrade"); | |
213 | req.insert(http::field::sec_websocket_key, "dGhlIHNhbXBsZSBub25jZQ=="); | |
214 | req.insert(http::field::sec_websocket_version, "13"); | |
215 | ||
216 | fail_loop([&](stream<test::stream>& ws) | |
217 | { | |
218 | api.accept(ws, req); | |
219 | }); | |
220 | } | |
221 | ||
222 | // request in message, decorator | |
223 | { | |
224 | request_type req; | |
225 | req.method(http::verb::get); | |
226 | req.target("/"); | |
227 | req.version(11); | |
228 | req.insert(http::field::host, "localhost"); | |
229 | req.insert(http::field::upgrade, "websocket"); | |
230 | req.insert(http::field::connection, "upgrade"); | |
231 | req.insert(http::field::sec_websocket_key, "dGhlIHNhbXBsZSBub25jZQ=="); | |
232 | req.insert(http::field::sec_websocket_version, "13"); | |
233 | ||
234 | fail_loop([&](stream<test::stream>& ws) | |
235 | { | |
236 | bool called = false; | |
237 | ws.set_option(stream_base::decorator( | |
238 | res_decorator{called})); | |
239 | api.accept(ws, req); | |
240 | BEAST_EXPECT(called); | |
241 | }); | |
242 | } | |
243 | ||
244 | // request in message, close frame in stream | |
245 | { | |
246 | request_type req; | |
247 | req.method(http::verb::get); | |
248 | req.target("/"); | |
249 | req.version(11); | |
250 | req.insert(http::field::host, "localhost"); | |
251 | req.insert(http::field::upgrade, "websocket"); | |
252 | req.insert(http::field::connection, "upgrade"); | |
253 | req.insert(http::field::sec_websocket_key, "dGhlIHNhbXBsZSBub25jZQ=="); | |
254 | req.insert(http::field::sec_websocket_version, "13"); | |
255 | ||
256 | fail_loop([&](stream<test::stream>& ws) | |
257 | { | |
258 | ws.next_layer().append("\x88\x82\xff\xff\xff\xff\xfc\x17"); | |
259 | api.accept(ws, req); | |
260 | try | |
261 | { | |
262 | static_buffer<1> b; | |
263 | api.read(ws, b); | |
264 | fail("success", __FILE__, __LINE__); | |
265 | } | |
266 | catch(system_error const& e) | |
267 | { | |
268 | if(e.code() != websocket::error::closed) | |
269 | throw; | |
270 | } | |
271 | }); | |
272 | } | |
273 | ||
274 | // failed handshake (missing Sec-WebSocket-Key) | |
275 | fail_loop([&](stream<test::stream>& ws) | |
276 | { | |
277 | ws.next_layer().append( | |
278 | "GET / HTTP/1.1\r\n" | |
279 | "Host: localhost\r\n" | |
280 | "Upgrade: websocket\r\n" | |
281 | "Connection: upgrade\r\n" | |
282 | "Sec-WebSocket-Version: 13\r\n" | |
283 | "\r\n"); | |
284 | ws.next_layer().read_size(20); | |
285 | try | |
286 | { | |
287 | api.accept(ws); | |
288 | BEAST_FAIL(); | |
289 | } | |
290 | catch(system_error const& e) | |
291 | { | |
292 | if( e.code() != websocket::error::no_sec_key && | |
293 | e.code() != net::error::eof) | |
294 | throw; | |
295 | } | |
296 | }); | |
297 | } | |
298 | ||
299 | template<class Api> | |
300 | void | |
301 | testOversized(Api const& api) | |
302 | { | |
303 | net::io_context ioc; | |
304 | ||
305 | auto const big = [] | |
306 | { | |
307 | std::string s; | |
308 | s += "X1: " + std::string(2000, '*') + "\r\n"; | |
309 | return s; | |
310 | }(); | |
311 | ||
312 | // request in stream | |
b32b8144 | 313 | { |
92f5a8d4 | 314 | stream<test::stream> ws{ioc, |
b32b8144 FG |
315 | "GET / HTTP/1.1\r\n" |
316 | "Host: localhost\r\n" | |
317 | "Upgrade: websocket\r\n" | |
318 | "Connection: upgrade\r\n" | |
319 | "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n" | |
320 | "Sec-WebSocket-Version: 13\r\n" | |
321 | + big + | |
322 | "\r\n"}; | |
323 | auto tr = connect(ws.next_layer()); | |
324 | try | |
325 | { | |
92f5a8d4 TL |
326 | api.accept(ws); |
327 | BEAST_FAIL(); | |
b32b8144 FG |
328 | } |
329 | catch(system_error const& se) | |
330 | { | |
331 | // VFALCO Its the http error category... | |
332 | BEAST_EXPECTS( | |
333 | se.code() == http::error::buffer_overflow, | |
334 | se.code().message()); | |
335 | } | |
336 | } | |
337 | ||
92f5a8d4 | 338 | // request in stream, decorator |
b32b8144 | 339 | { |
92f5a8d4 | 340 | stream<test::stream> ws{ioc, |
b32b8144 FG |
341 | "GET / HTTP/1.1\r\n" |
342 | "Host: localhost\r\n" | |
343 | "Upgrade: websocket\r\n" | |
344 | "Connection: upgrade\r\n" | |
345 | "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n" | |
346 | "Sec-WebSocket-Version: 13\r\n" | |
92f5a8d4 TL |
347 | + big + |
348 | "\r\n"}; | |
349 | auto tr = connect(ws.next_layer()); | |
350 | try | |
351 | { | |
352 | bool called = false; | |
353 | ws.set_option(stream_base::decorator( | |
354 | res_decorator{called})); | |
355 | api.accept(ws); | |
356 | BEAST_FAIL(); | |
357 | } | |
358 | catch(system_error const& se) | |
359 | { | |
360 | // VFALCO Its the http error category... | |
361 | BEAST_EXPECTS( | |
362 | se.code() == http::error::buffer_overflow, | |
363 | se.code().message()); | |
364 | } | |
365 | } | |
b32b8144 | 366 | |
92f5a8d4 | 367 | // request in buffers |
b32b8144 | 368 | { |
92f5a8d4 | 369 | stream<test::stream> ws{ioc}; |
b32b8144 FG |
370 | auto tr = connect(ws.next_layer()); |
371 | try | |
372 | { | |
92f5a8d4 | 373 | api.accept(ws, net::buffer( |
b32b8144 FG |
374 | "GET / HTTP/1.1\r\n" |
375 | "Host: localhost\r\n" | |
376 | "Upgrade: websocket\r\n" | |
377 | "Connection: upgrade\r\n" | |
378 | "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n" | |
379 | "Sec-WebSocket-Version: 13\r\n" | |
380 | + big + | |
381 | "\r\n" | |
382 | )); | |
92f5a8d4 | 383 | BEAST_FAIL(); |
b32b8144 FG |
384 | } |
385 | catch(system_error const& se) | |
386 | { | |
387 | BEAST_EXPECTS( | |
388 | se.code() == error::buffer_overflow, | |
389 | se.code().message()); | |
390 | } | |
391 | } | |
392 | ||
393 | // request in buffers, decorator | |
b32b8144 | 394 | { |
92f5a8d4 | 395 | stream<test::stream> ws{ioc}; |
b32b8144 FG |
396 | auto tr = connect(ws.next_layer()); |
397 | try | |
398 | { | |
399 | bool called = false; | |
92f5a8d4 TL |
400 | ws.set_option(stream_base::decorator( |
401 | res_decorator{called})); | |
402 | api.accept(ws, net::buffer( | |
b32b8144 FG |
403 | "GET / HTTP/1.1\r\n" |
404 | "Host: localhost\r\n" | |
405 | "Upgrade: websocket\r\n" | |
406 | "Connection: upgrade\r\n" | |
407 | "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n" | |
408 | "Sec-WebSocket-Version: 13\r\n" | |
409 | + big + | |
92f5a8d4 TL |
410 | "\r\n")); |
411 | BEAST_FAIL(); | |
b32b8144 FG |
412 | } |
413 | catch(system_error const& se) | |
414 | { | |
415 | BEAST_EXPECTS( | |
416 | se.code() == error::buffer_overflow, | |
417 | se.code().message()); | |
418 | } | |
419 | } | |
420 | ||
421 | // request in buffers and stream | |
b32b8144 | 422 | { |
92f5a8d4 | 423 | stream<test::stream> ws{ioc, |
b32b8144 FG |
424 | "Connection: upgrade\r\n" |
425 | "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n" | |
426 | "Sec-WebSocket-Version: 13\r\n" | |
427 | + big + | |
428 | "\r\n"}; | |
429 | auto tr = connect(ws.next_layer()); | |
430 | try | |
431 | { | |
92f5a8d4 | 432 | api.accept(ws, websocket_test_suite::sbuf( |
b32b8144 FG |
433 | "GET / HTTP/1.1\r\n" |
434 | "Host: localhost\r\n" | |
435 | "Upgrade: websocket\r\n" | |
436 | )); | |
92f5a8d4 | 437 | BEAST_FAIL(); |
b32b8144 FG |
438 | } |
439 | catch(system_error const& se) | |
440 | { | |
441 | BEAST_EXPECTS( | |
442 | se.code() == http::error::buffer_overflow, | |
443 | se.code().message()); | |
444 | } | |
445 | } | |
446 | ||
447 | // request in buffers and stream, decorator | |
b32b8144 | 448 | { |
92f5a8d4 | 449 | stream<test::stream> ws{ioc, |
b32b8144 FG |
450 | "Connection: upgrade\r\n" |
451 | "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n" | |
452 | "Sec-WebSocket-Version: 13\r\n" | |
453 | + big + | |
454 | "\r\n"}; | |
455 | auto tr = connect(ws.next_layer()); | |
456 | try | |
457 | { | |
458 | bool called = false; | |
92f5a8d4 TL |
459 | ws.set_option(stream_base::decorator( |
460 | res_decorator{called})); | |
461 | api.accept(ws, websocket_test_suite::sbuf( | |
b32b8144 FG |
462 | "GET / HTTP/1.1\r\n" |
463 | "Host: localhost\r\n" | |
92f5a8d4 TL |
464 | "Upgrade: websocket\r\n")); |
465 | BEAST_FAIL(); | |
b32b8144 FG |
466 | } |
467 | catch(system_error const& se) | |
468 | { | |
469 | BEAST_EXPECTS( | |
470 | se.code() == http::error::buffer_overflow, | |
471 | se.code().message()); | |
472 | } | |
473 | } | |
b32b8144 FG |
474 | } |
475 | ||
476 | void | |
92f5a8d4 | 477 | testInvalidInputs() |
b32b8144 | 478 | { |
92f5a8d4 | 479 | net::io_context ioc; |
b32b8144 FG |
480 | |
481 | auto const check = | |
92f5a8d4 | 482 | [&](error_code ev, string_view s) |
b32b8144 FG |
483 | { |
484 | for(int i = 0; i < 3; ++i) | |
485 | { | |
486 | std::size_t n; | |
487 | switch(i) | |
488 | { | |
489 | default: | |
490 | case 0: | |
491 | n = 1; | |
492 | break; | |
493 | case 1: | |
494 | n = s.size() / 2; | |
495 | break; | |
496 | case 2: | |
497 | n = s.size() - 1; | |
498 | break; | |
499 | } | |
92f5a8d4 | 500 | stream<test::stream> ws(ioc); |
b32b8144 FG |
501 | auto tr = connect(ws.next_layer()); |
502 | ws.next_layer().append( | |
503 | s.substr(n, s.size() - n)); | |
92f5a8d4 | 504 | tr.close(); |
b32b8144 FG |
505 | try |
506 | { | |
92f5a8d4 | 507 | ws.accept(net::buffer(s.data(), n)); |
b32b8144 FG |
508 | BEAST_EXPECTS(! ev, ev.message()); |
509 | } | |
510 | catch(system_error const& se) | |
511 | { | |
512 | BEAST_EXPECTS(se.code() == ev, se.what()); | |
513 | } | |
514 | } | |
515 | }; | |
516 | ||
11fdf7f2 TL |
517 | // bad version |
518 | check(error::bad_http_version, | |
b32b8144 FG |
519 | "GET / HTTP/1.0\r\n" |
520 | "Host: localhost:80\r\n" | |
521 | "Upgrade: WebSocket\r\n" | |
522 | "Connection: keep-alive,upgrade\r\n" | |
523 | "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n" | |
524 | "Sec-WebSocket-Version: 13\r\n" | |
525 | "\r\n" | |
526 | ); | |
92f5a8d4 | 527 | |
11fdf7f2 TL |
528 | // bad method |
529 | check(error::bad_method, | |
b32b8144 FG |
530 | "POST / HTTP/1.1\r\n" |
531 | "Host: localhost:80\r\n" | |
532 | "Upgrade: WebSocket\r\n" | |
533 | "Connection: keep-alive,upgrade\r\n" | |
534 | "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n" | |
535 | "Sec-WebSocket-Version: 13\r\n" | |
536 | "\r\n" | |
537 | ); | |
92f5a8d4 | 538 | |
11fdf7f2 TL |
539 | // no Host |
540 | check(error::no_host, | |
b32b8144 FG |
541 | "GET / HTTP/1.1\r\n" |
542 | "Upgrade: WebSocket\r\n" | |
543 | "Connection: keep-alive,upgrade\r\n" | |
544 | "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n" | |
545 | "Sec-WebSocket-Version: 13\r\n" | |
546 | "\r\n" | |
547 | ); | |
92f5a8d4 | 548 | |
11fdf7f2 TL |
549 | // no Connection |
550 | check(error::no_connection, | |
b32b8144 FG |
551 | "GET / HTTP/1.1\r\n" |
552 | "Host: localhost:80\r\n" | |
553 | "Upgrade: WebSocket\r\n" | |
11fdf7f2 | 554 | "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n" |
b32b8144 FG |
555 | "Sec-WebSocket-Version: 13\r\n" |
556 | "\r\n" | |
557 | ); | |
92f5a8d4 | 558 | |
11fdf7f2 TL |
559 | // no Connection upgrade |
560 | check(error::no_connection_upgrade, | |
b32b8144 FG |
561 | "GET / HTTP/1.1\r\n" |
562 | "Host: localhost:80\r\n" | |
563 | "Upgrade: WebSocket\r\n" | |
11fdf7f2 | 564 | "Connection: keep-alive\r\n" |
b32b8144 | 565 | "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n" |
11fdf7f2 | 566 | "Sec-WebSocket-Version: 13\r\n" |
b32b8144 FG |
567 | "\r\n" |
568 | ); | |
92f5a8d4 | 569 | |
11fdf7f2 TL |
570 | // no Upgrade |
571 | check(error::no_upgrade, | |
b32b8144 FG |
572 | "GET / HTTP/1.1\r\n" |
573 | "Host: localhost:80\r\n" | |
11fdf7f2 | 574 | "Connection: upgrade\r\n" |
b32b8144 | 575 | "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n" |
11fdf7f2 | 576 | "Sec-WebSocket-Version: 13\r\n" |
b32b8144 FG |
577 | "\r\n" |
578 | ); | |
92f5a8d4 | 579 | |
11fdf7f2 TL |
580 | // no Upgrade websocket |
581 | check(error::no_upgrade_websocket, | |
b32b8144 FG |
582 | "GET / HTTP/1.1\r\n" |
583 | "Host: localhost:80\r\n" | |
584 | "Upgrade: HTTP/2\r\n" | |
585 | "Connection: upgrade\r\n" | |
586 | "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n" | |
587 | "Sec-WebSocket-Version: 13\r\n" | |
588 | "\r\n" | |
589 | ); | |
92f5a8d4 | 590 | |
11fdf7f2 TL |
591 | // no Sec-WebSocket-Key |
592 | check(error::no_sec_key, | |
b32b8144 FG |
593 | "GET / HTTP/1.1\r\n" |
594 | "Host: localhost:80\r\n" | |
595 | "Upgrade: WebSocket\r\n" | |
11fdf7f2 | 596 | "Connection: keep-alive,upgrade\r\n" |
b32b8144 FG |
597 | "Sec-WebSocket-Version: 13\r\n" |
598 | "\r\n" | |
599 | ); | |
92f5a8d4 | 600 | |
11fdf7f2 TL |
601 | // bad Sec-WebSocket-Key |
602 | check(error::bad_sec_key, | |
b32b8144 FG |
603 | "GET / HTTP/1.1\r\n" |
604 | "Host: localhost:80\r\n" | |
605 | "Upgrade: WebSocket\r\n" | |
606 | "Connection: upgrade\r\n" | |
607 | "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQdGhlIHNhbXBsZSBub25jZQ==\r\n" | |
608 | "Sec-WebSocket-Version: 13\r\n" | |
609 | "\r\n" | |
610 | ); | |
92f5a8d4 | 611 | |
11fdf7f2 TL |
612 | // no Sec-WebSocket-Version |
613 | check(error::no_sec_version, | |
b32b8144 FG |
614 | "GET / HTTP/1.1\r\n" |
615 | "Host: localhost:80\r\n" | |
616 | "Upgrade: WebSocket\r\n" | |
11fdf7f2 | 617 | "Connection: keep-alive,upgrade\r\n" |
b32b8144 | 618 | "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n" |
b32b8144 FG |
619 | "\r\n" |
620 | ); | |
92f5a8d4 | 621 | |
11fdf7f2 TL |
622 | // bad Sec-WebSocket-Version |
623 | check(error::bad_sec_version, | |
624 | "GET / HTTP/1.1\r\n" | |
625 | "Host: localhost:80\r\n" | |
626 | "Upgrade: WebSocket\r\n" | |
627 | "Connection: keep-alive,upgrade\r\n" | |
628 | "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n" | |
629 | "Sec-WebSocket-Version: 1\r\n" | |
630 | "\r\n" | |
631 | ); | |
92f5a8d4 | 632 | |
11fdf7f2 TL |
633 | // bad Sec-WebSocket-Version |
634 | check(error::bad_sec_version, | |
b32b8144 FG |
635 | "GET / HTTP/1.1\r\n" |
636 | "Host: localhost:80\r\n" | |
637 | "Upgrade: WebSocket\r\n" | |
638 | "Connection: upgrade\r\n" | |
639 | "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n" | |
11fdf7f2 | 640 | "Sec-WebSocket-Version: 12\r\n" |
b32b8144 FG |
641 | "\r\n" |
642 | ); | |
92f5a8d4 | 643 | |
b32b8144 FG |
644 | // valid request |
645 | check({}, | |
646 | "GET / HTTP/1.1\r\n" | |
647 | "Host: localhost:80\r\n" | |
648 | "Upgrade: WebSocket\r\n" | |
649 | "Connection: upgrade\r\n" | |
650 | "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n" | |
651 | "Sec-WebSocket-Version: 13\r\n" | |
652 | "\r\n" | |
653 | ); | |
654 | } | |
655 | ||
11fdf7f2 | 656 | void |
92f5a8d4 | 657 | testEndOfStream() |
11fdf7f2 | 658 | { |
92f5a8d4 TL |
659 | net::io_context ioc; |
660 | { | |
661 | stream<test::stream> ws(ioc); | |
662 | auto tr = connect(ws.next_layer()); | |
663 | tr.close(); | |
664 | try | |
665 | { | |
666 | test_sync_api api; | |
667 | api.accept(ws, net::const_buffer{}); | |
668 | BEAST_FAIL(); | |
669 | } | |
670 | catch(system_error const& se) | |
671 | { | |
672 | BEAST_EXPECTS( | |
673 | se.code() == error::closed, | |
674 | se.code().message()); | |
675 | } | |
676 | } | |
677 | { | |
678 | stream<test::stream> ws(ioc); | |
679 | auto tr = connect(ws.next_layer()); | |
680 | tr.close(); | |
681 | try | |
682 | { | |
683 | test_async_api api; | |
684 | api.accept(ws, net::const_buffer{}); | |
685 | BEAST_FAIL(); | |
686 | } | |
687 | catch(system_error const& se) | |
688 | { | |
689 | BEAST_EXPECTS( | |
690 | se.code() == error::closed, | |
691 | se.code().message()); | |
692 | } | |
693 | } | |
11fdf7f2 TL |
694 | } |
695 | ||
92f5a8d4 TL |
696 | void |
697 | testAsync() | |
11fdf7f2 | 698 | { |
92f5a8d4 TL |
699 | using tcp = net::ip::tcp; |
700 | ||
701 | net::io_context ioc; | |
702 | ||
703 | // success, no timeout | |
704 | ||
11fdf7f2 | 705 | { |
92f5a8d4 TL |
706 | stream<tcp::socket> ws1(ioc); |
707 | stream<tcp::socket> ws2(ioc); | |
708 | test::connect(ws1.next_layer(), ws2.next_layer()); | |
709 | ||
710 | ws1.async_handshake("test", "/", test::success_handler()); | |
711 | ws2.async_accept(test::success_handler()); | |
712 | test::run_for(ioc, std::chrono::seconds(1)); | |
11fdf7f2 | 713 | } |
11fdf7f2 | 714 | |
92f5a8d4 TL |
715 | { |
716 | stream<test::stream> ws1(ioc); | |
717 | stream<test::stream> ws2(ioc); | |
718 | test::connect(ws1.next_layer(), ws2.next_layer()); | |
719 | ||
720 | ws1.async_handshake("test", "/", test::success_handler()); | |
721 | ws2.async_accept(test::success_handler()); | |
722 | test::run_for(ioc, std::chrono::seconds(1)); | |
723 | } | |
724 | ||
725 | // success, timeout enabled | |
726 | ||
727 | { | |
728 | stream<tcp::socket> ws1(ioc); | |
729 | stream<tcp::socket> ws2(ioc); | |
730 | test::connect(ws1.next_layer(), ws2.next_layer()); | |
731 | ||
732 | ws1.set_option(stream_base::timeout{ | |
733 | std::chrono::milliseconds(50), | |
734 | stream_base::none(), | |
735 | false}); | |
736 | ws1.async_accept(test::success_handler()); | |
737 | ws2.async_handshake("test", "/", test::success_handler()); | |
738 | test::run_for(ioc, std::chrono::seconds(1)); | |
739 | } | |
740 | ||
741 | { | |
742 | stream<test::stream> ws1(ioc); | |
743 | stream<test::stream> ws2(ioc); | |
744 | test::connect(ws1.next_layer(), ws2.next_layer()); | |
745 | ||
746 | ws1.set_option(stream_base::timeout{ | |
747 | std::chrono::milliseconds(50), | |
748 | stream_base::none(), | |
749 | false}); | |
750 | ws1.async_accept(test::success_handler()); | |
751 | ws2.async_handshake("test", "/", test::success_handler()); | |
752 | test::run_for(ioc, std::chrono::seconds(1)); | |
753 | } | |
754 | ||
755 | // timeout | |
756 | ||
757 | { | |
758 | stream<tcp::socket> ws1(ioc); | |
759 | stream<tcp::socket> ws2(ioc); | |
760 | test::connect(ws1.next_layer(), ws2.next_layer()); | |
761 | ||
762 | ws1.set_option(stream_base::timeout{ | |
763 | std::chrono::milliseconds(50), | |
764 | stream_base::none(), | |
765 | false}); | |
766 | ws1.async_accept(test::fail_handler(beast::error::timeout)); | |
767 | test::run_for(ioc, std::chrono::seconds(1)); | |
768 | } | |
769 | ||
770 | { | |
771 | stream<test::stream> ws1(ioc); | |
772 | stream<test::stream> ws2(ioc); | |
773 | test::connect(ws1.next_layer(), ws2.next_layer()); | |
774 | ||
775 | ws1.set_option(stream_base::timeout{ | |
776 | std::chrono::milliseconds(50), | |
777 | stream_base::none(), | |
778 | false}); | |
779 | ws1.async_accept(test::fail_handler(beast::error::timeout)); | |
780 | test::run_for(ioc, std::chrono::seconds(1)); | |
781 | } | |
782 | ||
783 | // abandoned operation | |
784 | ||
785 | { | |
786 | { | |
787 | stream<tcp::socket> ws1(ioc); | |
788 | ws1.async_accept(test::fail_handler( | |
789 | net::error::operation_aborted)); | |
790 | } | |
791 | test::run(ioc); | |
792 | } | |
793 | ||
794 | { | |
795 | { | |
796 | stream<tcp::socket> ws1(ioc); | |
797 | string_view s = | |
798 | "GET / HTTP/1.1\r\n" | |
799 | "Host: localhost\r\n" | |
800 | "Upgrade: websocket\r\n" | |
801 | "Connection: upgrade\r\n" | |
802 | "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n" | |
803 | "Sec-WebSocket-Version: 13\r\n" | |
804 | "\r\n"; | |
805 | error_code ec; | |
806 | http::request_parser<http::empty_body> p; | |
807 | p.put(net::const_buffer(s.data(), s.size()), ec); | |
808 | ws1.async_accept(p.get(), test::fail_handler( | |
809 | net::error::operation_aborted)); | |
810 | } | |
811 | test::run(ioc); | |
812 | } | |
11fdf7f2 TL |
813 | } |
814 | ||
20effc67 TL |
815 | #if BOOST_ASIO_HAS_CO_AWAIT |
816 | void testAwaitableCompiles( | |
817 | stream<net::ip::tcp::socket>& s, | |
818 | http::request<http::empty_body>& req, | |
819 | net::mutable_buffer buf | |
820 | ) | |
821 | { | |
822 | static_assert(std::is_same_v< | |
823 | net::awaitable<void>, decltype( | |
824 | s.async_accept(net::use_awaitable))>); | |
825 | ||
826 | static_assert(std::is_same_v< | |
827 | net::awaitable<void>, decltype( | |
828 | s.async_accept(req, net::use_awaitable))>); | |
829 | ||
830 | static_assert(std::is_same_v< | |
831 | net::awaitable<void>, decltype( | |
832 | s.async_accept(buf, net::use_awaitable))>); | |
833 | } | |
834 | #endif | |
835 | ||
b32b8144 FG |
836 | void |
837 | run() override | |
838 | { | |
92f5a8d4 TL |
839 | testMatrix(test_sync_api{}); |
840 | testMatrix(test_async_api{}); | |
841 | testOversized(test_sync_api{}); | |
842 | testOversized(test_async_api{}); | |
843 | testInvalidInputs(); | |
844 | testEndOfStream(); | |
845 | testAsync(); | |
20effc67 TL |
846 | #if BOOST_ASIO_HAS_CO_AWAIT |
847 | boost::ignore_unused(&accept_test::testAwaitableCompiles); | |
848 | #endif | |
b32b8144 FG |
849 | } |
850 | }; | |
851 | ||
852 | BEAST_DEFINE_TESTSUITE(beast,websocket,accept); | |
853 | ||
854 | } // websocket | |
855 | } // beast | |
856 | } // boost |