]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
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 |