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