Line data Source code
1 : //
2 : // Copyright (c) 2021 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 : // Official repository: https://github.com/CPPAlliance/http_proto
8 : //
9 :
10 : #ifndef BOOST_HTTP_PROTO_FIELDS_BASE_HPP
11 : #define BOOST_HTTP_PROTO_FIELDS_BASE_HPP
12 :
13 : #include <boost/http_proto/detail/config.hpp>
14 : #include <boost/http_proto/fields_view_base.hpp>
15 :
16 : namespace boost {
17 : namespace http_proto {
18 :
19 : /** Mixin for modifiable HTTP fields
20 :
21 : @par Iterators
22 :
23 : Iterators obtained from @ref fields
24 : containers are not invalidated when
25 : the underlying container is modified.
26 :
27 : @note HTTP field names are case-insensitive.
28 : */
29 : class BOOST_SYMBOL_VISIBLE
30 : fields_base
31 : : public virtual fields_view_base
32 : {
33 : detail::header h_;
34 :
35 : class op_t;
36 : using entry =
37 : detail::header::entry;
38 : using table =
39 : detail::header::table;
40 :
41 : friend class fields;
42 : friend class request;
43 : friend class response;
44 : friend class serializer;
45 : friend class message_base;
46 : friend struct detail::header;
47 :
48 : BOOST_HTTP_PROTO_DECL
49 : explicit fields_base(
50 : detail::kind) noexcept;
51 :
52 : fields_base(detail::header const&);
53 :
54 : public:
55 : /** Destructor
56 : */
57 : BOOST_HTTP_PROTO_DECL
58 : ~fields_base();
59 :
60 : //--------------------------------------------
61 : //
62 : // Capacity
63 : //
64 : //--------------------------------------------
65 :
66 : /** Returns the largest permissible capacity in bytes
67 : */
68 : static
69 : constexpr
70 : std::size_t
71 847 : max_capacity_in_bytes() noexcept
72 : {
73 : using T = detail::header::entry;
74 : return alignof(T) *
75 : (((max_off_t - 2 + sizeof(T) * (
76 : max_off_t / 4)) +
77 : alignof(T) - 1) /
78 847 : alignof(T));
79 : }
80 :
81 : /** Returns the total number of bytes allocated by the container
82 : */
83 : std::size_t
84 38 : capacity_in_bytes() const noexcept
85 : {
86 38 : return h_.cap;
87 : }
88 :
89 : /** Clear the contents, but not the capacity
90 : */
91 : BOOST_HTTP_PROTO_DECL
92 : void
93 : clear() noexcept;
94 :
95 : /** Reserve a minimum capacity
96 : */
97 : BOOST_HTTP_PROTO_DECL
98 : void
99 : reserve_bytes(std::size_t n);
100 :
101 : /** Remove excess capacity
102 : */
103 : BOOST_HTTP_PROTO_DECL
104 : void
105 : shrink_to_fit() noexcept;
106 :
107 : //--------------------------------------------
108 : //
109 : // Modifiers
110 : //
111 : //--------------------------------------------
112 :
113 : /** Append a header
114 :
115 : This function appends a new header.
116 : Existing headers with the same name are
117 : not changed. Names are not case-sensitive.
118 : <br>
119 : No iterators are invalidated.
120 :
121 : @par Example
122 : @code
123 : request req;
124 :
125 : req.append( field::user_agent, "Boost" );
126 : @endcode
127 :
128 : @par Complexity
129 : Linear in `to_string( id ).size() + value.size()`.
130 :
131 : @par Exception Safety
132 : Strong guarantee.
133 : Calls to allocate may throw.
134 :
135 : @param id The field name constant,
136 : which may not be @ref field::unknown.
137 :
138 : @param value A value, which
139 : @li Must be syntactically valid for the header,
140 : @li Must be semantically valid for the message, and
141 : @li May not contain leading or trailing whitespace.
142 : */
143 : void
144 20 : append(
145 : field id,
146 : string_view value)
147 : {
148 20 : BOOST_ASSERT(
149 : id != field::unknown);
150 20 : insert_impl(
151 : id,
152 : to_string(id),
153 : value,
154 20 : h_.count);
155 20 : }
156 :
157 : /** Append a header
158 :
159 : This function appends a new header.
160 : Existing headers with the same name are
161 : not changed. Names are not case-sensitive.
162 : <br>
163 : No iterators are invalidated.
164 :
165 : @par Example
166 : @code
167 : request req;
168 :
169 : req.append( "User-Agent", "Boost" );
170 : @endcode
171 :
172 : @par Complexity
173 : Linear in `name.size() + value.size()`.
174 :
175 : @par Exception Safety
176 : Strong guarantee.
177 : Calls to allocate may throw.
178 :
179 : @param name The header name.
180 :
181 : @param value A value, which
182 : @li Must be syntactically valid for the header,
183 : @li Must be semantically valid for the message, and
184 : @li May not contain leading or trailing whitespace.
185 : */
186 : void
187 723 : append(
188 : string_view name,
189 : string_view value)
190 : {
191 723 : insert_impl(
192 : string_to_field(
193 : name),
194 : name,
195 : value,
196 723 : h_.count);
197 722 : }
198 :
199 : /** Insert a header
200 :
201 : If a matching header with the same name
202 : exists, it is not replaced. Instead, an
203 : additional header with the same name is
204 : inserted. Names are not case-sensitive.
205 : <br>
206 : All iterators that are equal to `before`
207 : or come after are invalidated.
208 :
209 : @par Example
210 : @code
211 : request req;
212 :
213 : req.insert( req.begin(), field::user_agent, "Boost" );
214 : @endcode
215 :
216 : @par Complexity
217 : Linear in `to_string( id ).size() + value.size()`.
218 :
219 : @par Exception Safety
220 : Strong guarantee.
221 : Calls to allocate may throw.
222 :
223 : @return An iterator to the inserted
224 : element.
225 :
226 : @param before Position to insert before.
227 :
228 : @param id The field name constant,
229 : which may not be @ref field::unknown.
230 :
231 : @param value A value, which
232 : @li Must be syntactically valid for the header,
233 : @li Must be semantically valid for the message, and
234 : @li May not contain leading or trailing whitespace.
235 : */
236 : iterator
237 6 : insert(
238 : iterator before,
239 : field id,
240 : string_view value)
241 : {
242 6 : BOOST_ASSERT(
243 : id != field::unknown);
244 6 : insert_impl(
245 : id,
246 : to_string(id),
247 : value,
248 : before.i_);
249 6 : return before;
250 : }
251 :
252 : /** Insert a header
253 :
254 : If a matching header with the same name
255 : exists, it is not replaced. Instead, an
256 : additional header with the same name is
257 : inserted. Names are not case-sensitive.
258 : <br>
259 : All iterators that are equal to `before`
260 : or come after are invalidated.
261 :
262 : @par Example
263 : @code
264 : request req;
265 :
266 : req.insert( req.begin(), "User-Agent", "Boost" );
267 : @endcode
268 :
269 : @par Complexity
270 : Linear in `name.size() + value.size()`.
271 :
272 : @par Exception Safety
273 : Strong guarantee.
274 : Calls to allocate may throw.
275 :
276 : @return An iterator to the inserted
277 : element.
278 :
279 : @param before Position to insert before.
280 :
281 : @param name The header name.
282 :
283 : @param value A value, which
284 : @li Must be syntactically valid for the header,
285 : @li Must be semantically valid for the message, and
286 : @li May not contain leading or trailing whitespace.
287 : */
288 : iterator
289 12 : insert(
290 : iterator before,
291 : string_view name,
292 : string_view value)
293 : {
294 12 : insert_impl(
295 : string_to_field(
296 : name),
297 : name,
298 : value,
299 : before.i_);
300 12 : return before;
301 : }
302 :
303 : //--------------------------------------------
304 :
305 : /** Erase headers
306 :
307 : This function removes the header pointed
308 : to by `it`.
309 : <br>
310 : All iterators that are equal to `it`
311 : or come after are invalidated.
312 :
313 : @par Complexity
314 : Linear in `name.size() + value.size()`.
315 :
316 : @par Exception Safety
317 : Throws nothing.
318 :
319 : @return An iterator to the inserted
320 : element.
321 :
322 : @param it An iterator to the element
323 : to erase.
324 : */
325 : iterator
326 31 : erase(iterator it) noexcept
327 : {
328 31 : erase_impl(it.i_, it->id);
329 31 : return it;
330 : }
331 :
332 : /** Erase headers
333 :
334 : This removes all headers whose name
335 : constant is equal to `id`.
336 : <br>
337 : If any headers are erased, then all
338 : iterators equal to or that come after
339 : the first erased element are invalidated.
340 : Otherwise, no iterators are invalidated.
341 :
342 : @par Complexity
343 : Linear in `this->string().size()`.
344 :
345 : @par Exception Safety
346 : Throws nothing.
347 :
348 : @return The number of headers erased.
349 :
350 : @param id The field name constant,
351 : which may not be @ref field::unknown.
352 : */
353 : BOOST_HTTP_PROTO_DECL
354 : std::size_t
355 : erase(field id) noexcept;
356 :
357 : /** Erase all matching fields
358 :
359 : This removes all headers with a matching
360 : name, using a case-insensitive comparison.
361 : <br>
362 : If any headers are erased, then all
363 : iterators equal to or that come after
364 : the first erased element are invalidated.
365 : Otherwise, no iterators are invalidated.
366 :
367 : @par Complexity
368 : Linear in `this->string().size()`.
369 :
370 : @par Exception Safety
371 : Throws nothing.
372 :
373 : @return The number of fields erased
374 :
375 : @param name The header name.
376 : */
377 : BOOST_HTTP_PROTO_DECL
378 : std::size_t
379 : erase(string_view name) noexcept;
380 :
381 : //--------------------------------------------
382 :
383 : /** Set a header value
384 :
385 : This sets the value of the header
386 : at `it`. The name is not changed.
387 : <br>
388 : No iterators are invalidated.
389 :
390 : @par Complexity
391 :
392 : @par Exception Safety
393 : Strong guarantee.
394 : Calls to allocate may throw.
395 :
396 : @param it An iterator to the header.
397 :
398 : @param value A value, which
399 : @li Must be syntactically valid for the header,
400 : @li Must be semantically valid for the message, and
401 : @li May not contain leading or trailing whitespace.
402 : */
403 : BOOST_HTTP_PROTO_DECL
404 : void
405 : set(
406 : iterator it,
407 : string_view value);
408 :
409 : /** Set a header value
410 :
411 : This function sets the value of the
412 : header with the specified field id.
413 : Other headers with the same name
414 : are removed first.
415 :
416 : @par Postconditions
417 : @code
418 : this->count( id ) == 1 && this->at( id ) == value
419 : @endcode
420 :
421 : @par Complexity
422 :
423 : @param id The field constant of the
424 : header to set.
425 :
426 : @param value A value, which
427 : @li Must be syntactically valid for the header,
428 : @li Must be semantically valid for the message, and
429 : @li May not contain leading or trailing whitespace.
430 : */
431 : BOOST_HTTP_PROTO_DECL
432 : void
433 : set(
434 : field id,
435 : string_view value);
436 :
437 : /** Set a header value
438 :
439 : This function sets the value of the
440 : header with the specified name. Other
441 : headers with the same name are removed
442 : first.
443 :
444 : @par Postconditions
445 : @code
446 : this->count( name ) == 1 && this->at( name ) == value
447 : @endcode
448 :
449 : @param name The field name.
450 :
451 : @param value The corresponding value, which
452 : @li must be syntactically valid for the field,
453 : @li must be semantically valid for the message, and
454 : @li may not contain leading or trailing whitespace.
455 : */
456 : BOOST_HTTP_PROTO_DECL
457 : void
458 : set(
459 : string_view name,
460 : string_view value);
461 :
462 : //--------------------------------------------
463 :
464 : private:
465 : BOOST_HTTP_PROTO_DECL
466 : void
467 : copy_impl(
468 : detail::header const&);
469 :
470 : BOOST_HTTP_PROTO_DECL
471 : void
472 : insert_impl(
473 : field id,
474 : string_view name,
475 : string_view value,
476 : std::size_t before);
477 :
478 : BOOST_HTTP_PROTO_DECL
479 : void
480 : erase_impl(
481 : std::size_t i,
482 : field id) noexcept;
483 :
484 : void raw_erase(
485 : std::size_t) noexcept;
486 :
487 : std::size_t
488 : erase_all_impl(
489 : std::size_t i0,
490 : field id) noexcept;
491 :
492 : std::size_t
493 : offset(
494 : std::size_t i) const noexcept;
495 :
496 : std::size_t
497 : length(
498 : std::size_t i) const noexcept;
499 :
500 : void raw_erase_n(field, std::size_t) noexcept;
501 : };
502 :
503 : //------------------------------------------------
504 :
505 : #ifndef BOOST_HTTP_PROTO_DOCS
506 : namespace detail {
507 : inline
508 : header&
509 : header::
510 : get(fields_base& f) noexcept
511 : {
512 : return f.h_;
513 : }
514 : } // detail
515 : #endif
516 :
517 : } // http_proto
518 : } // boost
519 :
520 : #endif
|