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  
    */
78  
    fields() noexcept
78  
    fields() noexcept
79  
        : fields_base(detail::kind::fields)
79  
        : fields_base(detail::kind::fields)
80  
    {
80  
    {
81  
    }
81  
    }
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
120  
    fields(
120  
    fields(
121  
        core::string_view s)
121  
        core::string_view s)
122  
        : fields_base(detail::kind::fields, s)
122  
        : fields_base(detail::kind::fields, s)
123  
    {
123  
    {
124  
    }
124  
    }
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
153  
    fields(
153  
    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))
156  
        : fields()
156  
        : fields()
157  
    {
157  
    {
158  
        reserve_bytes(cap);
158  
        reserve_bytes(cap);
159  
        set_max_capacity_in_bytes(max_cap);
159  
        set_max_capacity_in_bytes(max_cap);
160  
    }
160  
    }
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  
    */
181  
    fields(fields&& f) noexcept
181  
    fields(fields&& f) noexcept
182  
        : fields_base(f.h_.kind)
182  
        : fields_base(f.h_.kind)
183  
    {
183  
    {
184  
        swap(f);
184  
        swap(f);
185  
    }
185  
    }
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  
    */
206  
    fields(fields const& f) = default;
206  
    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&
230  
    operator=(fields&& f) noexcept
230  
    operator=(fields&& f) noexcept
231  
    {
231  
    {
232  
        fields tmp(std::move(f));
232  
        fields tmp(std::move(f));
233  
        tmp.swap(*this);
233  
        tmp.swap(*this);
234  
        return *this;
234  
        return *this;
235  
    }
235  
    }
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&
264  
    operator=(fields const& f) noexcept
264  
    operator=(fields const& f) noexcept
265  
    {
265  
    {
266  
        copy_impl(f.h_);
266  
        copy_impl(f.h_);
267  
        return *this;
267  
        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
297  
    swap(fields& other) noexcept
297  
    swap(fields& other) noexcept
298  
    {
298  
    {
299  
        h_.swap(other.h_);
299  
        h_.swap(other.h_);
300  
        std::swap(max_cap_, other.max_cap_);
300  
        std::swap(max_cap_, other.max_cap_);
301  
    }
301  
    }
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