1  
//
1  
//
2  
// Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.com)
2  
// Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.com)
3  
//
3  
//
4  
// Distributed under the Boost Software License, Version 1.0. (See accompanying
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)
5  
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6  
//
6  
//
7  
// Official repository: https://github.com/boostorg/url
7  
// Official repository: https://github.com/boostorg/url
8  
//
8  
//
9  

9  

10  

10  

11  
#include <boost/url/detail/config.hpp>
11  
#include <boost/url/detail/config.hpp>
12  
#include <boost/url/detail/any_params_iter.hpp>
12  
#include <boost/url/detail/any_params_iter.hpp>
13  
#include <boost/url/encode.hpp>
13  
#include <boost/url/encode.hpp>
14  
#include <boost/core/detail/string_view.hpp>
14  
#include <boost/core/detail/string_view.hpp>
15  
#include "../rfc/detail/charsets.hpp"
15  
#include "../rfc/detail/charsets.hpp"
16  

16  

17  
namespace boost {
17  
namespace boost {
18  
namespace urls {
18  
namespace urls {
19  
namespace detail {
19  
namespace detail {
20  

20  

21  
/*
21  
/*
22  
    When a string is transformed into a range of
22  
    When a string is transformed into a range of
23  
    params, the empty string becomes ambiguous:
23  
    params, the empty string becomes ambiguous:
24  
    it can be an empty range, or a range with
24  
    it can be an empty range, or a range with
25  
    one param. The value `not_empty` is used on
25  
    one param. The value `not_empty` is used on
26  
    construction to inform the transformation
26  
    construction to inform the transformation
27  
    that the empty string should be treated as
27  
    that the empty string should be treated as
28  
    a one-element range. This simplifies
28  
    a one-element range. This simplifies
29  
    edit_params().
29  
    edit_params().
30  
*/
30  
*/
31  

31  

32  
//------------------------------------------------
32  
//------------------------------------------------
33  
//
33  
//
34  
// any_params_iter
34  
// any_params_iter
35  
//
35  
//
36  
//------------------------------------------------
36  
//------------------------------------------------
37  

37  

38  
any_params_iter::
38  
any_params_iter::
39  
~any_params_iter() noexcept = default;
39  
~any_params_iter() noexcept = default;
40  

40  

41  
//------------------------------------------------
41  
//------------------------------------------------
42  
//
42  
//
43  
// query_iter
43  
// query_iter
44  
//
44  
//
45  
//------------------------------------------------
45  
//------------------------------------------------
46  

46  

47  
query_string_iter::
47  
query_string_iter::
48  
query_string_iter(
48  
query_string_iter(
49  
    core::string_view s,
49  
    core::string_view s,
50  
    bool ne) noexcept
50  
    bool ne) noexcept
51  
    : any_params_iter(
51  
    : any_params_iter(
52  
        s.empty() && ! ne, s)
52  
        s.empty() && ! ne, s)
53  
{
53  
{
54  
    rewind();
54  
    rewind();
55  
}
55  
}
56  

56  

57  
void
57  
void
58  
query_string_iter::
58  
query_string_iter::
59  
rewind() noexcept
59  
rewind() noexcept
60  
{
60  
{
61  
    if(empty)
61  
    if(empty)
62  
    {
62  
    {
63  
        at_end_ = true;
63  
        at_end_ = true;
64  
        return;
64  
        return;
65  
    }
65  
    }
66  
    p_ = s0.begin();
66  
    p_ = s0.begin();
67  
    if(! s0.empty())
67  
    if(! s0.empty())
68  
    {
68  
    {
69  
        auto pos =
69  
        auto pos =
70  
            s0.find_first_of('&');
70  
            s0.find_first_of('&');
71  
        if(pos != core::string_view::npos)
71  
        if(pos != core::string_view::npos)
72  
            n_ = pos;
72  
            n_ = pos;
73  
        else
73  
        else
74  
            n_ = s0.size();
74  
            n_ = s0.size();
75  
    }
75  
    }
76  
    else
76  
    else
77  
    {
77  
    {
78  
        n_ = 0;
78  
        n_ = 0;
79  
    }
79  
    }
80  
    at_end_ = false;
80  
    at_end_ = false;
81  
}
81  
}
82  

82  

83  
bool
83  
bool
84  
query_string_iter::
84  
query_string_iter::
85  
measure(
85  
measure(
86  
    std::size_t& n) noexcept
86  
    std::size_t& n) noexcept
87  
{
87  
{
88  
    if(at_end_)
88  
    if(at_end_)
89  
        return false;
89  
        return false;
90  
    // When interacting with the query as
90  
    // When interacting with the query as
91  
    // an intact string, we do not treat
91  
    // an intact string, we do not treat
92  
    // the plus sign as an encoded space.
92  
    // the plus sign as an encoded space.
93  
    encoding_opts opt;
93  
    encoding_opts opt;
94  
    opt.space_as_plus = false;
94  
    opt.space_as_plus = false;
95  
    n += encoded_size(
95  
    n += encoded_size(
96  
        core::string_view(p_, n_),
96  
        core::string_view(p_, n_),
97  
        query_chars,
97  
        query_chars,
98  
        opt);
98  
        opt);
99  
    increment();
99  
    increment();
100  
    return true;
100  
    return true;
101  
}
101  
}
102  

102  

103  
void
103  
void
104  
query_string_iter::
104  
query_string_iter::
105  
copy(
105  
copy(
106  
    char*& dest,
106  
    char*& dest,
107  
    char const* end) noexcept
107  
    char const* end) noexcept
108  
{
108  
{
109  
    BOOST_ASSERT(! at_end_);
109  
    BOOST_ASSERT(! at_end_);
110  
    // When interacting with the query as
110  
    // When interacting with the query as
111  
    // an intact string, we do not treat
111  
    // an intact string, we do not treat
112  
    // the plus sign as an encoded space.
112  
    // the plus sign as an encoded space.
113  
    encoding_opts opt;
113  
    encoding_opts opt;
114  
    opt.space_as_plus = false;
114  
    opt.space_as_plus = false;
115  
    dest += encode_unsafe(
115  
    dest += encode_unsafe(
116  
        dest,
116  
        dest,
117  
        end - dest,
117  
        end - dest,
118  
        core::string_view(p_, n_),
118  
        core::string_view(p_, n_),
119  
        query_chars,
119  
        query_chars,
120  
        opt);
120  
        opt);
121  
    increment();
121  
    increment();
122  
}
122  
}
123  

123  

124  
void
124  
void
125  
query_string_iter::
125  
query_string_iter::
126  
increment() noexcept
126  
increment() noexcept
127  
{
127  
{
128  
    p_ += n_;
128  
    p_ += n_;
129  
    if(p_ == s0.end())
129  
    if(p_ == s0.end())
130  
    {
130  
    {
131  
        at_end_ = true;
131  
        at_end_ = true;
132  
        return;
132  
        return;
133  
    }
133  
    }
134  
    ++p_;
134  
    ++p_;
135  
    core::string_view s(p_, s0.end() - p_);
135  
    core::string_view s(p_, s0.end() - p_);
136  
    auto pos = s.find_first_of('&');
136  
    auto pos = s.find_first_of('&');
137  
    if(pos != core::string_view::npos)
137  
    if(pos != core::string_view::npos)
138  
        n_ = pos;
138  
        n_ = pos;
139  
    else
139  
    else
140  
        n_ = s.size();
140  
        n_ = s.size();
141  
}
141  
}
142  

142  

143  
//------------------------------------------------
143  
//------------------------------------------------
144  
//
144  
//
145  
// param_iter
145  
// param_iter
146  
//
146  
//
147  
//------------------------------------------------
147  
//------------------------------------------------
148  

148  

149  
single_param_iter::
149  
single_param_iter::
150  
single_param_iter(
150  
single_param_iter(
151  
    param_view const& p,
151  
    param_view const& p,
152  
    bool space_as_plus) noexcept
152  
    bool space_as_plus) noexcept
153  
    : any_params_iter(
153  
    : any_params_iter(
154  
        false,
154  
        false,
155  
        p.key,
155  
        p.key,
156  
        p.value)
156  
        p.value)
157  
    , has_value_(p.has_value)
157  
    , has_value_(p.has_value)
158  
    , space_as_plus_(space_as_plus)
158  
    , space_as_plus_(space_as_plus)
159  
{
159  
{
160  
}
160  
}
161  

161  

162  
void
162  
void
163  
single_param_iter::
163  
single_param_iter::
164  
rewind() noexcept
164  
rewind() noexcept
165  
{
165  
{
166  
    at_end_ = false;
166  
    at_end_ = false;
167  
}
167  
}
168  

168  

169  
bool
169  
bool
170  
single_param_iter::
170  
single_param_iter::
171  
measure(std::size_t& n) noexcept
171  
measure(std::size_t& n) noexcept
172  
{
172  
{
173  
    if(at_end_)
173  
    if(at_end_)
174  
        return false;
174  
        return false;
175  
    encoding_opts opt;
175  
    encoding_opts opt;
176  
    opt.space_as_plus = space_as_plus_;
176  
    opt.space_as_plus = space_as_plus_;
177  
    n += encoded_size(
177  
    n += encoded_size(
178  
        s0,
178  
        s0,
179  
        detail::param_key_chars,
179  
        detail::param_key_chars,
180  
        opt);
180  
        opt);
181  
    if(has_value_)
181  
    if(has_value_)
182  
    {
182  
    {
183  
        ++n; // '='
183  
        ++n; // '='
184  
        n += encoded_size(
184  
        n += encoded_size(
185  
            s1,
185  
            s1,
186  
            detail::param_value_chars,
186  
            detail::param_value_chars,
187  
            opt);
187  
            opt);
188  
    }
188  
    }
189  
    at_end_ = true;
189  
    at_end_ = true;
190  
    return true;
190  
    return true;
191  
}
191  
}
192  

192  

193  
void
193  
void
194  
single_param_iter::
194  
single_param_iter::
195  
copy(
195  
copy(
196  
    char*& dest,
196  
    char*& dest,
197  
    char const* end) noexcept
197  
    char const* end) noexcept
198  
{
198  
{
199  
    BOOST_ASSERT(! at_end_);
199  
    BOOST_ASSERT(! at_end_);
200  
    encoding_opts opt;
200  
    encoding_opts opt;
201  
    opt.space_as_plus = space_as_plus_;
201  
    opt.space_as_plus = space_as_plus_;
202  
    dest += encode(
202  
    dest += encode(
203  
        dest,
203  
        dest,
204  
        end - dest,
204  
        end - dest,
205  
        s0,
205  
        s0,
206  
        detail::param_key_chars,
206  
        detail::param_key_chars,
207  
        opt);
207  
        opt);
208  
    if (has_value_)
208  
    if (has_value_)
209  
    {
209  
    {
210  
        *dest++ = '=';
210  
        *dest++ = '=';
211  
        dest += encode(
211  
        dest += encode(
212  
            dest,
212  
            dest,
213  
            end - dest,
213  
            end - dest,
214  
            s1,
214  
            s1,
215  
            detail::param_value_chars,
215  
            detail::param_value_chars,
216  
            opt);
216  
            opt);
217  
    }
217  
    }
218  
}
218  
}
219  

219  

220  
//------------------------------------------------
220  
//------------------------------------------------
221  
//
221  
//
222  
// params_iter_base
222  
// params_iter_base
223  
//
223  
//
224  
//------------------------------------------------
224  
//------------------------------------------------
225  

225  

226  
void
226  
void
227  
params_iter_base::
227  
params_iter_base::
228  
measure_impl(
228  
measure_impl(
229  
    std::size_t& n,
229  
    std::size_t& n,
230  
    param_view const& p) noexcept
230  
    param_view const& p) noexcept
231  
{
231  
{
232  
    encoding_opts opt;
232  
    encoding_opts opt;
233  
    opt.space_as_plus = space_as_plus_;
233  
    opt.space_as_plus = space_as_plus_;
234  
    n += encoded_size(
234  
    n += encoded_size(
235  
        p.key,
235  
        p.key,
236  
        detail::param_key_chars,
236  
        detail::param_key_chars,
237  
        opt);
237  
        opt);
238  
    if(p.has_value)
238  
    if(p.has_value)
239  
    {
239  
    {
240  
        ++n; // '='
240  
        ++n; // '='
241  
        n += encoded_size(
241  
        n += encoded_size(
242  
            p.value,
242  
            p.value,
243  
            detail::param_value_chars,
243  
            detail::param_value_chars,
244  
            opt);
244  
            opt);
245  
    }
245  
    }
246  
}
246  
}
247  

247  

248  
void
248  
void
249  
params_iter_base::
249  
params_iter_base::
250  
copy_impl(
250  
copy_impl(
251  
    char*& dest,
251  
    char*& dest,
252  
    char const* end,
252  
    char const* end,
253  
    param_view const& p) noexcept
253  
    param_view const& p) noexcept
254  
{
254  
{
255  
    encoding_opts opt;
255  
    encoding_opts opt;
256  
    opt.space_as_plus = space_as_plus_;
256  
    opt.space_as_plus = space_as_plus_;
257  
    dest += encode(
257  
    dest += encode(
258  
        dest,
258  
        dest,
259  
        end - dest,
259  
        end - dest,
260  
        p.key,
260  
        p.key,
261  
        detail::param_key_chars,
261  
        detail::param_key_chars,
262  
        opt);
262  
        opt);
263  
    if(p.has_value)
263  
    if(p.has_value)
264  
    {
264  
    {
265  
        *dest++ = '=';
265  
        *dest++ = '=';
266  
        dest += encode(
266  
        dest += encode(
267  
            dest,
267  
            dest,
268  
            end - dest,
268  
            end - dest,
269  
            p.value,
269  
            p.value,
270  
            detail::param_value_chars,
270  
            detail::param_value_chars,
271  
            opt);
271  
            opt);
272  
    }
272  
    }
273  
}
273  
}
274  

274  

275  
//------------------------------------------------
275  
//------------------------------------------------
276  
//
276  
//
277  
// param_encoded_iter
277  
// param_encoded_iter
278  
//
278  
//
279  
//------------------------------------------------
279  
//------------------------------------------------
280  

280  

281  
param_encoded_iter::
281  
param_encoded_iter::
282  
param_encoded_iter(
282  
param_encoded_iter(
283  
    param_pct_view const& p) noexcept
283  
    param_pct_view const& p) noexcept
284  
    : any_params_iter(
284  
    : any_params_iter(
285  
        false,
285  
        false,
286  
        p.key,
286  
        p.key,
287  
        p.value)
287  
        p.value)
288  
    , has_value_(p.has_value)
288  
    , has_value_(p.has_value)
289  
{
289  
{
290  
}
290  
}
291  

291  

292  
void
292  
void
293  
param_encoded_iter::
293  
param_encoded_iter::
294  
rewind() noexcept
294  
rewind() noexcept
295  
{
295  
{
296  
    at_end_ = false;
296  
    at_end_ = false;
297  
}
297  
}
298  

298  

299  
bool
299  
bool
300  
param_encoded_iter::
300  
param_encoded_iter::
301  
measure(std::size_t& n) noexcept
301  
measure(std::size_t& n) noexcept
302  
{
302  
{
303  
    if(at_end_)
303  
    if(at_end_)
304  
        return false;
304  
        return false;
305  
    n += detail::re_encoded_size_unsafe(
305  
    n += detail::re_encoded_size_unsafe(
306  
        s0,
306  
        s0,
307  
        detail::param_key_chars);
307  
        detail::param_key_chars);
308  
    if(has_value_)
308  
    if(has_value_)
309  
        n += detail::re_encoded_size_unsafe(
309  
        n += detail::re_encoded_size_unsafe(
310  
            s1,
310  
            s1,
311  
            detail::param_value_chars) + 1; // for '='
311  
            detail::param_value_chars) + 1; // for '='
312  
    at_end_ = true;
312  
    at_end_ = true;
313  
    return true;
313  
    return true;
314  
}
314  
}
315  

315  

316  
void
316  
void
317  
param_encoded_iter::
317  
param_encoded_iter::
318  
copy(
318  
copy(
319  
    char*& dest,
319  
    char*& dest,
320  
    char const* end) noexcept
320  
    char const* end) noexcept
321  
{
321  
{
322  
    detail::re_encode_unsafe(
322  
    detail::re_encode_unsafe(
323  
        dest,
323  
        dest,
324  
        end,
324  
        end,
325  
        s0,
325  
        s0,
326  
        detail::param_key_chars);
326  
        detail::param_key_chars);
327  
    if(has_value_)
327  
    if(has_value_)
328  
    {
328  
    {
329  
        *dest++ = '=';
329  
        *dest++ = '=';
330  
        detail::re_encode_unsafe(
330  
        detail::re_encode_unsafe(
331  
            dest,
331  
            dest,
332  
            end,
332  
            end,
333  
            s1,
333  
            s1,
334  
            detail::param_value_chars);
334  
            detail::param_value_chars);
335  
    }
335  
    }
336  
}
336  
}
337  

337  

338  

338  

339  
//------------------------------------------------
339  
//------------------------------------------------
340  
//
340  
//
341  
// params_encoded_iter_base
341  
// params_encoded_iter_base
342  
//
342  
//
343  
//------------------------------------------------
343  
//------------------------------------------------
344  

344  

345  
void
345  
void
346  
params_encoded_iter_base::
346  
params_encoded_iter_base::
347  
measure_impl(
347  
measure_impl(
348  
    std::size_t& n,
348  
    std::size_t& n,
349  
    param_view const& p) noexcept
349  
    param_view const& p) noexcept
350  
{
350  
{
351  
    n += detail::re_encoded_size_unsafe(
351  
    n += detail::re_encoded_size_unsafe(
352  
        p.key,
352  
        p.key,
353  
        detail::param_key_chars);
353  
        detail::param_key_chars);
354  
    if(p.has_value)
354  
    if(p.has_value)
355  
        n += detail::re_encoded_size_unsafe(
355  
        n += detail::re_encoded_size_unsafe(
356  
            p.value,
356  
            p.value,
357  
            detail::param_value_chars) + 1; // for '='
357  
            detail::param_value_chars) + 1; // for '='
358  
}
358  
}
359  

359  

360  
void
360  
void
361  
params_encoded_iter_base::
361  
params_encoded_iter_base::
362  
copy_impl(
362  
copy_impl(
363  
    char*& dest,
363  
    char*& dest,
364  
    char const* end,
364  
    char const* end,
365  
    param_view const& p) noexcept
365  
    param_view const& p) noexcept
366  
{
366  
{
367  
    detail::re_encode_unsafe(
367  
    detail::re_encode_unsafe(
368  
        dest,
368  
        dest,
369  
        end,
369  
        end,
370  
        p.key,
370  
        p.key,
371  
        detail::param_key_chars);
371  
        detail::param_key_chars);
372  
    if(p.has_value)
372  
    if(p.has_value)
373  
    {
373  
    {
374  
        *dest++ = '=';
374  
        *dest++ = '=';
375  
        detail::re_encode_unsafe(
375  
        detail::re_encode_unsafe(
376  
            dest,
376  
            dest,
377  
            end,
377  
            end,
378  
            p.value,
378  
            p.value,
379  
            detail::param_value_chars);
379  
            detail::param_value_chars);
380  
    }
380  
    }
381  
}
381  
}
382  

382  

383  
//------------------------------------------------
383  
//------------------------------------------------
384  
//
384  
//
385  
// param_value_iter
385  
// param_value_iter
386  
//
386  
//
387  
//------------------------------------------------
387  
//------------------------------------------------
388  

388  

389  
void
389  
void
390  
param_value_iter::
390  
param_value_iter::
391  
rewind() noexcept
391  
rewind() noexcept
392  
{
392  
{
393  
    at_end_ = false;
393  
    at_end_ = false;
394  
}
394  
}
395  

395  

396  
bool
396  
bool
397  
param_value_iter::
397  
param_value_iter::
398  
measure(
398  
measure(
399  
    std::size_t& n) noexcept
399  
    std::size_t& n) noexcept
400  
{
400  
{
401  
    if(at_end_)
401  
    if(at_end_)
402  
        return false;
402  
        return false;
403  
    n += nk_; // skip key
403  
    n += nk_; // skip key
404  
    if(has_value_)
404  
    if(has_value_)
405  
    {
405  
    {
406  
        encoding_opts opt;
406  
        encoding_opts opt;
407  
        opt.space_as_plus = false;
407  
        opt.space_as_plus = false;
408  
        n += encoded_size(
408  
        n += encoded_size(
409  
            s0,
409  
            s0,
410  
            detail::param_value_chars,
410  
            detail::param_value_chars,
411  
            opt) + 1; // for '='
411  
            opt) + 1; // for '='
412  
    }
412  
    }
413  
    at_end_ = true;
413  
    at_end_ = true;
414  
    return true;
414  
    return true;
415  
}
415  
}
416  

416  

417  
void
417  
void
418  
param_value_iter::
418  
param_value_iter::
419  
copy(char*& it, char const* end) noexcept
419  
copy(char*& it, char const* end) noexcept
420  
{
420  
{
421  
    it += nk_; // skip key
421  
    it += nk_; // skip key
422  
    if(! has_value_)
422  
    if(! has_value_)
423  
        return;
423  
        return;
424  
    *it++ = '=';
424  
    *it++ = '=';
425  
    encoding_opts opt;
425  
    encoding_opts opt;
426  
    opt.space_as_plus = false;
426  
    opt.space_as_plus = false;
427  
    it += encode(
427  
    it += encode(
428  
        it,
428  
        it,
429  
        end - it,
429  
        end - it,
430  
        s0,
430  
        s0,
431  
        detail::param_value_chars,
431  
        detail::param_value_chars,
432  
        opt);
432  
        opt);
433  
}
433  
}
434  

434  

435  
//------------------------------------------------
435  
//------------------------------------------------
436  
//
436  
//
437  
// param_encoded_value_iter
437  
// param_encoded_value_iter
438  
//
438  
//
439  
//------------------------------------------------
439  
//------------------------------------------------
440  

440  

441  
void
441  
void
442  
param_encoded_value_iter::
442  
param_encoded_value_iter::
443  
rewind() noexcept
443  
rewind() noexcept
444  
{
444  
{
445  
    at_end_ = false;
445  
    at_end_ = false;
446  
}
446  
}
447  

447  

448  
bool
448  
bool
449  
param_encoded_value_iter::
449  
param_encoded_value_iter::
450  
measure(
450  
measure(
451  
    std::size_t& n) noexcept
451  
    std::size_t& n) noexcept
452  
{
452  
{
453  
    if(at_end_)
453  
    if(at_end_)
454  
        return false;
454  
        return false;
455  
    n += nk_; // skip key
455  
    n += nk_; // skip key
456  
    if(has_value_)
456  
    if(has_value_)
457  
    {
457  
    {
458  
        n += detail::re_encoded_size_unsafe(
458  
        n += detail::re_encoded_size_unsafe(
459  
            s0,
459  
            s0,
460  
            detail::param_value_chars) + 1; // for '='
460  
            detail::param_value_chars) + 1; // for '='
461  
    }
461  
    }
462  
    at_end_ = true;
462  
    at_end_ = true;
463  
    return true;
463  
    return true;
464  
}
464  
}
465  

465  

466  
void
466  
void
467  
param_encoded_value_iter::
467  
param_encoded_value_iter::
468  
copy(
468  
copy(
469  
    char*& dest,
469  
    char*& dest,
470  
    char const* end) noexcept
470  
    char const* end) noexcept
471  
{
471  
{
472  
    dest += nk_; // skip key
472  
    dest += nk_; // skip key
473  
    if(! has_value_)
473  
    if(! has_value_)
474  
        return;
474  
        return;
475  
    *dest++ = '=';
475  
    *dest++ = '=';
476  
    detail::re_encode_unsafe(
476  
    detail::re_encode_unsafe(
477  
        dest,
477  
        dest,
478  
        end,
478  
        end,
479  
        s0,
479  
        s0,
480  
        detail::param_value_chars);
480  
        detail::param_value_chars);
481  
}
481  
}
482  

482  

483  
} // detail
483  
} // detail
484  
} // urls
484  
} // urls
485  
} // boost
485  
} // boost
486  

486