]> git.proxmox.com Git - ceph.git/blame - ceph/src/Beast/include/beast/websocket/impl/stream.ipp
bump version to 12.2.2-pve1
[ceph.git] / ceph / src / Beast / include / beast / websocket / impl / stream.ipp
CommitLineData
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_STREAM_IPP
9#define BEAST_WEBSOCKET_IMPL_STREAM_IPP
10
11#include <beast/websocket/teardown.hpp>
12#include <beast/websocket/detail/hybi13.hpp>
13#include <beast/websocket/detail/pmd_extension.hpp>
14#include <beast/http/read.hpp>
15#include <beast/http/write.hpp>
16#include <beast/http/reason.hpp>
17#include <beast/http/rfc7230.hpp>
18#include <beast/core/buffer_cat.hpp>
19#include <beast/core/buffer_concepts.hpp>
20#include <beast/core/consuming_buffers.hpp>
21#include <beast/core/prepare_buffers.hpp>
22#include <beast/core/static_streambuf.hpp>
23#include <beast/core/stream_concepts.hpp>
24#include <beast/core/detail/type_traits.hpp>
25#include <boost/assert.hpp>
26#include <boost/endian/buffers.hpp>
27#include <algorithm>
28#include <memory>
29#include <stdexcept>
30#include <utility>
31
32namespace beast {
33namespace websocket {
34
35template<class NextLayer>
36template<class... Args>
37stream<NextLayer>::
38stream(Args&&... args)
39 : stream_(std::forward<Args>(args)...)
40{
41}
42
43template<class NextLayer>
44void
45stream<NextLayer>::
46set_option(permessage_deflate const& o)
47{
48 if( o.server_max_window_bits > 15 ||
49 o.server_max_window_bits < 9)
50 throw std::invalid_argument{
51 "invalid server_max_window_bits"};
52 if( o.client_max_window_bits > 15 ||
53 o.client_max_window_bits < 9)
54 throw std::invalid_argument{
55 "invalid client_max_window_bits"};
56 if( o.compLevel < 0 ||
57 o.compLevel > 9)
58 throw std::invalid_argument{
59 "invalid compLevel"};
60 if( o.memLevel < 1 ||
61 o.memLevel > 9)
62 throw std::invalid_argument{
63 "invalid memLevel"};
64 pmd_opts_ = o;
65}
66
67//------------------------------------------------------------------------------
68
69template<class NextLayer>
70void
71stream<NextLayer>::
72reset()
73{
74 failed_ = false;
75 rd_.cont = false;
76 wr_close_ = false;
77 wr_.cont = false;
78 wr_block_ = nullptr; // should be nullptr on close anyway
79 ping_data_ = nullptr; // should be nullptr on close anyway
80
81 stream_.buffer().consume(
82 stream_.buffer().size());
83}
84
85template<class NextLayer>
86http::request_header
87stream<NextLayer>::
88build_request(boost::string_ref const& host,
89 boost::string_ref const& resource, std::string& key)
90{
91 http::request_header req;
92 req.url = { resource.data(), resource.size() };
93 req.version = 11;
94 req.method = "GET";
95 req.fields.insert("Host", host);
96 req.fields.insert("Upgrade", "websocket");
97 req.fields.insert("Connection", "upgrade");
98 key = detail::make_sec_ws_key(maskgen_);
99 req.fields.insert("Sec-WebSocket-Key", key);
100 req.fields.insert("Sec-WebSocket-Version", "13");
101 if(pmd_opts_.client_enable)
102 {
103 detail::pmd_offer config;
104 config.accept = true;
105 config.server_max_window_bits =
106 pmd_opts_.server_max_window_bits;
107 config.client_max_window_bits =
108 pmd_opts_.client_max_window_bits;
109 config.server_no_context_takeover =
110 pmd_opts_.server_no_context_takeover;
111 config.client_no_context_takeover =
112 pmd_opts_.client_no_context_takeover;
113 detail::pmd_write(
114 req.fields, config);
115 }
116 d_(req);
117 return req;
118}
119
120template<class NextLayer>
121http::response_header
122stream<NextLayer>::
123build_response(http::request_header const& req)
124{
125 auto err =
126 [&](std::string const& text)
127 {
128 http::response<http::string_body> res;
129 res.status = 400;
130 res.reason = http::reason_string(res.status);
131 res.version = req.version;
132 res.body = text;
133 d_(res);
134 prepare(res,
135 (is_keep_alive(req) && keep_alive_) ?
136 http::connection::keep_alive :
137 http::connection::close);
138 return res;
139 };
140 if(req.version < 11)
141 return err("HTTP version 1.1 required");
142 if(req.method != "GET")
143 return err("Wrong method");
144 if(! is_upgrade(req))
145 return err("Expected Upgrade request");
146 if(! req.fields.exists("Host"))
147 return err("Missing Host");
148 if(! req.fields.exists("Sec-WebSocket-Key"))
149 return err("Missing Sec-WebSocket-Key");
150 if(! http::token_list{req.fields["Upgrade"]}.exists("websocket"))
151 return err("Missing websocket Upgrade token");
152 {
153 auto const version =
154 req.fields["Sec-WebSocket-Version"];
155 if(version.empty())
156 return err("Missing Sec-WebSocket-Version");
157 if(version != "13")
158 {
159 http::response<http::string_body> res;
160 res.status = 426;
161 res.reason = http::reason_string(res.status);
162 res.version = req.version;
163 res.fields.insert("Sec-WebSocket-Version", "13");
164 d_(res);
165 prepare(res,
166 (is_keep_alive(req) && keep_alive_) ?
167 http::connection::keep_alive :
168 http::connection::close);
169 return res;
170 }
171 }
172 http::response_header res;
173 {
174 detail::pmd_offer offer;
175 detail::pmd_offer unused;
176 pmd_read(offer, req.fields);
177 pmd_negotiate(
178 res.fields, unused, offer, pmd_opts_);
179 }
180 res.status = 101;
181 res.reason = http::reason_string(res.status);
182 res.version = req.version;
183 res.fields.insert("Upgrade", "websocket");
184 res.fields.insert("Connection", "upgrade");
185 {
186 auto const key =
187 req.fields["Sec-WebSocket-Key"];
188 res.fields.insert("Sec-WebSocket-Accept",
189 detail::make_sec_ws_accept(key));
190 }
191 res.fields.replace("Server", "Beast.WebSocket");
192 d_(res);
193 return res;
194}
195
196template<class NextLayer>
197void
198stream<NextLayer>::
199do_response(http::response_header const& res,
200 boost::string_ref const& key, error_code& ec)
201{
202 // VFALCO Review these error codes
203 auto fail = [&]{ ec = error::response_failed; };
204 if(res.version < 11)
205 return fail();
206 if(res.status != 101)
207 return fail();
208 if(! is_upgrade(res))
209 return fail();
210 if(! http::token_list{res.fields["Upgrade"]}.exists("websocket"))
211 return fail();
212 if(! res.fields.exists("Sec-WebSocket-Accept"))
213 return fail();
214 if(res.fields["Sec-WebSocket-Accept"] !=
215 detail::make_sec_ws_accept(key))
216 return fail();
217 detail::pmd_offer offer;
218 pmd_read(offer, res.fields);
219 // VFALCO see if offer satisfies pmd_config_,
220 // return an error if not.
221 pmd_config_ = offer; // overwrite for now
222 open(detail::role_type::client);
223}
224
225} // websocket
226} // beast
227
228#endif