libs/url/src/detail/url_impl.cpp

97.4% Lines (225/231) 100.0% Functions (35/35) 84.3% Branches (59/70)
libs/url/src/detail/url_impl.cpp
Line Branch Hits Source Code
1 //
2 // Copyright (c) 2022 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/boostorg/url
8 //
9
10
11 #include <boost/url/detail/config.hpp>
12 #include "path.hpp"
13 #include <boost/url/detail/url_impl.hpp>
14 #include <boost/url/authority_view.hpp>
15 #include <boost/assert.hpp>
16 #include <cstring>
17
18 namespace boost {
19 namespace urls {
20 namespace detail {
21
22 #if defined(__GNUC__) && ! defined(__clang__) && defined(__MINGW32__)
23 #pragma GCC diagnostic push
24 #pragma GCC diagnostic ignored "-Warray-bounds"
25 #endif
26
27 //------------------------------------------------
28 //
29 // url_impl
30 //
31 //------------------------------------------------
32
33 void
34 2422 url_impl::
35 apply_scheme(
36 core::string_view s) noexcept
37 {
38 2422 scheme_ = string_to_scheme(s);
39 2422 set_size(id_scheme, s.size() + 1);
40 2422 }
41
42 void
43 405 url_impl::
44 apply_userinfo(
45 pct_string_view const& user,
46 pct_string_view const* pass) noexcept
47 {
48 // this function is for
49 // authority_view_rule only
50
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 405 times.
405 BOOST_ASSERT(from_ == from::authority);
51
52 // userinfo
53 405 set_size(id_user, user.size());
54 405 decoded_[id_user] =
55 405 detail::to_size_type(
56 user.decoded_size());
57
2/2
✓ Branch 0 taken 270 times.
✓ Branch 1 taken 135 times.
405 if(pass)
58 {
59 270 set_size(id_pass,
60 270 pass->size() + 2);
61 270 decoded_[id_pass] =
62 270 detail::to_size_type(
63 pass->decoded_size());
64 }
65 else
66 {
67 // trailing '@'
68 135 set_size(id_pass, 1 );
69 }
70 405 }
71
72 void
73 2013 url_impl::
74 apply_host(
75 host_type ht,
76 pct_string_view s,
77 unsigned char const* addr) noexcept
78 {
79 // this function is for
80 // authority_view_rule only
81
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2013 times.
2013 BOOST_ASSERT(from_ == from::authority);
82
83 // host, port
84 2013 host_type_ = ht;
85 2013 set_size(id_host, s.size());
86 2013 decoded_[id_host] =
87 2013 detail::to_size_type(
88 s.decoded_size());
89 2013 std::memcpy(
90 2013 ip_addr_,
91 addr,
92 sizeof(ip_addr_));
93 2013 }
94
95 void
96 282 url_impl::
97 apply_port(
98 core::string_view s,
99 unsigned short pn) noexcept
100 {
101 // this function is for
102 // authority_view_rule only
103
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 282 times.
282 BOOST_ASSERT(from_ == from::authority);
104
105 282 port_number_ = pn;
106 282 set_size(id_port, 1 + s.size());
107 282 }
108
109 void
110 1953 url_impl::
111 apply_authority(
112 authority_view const& a) noexcept
113 {
114
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1953 times.
1953 BOOST_ASSERT(from_ != from::authority);
115
116 // userinfo
117 1953 set_size(id_user,
118 1953 a.u_.len(id_user) +
119
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1953 times.
1953 (from_ == from::authority ? 0 : 2));
120 1953 set_size(id_pass, a.u_.len(id_pass));
121 1953 decoded_[id_user] = a.u_.decoded_[id_user];
122 1953 decoded_[id_pass] = a.u_.decoded_[id_pass];
123
124 // host, port
125 1953 host_type_ = a.u_.host_type_;
126 1953 port_number_ = a.u_.port_number_;
127 1953 set_size(id_host, a.u_.len(id_host));
128 1953 set_size(id_port, a.u_.len(id_port));
129 1953 std::memcpy(
130 1953 ip_addr_,
131 1953 a.u_.ip_addr_,
132 sizeof(ip_addr_));
133 1953 decoded_[id_host] = a.u_.decoded_[id_host];
134 1953 }
135
136 void
137 3719 url_impl::
138 apply_path(
139 pct_string_view s,
140 std::size_t nseg) noexcept
141 {
142 3719 set_size(id_path, s.size());
143 3719 decoded_[id_path] =
144 3719 detail::to_size_type(
145 s.decoded_size());
146 3719 nseg_ = detail::to_size_type(
147 detail::path_segments(s, nseg));
148 3719 }
149
150 void
151 482 url_impl::
152 apply_query(
153 pct_string_view s,
154 std::size_t n) noexcept
155 {
156 482 nparam_ = detail::to_size_type(n);
157 482 set_size(id_query, 1 + s.size());
158 482 decoded_[id_query] =
159 482 detail::to_size_type(
160 s.decoded_size());
161 482 }
162
163 void
164 241 url_impl::
165 apply_frag(
166 pct_string_view s) noexcept
167 {
168 241 set_size(id_frag, s.size() + 1);
169 241 decoded_[id_frag] =
170 241 detail::to_size_type(
171 s.decoded_size());
172 241 }
173
174 // return length of [first, last)
175 auto
176 20889 url_impl::
177 len(
178 int first,
179 int last) const noexcept ->
180 std::size_t
181 {
182
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 20889 times.
20889 BOOST_ASSERT(first <= last);
183
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 20889 times.
20889 BOOST_ASSERT(last <= id_end);
184 20889 return offset(last) - offset(first);
185 }
186
187 // return length of part
188 auto
189 275912 url_impl::
190 len(int id) const noexcept ->
191 std::size_t
192 {
193 return id == id_end
194
1/2
✓ Branch 0 taken 275912 times.
✗ Branch 1 not taken.
551824 ? zero_
195 275912 : ( offset(id + 1) -
196 551824 offset(id) );
197 }
198
199 // return offset of id
200 auto
201 721806 url_impl::
202 offset(int id) const noexcept ->
203 std::size_t
204 {
205 return
206 id == id_scheme
207
2/2
✓ Branch 0 taken 667618 times.
✓ Branch 1 taken 54188 times.
721806 ? zero_
208 721806 : offset_[id];
209 }
210
211 // return id as string
212 core::string_view
213 49275 url_impl::
214 get(int id) const noexcept
215 {
216 return {
217 49275 cs_ + offset(id), len(id) };
218 }
219
220 // return [first, last) as string
221 core::string_view
222 926 url_impl::
223 get(int first,
224 int last) const noexcept
225 {
226 926 return { cs_ + offset(first),
227 926 offset(last) - offset(first) };
228 }
229
230 // return id as pct-string
231 pct_string_view
232 2309 url_impl::
233 pct_get(
234 int id) const noexcept
235 {
236 2309 return make_pct_string_view_unsafe(
237 2309 cs_ + offset(id),
238 len(id),
239 4618 decoded_[id]);
240 }
241
242 // return [first, last) as pct-string
243 pct_string_view
244 120 url_impl::
245 pct_get(
246 int first,
247 int last) const noexcept
248 {
249 120 auto const pos = offset(first);
250 120 std::size_t n = 0;
251
2/2
✓ Branch 0 taken 240 times.
✓ Branch 1 taken 120 times.
360 for(auto i = first; i < last;)
252 240 n += decoded_[i++];
253 120 return make_pct_string_view_unsafe(
254 120 cs_ + pos,
255 120 offset(last) - pos,
256 120 n);
257 }
258
259 //------------------------------------------------
260
261 // change id to size n
262 void
263 20564 url_impl::
264 set_size(
265 int id,
266 std::size_t n) noexcept
267 {
268 20564 auto const cur = len(id);
269
2/2
✓ Branch 0 taken 20199 times.
✓ Branch 1 taken 365 times.
20564 if(n >= cur)
270 {
271 20199 auto const d = n - cur;
272 20199 for(auto i = id + 1;
273
2/2
✓ Branch 0 taken 103048 times.
✓ Branch 1 taken 20199 times.
123247 i <= id_end; ++i)
274 103048 offset_[i] += detail::to_size_type(d);
275 20199 return;
276 }
277 365 auto const d = cur - n;
278 365 for(auto i = id + 1;
279
2/2
✓ Branch 0 taken 1429 times.
✓ Branch 1 taken 365 times.
1794 i <= id_end; ++i)
280 1429 offset_[i] -= detail::to_size_type(d);
281 }
282
283 // trim id to size n,
284 // moving excess into id+1
285 void
286 861 url_impl::
287 split(
288 int id,
289 std::size_t n) noexcept
290 {
291
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 861 times.
861 BOOST_ASSERT(id < id_end - 1);
292 //BOOST_ASSERT(n <= len(id));
293 861 offset_[id + 1] = detail::to_size_type(
294 861 offset(id) + n);
295 861 }
296
297 // add n to [first, last]
298 void
299 957 url_impl::
300 adjust_right(
301 int first,
302 int last,
303 std::size_t n) noexcept
304 {
305 957 for(int i = first;
306
2/2
✓ Branch 0 taken 4617 times.
✓ Branch 1 taken 957 times.
5574 i <= last; ++i)
307 4617 offset_[i] += detail::to_size_type(n);
308 957 }
309
310 // remove n from [first, last]
311 void
312 721 url_impl::
313 adjust_left(
314 int first,
315 int last,
316 std::size_t n) noexcept
317 {
318 721 for(int i = first;
319
2/2
✓ Branch 0 taken 2837 times.
✓ Branch 1 taken 721 times.
3558 i <= last; ++i)
320 2837 offset_[i] -= detail::to_size_type(n);
321 721 }
322
323 // set [first, last) offset
324 void
325 1659 url_impl::
326 collapse(
327 int first,
328 int last,
329 std::size_t n) noexcept
330 {
331 1659 for(int i = first + 1;
332
2/2
✓ Branch 0 taken 547 times.
✓ Branch 1 taken 1659 times.
2206 i < last; ++i)
333 547 offset_[i] = detail::to_size_type(n);
334 1659 }
335
336
337 //------------------------------------------------
338 //
339 // path_ref
340 //
341 //------------------------------------------------
342
343 2096 path_ref::
344 path_ref(
345 2096 url_impl const& impl) noexcept
346 {
347
2/2
✓ Branch 0 taken 1594 times.
✓ Branch 1 taken 502 times.
2096 if(impl.from_ == url_impl::from::url)
348 {
349 1594 impl_ = &impl;
350 }
351 else
352 {
353 502 core::string_view s = impl.get(id_path);
354 502 data_ = s.data();
355 502 size_ = s.size();
356 502 nseg_ = impl.nseg_;
357 502 dn_ = impl.decoded_[id_path];
358 }
359 2096 }
360
361 181 path_ref::
362 path_ref(
363 core::string_view s,
364 std::size_t dn,
365 181 std::size_t nseg) noexcept
366 362 : data_(s.data())
367 181 , size_(s.size())
368 181 , nseg_(nseg)
369 181 , dn_(dn)
370 {
371 181 }
372
373 pct_string_view
374 4738 path_ref::
375 buffer() const noexcept
376 {
377
2/2
✓ Branch 0 taken 2392 times.
✓ Branch 1 taken 2346 times.
4738 if(impl_)
378 2392 return make_pct_string_view_unsafe(
379 2392 impl_->cs_ +
380 2392 impl_->offset(id_path),
381 2392 impl_->len(id_path),
382 4784 impl_->decoded_[id_path]);
383 2346 return make_pct_string_view_unsafe(
384 2346 data_, size_, dn_);
385 }
386
387 std::size_t
388 4487 path_ref::
389 size() const noexcept
390 {
391
2/2
✓ Branch 0 taken 3116 times.
✓ Branch 1 taken 1371 times.
4487 if(impl_)
392 3116 return impl_->len(id_path);
393 1371 return size_;
394 }
395
396 char const*
397 12995 path_ref::
398 data() const noexcept
399 {
400
2/2
✓ Branch 0 taken 7472 times.
✓ Branch 1 taken 5523 times.
12995 if(impl_)
401 7472 return impl_->cs_ +
402 7472 impl_->offset(id_path);
403 5523 return data_;
404 }
405
406 char const*
407 4460 path_ref::
408 end() const noexcept
409 {
410
2/2
✓ Branch 0 taken 2842 times.
✓ Branch 1 taken 1618 times.
4460 if(impl_)
411 2842 return impl_->cs_ +
412 2842 impl_->offset(id_query);
413 1618 return data_ + size_;
414 }
415
416 std::size_t
417 9622 path_ref::
418 nseg() const noexcept
419 {
420
2/2
✓ Branch 0 taken 6161 times.
✓ Branch 1 taken 3461 times.
9622 if(impl_)
421 6161 return impl_->nseg_;
422 3461 return nseg_;
423 }
424
425 std::size_t
426 2040 path_ref::
427 decoded_size() const noexcept
428 {
429
2/2
✓ Branch 0 taken 1359 times.
✓ Branch 1 taken 681 times.
2040 if(impl_)
430 1359 return impl_->decoded_[id_path];
431 681 return dn_;
432 }
433
434 //------------------------------------------------
435 //
436 // query_ref
437 //
438 //------------------------------------------------
439
440 737 query_ref::
441 query_ref(
442 core::string_view s,
443 std::size_t dn,
444 737 std::size_t nparam) noexcept
445 1474 : data_(s.data())
446 737 , size_(s.size())
447 737 , nparam_(nparam)
448 737 , dn_(dn)
449 {
450 737 }
451
452 479 query_ref::
453 query_ref(
454 479 url_impl const& impl) noexcept
455 {
456
2/2
✓ Branch 0 taken 362 times.
✓ Branch 1 taken 117 times.
479 if(impl.from_ == url_impl::from::url)
457 {
458 362 impl_ = &impl;
459 }
460 else
461 {
462 117 core::string_view s = impl.get(id_query);
463
2/2
✓ Branch 1 taken 111 times.
✓ Branch 2 taken 6 times.
117 if (!s.empty())
464 {
465 111 s.remove_prefix(1);
466 111 question_mark_ = true;
467 }
468 117 data_ = s.data();
469 117 size_ = s.size();
470 117 nparam_ = impl.nparam_;
471 117 dn_ = impl.decoded_[id_query];
472 }
473 479 }
474
475 pct_string_view
476 506 query_ref::
477 buffer() const noexcept
478 {
479
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 504 times.
506 if(impl_)
480 {
481 2 auto pos = impl_->offset_[id_query];
482 2 auto pos1 = impl_->offset_[id_frag];
483
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if(pos < pos1)
484 {
485 ++pos; // no '?'
486 return make_pct_string_view_unsafe(
487 impl_->cs_ + pos,
488 pos1 - pos,
489 impl_->decoded_[id_query]);
490 }
491 // empty
492 2 return make_pct_string_view_unsafe(
493 2 impl_->cs_ + pos,
494 0,
495 2 0);
496 }
497 // no '?'
498 504 return make_pct_string_view_unsafe(
499 504 data_, size_, dn_);
500 }
501
502 // with '?'
503 std::size_t
504 5562 query_ref::
505 size() const noexcept
506 {
507
2/2
✓ Branch 0 taken 2029 times.
✓ Branch 1 taken 3533 times.
5562 if(impl_)
508 2029 return impl_->len(id_query);
509
2/2
✓ Branch 0 taken 3496 times.
✓ Branch 1 taken 37 times.
3533 if(size_ > 0)
510 3496 return size_ + 1;
511 37 return question_mark_;
512 }
513
514 // no '?'
515 char const*
516 6034 query_ref::
517 begin() const noexcept
518 {
519
2/2
✓ Branch 0 taken 2288 times.
✓ Branch 1 taken 3746 times.
6034 if(impl_)
520 {
521 // using the offset array here
522 2288 auto pos = impl_->offset_[id_query];
523 2288 auto pos1 = impl_->offset_[id_frag];
524
1/2
✓ Branch 0 taken 2288 times.
✗ Branch 1 not taken.
2288 if(pos < pos1)
525 2288 return impl_->cs_ + pos + 1; // no '?'
526 // empty
527 return impl_->cs_ + pos;
528 }
529 3746 return data_;
530
531 }
532
533 char const*
534 2380 query_ref::
535 end() const noexcept
536 {
537
2/2
✓ Branch 0 taken 917 times.
✓ Branch 1 taken 1463 times.
2380 if(impl_)
538 917 return impl_->cs_ +
539 917 impl_->offset(id_frag);
540 1463 return data_ + size_;
541 }
542
543 std::size_t
544 9344 query_ref::
545 nparam() const noexcept
546 {
547
2/2
✓ Branch 0 taken 3171 times.
✓ Branch 1 taken 6173 times.
9344 if(impl_)
548 3171 return impl_->nparam_;
549 6173 return nparam_;
550 }
551
552 #if defined(__GNUC__) && ! defined(__clang__) && defined(__MINGW32__)
553 #pragma GCC diagnostic pop
554 #endif
555
556 } // detail
557 } // urls
558 } // boost
559