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