]> git.proxmox.com Git - ceph.git/blob - ceph/src/Beast/include/beast/http/impl/message.ipp
bump version to 12.2.2-pve1
[ceph.git] / ceph / src / Beast / include / beast / http / impl / message.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_HTTP_IMPL_MESSAGE_IPP
9 #define BEAST_HTTP_IMPL_MESSAGE_IPP
10
11 #include <beast/core/error.hpp>
12 #include <beast/http/concepts.hpp>
13 #include <beast/http/rfc7230.hpp>
14 #include <beast/core/detail/ci_char_traits.hpp>
15 #include <beast/core/detail/type_traits.hpp>
16 #include <boost/assert.hpp>
17 #include <boost/optional.hpp>
18 #include <stdexcept>
19
20 namespace beast {
21 namespace http {
22
23 template<class Fields>
24 void
25 swap(
26 header<true, Fields>& m1,
27 header<true, Fields>& m2)
28 {
29 using std::swap;
30 swap(m1.version, m2.version);
31 swap(m1.method, m2.method);
32 swap(m1.url, m2.url);
33 swap(m1.fields, m2.fields);
34 }
35
36 template<class Fields>
37 void
38 swap(
39 header<false, Fields>& a,
40 header<false, Fields>& b)
41 {
42 using std::swap;
43 swap(a.version, b.version);
44 swap(a.status, b.status);
45 swap(a.reason, b.reason);
46 swap(a.fields, b.fields);
47 }
48
49 template<bool isRequest, class Body, class Fields>
50 void
51 swap(
52 message<isRequest, Body, Fields>& m1,
53 message<isRequest, Body, Fields>& m2)
54 {
55 using std::swap;
56 swap(m1.base(), m2.base());
57 swap(m1.body, m2.body);
58 }
59
60 template<bool isRequest, class Fields>
61 bool
62 is_keep_alive(header<isRequest, Fields> const& msg)
63 {
64 BOOST_ASSERT(msg.version == 10 || msg.version == 11);
65 if(msg.version == 11)
66 {
67 if(token_list{msg.fields["Connection"]}.exists("close"))
68 return false;
69 return true;
70 }
71 if(token_list{msg.fields["Connection"]}.exists("keep-alive"))
72 return true;
73 return false;
74 }
75
76 template<bool isRequest, class Fields>
77 bool
78 is_upgrade(header<isRequest, Fields> const& msg)
79 {
80 BOOST_ASSERT(msg.version == 10 || msg.version == 11);
81 if(msg.version == 10)
82 return false;
83 if(token_list{msg.fields["Connection"]}.exists("upgrade"))
84 return true;
85 return false;
86 }
87
88 namespace detail {
89
90 struct prepare_info
91 {
92 boost::optional<connection> connection_value;
93 boost::optional<std::uint64_t> content_length;
94 };
95
96 template<bool isRequest, class Body, class Fields>
97 inline
98 void
99 prepare_options(prepare_info& pi,
100 message<isRequest, Body, Fields>& msg)
101 {
102 beast::detail::ignore_unused(pi, msg);
103 }
104
105 template<bool isRequest, class Body, class Fields>
106 void
107 prepare_option(prepare_info& pi,
108 message<isRequest, Body, Fields>& msg,
109 connection value)
110 {
111 beast::detail::ignore_unused(msg);
112 pi.connection_value = value;
113 }
114
115 template<
116 bool isRequest, class Body, class Fields,
117 class Opt, class... Opts>
118 void
119 prepare_options(prepare_info& pi,
120 message<isRequest, Body, Fields>& msg,
121 Opt&& opt, Opts&&... opts)
122 {
123 prepare_option(pi, msg, opt);
124 prepare_options(pi, msg,
125 std::forward<Opts>(opts)...);
126 }
127
128 template<bool isRequest, class Body, class Fields>
129 void
130 prepare_content_length(prepare_info& pi,
131 message<isRequest, Body, Fields> const& msg,
132 std::true_type)
133 {
134 typename Body::writer w(msg);
135 // VFALCO This is a design problem!
136 error_code ec;
137 w.init(ec);
138 if(ec)
139 throw system_error{ec};
140 pi.content_length = w.content_length();
141 }
142
143 template<bool isRequest, class Body, class Fields>
144 void
145 prepare_content_length(prepare_info& pi,
146 message<isRequest, Body, Fields> const& msg,
147 std::false_type)
148 {
149 beast::detail::ignore_unused(msg);
150 pi.content_length = boost::none;
151 }
152
153 } // detail
154
155 template<
156 bool isRequest, class Body, class Fields,
157 class... Options>
158 void
159 prepare(message<isRequest, Body, Fields>& msg,
160 Options&&... options)
161 {
162 using beast::detail::make_exception;
163
164 // VFALCO TODO
165 static_assert(is_Body<Body>::value,
166 "Body requirements not met");
167 static_assert(has_writer<Body>::value,
168 "Body has no writer");
169 static_assert(is_Writer<typename Body::writer,
170 message<isRequest, Body, Fields>>::value,
171 "Writer requirements not met");
172 detail::prepare_info pi;
173 detail::prepare_content_length(pi, msg,
174 detail::has_content_length<typename Body::writer>{});
175 detail::prepare_options(pi, msg,
176 std::forward<Options>(options)...);
177
178 if(msg.fields.exists("Connection"))
179 throw make_exception<std::invalid_argument>(
180 "prepare called with Connection field set", __FILE__, __LINE__);
181
182 if(msg.fields.exists("Content-Length"))
183 throw make_exception<std::invalid_argument>(
184 "prepare called with Content-Length field set", __FILE__, __LINE__);
185
186 if(token_list{msg.fields["Transfer-Encoding"]}.exists("chunked"))
187 throw make_exception<std::invalid_argument>(
188 "prepare called with Transfer-Encoding: chunked set", __FILE__, __LINE__);
189
190 if(pi.connection_value != connection::upgrade)
191 {
192 if(pi.content_length)
193 {
194 struct set_field
195 {
196 void
197 operator()(message<true, Body, Fields>& msg,
198 detail::prepare_info const& pi) const
199 {
200 using beast::detail::ci_equal;
201 if(*pi.content_length > 0 ||
202 ci_equal(msg.method, "POST"))
203 {
204 msg.fields.insert(
205 "Content-Length", *pi.content_length);
206 }
207 }
208
209 void
210 operator()(message<false, Body, Fields>& msg,
211 detail::prepare_info const& pi) const
212 {
213 if((msg.status / 100 ) != 1 &&
214 msg.status != 204 &&
215 msg.status != 304)
216 {
217 msg.fields.insert(
218 "Content-Length", *pi.content_length);
219 }
220 }
221 };
222 set_field{}(msg, pi);
223 }
224 else if(msg.version >= 11)
225 {
226 msg.fields.insert("Transfer-Encoding", "chunked");
227 }
228 }
229
230 auto const content_length =
231 msg.fields.exists("Content-Length");
232
233 if(pi.connection_value)
234 {
235 switch(*pi.connection_value)
236 {
237 case connection::upgrade:
238 msg.fields.insert("Connection", "upgrade");
239 break;
240
241 case connection::keep_alive:
242 if(msg.version < 11)
243 {
244 if(content_length)
245 msg.fields.insert("Connection", "keep-alive");
246 }
247 break;
248
249 case connection::close:
250 if(msg.version >= 11)
251 msg.fields.insert("Connection", "close");
252 break;
253 }
254 }
255
256 // rfc7230 6.7.
257 if(msg.version < 11 && token_list{
258 msg.fields["Connection"]}.exists("upgrade"))
259 throw make_exception<std::invalid_argument>(
260 "invalid version for Connection: upgrade", __FILE__, __LINE__);
261 }
262
263 } // http
264 } // beast
265
266 #endif