]> git.proxmox.com Git - ceph.git/blame - 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
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_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
20namespace beast {
21namespace http {
22
23template<class Fields>
24void
25swap(
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
36template<class Fields>
37void
38swap(
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
49template<bool isRequest, class Body, class Fields>
50void
51swap(
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
60template<bool isRequest, class Fields>
61bool
62is_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
76template<bool isRequest, class Fields>
77bool
78is_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
88namespace detail {
89
90struct prepare_info
91{
92 boost::optional<connection> connection_value;
93 boost::optional<std::uint64_t> content_length;
94};
95
96template<bool isRequest, class Body, class Fields>
97inline
98void
99prepare_options(prepare_info& pi,
100 message<isRequest, Body, Fields>& msg)
101{
102 beast::detail::ignore_unused(pi, msg);
103}
104
105template<bool isRequest, class Body, class Fields>
106void
107prepare_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
115template<
116 bool isRequest, class Body, class Fields,
117 class Opt, class... Opts>
118void
119prepare_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
128template<bool isRequest, class Body, class Fields>
129void
130prepare_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
143template<bool isRequest, class Body, class Fields>
144void
145prepare_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
155template<
156 bool isRequest, class Body, class Fields,
157 class... Options>
158void
159prepare(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