2 // Copyright (c) 2013-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)
8 #ifndef BEAST_WEBSOCKET_IMPL_ACCEPT_IPP
9 #define BEAST_WEBSOCKET_IMPL_ACCEPT_IPP
11 #include <beast/http/message.hpp>
12 #include <beast/http/header_parser.hpp>
13 #include <beast/http/read.hpp>
14 #include <beast/http/string_body.hpp>
15 #include <beast/http/write.hpp>
16 #include <beast/core/handler_helpers.hpp>
17 #include <beast/core/handler_ptr.hpp>
18 #include <beast/core/prepare_buffers.hpp>
19 #include <beast/core/detail/type_traits.hpp>
20 #include <boost/assert.hpp>
22 #include <type_traits>
27 //------------------------------------------------------------------------------
29 // Respond to an upgrade HTTP request
30 template<class NextLayer>
31 template<class Handler>
32 class stream<NextLayer>::response_op
37 stream<NextLayer>& ws;
38 http::response_header res;
42 template<class Fields>
43 data(Handler&, stream<NextLayer>& ws_,
44 http::header<true, Fields> const& req,
48 , res(ws_.build_response(req))
50 // can't call stream::reset() here
51 // otherwise accept_op will malfunction
54 final_ec = error::handshake_failed;
58 handler_ptr<data, Handler> d_;
61 response_op(response_op&&) = default;
62 response_op(response_op const&) = default;
64 template<class DeducedHandler, class... Args>
65 response_op(DeducedHandler&& h,
66 stream<NextLayer>& ws, Args&&... args)
67 : d_(std::forward<DeducedHandler>(h),
68 ws, std::forward<Args>(args)...)
70 (*this)(error_code{}, false);
74 error_code ec, bool again = true);
77 void* asio_handler_allocate(
78 std::size_t size, response_op* op)
80 return beast_asio_helpers::
81 allocate(size, op->d_.handler());
85 void asio_handler_deallocate(
86 void* p, std::size_t size, response_op* op)
88 return beast_asio_helpers::
89 deallocate(p, size, op->d_.handler());
93 bool asio_handler_is_continuation(response_op* op)
98 template<class Function>
100 void asio_handler_invoke(Function&& f, response_op* op)
102 return beast_asio_helpers::
103 invoke(f, op->d_.handler());
107 template<class NextLayer>
108 template<class Handler>
110 stream<NextLayer>::response_op<Handler>::
111 operator()(error_code ec, bool again)
114 d.cont = d.cont || again;
115 while(! ec && d.state != 99)
122 http::async_write(d.ws.next_layer(),
123 d.res, std::move(*this));
133 d.ws.pmd_config_, d.res.fields);
134 d.ws.open(detail::role_type::server);
142 //------------------------------------------------------------------------------
144 // read and respond to an upgrade request
146 template<class NextLayer>
147 template<class Handler>
148 class stream<NextLayer>::accept_op
153 stream<NextLayer>& ws;
154 http::header_parser<true, http::fields> p;
157 template<class Buffers>
158 data(Handler& handler, stream<NextLayer>& ws_,
159 Buffers const& buffers)
160 : cont(beast_asio_helpers::
161 is_continuation(handler))
164 using boost::asio::buffer_copy;
165 using boost::asio::buffer_size;
167 ws.stream_.buffer().commit(buffer_copy(
168 ws.stream_.buffer().prepare(
169 buffer_size(buffers)), buffers));
173 handler_ptr<data, Handler> d_;
176 accept_op(accept_op&&) = default;
177 accept_op(accept_op const&) = default;
179 template<class DeducedHandler, class... Args>
180 accept_op(DeducedHandler&& h,
181 stream<NextLayer>& ws, Args&&... args)
182 : d_(std::forward<DeducedHandler>(h),
183 ws, std::forward<Args>(args)...)
185 (*this)(error_code{}, 0, false);
188 void operator()(error_code const& ec)
193 void operator()(error_code ec,
194 std::size_t bytes_used, bool again = true);
197 void* asio_handler_allocate(
198 std::size_t size, accept_op* op)
200 return beast_asio_helpers::
201 allocate(size, op->d_.handler());
205 void asio_handler_deallocate(
206 void* p, std::size_t size, accept_op* op)
208 return beast_asio_helpers::
209 deallocate(p, size, op->d_.handler());
213 bool asio_handler_is_continuation(accept_op* op)
218 template<class Function>
220 void asio_handler_invoke(Function&& f, accept_op* op)
222 return beast_asio_helpers::
223 invoke(f, op->d_.handler());
227 template<class NextLayer>
228 template<class Handler>
230 stream<NextLayer>::accept_op<Handler>::
231 operator()(error_code ec,
232 std::size_t bytes_used, bool again)
235 d.cont = d.cont || again;
243 http::async_read_some(d.ws.next_layer(),
244 d.ws.stream_.buffer(), d.p,
250 BOOST_ASSERT(d.p.got_header());
251 d.ws.stream_.buffer().consume(bytes_used);
252 // Arguments from our state must be
253 // moved to the stack before releasing
256 auto m = d.p.release();
257 response_op<Handler>{
258 d_.release_handler(),
259 ws, std::move(m), true};
267 template<class NextLayer>
268 template<class AcceptHandler>
269 typename async_completion<
270 AcceptHandler, void(error_code)>::result_type
272 async_accept(AcceptHandler&& handler)
274 static_assert(is_AsyncStream<next_layer_type>::value,
275 "AsyncStream requirements requirements not met");
276 return async_accept(boost::asio::null_buffers{},
277 std::forward<AcceptHandler>(handler));
280 template<class NextLayer>
281 template<class ConstBufferSequence, class AcceptHandler>
282 typename async_completion<
283 AcceptHandler, void(error_code)>::result_type
285 async_accept(ConstBufferSequence const& bs, AcceptHandler&& handler)
287 static_assert(is_AsyncStream<next_layer_type>::value,
288 "AsyncStream requirements requirements not met");
289 static_assert(beast::is_ConstBufferSequence<
290 ConstBufferSequence>::value,
291 "ConstBufferSequence requirements not met");
292 beast::async_completion<
293 AcceptHandler, void(error_code)
294 > completion{handler};
295 accept_op<decltype(completion.handler)>{
296 completion.handler, *this, bs};
297 return completion.result.get();
300 template<class NextLayer>
301 template<class Fields, class AcceptHandler>
302 typename async_completion<
303 AcceptHandler, void(error_code)>::result_type
305 async_accept(http::header<true, Fields> const& req,
306 AcceptHandler&& handler)
308 static_assert(is_AsyncStream<next_layer_type>::value,
309 "AsyncStream requirements requirements not met");
310 beast::async_completion<
311 AcceptHandler, void(error_code)
312 > completion{handler};
314 response_op<decltype(completion.handler)>{
315 completion.handler, *this, req,
317 is_continuation(completion.handler)};
318 return completion.result.get();
321 template<class NextLayer>
326 static_assert(is_SyncStream<next_layer_type>::value,
327 "SyncStream requirements not met");
329 accept(boost::asio::null_buffers{}, ec);
331 throw system_error{ec};
334 template<class NextLayer>
337 accept(error_code& ec)
339 static_assert(is_SyncStream<next_layer_type>::value,
340 "SyncStream requirements not met");
341 accept(boost::asio::null_buffers{}, ec);
344 template<class NextLayer>
345 template<class ConstBufferSequence>
348 accept(ConstBufferSequence const& buffers)
350 static_assert(is_SyncStream<next_layer_type>::value,
351 "SyncStream requirements not met");
352 static_assert(is_ConstBufferSequence<
353 ConstBufferSequence>::value,
354 "ConstBufferSequence requirements not met");
358 throw system_error{ec};
361 template<class NextLayer>
362 template<class ConstBufferSequence>
365 accept(ConstBufferSequence const& buffers, error_code& ec)
367 static_assert(is_SyncStream<next_layer_type>::value,
368 "SyncStream requirements not met");
369 static_assert(beast::is_ConstBufferSequence<
370 ConstBufferSequence>::value,
371 "ConstBufferSequence requirements not met");
372 using boost::asio::buffer_copy;
373 using boost::asio::buffer_size;
375 stream_.buffer().commit(buffer_copy(
376 stream_.buffer().prepare(
377 buffer_size(buffers)), buffers));
378 http::header_parser<true, http::fields> p;
379 auto const bytes_used = http::read_some(
380 next_layer(), stream_.buffer(), p, ec);
383 BOOST_ASSERT(p.got_header());
384 stream_.buffer().consume(bytes_used);
388 template<class NextLayer>
389 template<class Fields>
392 accept(http::header<true, Fields> const& request)
394 static_assert(is_SyncStream<next_layer_type>::value,
395 "SyncStream requirements not met");
399 throw system_error{ec};
402 template<class NextLayer>
403 template<class Fields>
406 accept(http::header<true, Fields> const& req,
409 static_assert(is_SyncStream<next_layer_type>::value,
410 "SyncStream requirements not met");
412 auto const res = build_response(req);
413 http::write(stream_, res, ec);
416 if(res.status != 101)
418 ec = error::handshake_failed;
419 // VFALCO TODO Respect keep alive setting, perform
420 // teardown if Connection: close.
423 pmd_read(pmd_config_, req.fields);
424 open(detail::role_type::server);