1  
//
1  
//
2  
// Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.com)
2  
// Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.com)
3  
// Copyright (c) 2022 Alan de Freitas (alandefreitas@gmail.com)
3  
// Copyright (c) 2022 Alan de Freitas (alandefreitas@gmail.com)
4  
//
4  
//
5  
// Distributed under the Boost Software License, Version 1.0. (See accompanying
5  
// Distributed under the Boost Software License, Version 1.0. (See accompanying
6  
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6  
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
7  
//
7  
//
8  
// Official repository: https://github.com/boostorg/url
8  
// Official repository: https://github.com/boostorg/url
9  
//
9  
//
10  

10  

11  
#ifndef BOOST_URL_PARAMS_VIEW_HPP
11  
#ifndef BOOST_URL_PARAMS_VIEW_HPP
12  
#define BOOST_URL_PARAMS_VIEW_HPP
12  
#define BOOST_URL_PARAMS_VIEW_HPP
13  

13  

14  
#include <boost/url/detail/config.hpp>
14  
#include <boost/url/detail/config.hpp>
15  
#include <boost/url/params_base.hpp>
15  
#include <boost/url/params_base.hpp>
16  

16  

17  
namespace boost {
17  
namespace boost {
18  
namespace urls {
18  
namespace urls {
19  

19  

20  
/** Non-owning decoded query parameter view
20  
/** Non-owning decoded query parameter view
21  

21  

22  
    This read-only range interprets the query
22  
    This read-only range interprets the query
23  
    string of a URL as bidirectional key/value
23  
    string of a URL as bidirectional key/value
24  
    pairs with percent-decoding applied on
24  
    pairs with percent-decoding applied on
25  
    access. It merely references the original
25  
    access. It merely references the original
26  
    character buffer; callers must keep that
26  
    character buffer; callers must keep that
27  
    buffer alive while the view is used.
27  
    buffer alive while the view is used.
28  

28  

29  
    @par Example
29  
    @par Example
30  
    @code
30  
    @code
31  
    url_view u( "?first=John&last=Doe" );
31  
    url_view u( "?first=John&last=Doe" );
32  

32  

33  
    params_view p = u.params();
33  
    params_view p = u.params();
34  
    @endcode
34  
    @endcode
35  

35  

36  
    Strings retrieved from the iterators are
36  
    Strings retrieved from the iterators are
37  
    automatically percent-decoded.
37  
    automatically percent-decoded.
38  

38  

39  
    @par Iterator Invalidation
39  
    @par Iterator Invalidation
40  
    Changes to the underlying character buffer
40  
    Changes to the underlying character buffer
41  
    can invalidate iterators which reference it.
41  
    can invalidate iterators which reference it.
42  
*/
42  
*/
43  
class params_view
43  
class params_view
44  
    : public params_base
44  
    : public params_base
45  
{
45  
{
46  
    friend class url_view_base;
46  
    friend class url_view_base;
47  
    friend class params_encoded_view;
47  
    friend class params_encoded_view;
48  
    friend class params_ref;
48  
    friend class params_ref;
49  

49  

50  
    params_view(
50  
    params_view(
51  
        detail::query_ref const& ref,
51  
        detail::query_ref const& ref,
52  
        encoding_opts opt) noexcept;
52  
        encoding_opts opt) noexcept;
53  

53  

54  
public:
54  
public:
55  
    /** Constructor
55  
    /** Constructor
56  

56  

57  
        Default-constructed params have
57  
        Default-constructed params have
58  
        zero elements.
58  
        zero elements.
59  

59  

60  
        @par Example
60  
        @par Example
61  
        @code
61  
        @code
62  
        params_view qp;
62  
        params_view qp;
63  
        @endcode
63  
        @endcode
64  

64  

65  
        @par Effects
65  
        @par Effects
66  
        @code
66  
        @code
67  
        return params_view( "" );
67  
        return params_view( "" );
68  
        @endcode
68  
        @endcode
69  

69  

70  
        @par Complexity
70  
        @par Complexity
71  
        Constant.
71  
        Constant.
72  

72  

73  
        @par Exception Safety
73  
        @par Exception Safety
74  
        Throws nothing.
74  
        Throws nothing.
75  
    */
75  
    */
76  
    params_view() = default;
76  
    params_view() = default;
77  

77  

78  
    /** Constructor
78  
    /** Constructor
79  

79  

80  
        After construction both views reference
80  
        After construction both views reference
81  
        the same character buffer.
81  
        the same character buffer.
82  

82  

83  
        Ownership is not transferred; the caller
83  
        Ownership is not transferred; the caller
84  
        is responsible for ensuring the lifetime
84  
        is responsible for ensuring the lifetime
85  
        of the buffer extends until it is no
85  
        of the buffer extends until it is no
86  
        longer referenced.
86  
        longer referenced.
87  

87  

88  
        @par Postconditions
88  
        @par Postconditions
89  
        @code
89  
        @code
90  
        this->buffer().data() == other.buffer().data()
90  
        this->buffer().data() == other.buffer().data()
91  
        @endcode
91  
        @endcode
92  

92  

93  
        @par Complexity
93  
        @par Complexity
94  
        Constant.
94  
        Constant.
95  

95  

96  
        @par Exception Safety
96  
        @par Exception Safety
97  
        Throws nothing
97  
        Throws nothing
98  

98  

99  
        @param other The object to copy
99  
        @param other The object to copy
100  
    */
100  
    */
101  
    params_view(
101  
    params_view(
102  
        params_view const& other) = default;
102  
        params_view const& other) = default;
103  

103  

104  
    /** Constructor
104  
    /** Constructor
105  

105  

106  
        After construction both views will
106  
        After construction both views will
107  
        reference the same character buffer
107  
        reference the same character buffer
108  
        but this instance will use the specified
108  
        but this instance will use the specified
109  
        @ref encoding_opts when the values
109  
        @ref encoding_opts when the values
110  
        are decoded.
110  
        are decoded.
111  

111  

112  
        Ownership is not transferred; the caller
112  
        Ownership is not transferred; the caller
113  
        is responsible for ensuring the lifetime
113  
        is responsible for ensuring the lifetime
114  
        of the buffer extends until it is no
114  
        of the buffer extends until it is no
115  
        longer referenced.
115  
        longer referenced.
116  

116  

117  
        @par Postconditions
117  
        @par Postconditions
118  
        @code
118  
        @code
119  
        this->buffer().data() == other.buffer().data()
119  
        this->buffer().data() == other.buffer().data()
120  
        @endcode
120  
        @endcode
121  

121  

122  
        @par Complexity
122  
        @par Complexity
123  
        Constant.
123  
        Constant.
124  

124  

125  
        @par Exception Safety
125  
        @par Exception Safety
126  
        Throws nothing
126  
        Throws nothing
127  

127  

128  
        @param other The object to copy
128  
        @param other The object to copy
129  
        @param opt The options for decoding
129  
        @param opt The options for decoding
130  
    */
130  
    */
131  
    params_view(
131  
    params_view(
132  
        params_view const& other,
132  
        params_view const& other,
133  
        encoding_opts opt) noexcept;
133  
        encoding_opts opt) noexcept;
134  

134  

135  
    /** Constructor
135  
    /** Constructor
136  

136  

137  
        This function constructs params from
137  
        This function constructs params from
138  
        a valid query parameter string, which
138  
        a valid query parameter string, which
139  
        can contain percent escapes. Unlike
139  
        can contain percent escapes. Unlike
140  
        the parameters in URLs, the string
140  
        the parameters in URLs, the string
141  
        passed here should not start with "?".
141  
        passed here should not start with "?".
142  
        Upon construction, the view references
142  
        Upon construction, the view references
143  
        the character buffer pointed to by `s`.
143  
        the character buffer pointed to by `s`.
144  
        The caller is responsible for ensuring
144  
        The caller is responsible for ensuring
145  
        that the lifetime of the buffer extends
145  
        that the lifetime of the buffer extends
146  
        until it is no longer referenced.
146  
        until it is no longer referenced.
147  

147  

148  
        @par Example
148  
        @par Example
149  
        @code
149  
        @code
150  
        params_view qp( "first=John&last=Doe" );
150  
        params_view qp( "first=John&last=Doe" );
151  
        @endcode
151  
        @endcode
152  

152  

153  
        @par Effects
153  
        @par Effects
154  
        @code
154  
        @code
155  
        return parse_query( s ).value();
155  
        return parse_query( s ).value();
156  
        @endcode
156  
        @endcode
157  

157  

158  
        @par Postconditions
158  
        @par Postconditions
159  
        @code
159  
        @code
160  
        this->buffer().data() == s.data()
160  
        this->buffer().data() == s.data()
161  
        @endcode
161  
        @endcode
162  

162  

163  
        @par Complexity
163  
        @par Complexity
164  
        Linear in `s`.
164  
        Linear in `s`.
165  

165  

166  
        @par Exception Safety
166  
        @par Exception Safety
167  
        Exceptions thrown on invalid input.
167  
        Exceptions thrown on invalid input.
168  

168  

169  
        @throw system_error
169  
        @throw system_error
170  
        `s` contains an invalid query parameter
170  
        `s` contains an invalid query parameter
171  
        string.
171  
        string.
172  

172  

173  
        @param s The string to parse.
173  
        @param s The string to parse.
174  

174  

175  
        @par BNF
175  
        @par BNF
176  
        @code
176  
        @code
177  
        query-params    = [ query-param ] *( "&" query-param )
177  
        query-params    = [ query-param ] *( "&" query-param )
178  

178  

179  
        query-param     = key [ "=" value ]
179  
        query-param     = key [ "=" value ]
180  
        @endcode
180  
        @endcode
181  

181  

182  
        @par Specification
182  
        @par Specification
183  
        @li <a href="https://datatracker.ietf.org/doc/html/rfc3986#section-3.4"
183  
        @li <a href="https://datatracker.ietf.org/doc/html/rfc3986#section-3.4"
184  
            >3.4.  Query</a>
184  
            >3.4.  Query</a>
185  
    */
185  
    */
186  
    BOOST_URL_DECL
186  
    BOOST_URL_DECL
187  
    params_view(
187  
    params_view(
188  
        core::string_view s);
188  
        core::string_view s);
189  

189  

190  
    /** Constructor
190  
    /** Constructor
191  

191  

192  
        This function constructs params from
192  
        This function constructs params from
193  
        a valid query parameter string, which
193  
        a valid query parameter string, which
194  
        can contain percent escapes.
194  
        can contain percent escapes.
195  

195  

196  
        This instance will use the specified
196  
        This instance will use the specified
197  
        @ref encoding_opts when the values
197  
        @ref encoding_opts when the values
198  
        are decoded.
198  
        are decoded.
199  

199  

200  
        Unlike the parameters in URLs, the string
200  
        Unlike the parameters in URLs, the string
201  
        passed here should not start with "?".
201  
        passed here should not start with "?".
202  
        Upon construction, the view will
202  
        Upon construction, the view will
203  
        reference the character buffer pointed
203  
        reference the character buffer pointed
204  
        to by `s`. The caller is responsible
204  
        to by `s`. The caller is responsible
205  
        for ensuring that the lifetime of the
205  
        for ensuring that the lifetime of the
206  
        buffer extends until it is no longer
206  
        buffer extends until it is no longer
207  
        referenced.
207  
        referenced.
208  

208  

209  
        @par Example
209  
        @par Example
210  
        @code
210  
        @code
211  
        encoding_opts opt;
211  
        encoding_opts opt;
212  
        opt.space_as_plus = true;
212  
        opt.space_as_plus = true;
213  
        params_view qp( "name=John+Doe", opt );
213  
        params_view qp( "name=John+Doe", opt );
214  
        @endcode
214  
        @endcode
215  

215  

216  
        @par Effects
216  
        @par Effects
217  
        @code
217  
        @code
218  
        return params_view(parse_query( s ).value(), opt);
218  
        return params_view(parse_query( s ).value(), opt);
219  
        @endcode
219  
        @endcode
220  

220  

221  
        @par Postconditions
221  
        @par Postconditions
222  
        @code
222  
        @code
223  
        this->buffer().data() == s.data()
223  
        this->buffer().data() == s.data()
224  
        @endcode
224  
        @endcode
225  

225  

226  
        @par Complexity
226  
        @par Complexity
227  
        Linear in `s`.
227  
        Linear in `s`.
228  

228  

229  
        @par Exception Safety
229  
        @par Exception Safety
230  
        Exceptions thrown on invalid input.
230  
        Exceptions thrown on invalid input.
231  

231  

232  
        @throw system_error
232  
        @throw system_error
233  
        `s` contains an invalid query parameter
233  
        `s` contains an invalid query parameter
234  
        string.
234  
        string.
235  

235  

236  
        @param s The string to parse.
236  
        @param s The string to parse.
237  

237  

238  
        @param opt The options for decoding. If
238  
        @param opt The options for decoding. If
239  
        this parameter is omitted, `space_as_plus`
239  
        this parameter is omitted, `space_as_plus`
240  
        is used.
240  
        is used.
241  

241  

242  
        @par BNF
242  
        @par BNF
243  
        @code
243  
        @code
244  
        query-params    = [ query-param ] *( "&" query-param )
244  
        query-params    = [ query-param ] *( "&" query-param )
245  

245  

246  
        query-param     = key [ "=" value ]
246  
        query-param     = key [ "=" value ]
247  
        @endcode
247  
        @endcode
248  

248  

249  
        @par Specification
249  
        @par Specification
250  
        @li <a href="https://datatracker.ietf.org/doc/html/rfc3986#section-3.4"
250  
        @li <a href="https://datatracker.ietf.org/doc/html/rfc3986#section-3.4"
251  
            >3.4.  Query</a>
251  
            >3.4.  Query</a>
252  
    */
252  
    */
253  
    BOOST_URL_DECL
253  
    BOOST_URL_DECL
254  
    params_view(
254  
    params_view(
255  
        core::string_view s,
255  
        core::string_view s,
256  
        encoding_opts opt);
256  
        encoding_opts opt);
257  

257  

258  
    /** Assignment
258  
    /** Assignment
259  

259  

260  
        After assignment, both views reference
260  
        After assignment, both views reference
261  
        the same underlying character buffer.
261  
        the same underlying character buffer.
262  

262  

263  
        Ownership is not transferred; the caller
263  
        Ownership is not transferred; the caller
264  
        is responsible for ensuring the lifetime
264  
        is responsible for ensuring the lifetime
265  
        of the buffer extends until it is no
265  
        of the buffer extends until it is no
266  
        longer referenced.
266  
        longer referenced.
267  

267  

268  
        @par Postconditions
268  
        @par Postconditions
269  
        @code
269  
        @code
270  
        this->buffer().data() == other.buffer().data()
270  
        this->buffer().data() == other.buffer().data()
271  
        @endcode
271  
        @endcode
272  

272  

273  
        @par Complexity
273  
        @par Complexity
274  
        Constant
274  
        Constant
275  

275  

276  
        @par Exception Safety
276  
        @par Exception Safety
277  
        Throws nothing
277  
        Throws nothing
278  

278  

279  
        @param other The object to assign
279  
        @param other The object to assign
280  
        @return A reference to this object
280  
        @return A reference to this object
281  
    */
281  
    */
282  
    params_view&
282  
    params_view&
283  
    operator=(
283  
    operator=(
284  
        params_view const& other) = default;
284  
        params_view const& other) = default;
285  
};
285  
};
286  

286  

287  
} // urls
287  
} // urls
288  
} // boost
288  
} // boost
289  

289  

290  
//------------------------------------------------
290  
//------------------------------------------------
291  
//
291  
//
292  
// std::ranges::enable_borrowed_range
292  
// std::ranges::enable_borrowed_range
293  
//
293  
//
294  
//------------------------------------------------
294  
//------------------------------------------------
295  

295  

296  
#ifdef BOOST_URL_HAS_CONCEPTS
296  
#ifdef BOOST_URL_HAS_CONCEPTS
297  
#include <ranges>
297  
#include <ranges>
298  
namespace std::ranges {
298  
namespace std::ranges {
299  
    template<>
299  
    template<>
300  
    inline constexpr bool
300  
    inline constexpr bool
301  
        enable_borrowed_range<
301  
        enable_borrowed_range<
302  
            boost::urls::params_view> = true;
302  
            boost::urls::params_view> = true;
303  
} // std::ranges
303  
} // std::ranges
304  
#endif
304  
#endif
305  

305  

306  
#endif
306  
#endif