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 : #include <boost/http_proto/fields_view.hpp>
18 : #include <boost/core/detail/string_view.hpp>
19 :
20 : namespace boost {
21 : namespace http_proto {
22 :
23 : /** A modifiable container of HTTP fields.
24 :
25 : This container owns a collection of HTTP
26 : fields, represented by a buffer which is
27 : managed by performing dynamic memory
28 : allocations as needed. The contents may be
29 : inspected and modified, and the implementation
30 : maintains a useful invariant: changes to the
31 : fields always leave it in a valid state.
32 :
33 : @par Example
34 : @code
35 : fields fs;
36 :
37 : fs.set(field::host, "example.com");
38 : fs.set(field::accept_encoding, "gzip, deflate, br");
39 : fs.set(field::cache_control, "no-cache");
40 :
41 : assert(fs.buffer() ==
42 : "Host: example.com\r\n"
43 : "Accept-Encoding: gzip, deflate, br\r\n"
44 : "Cache-Control: no-cache\r\n"
45 : "\r\n");
46 : @endcode
47 :
48 : @see
49 : @ref static_fields,
50 : @ref fields_view.
51 : */
52 : class fields final
53 : : public fields_base
54 : {
55 : public:
56 :
57 : //--------------------------------------------
58 : //
59 : // Special Members
60 : //
61 : //--------------------------------------------
62 :
63 : /** Constructor.
64 :
65 : A default-constructed fields container
66 : contain no name-value pairs.
67 :
68 : @par Example
69 : @code
70 : fields fs;
71 : @endcode
72 :
73 : @par Postconditions
74 : @code
75 : this->buffer() == "\r\n"
76 : @endcode
77 :
78 : @par Complexity
79 : Constant.
80 : */
81 : BOOST_HTTP_PROTO_DECL
82 : fields() noexcept;
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 : BOOST_HTTP_PROTO_DECL
120 : explicit
121 : fields(
122 : core::string_view s);
123 :
124 : /** Constructor.
125 :
126 : Allocates `cap` bytes initially, with an
127 : upper limit of `max_cap`. Growing beyond
128 : `max_cap` will throw an exception.
129 :
130 : Useful when an estimated initial size is
131 : known, but further growth up to a
132 : maximum is allowed.
133 :
134 : @par Preconditions
135 : @code
136 : max_cap >= cap
137 : @endcode
138 :
139 : @par Exception Safety
140 : Calls to allocate may throw.
141 : Exception thrown on invalid input.
142 :
143 : @throw system_error
144 : Input is invalid.
145 :
146 : @param cap Initial capacity in bytes (may be `0`).
147 :
148 : @param max_cap Maximum allowed capacity in bytes.
149 : */
150 : BOOST_HTTP_PROTO_DECL
151 : explicit
152 : fields(
153 : std::size_t cap,
154 : std::size_t max_cap = std::size_t(-1));
155 :
156 : /** Constructor.
157 :
158 : The contents of `f` are transferred
159 : to the newly constructed object,
160 : which includes the underlying
161 : character buffer.
162 : After construction, the moved-from
163 : object is as if default-constructed.
164 :
165 : @par Postconditions
166 : @code
167 : f.buffer() == "\r\n"
168 : @endcode
169 :
170 : @par Complexity
171 : Constant.
172 :
173 : @param f The fields to move from.
174 : */
175 : BOOST_HTTP_PROTO_DECL
176 : fields(fields&& f) noexcept;
177 :
178 : /** Constructor.
179 :
180 : The newly constructed object contains
181 : a copy of `f`.
182 :
183 : @par Postconditions
184 : @code
185 : this->buffer() == f.buffer() && this->buffer().data() != f.buffer().data()
186 : @endcode
187 :
188 : @par Complexity
189 : Linear in `f.size()`.
190 :
191 : @par Exception Safety
192 : Calls to allocate may throw.
193 :
194 : @param f The fields to copy.
195 : */
196 : BOOST_HTTP_PROTO_DECL
197 : fields(fields const& f);
198 :
199 : /** Constructor.
200 :
201 : The newly constructed object contains
202 : a copy of `f`.
203 :
204 : @par Postconditions
205 : @code
206 : this->buffer() == f.buffer() && this->buffer().data() != f.buffer().data()
207 : @endcode
208 :
209 : @par Complexity
210 : Linear in `f.size()`.
211 :
212 : @par Exception Safety
213 : Strong guarantee.
214 : Calls to allocate may throw.
215 :
216 : @param f The fields to copy.
217 : */
218 : BOOST_HTTP_PROTO_DECL
219 : fields(fields_view const& f);
220 :
221 : /** Assignment.
222 :
223 : The contents of `f` are transferred to
224 : `this`, including the underlying
225 : character buffer. The previous contents
226 : of `this` are destroyed.
227 : After assignment, the moved-from
228 : object is as if default-constructed.
229 :
230 : @par Postconditions
231 : @code
232 : f.buffer() == "\r\n"
233 : @endcode
234 :
235 : @par Complexity
236 : Constant.
237 :
238 : @param f The fields to assign from.
239 :
240 : @return A reference to this object.
241 : */
242 : BOOST_HTTP_PROTO_DECL
243 : fields&
244 : operator=(fields&& f) noexcept;
245 :
246 : /** Assignment.
247 :
248 : The contents of `f` are copied and
249 : the previous contents of `this` are
250 : discarded.
251 :
252 : @par Postconditions
253 : @code
254 : this->buffer() == f.buffer() && this->buffer().data() != f.buffer().data()
255 : @endcode
256 :
257 : @par Complexity
258 : Linear in `f.size()`.
259 :
260 : @par Exception Safety
261 : Strong guarantee.
262 : Calls to allocate may throw.
263 : Exception thrown if max capacity exceeded.
264 :
265 : @throw std::length_error
266 : Max capacity would be exceeded.
267 :
268 : @return A reference to this object.
269 :
270 : @param f The fields to copy.
271 : */
272 : fields&
273 4 : operator=(fields const& f) noexcept
274 : {
275 4 : copy_impl(*f.ph_);
276 4 : return *this;
277 : }
278 :
279 : /** Assignment.
280 :
281 : The contents of `f` are copied and
282 : the previous contents of `this` are
283 : discarded.
284 :
285 : @par Postconditions
286 : @code
287 : this->buffer() == f.buffer() && this->buffer().data() != f.buffer().data()
288 : @endcode
289 :
290 : @par Complexity
291 : Linear in `r.size()`.
292 :
293 : @par Exception Safety
294 : Strong guarantee.
295 : Calls to allocate may throw.
296 : Exception thrown if max capacity exceeded.
297 :
298 : @throw std::length_error
299 : Max capacity would be exceeded.
300 :
301 : @return A reference to this object.
302 :
303 : @param f The fields to copy.
304 : */
305 : fields&
306 4 : operator=(fields_view const& f)
307 : {
308 4 : copy_impl(*f.ph_);
309 4 : return *this;
310 : }
311 :
312 : /** Conversion.
313 :
314 : @see
315 : @ref fields_view.
316 :
317 : @return A view of the fields.
318 : */
319 4 : operator fields_view() const noexcept
320 : {
321 4 : return fields_view(ph_);
322 : }
323 :
324 : //--------------------------------------------
325 :
326 : /** Swap.
327 :
328 : Exchanges the contents of this fields
329 : object with another. All views, iterators
330 : and references remain valid.
331 :
332 : If `this == &other`, this function call has no effect.
333 :
334 : @par Example
335 : @code
336 : fields f1;
337 : f1.set(field::accept, "text/html");
338 : fields f2;
339 : f2.set(field::connection, "keep-alive");
340 : f1.swap(f2);
341 : assert(f1.buffer() == "Connection: keep-alive\r\n\r\n" );
342 : assert(f2.buffer() == "Accept: text/html\r\n\r\n" );
343 : @endcode
344 :
345 : @par Complexity
346 : Constant.
347 :
348 : @param other The object to swap with.
349 : */
350 : void
351 10 : swap(fields& other) noexcept
352 : {
353 10 : h_.swap(other.h_);
354 10 : std::swap(max_cap_, other.max_cap_);
355 10 : }
356 :
357 : /** Swap.
358 :
359 : Exchanges the contents of `v0` with
360 : another `v1`. All views, iterators and
361 : references remain valid.
362 :
363 : If `&v0 == &v1`, this function call has no effect.
364 :
365 : @par Example
366 : @code
367 : fields f1;
368 : f1.set(field::accept, "text/html");
369 : fields f2;
370 : f2.set(field::connection, "keep-alive");
371 : std::swap(f1, f2);
372 : assert(f1.buffer() == "Connection: keep-alive\r\n\r\n" );
373 : assert(f2.buffer() == "Accept: text/html\r\n\r\n" );
374 : @endcode
375 :
376 : @par Effects
377 : @code
378 : v0.swap(v1);
379 : @endcode
380 :
381 : @par Complexity
382 : Constant.
383 :
384 : @param v0 The first object to swap.
385 : @param v1 The second object to swap.
386 :
387 : @see
388 : @ref fields::swap.
389 : */
390 : friend
391 : void
392 : swap(
393 : fields& v0,
394 : fields& v1) noexcept
395 : {
396 : v0.swap(v1);
397 : }
398 : };
399 :
400 : } // http_proto
401 : } // boost
402 :
403 : #endif
|