Line data 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 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 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 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 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 1953 : BOOST_ASSERT(from_ != from::authority);
115 :
116 : // userinfo
117 1953 : set_size(id_user,
118 1953 : a.u_.len(id_user) +
119 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 20889 : BOOST_ASSERT(first <= last);
183 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 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 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 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 20564 : if(n >= cur)
270 : {
271 20199 : auto const d = n - cur;
272 20199 : for(auto i = id + 1;
273 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 506 : if(impl_)
480 : {
481 2 : auto pos = impl_->offset_[id_query];
482 2 : auto pos1 = impl_->offset_[id_frag];
483 2 : if(pos < pos1)
484 : {
485 0 : ++pos; // no '?'
486 0 : return make_pct_string_view_unsafe(
487 0 : impl_->cs_ + pos,
488 0 : pos1 - pos,
489 0 : 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 5562 : if(impl_)
508 2029 : return impl_->len(id_query);
509 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 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 2288 : if(pos < pos1)
525 2288 : return impl_->cs_ + pos + 1; // no '?'
526 : // empty
527 0 : 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 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 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
|