2 // Copyright (c) 2016-2017 Vinnie Falco (vinnie dot falco at gmail dot com)
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)
7 // Official repository: https://github.com/boostorg/beast
10 #ifndef BOOST_BEAST_WEBSOCKET_IMPL_HANDSHAKE_IPP
11 #define BOOST_BEAST_WEBSOCKET_IMPL_HANDSHAKE_IPP
13 #include <boost/beast/websocket/detail/type_traits.hpp>
14 #include <boost/beast/http/empty_body.hpp>
15 #include <boost/beast/http/message.hpp>
16 #include <boost/beast/http/read.hpp>
17 #include <boost/beast/http/write.hpp>
18 #include <boost/beast/core/handler_ptr.hpp>
19 #include <boost/beast/core/type_traits.hpp>
20 #include <boost/asio/associated_allocator.hpp>
21 #include <boost/asio/associated_executor.hpp>
22 #include <boost/asio/coroutine.hpp>
23 #include <boost/asio/handler_continuation_hook.hpp>
24 #include <boost/assert.hpp>
25 #include <boost/throw_exception.hpp>
32 //------------------------------------------------------------------------------
34 // send the upgrade request and process the response
36 template<class NextLayer>
37 template<class Handler>
38 class stream<NextLayer>::handshake_op
39 : public boost::asio::coroutine
43 stream<NextLayer>& ws;
45 detail::sec_ws_key_type key;
46 http::request<http::empty_body> req;
49 template<class Decorator>
50 data(Handler&, stream<NextLayer>& ws_,
51 response_type* res_p_,
54 Decorator const& decorator)
57 , req(ws.build_request(key,
58 host, target, decorator))
64 handler_ptr<data, Handler> d_;
67 handshake_op(handshake_op&&) = default;
68 handshake_op(handshake_op const&) = default;
70 template<class DeducedHandler, class... Args>
71 handshake_op(DeducedHandler&& h,
72 stream<NextLayer>& ws, Args&&... args)
73 : d_(std::forward<DeducedHandler>(h),
74 ws, std::forward<Args>(args)...)
78 using allocator_type =
79 boost::asio::associated_allocator_t<Handler>;
82 get_allocator() const noexcept
84 return boost::asio::get_associated_allocator(d_.handler());
87 using executor_type = boost::asio::associated_executor_t<
88 Handler, decltype(std::declval<stream<NextLayer>&>().get_executor())>;
91 get_executor() const noexcept
93 return boost::asio::get_associated_executor(
94 d_.handler(), d_->ws.get_executor());
100 std::size_t bytes_used = 0);
103 bool asio_handler_is_continuation(handshake_op* op)
105 using boost::asio::asio_handler_is_continuation;
106 return asio_handler_is_continuation(
107 std::addressof(op->d_.handler()));
111 template<class NextLayer>
112 template<class Handler>
114 stream<NextLayer>::handshake_op<Handler>::
115 operator()(error_code ec, std::size_t)
118 BOOST_ASIO_CORO_REENTER(*this)
121 pmd_read(d.ws.pmd_config_, d.req);
122 BOOST_ASIO_CORO_YIELD
123 http::async_write(d.ws.stream_,
124 d.req, std::move(*this));
128 // VFALCO We could pre-serialize the request to
129 // a single buffer, send that instead,
130 // and delete the buffer here. The buffer
131 // could be a variable block at the end
132 // of handler_ptr's allocation.
134 // Read HTTP response
135 BOOST_ASIO_CORO_YIELD
136 http::async_read(d.ws.next_layer(),
141 d.ws.on_response(d.res, d.key, ec);
143 swap(d.res, *d.res_p);
149 template<class NextLayer>
150 template<class HandshakeHandler>
151 BOOST_ASIO_INITFN_RESULT_TYPE(
152 HandshakeHandler, void(error_code))
154 async_handshake(string_view host,
156 HandshakeHandler&& handler)
158 static_assert(is_async_stream<next_layer_type>::value,
159 "AsyncStream requirements not met");
160 boost::asio::async_completion<HandshakeHandler,
161 void(error_code)> init{handler};
162 handshake_op<BOOST_ASIO_HANDLER_TYPE(
163 HandshakeHandler, void(error_code))>{
164 init.completion_handler, *this, nullptr, host,
165 target, &default_decorate_req}();
166 return init.result.get();
169 template<class NextLayer>
170 template<class HandshakeHandler>
171 BOOST_ASIO_INITFN_RESULT_TYPE(
172 HandshakeHandler, void(error_code))
174 async_handshake(response_type& res,
177 HandshakeHandler&& handler)
179 static_assert(is_async_stream<next_layer_type>::value,
180 "AsyncStream requirements not met");
181 boost::asio::async_completion<HandshakeHandler,
182 void(error_code)> init{handler};
183 handshake_op<BOOST_ASIO_HANDLER_TYPE(
184 HandshakeHandler, void(error_code))>{
185 init.completion_handler, *this, &res, host,
186 target, &default_decorate_req}();
187 return init.result.get();
190 template<class NextLayer>
191 template<class RequestDecorator, class HandshakeHandler>
192 BOOST_ASIO_INITFN_RESULT_TYPE(
193 HandshakeHandler, void(error_code))
195 async_handshake_ex(string_view host,
197 RequestDecorator const& decorator,
198 HandshakeHandler&& handler)
200 static_assert(is_async_stream<next_layer_type>::value,
201 "AsyncStream requirements not met");
202 static_assert(detail::is_RequestDecorator<
203 RequestDecorator>::value,
204 "RequestDecorator requirements not met");
205 boost::asio::async_completion<HandshakeHandler,
206 void(error_code)> init{handler};
207 handshake_op<BOOST_ASIO_HANDLER_TYPE(
208 HandshakeHandler, void(error_code))>{
209 init.completion_handler, *this, nullptr, host,
210 target, decorator}();
211 return init.result.get();
214 template<class NextLayer>
215 template<class RequestDecorator, class HandshakeHandler>
216 BOOST_ASIO_INITFN_RESULT_TYPE(
217 HandshakeHandler, void(error_code))
219 async_handshake_ex(response_type& res,
222 RequestDecorator const& decorator,
223 HandshakeHandler&& handler)
225 static_assert(is_async_stream<next_layer_type>::value,
226 "AsyncStream requirements not met");
227 static_assert(detail::is_RequestDecorator<
228 RequestDecorator>::value,
229 "RequestDecorator requirements not met");
230 boost::asio::async_completion<HandshakeHandler,
231 void(error_code)> init{handler};
232 handshake_op<BOOST_ASIO_HANDLER_TYPE(
233 HandshakeHandler, void(error_code))>{
234 init.completion_handler, *this, &res, host,
235 target, decorator}();
236 return init.result.get();
239 template<class NextLayer>
242 handshake(string_view host,
245 static_assert(is_sync_stream<next_layer_type>::value,
246 "SyncStream requirements not met");
251 BOOST_THROW_EXCEPTION(system_error{ec});
254 template<class NextLayer>
257 handshake(response_type& res,
261 static_assert(is_sync_stream<next_layer_type>::value,
262 "SyncStream requirements not met");
264 handshake(res, host, target, ec);
266 BOOST_THROW_EXCEPTION(system_error{ec});
269 template<class NextLayer>
270 template<class RequestDecorator>
273 handshake_ex(string_view host,
275 RequestDecorator const& decorator)
277 static_assert(is_sync_stream<next_layer_type>::value,
278 "SyncStream requirements not met");
279 static_assert(detail::is_RequestDecorator<
280 RequestDecorator>::value,
281 "RequestDecorator requirements not met");
283 handshake_ex(host, target, decorator, ec);
285 BOOST_THROW_EXCEPTION(system_error{ec});
288 template<class NextLayer>
289 template<class RequestDecorator>
292 handshake_ex(response_type& res,
295 RequestDecorator const& decorator)
297 static_assert(is_sync_stream<next_layer_type>::value,
298 "SyncStream requirements not met");
299 static_assert(detail::is_RequestDecorator<
300 RequestDecorator>::value,
301 "RequestDecorator requirements not met");
303 handshake_ex(res, host, target, decorator, ec);
305 BOOST_THROW_EXCEPTION(system_error{ec});
308 template<class NextLayer>
311 handshake(string_view host,
312 string_view target, error_code& ec)
314 static_assert(is_sync_stream<next_layer_type>::value,
315 "SyncStream requirements not met");
316 do_handshake(nullptr,
317 host, target, &default_decorate_req, ec);
320 template<class NextLayer>
323 handshake(response_type& res,
328 static_assert(is_sync_stream<next_layer_type>::value,
329 "SyncStream requirements not met");
331 host, target, &default_decorate_req, ec);
334 template<class NextLayer>
335 template<class RequestDecorator>
338 handshake_ex(string_view host,
340 RequestDecorator const& decorator,
343 static_assert(is_sync_stream<next_layer_type>::value,
344 "SyncStream requirements not met");
345 static_assert(detail::is_RequestDecorator<
346 RequestDecorator>::value,
347 "RequestDecorator requirements not met");
348 do_handshake(nullptr,
349 host, target, decorator, ec);
352 template<class NextLayer>
353 template<class RequestDecorator>
356 handshake_ex(response_type& res,
359 RequestDecorator const& decorator,
362 static_assert(is_sync_stream<next_layer_type>::value,
363 "SyncStream requirements not met");
364 static_assert(detail::is_RequestDecorator<
365 RequestDecorator>::value,
366 "RequestDecorator requirements not met");
368 host, target, decorator, ec);
371 //------------------------------------------------------------------------------
373 template<class NextLayer>
374 template<class RequestDecorator>
378 response_type* res_p,
381 RequestDecorator const& decorator,
386 detail::sec_ws_key_type key;
388 auto const req = build_request(
389 key, host, target, decorator);
390 pmd_read(pmd_config_, req);
391 http::write(stream_, req, ec);
395 http::read(next_layer(), rd_buf_, res, ec);
398 on_response(res, key, ec);
400 *res_p = std::move(res);