Line | Branch | Exec | Source |
---|---|---|---|
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 |
1/2✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
|
10 | reserve_bytes(cap); |
159 |
2/2✓ Branch 1 taken 8 times.
✓ Branch 2 taken 2 times.
|
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 | ||
350 |