100.00% Lines (28/28) 100.00% Functions (8/8)
TLA Baseline Branch
Line Hits Code Line Hits Code
1   // 1   //
2   // Copyright (c) 2021 Vinnie Falco (vinnie.falco@gmail.com) 2   // Copyright (c) 2021 Vinnie Falco (vinnie.falco@gmail.com)
3   // Copyright (c) 2024 Christian Mazakas 3   // Copyright (c) 2024 Christian Mazakas
4   // Copyright (c) 2025 Mohammad Nejati 4   // Copyright (c) 2025 Mohammad Nejati
5   // 5   //
6   // Distributed under the Boost Software License, Version 1.0. (See accompanying 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) 7   // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
8   // 8   //
9   // Official repository: https://github.com/cppalliance/http 9   // Official repository: https://github.com/cppalliance/http
10   // 10   //
11   11  
12   #ifndef BOOST_HTTP_FIELDS_HPP 12   #ifndef BOOST_HTTP_FIELDS_HPP
13   #define BOOST_HTTP_FIELDS_HPP 13   #define BOOST_HTTP_FIELDS_HPP
14   14  
15   #include <boost/http/detail/config.hpp> 15   #include <boost/http/detail/config.hpp>
16   #include <boost/http/fields_base.hpp> 16   #include <boost/http/fields_base.hpp>
17   17  
18   namespace boost { 18   namespace boost {
19   namespace http { 19   namespace http {
20   20  
21   /** A modifiable container of HTTP fields. 21   /** A modifiable container of HTTP fields.
22   22  
23   This container owns a collection of HTTP 23   This container owns a collection of HTTP
24   fields, represented by a buffer which is 24   fields, represented by a buffer which is
25   managed by performing dynamic memory 25   managed by performing dynamic memory
26   allocations as needed. The contents may be 26   allocations as needed. The contents may be
27   inspected and modified, and the implementation 27   inspected and modified, and the implementation
28   maintains a useful invariant: changes to the 28   maintains a useful invariant: changes to the
29   fields always leave it in a valid state. 29   fields always leave it in a valid state.
30   30  
31   @par Example 31   @par Example
32   @code 32   @code
33   fields fs; 33   fields fs;
34   34  
35   fs.set(field::host, "example.com"); 35   fs.set(field::host, "example.com");
36   fs.set(field::accept_encoding, "gzip, deflate, br"); 36   fs.set(field::accept_encoding, "gzip, deflate, br");
37   fs.set(field::cache_control, "no-cache"); 37   fs.set(field::cache_control, "no-cache");
38   38  
39   assert(fs.buffer() == 39   assert(fs.buffer() ==
40   "Host: example.com\r\n" 40   "Host: example.com\r\n"
41   "Accept-Encoding: gzip, deflate, br\r\n" 41   "Accept-Encoding: gzip, deflate, br\r\n"
42   "Cache-Control: no-cache\r\n" 42   "Cache-Control: no-cache\r\n"
43   "\r\n"); 43   "\r\n");
44   @endcode 44   @endcode
45   45  
46   @see 46   @see
47   @ref fields_base. 47   @ref fields_base.
48   */ 48   */
49   class fields final 49   class fields final
50   : public fields_base 50   : public fields_base
51   { 51   {
52   public: 52   public:
53   53  
54   //-------------------------------------------- 54   //--------------------------------------------
55   // 55   //
56   // Special Members 56   // Special Members
57   // 57   //
58   //-------------------------------------------- 58   //--------------------------------------------
59   59  
60   /** Constructor. 60   /** Constructor.
61   61  
62   A default-constructed fields container 62   A default-constructed fields container
63   contain no name-value pairs. 63   contain no name-value pairs.
64   64  
65   @par Example 65   @par Example
66   @code 66   @code
67   fields fs; 67   fields fs;
68   @endcode 68   @endcode
69   69  
70   @par Postconditions 70   @par Postconditions
71   @code 71   @code
72   this->buffer() == "\r\n" 72   this->buffer() == "\r\n"
73   @endcode 73   @endcode
74   74  
75   @par Complexity 75   @par Complexity
76   Constant. 76   Constant.
77   */ 77   */
HITCBC 78   26 fields() noexcept 78   26 fields() noexcept
HITCBC 79   26 : fields_base(detail::kind::fields) 79   26 : fields_base(detail::kind::fields)
80   { 80   {
HITCBC 81   26 } 81   26 }
82   82  
83   83  
84   /** Constructor. 84   /** Constructor.
85   85  
86   Constructs a fields container from the string 86   Constructs a fields container from the string
87   `s`, which must contain valid HTTP headers or 87   `s`, which must contain valid HTTP headers or
88   else an exception is thrown. 88   else an exception is thrown.
89   The new fields container retains ownership by 89   The new fields container retains ownership by
90   allocating a copy of the passed string. 90   allocating a copy of the passed string.
91   91  
92   @par Example 92   @par Example
93   @code 93   @code
94   fields f( 94   fields f(
95   "Server: Boost.HTTP\r\n" 95   "Server: Boost.HTTP\r\n"
96   "Content-Type: text/plain\r\n" 96   "Content-Type: text/plain\r\n"
97   "Connection: close\r\n" 97   "Connection: close\r\n"
98   "Content-Length: 73\r\n" 98   "Content-Length: 73\r\n"
99   "\r\n"); 99   "\r\n");
100   @endcode 100   @endcode
101   101  
102   @par Postconditions 102   @par Postconditions
103   @code 103   @code
104   this->buffer() == s && this->buffer().data() != s.data() 104   this->buffer() == s && this->buffer().data() != s.data()
105   @endcode 105   @endcode
106   106  
107   @par Complexity 107   @par Complexity
108   Linear in `s.size()`. 108   Linear in `s.size()`.
109   109  
110   @par Exception Safety 110   @par Exception Safety
111   Calls to allocate may throw. 111   Calls to allocate may throw.
112   Exception thrown on invalid input. 112   Exception thrown on invalid input.
113   113  
114   @throw system_error 114   @throw system_error
115   Input is invalid. 115   Input is invalid.
116   116  
117   @param s The string to parse. 117   @param s The string to parse.
118   */ 118   */
119   explicit 119   explicit
HITCBC 120   235 fields( 120   235 fields(
121   core::string_view s) 121   core::string_view s)
HITCBC 122   235 : fields_base(detail::kind::fields, s) 122   235 : fields_base(detail::kind::fields, s)
123   { 123   {
HITCBC 124   234 } 124   234 }
125   125  
126   /** Constructor. 126   /** Constructor.
127   127  
128   Allocates `cap` bytes initially, with an 128   Allocates `cap` bytes initially, with an
129   upper limit of `max_cap`. Growing beyond 129   upper limit of `max_cap`. Growing beyond
130   `max_cap` will throw an exception. 130   `max_cap` will throw an exception.
131   131  
132   Useful when an estimated initial size is 132   Useful when an estimated initial size is
133   known, but further growth up to a 133   known, but further growth up to a
134   maximum is allowed. 134   maximum is allowed.
135   135  
136   @par Preconditions 136   @par Preconditions
137   @code 137   @code
138   max_cap >= cap 138   max_cap >= cap
139   @endcode 139   @endcode
140   140  
141   @par Exception Safety 141   @par Exception Safety
142   Calls to allocate may throw. 142   Calls to allocate may throw.
143   Exception thrown on invalid input. 143   Exception thrown on invalid input.
144   144  
145   @throw system_error 145   @throw system_error
146   Input is invalid. 146   Input is invalid.
147   147  
148   @param cap Initial capacity in bytes (may be `0`). 148   @param cap Initial capacity in bytes (may be `0`).
149   149  
150   @param max_cap Maximum allowed capacity in bytes. 150   @param max_cap Maximum allowed capacity in bytes.
151   */ 151   */
152   explicit 152   explicit
HITCBC 153   10 fields( 153   10 fields(
154   std::size_t cap, 154   std::size_t cap,
155   std::size_t max_cap = std::size_t(-1)) 155   std::size_t max_cap = std::size_t(-1))
HITCBC 156   10 : fields() 156   10 : fields()
157   { 157   {
HITCBC 158   10 reserve_bytes(cap); 158   10 reserve_bytes(cap);
HITCBC 159   10 set_max_capacity_in_bytes(max_cap); 159   10 set_max_capacity_in_bytes(max_cap);
HITCBC 160   10 } 160   10 }
161   161  
162   /** Constructor. 162   /** Constructor.
163   163  
164   The contents of `f` are transferred 164   The contents of `f` are transferred
165   to the newly constructed object, 165   to the newly constructed object,
166   which includes the underlying 166   which includes the underlying
167   character buffer. 167   character buffer.
168   After construction, the moved-from 168   After construction, the moved-from
169   object is as if default-constructed. 169   object is as if default-constructed.
170   170  
171   @par Postconditions 171   @par Postconditions
172   @code 172   @code
173   f.buffer() == "\r\n" 173   f.buffer() == "\r\n"
174   @endcode 174   @endcode
175   175  
176   @par Complexity 176   @par Complexity
177   Constant. 177   Constant.
178   178  
179   @param f The fields to move from. 179   @param f The fields to move from.
180   */ 180   */
HITCBC 181   6 fields(fields&& f) noexcept 181   6 fields(fields&& f) noexcept
HITCBC 182   6 : fields_base(f.h_.kind) 182   6 : fields_base(f.h_.kind)
183   { 183   {
HITCBC 184   6 swap(f); 184   6 swap(f);
HITCBC 185   6 } 185   6 }
186   186  
187   187  
188   /** Constructor. 188   /** Constructor.
189   189  
190   The newly constructed object contains 190   The newly constructed object contains
191   a copy of `f`. 191   a copy of `f`.
192   192  
193   @par Postconditions 193   @par Postconditions
194   @code 194   @code
195   this->buffer() == f.buffer() && this->buffer().data() != f.buffer().data() 195   this->buffer() == f.buffer() && this->buffer().data() != f.buffer().data()
196   @endcode 196   @endcode
197   197  
198   @par Complexity 198   @par Complexity
199   Linear in `f.size()`. 199   Linear in `f.size()`.
200   200  
201   @par Exception Safety 201   @par Exception Safety
202   Calls to allocate may throw. 202   Calls to allocate may throw.
203   203  
204   @param f The fields to copy. 204   @param f The fields to copy.
205   */ 205   */
HITCBC 206   2 fields(fields const& f) = default; 206   2 fields(fields const& f) = default;
207   207  
208   /** Assignment. 208   /** Assignment.
209   209  
210   The contents of `f` are transferred to 210   The contents of `f` are transferred to
211   `this`, including the underlying 211   `this`, including the underlying
212   character buffer. The previous contents 212   character buffer. The previous contents
213   of `this` are destroyed. 213   of `this` are destroyed.
214   After assignment, the moved-from 214   After assignment, the moved-from
215   object is as if default-constructed. 215   object is as if default-constructed.
216   216  
217   @par Postconditions 217   @par Postconditions
218   @code 218   @code
219   f.buffer() == "\r\n" 219   f.buffer() == "\r\n"
220   @endcode 220   @endcode
221   221  
222   @par Complexity 222   @par Complexity
223   Constant. 223   Constant.
224   224  
225   @param f The fields to assign from. 225   @param f The fields to assign from.
226   226  
227   @return A reference to this object. 227   @return A reference to this object.
228   */ 228   */
229   fields& 229   fields&
HITCBC 230   4 operator=(fields&& f) noexcept 230   4 operator=(fields&& f) noexcept
231   { 231   {
HITCBC 232   4 fields tmp(std::move(f)); 232   4 fields tmp(std::move(f));
HITCBC 233   4 tmp.swap(*this); 233   4 tmp.swap(*this);
HITCBC 234   8 return *this; 234   8 return *this;
HITCBC 235   4 } 235   4 }
236   236  
237   /** Assignment. 237   /** Assignment.
238   238  
239   The contents of `f` are copied and 239   The contents of `f` are copied and
240   the previous contents of `this` are 240   the previous contents of `this` are
241   discarded. 241   discarded.
242   242  
243   @par Postconditions 243   @par Postconditions
244   @code 244   @code
245   this->buffer() == f.buffer() && this->buffer().data() != f.buffer().data() 245   this->buffer() == f.buffer() && this->buffer().data() != f.buffer().data()
246   @endcode 246   @endcode
247   247  
248   @par Complexity 248   @par Complexity
249   Linear in `f.size()`. 249   Linear in `f.size()`.
250   250  
251   @par Exception Safety 251   @par Exception Safety
252   Strong guarantee. 252   Strong guarantee.
253   Calls to allocate may throw. 253   Calls to allocate may throw.
254   Exception thrown if max capacity exceeded. 254   Exception thrown if max capacity exceeded.
255   255  
256   @throw std::length_error 256   @throw std::length_error
257   Max capacity would be exceeded. 257   Max capacity would be exceeded.
258   258  
259   @return A reference to this object. 259   @return A reference to this object.
260   260  
261   @param f The fields to copy. 261   @param f The fields to copy.
262   */ 262   */
263   fields& 263   fields&
HITCBC 264   4 operator=(fields const& f) noexcept 264   4 operator=(fields const& f) noexcept
265   { 265   {
HITCBC 266   4 copy_impl(f.h_); 266   4 copy_impl(f.h_);
HITCBC 267   4 return *this; 267   4 return *this;
268   } 268   }
269   269  
270   //-------------------------------------------- 270   //--------------------------------------------
271   271  
272   /** Swap. 272   /** Swap.
273   273  
274   Exchanges the contents of this fields 274   Exchanges the contents of this fields
275   object with another. All views, iterators 275   object with another. All views, iterators
276   and references remain valid. 276   and references remain valid.
277   277  
278   If `this == &other`, this function call has no effect. 278   If `this == &other`, this function call has no effect.
279   279  
280   @par Example 280   @par Example
281   @code 281   @code
282   fields f1; 282   fields f1;
283   f1.set(field::accept, "text/html"); 283   f1.set(field::accept, "text/html");
284   fields f2; 284   fields f2;
285   f2.set(field::connection, "keep-alive"); 285   f2.set(field::connection, "keep-alive");
286   f1.swap(f2); 286   f1.swap(f2);
287   assert(f1.buffer() == "Connection: keep-alive\r\n\r\n" ); 287   assert(f1.buffer() == "Connection: keep-alive\r\n\r\n" );
288   assert(f2.buffer() == "Accept: text/html\r\n\r\n" ); 288   assert(f2.buffer() == "Accept: text/html\r\n\r\n" );
289   @endcode 289   @endcode
290   290  
291   @par Complexity 291   @par Complexity
292   Constant. 292   Constant.
293   293  
294   @param other The object to swap with. 294   @param other The object to swap with.
295   */ 295   */
296   void 296   void
HITCBC 297   10 swap(fields& other) noexcept 297   10 swap(fields& other) noexcept
298   { 298   {
HITCBC 299   10 h_.swap(other.h_); 299   10 h_.swap(other.h_);
HITCBC 300   10 std::swap(max_cap_, other.max_cap_); 300   10 std::swap(max_cap_, other.max_cap_);
HITCBC 301   10 } 301   10 }
302   302  
303   /** Swap. 303   /** Swap.
304   304  
305   Exchanges the contents of `v0` with 305   Exchanges the contents of `v0` with
306   another `v1`. All views, iterators and 306   another `v1`. All views, iterators and
307   references remain valid. 307   references remain valid.
308   308  
309   If `&v0 == &v1`, this function call has no effect. 309   If `&v0 == &v1`, this function call has no effect.
310   310  
311   @par Example 311   @par Example
312   @code 312   @code
313   fields f1; 313   fields f1;
314   f1.set(field::accept, "text/html"); 314   f1.set(field::accept, "text/html");
315   fields f2; 315   fields f2;
316   f2.set(field::connection, "keep-alive"); 316   f2.set(field::connection, "keep-alive");
317   std::swap(f1, f2); 317   std::swap(f1, f2);
318   assert(f1.buffer() == "Connection: keep-alive\r\n\r\n" ); 318   assert(f1.buffer() == "Connection: keep-alive\r\n\r\n" );
319   assert(f2.buffer() == "Accept: text/html\r\n\r\n" ); 319   assert(f2.buffer() == "Accept: text/html\r\n\r\n" );
320   @endcode 320   @endcode
321   321  
322   @par Effects 322   @par Effects
323   @code 323   @code
324   v0.swap(v1); 324   v0.swap(v1);
325   @endcode 325   @endcode
326   326  
327   @par Complexity 327   @par Complexity
328   Constant. 328   Constant.
329   329  
330   @param v0 The first object to swap. 330   @param v0 The first object to swap.
331   @param v1 The second object to swap. 331   @param v1 The second object to swap.
332   332  
333   @see 333   @see
334   @ref fields::swap. 334   @ref fields::swap.
335   */ 335   */
336   friend 336   friend
337   void 337   void
338   swap( 338   swap(
339   fields& v0, 339   fields& v0,
340   fields& v1) noexcept 340   fields& v1) noexcept
341   { 341   {
342   v0.swap(v1); 342   v0.swap(v1);
343   } 343   }
344   }; 344   };
345   345  
346   } // http 346   } // http
347   } // boost 347   } // boost
348   348  
349   #endif 349   #endif