]> git.proxmox.com Git - ceph.git/blob - ceph/src/Beast/include/beast/websocket/impl/accept.ipp
bump version to 12.2.2-pve1
[ceph.git] / ceph / src / Beast / include / beast / websocket / impl / accept.ipp
1 //
2 // Copyright (c) 2013-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
8 #ifndef BEAST_WEBSOCKET_IMPL_ACCEPT_IPP
9 #define BEAST_WEBSOCKET_IMPL_ACCEPT_IPP
10
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>
21 #include <memory>
22 #include <type_traits>
23
24 namespace beast {
25 namespace websocket {
26
27 //------------------------------------------------------------------------------
28
29 // Respond to an upgrade HTTP request
30 template<class NextLayer>
31 template<class Handler>
32 class stream<NextLayer>::response_op
33 {
34 struct data
35 {
36 bool cont;
37 stream<NextLayer>& ws;
38 http::response_header res;
39 error_code final_ec;
40 int state = 0;
41
42 template<class Fields>
43 data(Handler&, stream<NextLayer>& ws_,
44 http::header<true, Fields> const& req,
45 bool cont_)
46 : cont(cont_)
47 , ws(ws_)
48 , res(ws_.build_response(req))
49 {
50 // can't call stream::reset() here
51 // otherwise accept_op will malfunction
52 //
53 if(res.status != 101)
54 final_ec = error::handshake_failed;
55 }
56 };
57
58 handler_ptr<data, Handler> d_;
59
60 public:
61 response_op(response_op&&) = default;
62 response_op(response_op const&) = default;
63
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)...)
69 {
70 (*this)(error_code{}, false);
71 }
72
73 void operator()(
74 error_code ec, bool again = true);
75
76 friend
77 void* asio_handler_allocate(
78 std::size_t size, response_op* op)
79 {
80 return beast_asio_helpers::
81 allocate(size, op->d_.handler());
82 }
83
84 friend
85 void asio_handler_deallocate(
86 void* p, std::size_t size, response_op* op)
87 {
88 return beast_asio_helpers::
89 deallocate(p, size, op->d_.handler());
90 }
91
92 friend
93 bool asio_handler_is_continuation(response_op* op)
94 {
95 return op->d_->cont;
96 }
97
98 template<class Function>
99 friend
100 void asio_handler_invoke(Function&& f, response_op* op)
101 {
102 return beast_asio_helpers::
103 invoke(f, op->d_.handler());
104 }
105 };
106
107 template<class NextLayer>
108 template<class Handler>
109 void
110 stream<NextLayer>::response_op<Handler>::
111 operator()(error_code ec, bool again)
112 {
113 auto& d = *d_;
114 d.cont = d.cont || again;
115 while(! ec && d.state != 99)
116 {
117 switch(d.state)
118 {
119 case 0:
120 // send response
121 d.state = 1;
122 http::async_write(d.ws.next_layer(),
123 d.res, std::move(*this));
124 return;
125
126 // sent response
127 case 1:
128 d.state = 99;
129 ec = d.final_ec;
130 if(! ec)
131 {
132 pmd_read(
133 d.ws.pmd_config_, d.res.fields);
134 d.ws.open(detail::role_type::server);
135 }
136 break;
137 }
138 }
139 d_.invoke(ec);
140 }
141
142 //------------------------------------------------------------------------------
143
144 // read and respond to an upgrade request
145 //
146 template<class NextLayer>
147 template<class Handler>
148 class stream<NextLayer>::accept_op
149 {
150 struct data
151 {
152 bool cont;
153 stream<NextLayer>& ws;
154 http::header_parser<true, http::fields> p;
155 int state = 0;
156
157 template<class Buffers>
158 data(Handler& handler, stream<NextLayer>& ws_,
159 Buffers const& buffers)
160 : cont(beast_asio_helpers::
161 is_continuation(handler))
162 , ws(ws_)
163 {
164 using boost::asio::buffer_copy;
165 using boost::asio::buffer_size;
166 ws.reset();
167 ws.stream_.buffer().commit(buffer_copy(
168 ws.stream_.buffer().prepare(
169 buffer_size(buffers)), buffers));
170 }
171 };
172
173 handler_ptr<data, Handler> d_;
174
175 public:
176 accept_op(accept_op&&) = default;
177 accept_op(accept_op const&) = default;
178
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)...)
184 {
185 (*this)(error_code{}, 0, false);
186 }
187
188 void operator()(error_code const& ec)
189 {
190 (*this)(ec, 0);
191 }
192
193 void operator()(error_code ec,
194 std::size_t bytes_used, bool again = true);
195
196 friend
197 void* asio_handler_allocate(
198 std::size_t size, accept_op* op)
199 {
200 return beast_asio_helpers::
201 allocate(size, op->d_.handler());
202 }
203
204 friend
205 void asio_handler_deallocate(
206 void* p, std::size_t size, accept_op* op)
207 {
208 return beast_asio_helpers::
209 deallocate(p, size, op->d_.handler());
210 }
211
212 friend
213 bool asio_handler_is_continuation(accept_op* op)
214 {
215 return op->d_->cont;
216 }
217
218 template<class Function>
219 friend
220 void asio_handler_invoke(Function&& f, accept_op* op)
221 {
222 return beast_asio_helpers::
223 invoke(f, op->d_.handler());
224 }
225 };
226
227 template<class NextLayer>
228 template<class Handler>
229 void
230 stream<NextLayer>::accept_op<Handler>::
231 operator()(error_code ec,
232 std::size_t bytes_used, bool again)
233 {
234 auto& d = *d_;
235 d.cont = d.cont || again;
236 if(ec)
237 goto upcall;
238 switch(d.state)
239 {
240 case 0:
241 // read message
242 d.state = 1;
243 http::async_read_some(d.ws.next_layer(),
244 d.ws.stream_.buffer(), d.p,
245 std::move(*this));
246 return;
247
248 case 1:
249 {
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
254 // the handler.
255 auto& ws = d.ws;
256 auto m = d.p.release();
257 response_op<Handler>{
258 d_.release_handler(),
259 ws, std::move(m), true};
260 return;
261 }
262 }
263 upcall:
264 d_.invoke(ec);
265 }
266
267 template<class NextLayer>
268 template<class AcceptHandler>
269 typename async_completion<
270 AcceptHandler, void(error_code)>::result_type
271 stream<NextLayer>::
272 async_accept(AcceptHandler&& handler)
273 {
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));
278 }
279
280 template<class NextLayer>
281 template<class ConstBufferSequence, class AcceptHandler>
282 typename async_completion<
283 AcceptHandler, void(error_code)>::result_type
284 stream<NextLayer>::
285 async_accept(ConstBufferSequence const& bs, AcceptHandler&& handler)
286 {
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();
298 }
299
300 template<class NextLayer>
301 template<class Fields, class AcceptHandler>
302 typename async_completion<
303 AcceptHandler, void(error_code)>::result_type
304 stream<NextLayer>::
305 async_accept(http::header<true, Fields> const& req,
306 AcceptHandler&& handler)
307 {
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};
313 reset();
314 response_op<decltype(completion.handler)>{
315 completion.handler, *this, req,
316 beast_asio_helpers::
317 is_continuation(completion.handler)};
318 return completion.result.get();
319 }
320
321 template<class NextLayer>
322 void
323 stream<NextLayer>::
324 accept()
325 {
326 static_assert(is_SyncStream<next_layer_type>::value,
327 "SyncStream requirements not met");
328 error_code ec;
329 accept(boost::asio::null_buffers{}, ec);
330 if(ec)
331 throw system_error{ec};
332 }
333
334 template<class NextLayer>
335 void
336 stream<NextLayer>::
337 accept(error_code& ec)
338 {
339 static_assert(is_SyncStream<next_layer_type>::value,
340 "SyncStream requirements not met");
341 accept(boost::asio::null_buffers{}, ec);
342 }
343
344 template<class NextLayer>
345 template<class ConstBufferSequence>
346 void
347 stream<NextLayer>::
348 accept(ConstBufferSequence const& buffers)
349 {
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");
355 error_code ec;
356 accept(buffers, ec);
357 if(ec)
358 throw system_error{ec};
359 }
360
361 template<class NextLayer>
362 template<class ConstBufferSequence>
363 void
364 stream<NextLayer>::
365 accept(ConstBufferSequence const& buffers, error_code& ec)
366 {
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;
374 reset();
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);
381 if(ec)
382 return;
383 BOOST_ASSERT(p.got_header());
384 stream_.buffer().consume(bytes_used);
385 accept(p.get(), ec);
386 }
387
388 template<class NextLayer>
389 template<class Fields>
390 void
391 stream<NextLayer>::
392 accept(http::header<true, Fields> const& request)
393 {
394 static_assert(is_SyncStream<next_layer_type>::value,
395 "SyncStream requirements not met");
396 error_code ec;
397 accept(request, ec);
398 if(ec)
399 throw system_error{ec};
400 }
401
402 template<class NextLayer>
403 template<class Fields>
404 void
405 stream<NextLayer>::
406 accept(http::header<true, Fields> const& req,
407 error_code& ec)
408 {
409 static_assert(is_SyncStream<next_layer_type>::value,
410 "SyncStream requirements not met");
411 reset();
412 auto const res = build_response(req);
413 http::write(stream_, res, ec);
414 if(ec)
415 return;
416 if(res.status != 101)
417 {
418 ec = error::handshake_failed;
419 // VFALCO TODO Respect keep alive setting, perform
420 // teardown if Connection: close.
421 return;
422 }
423 pmd_read(pmd_config_, req.fields);
424 open(detail::role_type::server);
425 }
426
427 } // websocket
428 } // beast
429
430 #endif