]> git.proxmox.com Git - ceph.git/blob - ceph/src/Beast/include/beast/websocket/impl/handshake.ipp
bump version to 12.2.2-pve1
[ceph.git] / ceph / src / Beast / include / beast / websocket / impl / handshake.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_HANDSHAKE_IPP
9 #define BEAST_WEBSOCKET_IMPL_HANDSHAKE_IPP
10
11 #include <beast/http/message.hpp>
12 #include <beast/http/read.hpp>
13 #include <beast/http/streambuf_body.hpp>
14 #include <beast/http/write.hpp>
15 #include <beast/core/handler_helpers.hpp>
16 #include <beast/core/handler_ptr.hpp>
17 #include <beast/core/stream_concepts.hpp>
18 #include <boost/assert.hpp>
19 #include <memory>
20
21 namespace beast {
22 namespace websocket {
23
24 //------------------------------------------------------------------------------
25
26 // send the upgrade request and process the response
27 //
28 template<class NextLayer>
29 template<class Handler>
30 class stream<NextLayer>::handshake_op
31 {
32 struct data
33 {
34 bool cont;
35 stream<NextLayer>& ws;
36 std::string key;
37 http::request_header req;
38 http::response<http::streambuf_body> res;
39 int state = 0;
40
41 data(Handler& handler, stream<NextLayer>& ws_,
42 boost::string_ref const& host,
43 boost::string_ref const& resource)
44 : cont(beast_asio_helpers::
45 is_continuation(handler))
46 , ws(ws_)
47 , req(ws.build_request(host, resource, key))
48 {
49 ws.reset();
50 }
51 };
52
53 handler_ptr<data, Handler> d_;
54
55 public:
56 handshake_op(handshake_op&&) = default;
57 handshake_op(handshake_op const&) = default;
58
59 template<class DeducedHandler, class... Args>
60 handshake_op(DeducedHandler&& h,
61 stream<NextLayer>& ws, Args&&... args)
62 : d_(std::forward<DeducedHandler>(h),
63 ws, std::forward<Args>(args)...)
64 {
65 (*this)(error_code{}, false);
66 }
67
68 void
69 operator()(error_code ec, bool again = true);
70
71 friend
72 void* asio_handler_allocate(
73 std::size_t size, handshake_op* op)
74 {
75 return beast_asio_helpers::
76 allocate(size, op->d_.handler());
77 }
78
79 friend
80 void asio_handler_deallocate(
81 void* p, std::size_t size, handshake_op* op)
82 {
83 return beast_asio_helpers::
84 deallocate(p, size, op->d_.handler());
85 }
86
87 friend
88 bool asio_handler_is_continuation(handshake_op* op)
89 {
90 return op->d_->cont;
91 }
92
93 template<class Function>
94 friend
95 void asio_handler_invoke(Function&& f, handshake_op* op)
96 {
97 return beast_asio_helpers::
98 invoke(f, op->d_.handler());
99 }
100 };
101
102 template<class NextLayer>
103 template<class Handler>
104 void
105 stream<NextLayer>::handshake_op<Handler>::
106 operator()(error_code ec, bool again)
107 {
108 auto& d = *d_;
109 d.cont = d.cont || again;
110 while(! ec && d.state != 99)
111 {
112 switch(d.state)
113 {
114 case 0:
115 {
116 // send http upgrade
117 d.state = 1;
118 // VFALCO Do we need the ability to move
119 // a message on the async_write?
120 pmd_read(
121 d.ws.pmd_config_, d.req.fields);
122 http::async_write(d.ws.stream_,
123 d.req, std::move(*this));
124 return;
125 }
126
127 // sent upgrade
128 case 1:
129 // read http response
130 d.state = 2;
131 http::async_read(d.ws.next_layer(),
132 d.ws.stream_.buffer(), d.res,
133 std::move(*this));
134 return;
135
136 // got response
137 case 2:
138 {
139 d.ws.do_response(d.res, d.key, ec);
140 // call handler
141 d.state = 99;
142 break;
143 }
144 }
145 }
146 d_.invoke(ec);
147 }
148
149 template<class NextLayer>
150 template<class HandshakeHandler>
151 typename async_completion<
152 HandshakeHandler, void(error_code)>::result_type
153 stream<NextLayer>::
154 async_handshake(boost::string_ref const& host,
155 boost::string_ref const& resource, HandshakeHandler&& handler)
156 {
157 static_assert(is_AsyncStream<next_layer_type>::value,
158 "AsyncStream requirements not met");
159 beast::async_completion<
160 HandshakeHandler, void(error_code)
161 > completion{handler};
162 handshake_op<decltype(completion.handler)>{
163 completion.handler, *this, host, resource};
164 return completion.result.get();
165 }
166
167 template<class NextLayer>
168 void
169 stream<NextLayer>::
170 handshake(boost::string_ref const& host,
171 boost::string_ref const& resource)
172 {
173 static_assert(is_SyncStream<next_layer_type>::value,
174 "SyncStream requirements not met");
175 error_code ec;
176 handshake(host, resource, ec);
177 if(ec)
178 throw system_error{ec};
179 }
180
181 template<class NextLayer>
182 void
183 stream<NextLayer>::
184 handshake(boost::string_ref const& host,
185 boost::string_ref const& resource, error_code& ec)
186 {
187 static_assert(is_SyncStream<next_layer_type>::value,
188 "SyncStream requirements not met");
189 reset();
190 std::string key;
191 {
192 auto const req =
193 build_request(host, resource, key);
194 pmd_read(pmd_config_, req.fields);
195 http::write(stream_, req, ec);
196 }
197 if(ec)
198 return;
199 http::response<http::streambuf_body> res;
200 http::read(next_layer(), stream_.buffer(), res, ec);
201 if(ec)
202 return;
203 do_response(res, key, ec);
204 }
205
206 //------------------------------------------------------------------------------
207
208 } // websocket
209 } // beast
210
211 #endif