Line data Source code
1 : //
2 : // Copyright (c) 2021 Vinnie Falco (vinnie.falco@gmail.com)
3 : // Copyright (c) 2024 Christian Mazakas
4 : // Copyright (c) 2025 Mohammad Nejati
5 : //
6 : // Distributed under the Boost Software License, Version 1.0. (See accompanying
7 : // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
8 : //
9 : // Official repository: https://github.com/cppalliance/http_proto
10 : //
11 :
12 : #ifndef BOOST_HTTP_PROTO_FIELDS_HPP
13 : #define BOOST_HTTP_PROTO_FIELDS_HPP
14 :
15 : #include <boost/http_proto/detail/config.hpp>
16 : #include <boost/http_proto/fields_base.hpp>
17 :
18 : namespace boost {
19 : namespace http_proto {
20 :
21 : /** A modifiable container of HTTP fields.
22 :
23 : This container owns a collection of HTTP
24 : fields, represented by a buffer which is
25 : managed by performing dynamic memory
26 : allocations as needed. The contents may be
27 : inspected and modified, and the implementation
28 : maintains a useful invariant: changes to the
29 : fields always leave it in a valid state.
30 :
31 : @par Example
32 : @code
33 : fields fs;
34 :
35 : fs.set(field::host, "example.com");
36 : fs.set(field::accept_encoding, "gzip, deflate, br");
37 : fs.set(field::cache_control, "no-cache");
38 :
39 : assert(fs.buffer() ==
40 : "Host: example.com\r\n"
41 : "Accept-Encoding: gzip, deflate, br\r\n"
42 : "Cache-Control: no-cache\r\n"
43 : "\r\n");
44 : @endcode
45 :
46 : @see
47 : @ref fields_base.
48 : */
49 : class fields final
50 : : public fields_base
51 : {
52 : public:
53 :
54 : //--------------------------------------------
55 : //
56 : // Special Members
57 : //
58 : //--------------------------------------------
59 :
60 : /** Constructor.
61 :
62 : A default-constructed fields container
63 : contain no name-value pairs.
64 :
65 : @par Example
66 : @code
67 : fields fs;
68 : @endcode
69 :
70 : @par Postconditions
71 : @code
72 : this->buffer() == "\r\n"
73 : @endcode
74 :
75 : @par Complexity
76 : Constant.
77 : */
78 27 : fields() noexcept
79 27 : : fields_base(detail::kind::fields)
80 : {
81 27 : }
82 :
83 :
84 : /** Constructor.
85 :
86 : Constructs a fields container from the string
87 : `s`, which must contain valid HTTP headers or
88 : else an exception is thrown.
89 : The new fields container retains ownership by
90 : allocating a copy of the passed string.
91 :
92 : @par Example
93 : @code
94 : fields f(
95 : "Server: Boost.HttpProto\r\n"
96 : "Content-Type: text/plain\r\n"
97 : "Connection: close\r\n"
98 : "Content-Length: 73\r\n"
99 : "\r\n");
100 : @endcode
101 :
102 : @par Postconditions
103 : @code
104 : this->buffer() == s && this->buffer().data() != s.data()
105 : @endcode
106 :
107 : @par Complexity
108 : Linear in `s.size()`.
109 :
110 : @par Exception Safety
111 : Calls to allocate may throw.
112 : Exception thrown on invalid input.
113 :
114 : @throw system_error
115 : Input is invalid.
116 :
117 : @param s The string to parse.
118 : */
119 : explicit
120 235 : fields(
121 : core::string_view s)
122 235 : : fields_base(detail::kind::fields, s)
123 : {
124 234 : }
125 :
126 : /** Constructor.
127 :
128 : Allocates `cap` bytes initially, with an
129 : upper limit of `max_cap`. Growing beyond
130 : `max_cap` will throw an exception.
131 :
132 : Useful when an estimated initial size is
133 : known, but further growth up to a
134 : maximum is allowed.
135 :
136 : @par Preconditions
137 : @code
138 : max_cap >= cap
139 : @endcode
140 :
141 : @par Exception Safety
142 : Calls to allocate may throw.
143 : Exception thrown on invalid input.
144 :
145 : @throw system_error
146 : Input is invalid.
147 :
148 : @param cap Initial capacity in bytes (may be `0`).
149 :
150 : @param max_cap Maximum allowed capacity in bytes.
151 : */
152 : explicit
153 10 : fields(
154 : std::size_t cap,
155 : std::size_t max_cap = std::size_t(-1))
156 10 : : fields()
157 : {
158 10 : reserve_bytes(cap);
159 10 : set_max_capacity_in_bytes(max_cap);
160 10 : }
161 :
162 : /** Constructor.
163 :
164 : The contents of `f` are transferred
165 : to the newly constructed object,
166 : which includes the underlying
167 : character buffer.
168 : After construction, the moved-from
169 : object is as if default-constructed.
170 :
171 : @par Postconditions
172 : @code
173 : f.buffer() == "\r\n"
174 : @endcode
175 :
176 : @par Complexity
177 : Constant.
178 :
179 : @param f The fields to move from.
180 : */
181 6 : fields(fields&& f) noexcept
182 6 : : fields_base(f.h_.kind)
183 : {
184 6 : swap(f);
185 6 : }
186 :
187 :
188 : /** Constructor.
189 :
190 : The newly constructed object contains
191 : a copy of `f`.
192 :
193 : @par Postconditions
194 : @code
195 : this->buffer() == f.buffer() && this->buffer().data() != f.buffer().data()
196 : @endcode
197 :
198 : @par Complexity
199 : Linear in `f.size()`.
200 :
201 : @par Exception Safety
202 : Calls to allocate may throw.
203 :
204 : @param f The fields to copy.
205 : */
206 2 : fields(fields const& f) = default;
207 :
208 : /** Assignment.
209 :
210 : The contents of `f` are transferred to
211 : `this`, including the underlying
212 : character buffer. The previous contents
213 : of `this` are destroyed.
214 : After assignment, the moved-from
215 : object is as if default-constructed.
216 :
217 : @par Postconditions
218 : @code
219 : f.buffer() == "\r\n"
220 : @endcode
221 :
222 : @par Complexity
223 : Constant.
224 :
225 : @param f The fields to assign from.
226 :
227 : @return A reference to this object.
228 : */
229 : fields&
230 4 : operator=(fields&& f) noexcept
231 : {
232 4 : fields tmp(std::move(f));
233 4 : tmp.swap(*this);
234 8 : return *this;
235 4 : }
236 :
237 : /** Assignment.
238 :
239 : The contents of `f` are copied and
240 : the previous contents of `this` are
241 : discarded.
242 :
243 : @par Postconditions
244 : @code
245 : this->buffer() == f.buffer() && this->buffer().data() != f.buffer().data()
246 : @endcode
247 :
248 : @par Complexity
249 : Linear in `f.size()`.
250 :
251 : @par Exception Safety
252 : Strong guarantee.
253 : Calls to allocate may throw.
254 : Exception thrown if max capacity exceeded.
255 :
256 : @throw std::length_error
257 : Max capacity would be exceeded.
258 :
259 : @return A reference to this object.
260 :
261 : @param f The fields to copy.
262 : */
263 : fields&
264 4 : operator=(fields const& f) noexcept
265 : {
266 4 : copy_impl(f.h_);
267 4 : return *this;
268 : }
269 :
270 : //--------------------------------------------
271 :
272 : /** Swap.
273 :
274 : Exchanges the contents of this fields
275 : object with another. All views, iterators
276 : and references remain valid.
277 :
278 : If `this == &other`, this function call has no effect.
279 :
280 : @par Example
281 : @code
282 : fields f1;
283 : f1.set(field::accept, "text/html");
284 : fields f2;
285 : f2.set(field::connection, "keep-alive");
286 : f1.swap(f2);
287 : assert(f1.buffer() == "Connection: keep-alive\r\n\r\n" );
288 : assert(f2.buffer() == "Accept: text/html\r\n\r\n" );
289 : @endcode
290 :
291 : @par Complexity
292 : Constant.
293 :
294 : @param other The object to swap with.
295 : */
296 : void
297 10 : swap(fields& other) noexcept
298 : {
299 10 : h_.swap(other.h_);
300 10 : std::swap(max_cap_, other.max_cap_);
301 10 : }
302 :
303 : /** Swap.
304 :
305 : Exchanges the contents of `v0` with
306 : another `v1`. All views, iterators and
307 : references remain valid.
308 :
309 : If `&v0 == &v1`, this function call has no effect.
310 :
311 : @par Example
312 : @code
313 : fields f1;
314 : f1.set(field::accept, "text/html");
315 : fields f2;
316 : f2.set(field::connection, "keep-alive");
317 : std::swap(f1, f2);
318 : assert(f1.buffer() == "Connection: keep-alive\r\n\r\n" );
319 : assert(f2.buffer() == "Accept: text/html\r\n\r\n" );
320 : @endcode
321 :
322 : @par Effects
323 : @code
324 : v0.swap(v1);
325 : @endcode
326 :
327 : @par Complexity
328 : Constant.
329 :
330 : @param v0 The first object to swap.
331 : @param v1 The second object to swap.
332 :
333 : @see
334 : @ref fields::swap.
335 : */
336 : friend
337 : void
338 : swap(
339 : fields& v0,
340 : fields& v1) noexcept
341 : {
342 : v0.swap(v1);
343 : }
344 : };
345 :
346 : } // http_proto
347 : } // boost
348 :
349 : #endif
|