]> git.proxmox.com Git - ceph.git/blame - ceph/src/boost/boost/beast/websocket/impl/stream.ipp
update sources to ceph Nautilus 14.2.1
[ceph.git] / ceph / src / boost / boost / beast / websocket / impl / stream.ipp
CommitLineData
b32b8144
FG
1//
2// Copyright (c) 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#ifndef BOOST_BEAST_WEBSOCKET_IMPL_STREAM_IPP
11#define BOOST_BEAST_WEBSOCKET_IMPL_STREAM_IPP
12
13#include <boost/beast/websocket/rfc6455.hpp>
14#include <boost/beast/websocket/teardown.hpp>
15#include <boost/beast/websocket/detail/hybi13.hpp>
16#include <boost/beast/websocket/detail/pmd_extension.hpp>
17#include <boost/beast/version.hpp>
18#include <boost/beast/http/read.hpp>
19#include <boost/beast/http/write.hpp>
20#include <boost/beast/http/rfc7230.hpp>
21#include <boost/beast/core/buffers_cat.hpp>
22#include <boost/beast/core/buffers_prefix.hpp>
23#include <boost/beast/core/buffers_suffix.hpp>
24#include <boost/beast/core/flat_static_buffer.hpp>
25#include <boost/beast/core/type_traits.hpp>
26#include <boost/beast/core/detail/clamp.hpp>
27#include <boost/beast/core/detail/type_traits.hpp>
28#include <boost/assert.hpp>
29#include <boost/endian/buffers.hpp>
30#include <boost/make_unique.hpp>
31#include <boost/throw_exception.hpp>
32#include <algorithm>
33#include <memory>
34#include <stdexcept>
35#include <utility>
36
37#include <iostream>
38
39namespace boost {
40namespace beast {
41namespace websocket {
42
11fdf7f2 43template<class NextLayer, bool deflateSupported>
b32b8144 44template<class... Args>
11fdf7f2 45stream<NextLayer, deflateSupported>::
b32b8144
FG
46stream(Args&&... args)
47 : stream_(std::forward<Args>(args)...)
b32b8144
FG
48{
49 BOOST_ASSERT(rd_buf_.max_size() >=
50 max_control_frame_size);
51}
52
11fdf7f2 53template<class NextLayer, bool deflateSupported>
b32b8144
FG
54template<class DynamicBuffer, class>
55std::size_t
11fdf7f2 56stream<NextLayer, deflateSupported>::
b32b8144
FG
57read_size_hint(DynamicBuffer& buffer) const
58{
59 static_assert(
60 boost::asio::is_dynamic_buffer<DynamicBuffer>::value,
61 "DynamicBuffer requirements not met");
62 auto const initial_size = (std::min)(
63 +tcp_frame_size,
64 buffer.max_size() - buffer.size());
65 if(initial_size == 0)
66 return 1; // buffer is full
67 return read_size_hint(initial_size);
68}
69
11fdf7f2
TL
70//------------------------------------------------------------------------------
71
72template<class NextLayer, bool deflateSupported>
b32b8144 73void
11fdf7f2
TL
74stream<NextLayer, deflateSupported>::
75set_option(permessage_deflate const& o, std::true_type)
b32b8144
FG
76{
77 if( o.server_max_window_bits > 15 ||
78 o.server_max_window_bits < 9)
79 BOOST_THROW_EXCEPTION(std::invalid_argument{
80 "invalid server_max_window_bits"});
81 if( o.client_max_window_bits > 15 ||
82 o.client_max_window_bits < 9)
83 BOOST_THROW_EXCEPTION(std::invalid_argument{
84 "invalid client_max_window_bits"});
85 if( o.compLevel < 0 ||
86 o.compLevel > 9)
87 BOOST_THROW_EXCEPTION(std::invalid_argument{
88 "invalid compLevel"});
89 if( o.memLevel < 1 ||
90 o.memLevel > 9)
91 BOOST_THROW_EXCEPTION(std::invalid_argument{
92 "invalid memLevel"});
11fdf7f2 93 this->pmd_opts_ = o;
b32b8144
FG
94}
95
11fdf7f2
TL
96template<class NextLayer, bool deflateSupported>
97void
98stream<NextLayer, deflateSupported>::
99set_option(permessage_deflate const& o, std::false_type)
100{
101 if(o.client_enable || o.server_enable)
102 {
103 // Can't enable permessage-deflate
104 // when deflateSupported == false.
105 //
106 BOOST_THROW_EXCEPTION(std::invalid_argument{
107 "deflateSupported == false"});
108 }
109}
b32b8144 110
11fdf7f2 111template<class NextLayer, bool deflateSupported>
b32b8144 112void
11fdf7f2 113stream<NextLayer, deflateSupported>::
b32b8144
FG
114open(role_type role)
115{
116 // VFALCO TODO analyze and remove dupe code in reset()
117 role_ = role;
118 status_ = status::open;
119 rd_remain_ = 0;
120 rd_cont_ = false;
121 rd_done_ = true;
122 // Can't clear this because accept uses it
123 //rd_buf_.reset();
124 rd_fh_.fin = false;
125 rd_close_ = false;
126 wr_close_ = false;
11fdf7f2
TL
127 // These should not be necessary, because all completion
128 // handlers must be allowed to execute otherwise the
129 // stream exhibits undefined behavior.
b32b8144
FG
130 wr_block_.reset();
131 rd_block_.reset();
132 cr_.code = close_code::none;
133
134 wr_cont_ = false;
135 wr_buf_size_ = 0;
136
11fdf7f2
TL
137 open_pmd(is_deflate_supported{});
138}
139
140template<class NextLayer, bool deflateSupported>
141inline
142void
143stream<NextLayer, deflateSupported>::
144open_pmd(std::true_type)
145{
146 if(((role_ == role_type::client &&
147 this->pmd_opts_.client_enable) ||
148 (role_ == role_type::server &&
149 this->pmd_opts_.server_enable)) &&
150 this->pmd_config_.accept)
b32b8144 151 {
11fdf7f2
TL
152 pmd_normalize(this->pmd_config_);
153 this->pmd_.reset(new typename
154 detail::stream_base<deflateSupported>::pmd_type);
b32b8144
FG
155 if(role_ == role_type::client)
156 {
11fdf7f2
TL
157 this->pmd_->zi.reset(
158 this->pmd_config_.server_max_window_bits);
159 this->pmd_->zo.reset(
160 this->pmd_opts_.compLevel,
161 this->pmd_config_.client_max_window_bits,
162 this->pmd_opts_.memLevel,
b32b8144
FG
163 zlib::Strategy::normal);
164 }
165 else
166 {
11fdf7f2
TL
167 this->pmd_->zi.reset(
168 this->pmd_config_.client_max_window_bits);
169 this->pmd_->zo.reset(
170 this->pmd_opts_.compLevel,
171 this->pmd_config_.server_max_window_bits,
172 this->pmd_opts_.memLevel,
b32b8144
FG
173 zlib::Strategy::normal);
174 }
175 }
176}
177
11fdf7f2 178template<class NextLayer, bool deflateSupported>
b32b8144 179void
11fdf7f2 180stream<NextLayer, deflateSupported>::
b32b8144
FG
181close()
182{
183 wr_buf_.reset();
11fdf7f2 184 close_pmd(is_deflate_supported{});
b32b8144
FG
185}
186
11fdf7f2 187template<class NextLayer, bool deflateSupported>
b32b8144 188void
11fdf7f2 189stream<NextLayer, deflateSupported>::
b32b8144
FG
190reset()
191{
192 BOOST_ASSERT(status_ != status::open);
193 rd_remain_ = 0;
194 rd_cont_ = false;
195 rd_done_ = true;
196 rd_buf_.consume(rd_buf_.size());
197 rd_fh_.fin = false;
198 rd_close_ = false;
199 wr_close_ = false;
200 wr_cont_ = false;
11fdf7f2
TL
201 // These should not be necessary, because all completion
202 // handlers must be allowed to execute otherwise the
203 // stream exhibits undefined behavior.
b32b8144
FG
204 wr_block_.reset();
205 rd_block_.reset();
206 cr_.code = close_code::none;
207}
208
209// Called before each write frame
11fdf7f2
TL
210template<class NextLayer, bool deflateSupported>
211inline
b32b8144 212void
11fdf7f2
TL
213stream<NextLayer, deflateSupported>::
214begin_msg(std::true_type)
b32b8144
FG
215{
216 wr_frag_ = wr_frag_opt_;
11fdf7f2 217 wr_compress_ = static_cast<bool>(this->pmd_);
b32b8144
FG
218
219 // Maintain the write buffer
220 if( wr_compress_ ||
221 role_ == role_type::client)
222 {
223 if(! wr_buf_ || wr_buf_size_ != wr_buf_opt_)
224 {
225 wr_buf_size_ = wr_buf_opt_;
226 wr_buf_ = boost::make_unique_noinit<
227 std::uint8_t[]>(wr_buf_size_);
228 }
229 }
230 else
231 {
232 wr_buf_size_ = wr_buf_opt_;
233 wr_buf_.reset();
234 }
235}
236
11fdf7f2
TL
237// Called before each write frame
238template<class NextLayer, bool deflateSupported>
239inline
240void
241stream<NextLayer, deflateSupported>::
242begin_msg(std::false_type)
243{
244 wr_frag_ = wr_frag_opt_;
245
246 // Maintain the write buffer
247 if(role_ == role_type::client)
248 {
249 if(! wr_buf_ || wr_buf_size_ != wr_buf_opt_)
250 {
251 wr_buf_size_ = wr_buf_opt_;
252 wr_buf_ = boost::make_unique_noinit<
253 std::uint8_t[]>(wr_buf_size_);
254 }
255 }
256 else
257 {
258 wr_buf_size_ = wr_buf_opt_;
259 wr_buf_.reset();
260 }
261}
262
263template<class NextLayer, bool deflateSupported>
264std::size_t
265stream<NextLayer, deflateSupported>::
266read_size_hint(
267 std::size_t initial_size,
268 std::true_type) const
269{
270 using beast::detail::clamp;
271 std::size_t result;
272 BOOST_ASSERT(initial_size > 0);
273 if(! this->pmd_ || (! rd_done_ && ! this->pmd_->rd_set))
274 {
275 // current message is uncompressed
276
277 if(rd_done_)
278 {
279 // first message frame
280 result = initial_size;
281 goto done;
282 }
283 else if(rd_fh_.fin)
284 {
285 // last message frame
286 BOOST_ASSERT(rd_remain_ > 0);
287 result = clamp(rd_remain_);
288 goto done;
289 }
290 }
291 result = (std::max)(
292 initial_size, clamp(rd_remain_));
293done:
294 BOOST_ASSERT(result != 0);
295 return result;
296}
297
298template<class NextLayer, bool deflateSupported>
299std::size_t
300stream<NextLayer, deflateSupported>::
301read_size_hint(
302 std::size_t initial_size,
303 std::false_type) const
304{
305 using beast::detail::clamp;
306 std::size_t result;
307 BOOST_ASSERT(initial_size > 0);
308 // compression is not supported
309 if(rd_done_)
310 {
311 // first message frame
312 result = initial_size;
313 }
314 else if(rd_fh_.fin)
315 {
316 // last message frame
317 BOOST_ASSERT(rd_remain_ > 0);
318 result = clamp(rd_remain_);
319 }
320 else
321 {
322 result = (std::max)(
323 initial_size, clamp(rd_remain_));
324 }
325 BOOST_ASSERT(result != 0);
326 return result;
327}
328
b32b8144
FG
329//------------------------------------------------------------------------------
330
331// Attempt to read a complete frame header.
332// Returns `false` if more bytes are needed
11fdf7f2 333template<class NextLayer, bool deflateSupported>
b32b8144
FG
334template<class DynamicBuffer>
335bool
11fdf7f2 336stream<NextLayer, deflateSupported>::
b32b8144
FG
337parse_fh(
338 detail::frame_header& fh,
339 DynamicBuffer& b,
11fdf7f2 340 error_code& ec)
b32b8144
FG
341{
342 using boost::asio::buffer;
343 using boost::asio::buffer_copy;
344 using boost::asio::buffer_size;
b32b8144
FG
345 if(buffer_size(b.data()) < 2)
346 {
11fdf7f2
TL
347 // need more bytes
348 ec.assign(0, ec.category());
b32b8144
FG
349 return false;
350 }
351 buffers_suffix<typename
352 DynamicBuffer::const_buffers_type> cb{
353 b.data()};
354 std::size_t need;
355 {
356 std::uint8_t tmp[2];
357 cb.consume(buffer_copy(buffer(tmp), cb));
358 fh.len = tmp[1] & 0x7f;
359 switch(fh.len)
360 {
361 case 126: need = 2; break;
362 case 127: need = 8; break;
363 default:
364 need = 0;
365 }
366 fh.mask = (tmp[1] & 0x80) != 0;
367 if(fh.mask)
368 need += 4;
369 if(buffer_size(cb) < need)
370 {
11fdf7f2
TL
371 // need more bytes
372 ec.assign(0, ec.category());
b32b8144
FG
373 return false;
374 }
375 fh.op = static_cast<
376 detail::opcode>(tmp[0] & 0x0f);
377 fh.fin = (tmp[0] & 0x80) != 0;
378 fh.rsv1 = (tmp[0] & 0x40) != 0;
379 fh.rsv2 = (tmp[0] & 0x20) != 0;
380 fh.rsv3 = (tmp[0] & 0x10) != 0;
381 }
382 switch(fh.op)
383 {
384 case detail::opcode::binary:
385 case detail::opcode::text:
386 if(rd_cont_)
387 {
388 // new data frame when continuation expected
11fdf7f2
TL
389 ec = error::bad_data_frame;
390 return false;
b32b8144 391 }
11fdf7f2
TL
392 if(fh.rsv2 || fh.rsv3 ||
393 ! this->rd_deflated(fh.rsv1))
b32b8144
FG
394 {
395 // reserved bits not cleared
11fdf7f2
TL
396 ec = error::bad_reserved_bits;
397 return false;
b32b8144 398 }
b32b8144
FG
399 break;
400
401 case detail::opcode::cont:
402 if(! rd_cont_)
403 {
404 // continuation without an active message
11fdf7f2
TL
405 ec = error::bad_continuation;
406 return false;
b32b8144
FG
407 }
408 if(fh.rsv1 || fh.rsv2 || fh.rsv3)
409 {
410 // reserved bits not cleared
11fdf7f2
TL
411 ec = error::bad_reserved_bits;
412 return false;
b32b8144
FG
413 }
414 break;
415
416 default:
417 if(detail::is_reserved(fh.op))
418 {
419 // reserved opcode
11fdf7f2
TL
420 ec = error::bad_opcode;
421 return false;
b32b8144
FG
422 }
423 if(! fh.fin)
424 {
425 // fragmented control message
11fdf7f2
TL
426 ec = error::bad_control_fragment;
427 return false;
b32b8144
FG
428 }
429 if(fh.len > 125)
430 {
431 // invalid length for control message
11fdf7f2
TL
432 ec = error::bad_control_size;
433 return false;
b32b8144
FG
434 }
435 if(fh.rsv1 || fh.rsv2 || fh.rsv3)
436 {
437 // reserved bits not cleared
11fdf7f2
TL
438 ec = error::bad_reserved_bits;
439 return false;
b32b8144
FG
440 }
441 break;
442 }
b32b8144 443 if(role_ == role_type::server && ! fh.mask)
11fdf7f2
TL
444 {
445 // unmasked frame from client
446 ec = error::bad_unmasked_frame;
447 return false;
448 }
b32b8144 449 if(role_ == role_type::client && fh.mask)
11fdf7f2
TL
450 {
451 // masked frame from server
452 ec = error::bad_masked_frame;
453 return false;
454 }
b32b8144
FG
455 if(detail::is_control(fh.op) &&
456 buffer_size(cb) < need + fh.len)
457 {
458 // Make the entire control frame payload
459 // get read in before we return `true`
460 return false;
461 }
462 switch(fh.len)
463 {
464 case 126:
465 {
466 std::uint8_t tmp[2];
467 BOOST_ASSERT(buffer_size(cb) >= sizeof(tmp));
468 cb.consume(buffer_copy(buffer(tmp), cb));
469 fh.len = detail::big_uint16_to_native(&tmp[0]);
b32b8144 470 if(fh.len < 126)
11fdf7f2
TL
471 {
472 // length not canonical
473 ec = error::bad_size;
474 return false;
475 }
b32b8144
FG
476 break;
477 }
478 case 127:
479 {
480 std::uint8_t tmp[8];
481 BOOST_ASSERT(buffer_size(cb) >= sizeof(tmp));
482 cb.consume(buffer_copy(buffer(tmp), cb));
483 fh.len = detail::big_uint64_to_native(&tmp[0]);
b32b8144 484 if(fh.len < 65536)
11fdf7f2
TL
485 {
486 // length not canonical
487 ec = error::bad_size;
488 return false;
489 }
b32b8144
FG
490 break;
491 }
492 }
493 if(fh.mask)
494 {
495 std::uint8_t tmp[4];
496 BOOST_ASSERT(buffer_size(cb) >= sizeof(tmp));
497 cb.consume(buffer_copy(buffer(tmp), cb));
498 fh.key = detail::little_uint32_to_native(&tmp[0]);
499 detail::prepare_key(rd_key_, fh.key);
500 }
501 else
502 {
503 // initialize this otherwise operator== breaks
504 fh.key = 0;
505 }
506 if(! detail::is_control(fh.op))
507 {
508 if(fh.op != detail::opcode::cont)
509 {
510 rd_size_ = 0;
511 rd_op_ = fh.op;
512 }
513 else
514 {
515 if(rd_size_ > (std::numeric_limits<
516 std::uint64_t>::max)() - fh.len)
11fdf7f2
TL
517 {
518 // message size exceeds configured limit
519 ec = error::message_too_big;
520 return false;
521 }
b32b8144 522 }
11fdf7f2 523 if(! this->rd_deflated())
b32b8144
FG
524 {
525 if(rd_msg_max_ && beast::detail::sum_exceeds(
526 rd_size_, fh.len, rd_msg_max_))
11fdf7f2
TL
527 {
528 // message size exceeds configured limit
529 ec = error::message_too_big;
530 return false;
531 }
b32b8144
FG
532 }
533 rd_cont_ = ! fh.fin;
534 rd_remain_ = fh.len;
535 }
536 b.consume(b.size() - buffer_size(cb));
11fdf7f2 537 ec.assign(0, ec.category());
b32b8144
FG
538 return true;
539}
540
11fdf7f2 541template<class NextLayer, bool deflateSupported>
b32b8144
FG
542template<class DynamicBuffer>
543void
11fdf7f2 544stream<NextLayer, deflateSupported>::
b32b8144
FG
545write_close(DynamicBuffer& db, close_reason const& cr)
546{
547 using namespace boost::endian;
548 detail::frame_header fh;
549 fh.op = detail::opcode::close;
550 fh.fin = true;
551 fh.rsv1 = false;
552 fh.rsv2 = false;
553 fh.rsv3 = false;
554 fh.len = cr.code == close_code::none ?
555 0 : 2 + cr.reason.size();
556 if(role_ == role_type::client)
557 {
558 fh.mask = true;
559 fh.key = wr_gen_();
560 }
561 else
562 {
563 fh.mask = false;
564 }
565 detail::write(db, fh);
566 if(cr.code != close_code::none)
567 {
568 detail::prepared_key key;
569 if(fh.mask)
570 detail::prepare_key(key, fh.key);
571 {
572 std::uint8_t tmp[2];
573 ::new(&tmp[0]) big_uint16_buf_t{
574 (std::uint16_t)cr.code};
575 auto mb = db.prepare(2);
576 boost::asio::buffer_copy(mb,
577 boost::asio::buffer(tmp));
578 if(fh.mask)
579 detail::mask_inplace(mb, key);
580 db.commit(2);
581 }
582 if(! cr.reason.empty())
583 {
584 auto mb = db.prepare(cr.reason.size());
585 boost::asio::buffer_copy(mb,
586 boost::asio::const_buffer(
587 cr.reason.data(), cr.reason.size()));
588 if(fh.mask)
589 detail::mask_inplace(mb, key);
590 db.commit(cr.reason.size());
591 }
592 }
593}
594
11fdf7f2 595template<class NextLayer, bool deflateSupported>
b32b8144
FG
596template<class DynamicBuffer>
597void
11fdf7f2 598stream<NextLayer, deflateSupported>::
b32b8144
FG
599write_ping(DynamicBuffer& db,
600 detail::opcode code, ping_data const& data)
601{
602 detail::frame_header fh;
603 fh.op = code;
604 fh.fin = true;
605 fh.rsv1 = false;
606 fh.rsv2 = false;
607 fh.rsv3 = false;
608 fh.len = data.size();
609 fh.mask = role_ == role_type::client;
610 if(fh.mask)
611 fh.key = wr_gen_();
612 detail::write(db, fh);
613 if(data.empty())
614 return;
615 detail::prepared_key key;
616 if(fh.mask)
617 detail::prepare_key(key, fh.key);
618 auto mb = db.prepare(data.size());
619 boost::asio::buffer_copy(mb,
620 boost::asio::const_buffer(
621 data.data(), data.size()));
622 if(fh.mask)
623 detail::mask_inplace(mb, key);
624 db.commit(data.size());
625}
626
627//------------------------------------------------------------------------------
628
11fdf7f2 629template<class NextLayer, bool deflateSupported>
b32b8144
FG
630template<class Decorator>
631request_type
11fdf7f2 632stream<NextLayer, deflateSupported>::
b32b8144 633build_request(detail::sec_ws_key_type& key,
11fdf7f2
TL
634 string_view host, string_view target,
635 Decorator const& decorator)
b32b8144
FG
636{
637 request_type req;
638 req.target(target);
639 req.version(11);
640 req.method(http::verb::get);
641 req.set(http::field::host, host);
642 req.set(http::field::upgrade, "websocket");
643 req.set(http::field::connection, "upgrade");
644 detail::make_sec_ws_key(key, wr_gen_);
645 req.set(http::field::sec_websocket_key, key);
646 req.set(http::field::sec_websocket_version, "13");
11fdf7f2
TL
647 build_request_pmd(req, is_deflate_supported{});
648 decorator(req);
649 if(! req.count(http::field::user_agent))
650 req.set(http::field::user_agent,
651 BOOST_BEAST_VERSION_STRING);
652 return req;
653}
654
655template<class NextLayer, bool deflateSupported>
656inline
657void
658stream<NextLayer, deflateSupported>::
659build_request_pmd(request_type& req, std::true_type)
660{
661 if(this->pmd_opts_.client_enable)
b32b8144
FG
662 {
663 detail::pmd_offer config;
664 config.accept = true;
665 config.server_max_window_bits =
11fdf7f2 666 this->pmd_opts_.server_max_window_bits;
b32b8144 667 config.client_max_window_bits =
11fdf7f2 668 this->pmd_opts_.client_max_window_bits;
b32b8144 669 config.server_no_context_takeover =
11fdf7f2 670 this->pmd_opts_.server_no_context_takeover;
b32b8144 671 config.client_no_context_takeover =
11fdf7f2 672 this->pmd_opts_.client_no_context_takeover;
b32b8144
FG
673 detail::pmd_write(req, config);
674 }
b32b8144
FG
675}
676
11fdf7f2 677template<class NextLayer, bool deflateSupported>
b32b8144
FG
678template<class Body, class Allocator, class Decorator>
679response_type
11fdf7f2
TL
680stream<NextLayer, deflateSupported>::
681build_response(
682 http::request<Body,
683 http::basic_fields<Allocator>> const& req,
684 Decorator const& decorator,
685 error_code& result)
b32b8144
FG
686{
687 auto const decorate =
688 [&decorator](response_type& res)
689 {
690 decorator(res);
691 if(! res.count(http::field::server))
692 {
693 BOOST_STATIC_ASSERT(sizeof(BOOST_BEAST_VERSION_STRING) < 20);
694 static_string<20> s(BOOST_BEAST_VERSION_STRING);
695 res.set(http::field::server, s);
696 }
697 };
698 auto err =
11fdf7f2 699 [&](error e)
b32b8144 700 {
11fdf7f2 701 result = e;
b32b8144
FG
702 response_type res;
703 res.version(req.version());
704 res.result(http::status::bad_request);
11fdf7f2 705 res.body() = result.message();
b32b8144
FG
706 res.prepare_payload();
707 decorate(res);
708 return res;
709 };
11fdf7f2
TL
710 if(req.version() != 11)
711 return err(error::bad_http_version);
b32b8144 712 if(req.method() != http::verb::get)
11fdf7f2 713 return err(error::bad_method);
b32b8144 714 if(! req.count(http::field::host))
11fdf7f2
TL
715 return err(error::no_host);
716 {
717 auto const it = req.find(http::field::connection);
718 if(it == req.end())
719 return err(error::no_connection);
720 if(! http::token_list{it->value()}.exists("upgrade"))
721 return err(error::no_connection_upgrade);
722 }
723 {
724 auto const it = req.find(http::field::upgrade);
725 if(it == req.end())
726 return err(error::no_upgrade);
727 if(! http::token_list{it->value()}.exists("websocket"))
728 return err(error::no_upgrade_websocket);
729 }
730 string_view key;
731 {
732 auto const it = req.find(http::field::sec_websocket_key);
733 if(it == req.end())
734 return err(error::no_sec_key);
735 key = it->value();
736 if(key.size() > detail::sec_ws_key_type::max_size_n)
737 return err(error::bad_sec_key);
738 }
739 {
740 auto const it = req.find(http::field::sec_websocket_version);
741 if(it == req.end())
742 return err(error::no_sec_version);
743 if(it->value() != "13")
b32b8144
FG
744 {
745 response_type res;
746 res.result(http::status::upgrade_required);
747 res.version(req.version());
748 res.set(http::field::sec_websocket_version, "13");
11fdf7f2
TL
749 result = error::bad_sec_version;
750 res.body() = result.message();
b32b8144
FG
751 res.prepare_payload();
752 decorate(res);
753 return res;
754 }
755 }
756
757 response_type res;
b32b8144
FG
758 res.result(http::status::switching_protocols);
759 res.version(req.version());
760 res.set(http::field::upgrade, "websocket");
761 res.set(http::field::connection, "upgrade");
762 {
763 detail::sec_ws_accept_type acc;
764 detail::make_sec_ws_accept(acc, key);
765 res.set(http::field::sec_websocket_accept, acc);
766 }
11fdf7f2 767 build_response_pmd(res, req, is_deflate_supported{});
b32b8144 768 decorate(res);
11fdf7f2 769 result = {};
b32b8144
FG
770 return res;
771}
772
11fdf7f2
TL
773template<class NextLayer, bool deflateSupported>
774template<class Body, class Allocator>
775inline
776void
777stream<NextLayer, deflateSupported>::
778build_response_pmd(
779 response_type& res,
780 http::request<Body,
781 http::basic_fields<Allocator>> const& req,
782 std::true_type)
783{
784 detail::pmd_offer offer;
785 detail::pmd_offer unused;
786 pmd_read(offer, req);
787 pmd_negotiate(res, unused, offer, this->pmd_opts_);
788}
789
790// Called when the WebSocket Upgrade response is received
791template<class NextLayer, bool deflateSupported>
b32b8144 792void
11fdf7f2
TL
793stream<NextLayer, deflateSupported>::
794on_response(
795 response_type const& res,
796 detail::sec_ws_key_type const& key,
797 error_code& ec)
b32b8144 798{
11fdf7f2
TL
799 auto const err =
800 [&](error e)
801 {
802 ec = e;
803 };
804 if(res.result() != http::status::switching_protocols)
805 return err(error::upgrade_declined);
806 if(res.version() != 11)
807 return err(error::bad_http_version);
b32b8144 808 {
11fdf7f2
TL
809 auto const it = res.find(http::field::connection);
810 if(it == res.end())
811 return err(error::no_connection);
812 if(! http::token_list{it->value()}.exists("upgrade"))
813 return err(error::no_connection_upgrade);
814 }
815 {
816 auto const it = res.find(http::field::upgrade);
817 if(it == res.end())
818 return err(error::no_upgrade);
819 if(! http::token_list{it->value()}.exists("websocket"))
820 return err(error::no_upgrade_websocket);
821 }
822 {
823 auto const it = res.find(http::field::sec_websocket_accept);
824 if(it == res.end())
825 return err(error::no_sec_accept);
b32b8144
FG
826 detail::sec_ws_accept_type acc;
827 detail::make_sec_ws_accept(acc, key);
11fdf7f2
TL
828 if(acc.compare(it->value()) != 0)
829 return err(error::bad_sec_accept);
b32b8144 830 }
11fdf7f2 831
b32b8144 832 ec.assign(0, ec.category());
11fdf7f2
TL
833 on_response_pmd(res, is_deflate_supported{});
834 open(role_type::client);
835}
836
837template<class NextLayer, bool deflateSupported>
838inline
839void
840stream<NextLayer, deflateSupported>::
841on_response_pmd(
842 response_type const& res,
843 std::true_type)
844{
b32b8144
FG
845 detail::pmd_offer offer;
846 pmd_read(offer, res);
847 // VFALCO see if offer satisfies pmd_config_,
848 // return an error if not.
11fdf7f2 849 this->pmd_config_ = offer; // overwrite for now
b32b8144
FG
850}
851
852// _Fail the WebSocket Connection_
11fdf7f2 853template<class NextLayer, bool deflateSupported>
b32b8144 854void
11fdf7f2 855stream<NextLayer, deflateSupported>::
b32b8144
FG
856do_fail(
857 std::uint16_t code, // if set, send a close frame first
858 error_code ev, // error code to use upon success
859 error_code& ec) // set to the error, else set to ev
860{
861 BOOST_ASSERT(ev);
862 status_ = status::closing;
863 if(code != close_code::none && ! wr_close_)
864 {
865 wr_close_ = true;
866 detail::frame_buffer fb;
867 write_close<
868 flat_static_buffer_base>(fb, code);
869 boost::asio::write(stream_, fb.data(), ec);
870 if(! check_ok(ec))
871 return;
872 }
873 using beast::websocket::teardown;
874 teardown(role_, stream_, ec);
875 if(ec == boost::asio::error::eof)
876 {
877 // Rationale:
878 // http://stackoverflow.com/questions/25587403/boost-asio-ssl-async-shutdown-always-finishes-with-an-error
879 ec.assign(0, ec.category());
880 }
881 if(! ec)
882 ec = ev;
883 if(ec && ec != error::closed)
884 status_ = status::failed;
885 else
886 status_ = status::closed;
887 close();
888}
889
890} // websocket
891} // beast
892} // boost
893
894#endif