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 2249 : url_impl::
35 : apply_scheme(
36 : core::string_view s) noexcept
37 : {
38 2249 : scheme_ = string_to_scheme(s);
39 2249 : set_size(id_scheme, s.size() + 1);
40 2249 : }
41 :
42 : void
43 381 : 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 381 : BOOST_ASSERT(from_ == from::authority);
51 :
52 : // userinfo
53 381 : set_size(id_user, user.size());
54 381 : decoded_[id_user] =
55 381 : user.decoded_size();
56 381 : if(pass)
57 : {
58 252 : set_size(id_pass,
59 252 : pass->size() + 2);
60 252 : decoded_[id_pass] =
61 252 : pass->decoded_size();
62 : }
63 : else
64 : {
65 : // trailing '@'
66 129 : set_size(id_pass, 1 );
67 : }
68 381 : }
69 :
70 : void
71 1853 : url_impl::
72 : apply_host(
73 : host_type ht,
74 : pct_string_view s,
75 : unsigned char const* addr) noexcept
76 : {
77 : // this function is for
78 : // authority_view_rule only
79 1853 : BOOST_ASSERT(from_ == from::authority);
80 :
81 : // host, port
82 1853 : host_type_ = ht;
83 1853 : set_size(id_host, s.size());
84 1853 : decoded_[id_host] =
85 1853 : s.decoded_size();
86 1853 : std::memcpy(
87 1853 : ip_addr_,
88 : addr,
89 : sizeof(ip_addr_));
90 1853 : }
91 :
92 : void
93 258 : url_impl::
94 : apply_port(
95 : core::string_view s,
96 : unsigned short pn) noexcept
97 : {
98 : // this function is for
99 : // authority_view_rule only
100 258 : BOOST_ASSERT(from_ == from::authority);
101 :
102 258 : port_number_ = pn;
103 258 : set_size(id_port, 1 + s.size());
104 258 : }
105 :
106 : void
107 1795 : url_impl::
108 : apply_authority(
109 : authority_view const& a) noexcept
110 : {
111 1795 : BOOST_ASSERT(from_ != from::authority);
112 :
113 : // userinfo
114 1795 : set_size(id_user,
115 1795 : a.u_.len(id_user) +
116 1795 : (from_ == from::authority ? 0 : 2));
117 1795 : set_size(id_pass, a.u_.len(id_pass));
118 1795 : decoded_[id_user] = a.u_.decoded_[id_user];
119 1795 : decoded_[id_pass] = a.u_.decoded_[id_pass];
120 :
121 : // host, port
122 1795 : host_type_ = a.u_.host_type_;
123 1795 : port_number_ = a.u_.port_number_;
124 1795 : set_size(id_host, a.u_.len(id_host));
125 1795 : set_size(id_port, a.u_.len(id_port));
126 1795 : std::memcpy(
127 1795 : ip_addr_,
128 1795 : a.u_.ip_addr_,
129 : sizeof(ip_addr_));
130 1795 : decoded_[id_host] = a.u_.decoded_[id_host];
131 1795 : }
132 :
133 : void
134 3522 : url_impl::
135 : apply_path(
136 : pct_string_view s,
137 : std::size_t nseg) noexcept
138 : {
139 3522 : set_size(id_path, s.size());
140 3522 : decoded_[id_path] = s.decoded_size();
141 3522 : nseg_ = detail::path_segments(s, nseg);
142 3522 : }
143 :
144 : void
145 429 : url_impl::
146 : apply_query(
147 : pct_string_view s,
148 : std::size_t n) noexcept
149 : {
150 429 : nparam_ = n;
151 429 : set_size(id_query, 1 + s.size());
152 429 : decoded_[id_query] = s.decoded_size();
153 429 : }
154 :
155 : void
156 210 : url_impl::
157 : apply_frag(
158 : pct_string_view s) noexcept
159 : {
160 210 : set_size(id_frag, s.size() + 1);
161 210 : decoded_[id_frag] = s.decoded_size();
162 210 : }
163 :
164 : // return length of [first, last)
165 : auto
166 20032 : url_impl::
167 : len(
168 : int first,
169 : int last) const noexcept ->
170 : std::size_t
171 : {
172 20032 : BOOST_ASSERT(first <= last);
173 20032 : BOOST_ASSERT(last <= id_end);
174 20032 : return offset(last) - offset(first);
175 : }
176 :
177 : // return length of part
178 : auto
179 263489 : url_impl::
180 : len(int id) const noexcept ->
181 : std::size_t
182 : {
183 : return id == id_end
184 526978 : ? zero_
185 263489 : : ( offset(id + 1) -
186 526978 : offset(id) );
187 : }
188 :
189 : // return offset of id
190 : auto
191 690051 : url_impl::
192 : offset(int id) const noexcept ->
193 : std::size_t
194 : {
195 : return
196 : id == id_scheme
197 690051 : ? zero_
198 690051 : : offset_[id];
199 : }
200 :
201 : // return id as string
202 : core::string_view
203 46910 : url_impl::
204 : get(int id) const noexcept
205 : {
206 : return {
207 46910 : cs_ + offset(id), len(id) };
208 : }
209 :
210 : // return [first, last) as string
211 : core::string_view
212 867 : url_impl::
213 : get(int first,
214 : int last) const noexcept
215 : {
216 867 : return { cs_ + offset(first),
217 867 : offset(last) - offset(first) };
218 : }
219 :
220 : // return id as pct-string
221 : pct_string_view
222 2136 : url_impl::
223 : pct_get(
224 : int id) const noexcept
225 : {
226 2136 : return make_pct_string_view_unsafe(
227 2136 : cs_ + offset(id),
228 : len(id),
229 4272 : decoded_[id]);
230 : }
231 :
232 : // return [first, last) as pct-string
233 : pct_string_view
234 120 : url_impl::
235 : pct_get(
236 : int first,
237 : int last) const noexcept
238 : {
239 120 : auto const pos = offset(first);
240 120 : std::size_t n = 0;
241 360 : for(auto i = first; i < last;)
242 240 : n += decoded_[i++];
243 120 : return make_pct_string_view_unsafe(
244 120 : cs_ + pos,
245 120 : offset(last) - pos,
246 120 : n);
247 : }
248 :
249 : //------------------------------------------------
250 :
251 : // change id to size n
252 : void
253 19086 : url_impl::
254 : set_size(
255 : int id,
256 : std::size_t n) noexcept
257 : {
258 19086 : auto d = n - len(id);
259 19086 : for(auto i = id + 1;
260 115918 : i <= id_end; ++i)
261 96832 : offset_[i] += d;
262 19086 : }
263 :
264 : // trim id to size n,
265 : // moving excess into id+1
266 : void
267 781 : url_impl::
268 : split(
269 : int id,
270 : std::size_t n) noexcept
271 : {
272 781 : BOOST_ASSERT(id < id_end - 1);
273 : //BOOST_ASSERT(n <= len(id));
274 781 : offset_[id + 1] = offset(id) + n;
275 781 : }
276 :
277 : // add n to [first, last]
278 : void
279 881 : url_impl::
280 : adjust_right(
281 : int first,
282 : int last,
283 : std::size_t n) noexcept
284 : {
285 881 : for(int i = first;
286 5122 : i <= last; ++i)
287 4241 : offset_[i] += n;
288 881 : }
289 :
290 : // remove n from [first, last]
291 : void
292 671 : url_impl::
293 : adjust_left(
294 : int first,
295 : int last,
296 : std::size_t n) noexcept
297 : {
298 671 : for(int i = first;
299 3311 : i <= last; ++i)
300 2640 : offset_[i] -= n;
301 671 : }
302 :
303 : // set [first, last) offset
304 : void
305 1533 : url_impl::
306 : collapse(
307 : int first,
308 : int last,
309 : std::size_t n) noexcept
310 : {
311 1533 : for(int i = first + 1;
312 2078 : i < last; ++i)
313 545 : offset_[i] = n;
314 1533 : }
315 :
316 :
317 : //------------------------------------------------
318 : //
319 : // path_ref
320 : //
321 : //------------------------------------------------
322 :
323 2019 : path_ref::
324 : path_ref(
325 2019 : url_impl const& impl) noexcept
326 : {
327 2019 : if(impl.from_ == url_impl::from::url)
328 : {
329 1568 : impl_ = &impl;
330 : }
331 : else
332 : {
333 451 : core::string_view s = impl.get(id_path);
334 451 : data_ = s.data();
335 451 : size_ = s.size();
336 451 : nseg_ = impl.nseg_;
337 451 : dn_ = impl.decoded_[id_path];
338 : }
339 2019 : }
340 :
341 141 : path_ref::
342 : path_ref(
343 : core::string_view s,
344 : std::size_t dn,
345 141 : std::size_t nseg) noexcept
346 282 : : data_(s.data())
347 141 : , size_(s.size())
348 141 : , nseg_(nseg)
349 141 : , dn_(dn)
350 : {
351 141 : }
352 :
353 : pct_string_view
354 4475 : path_ref::
355 : buffer() const noexcept
356 : {
357 4475 : if(impl_)
358 2318 : return make_pct_string_view_unsafe(
359 2318 : impl_->cs_ +
360 2318 : impl_->offset(id_path),
361 2318 : impl_->len(id_path),
362 4636 : impl_->decoded_[id_path]);
363 2157 : return make_pct_string_view_unsafe(
364 2157 : data_, size_, dn_);
365 : }
366 :
367 : std::size_t
368 3901 : path_ref::
369 : size() const noexcept
370 : {
371 3901 : if(impl_)
372 2657 : return impl_->len(id_path);
373 1244 : return size_;
374 : }
375 :
376 : char const*
377 12586 : path_ref::
378 : data() const noexcept
379 : {
380 12586 : if(impl_)
381 7437 : return impl_->cs_ +
382 7437 : impl_->offset(id_path);
383 5149 : return data_;
384 : }
385 :
386 : char const*
387 4399 : path_ref::
388 : end() const noexcept
389 : {
390 4399 : if(impl_)
391 2944 : return impl_->cs_ +
392 2944 : impl_->offset(id_query);
393 1455 : return data_ + size_;
394 : }
395 :
396 : std::size_t
397 8628 : path_ref::
398 : nseg() const noexcept
399 : {
400 8628 : if(impl_)
401 5507 : return impl_->nseg_;
402 3121 : return nseg_;
403 : }
404 :
405 : //------------------------------------------------
406 : //
407 : // query_ref
408 : //
409 : //------------------------------------------------
410 :
411 673 : query_ref::
412 : query_ref(
413 : core::string_view s,
414 : std::size_t dn,
415 673 : std::size_t nparam) noexcept
416 1346 : : data_(s.data())
417 673 : , size_(s.size())
418 673 : , nparam_(nparam)
419 673 : , dn_(dn)
420 : {
421 673 : }
422 :
423 425 : query_ref::
424 : query_ref(
425 425 : url_impl const& impl) noexcept
426 : {
427 425 : if(impl.from_ == url_impl::from::url)
428 : {
429 344 : impl_ = &impl;
430 : }
431 : else
432 : {
433 81 : core::string_view s = impl.get(id_query);
434 81 : if (!s.empty())
435 : {
436 79 : s.remove_prefix(1);
437 79 : question_mark_ = true;
438 : }
439 81 : data_ = s.data();
440 81 : size_ = s.size();
441 81 : nparam_ = impl.nparam_;
442 81 : dn_ = impl.decoded_[id_query];
443 : }
444 425 : }
445 :
446 : pct_string_view
447 453 : query_ref::
448 : buffer() const noexcept
449 : {
450 453 : if(impl_)
451 : {
452 2 : auto pos = impl_->offset_[id_query];
453 2 : auto pos1 = impl_->offset_[id_frag];
454 2 : if(pos < pos1)
455 : {
456 0 : ++pos; // no '?'
457 0 : return make_pct_string_view_unsafe(
458 0 : impl_->cs_ + pos,
459 : pos1 - pos,
460 0 : impl_->decoded_[id_query]);
461 : }
462 : // empty
463 2 : return make_pct_string_view_unsafe(
464 2 : impl_->cs_ + pos,
465 : 0,
466 2 : 0);
467 : }
468 : // no '?'
469 451 : return make_pct_string_view_unsafe(
470 451 : data_, size_, dn_);
471 : }
472 :
473 : // with '?'
474 : std::size_t
475 5282 : query_ref::
476 : size() const noexcept
477 : {
478 5282 : if(impl_)
479 1990 : return impl_->len(id_query);
480 3292 : if(size_ > 0)
481 3264 : return size_ + 1;
482 28 : return question_mark_;
483 : }
484 :
485 : // no '?'
486 : char const*
487 5807 : query_ref::
488 : begin() const noexcept
489 : {
490 5807 : if(impl_)
491 : {
492 : // using the offset array here
493 2267 : auto pos = impl_->offset_[id_query];
494 2267 : auto pos1 = impl_->offset_[id_frag];
495 2267 : if(pos < pos1)
496 2267 : return impl_->cs_ + pos + 1; // no '?'
497 : // empty
498 0 : return impl_->cs_ + pos;
499 : }
500 3540 : return data_;
501 :
502 : }
503 :
504 : char const*
505 2282 : query_ref::
506 : end() const noexcept
507 : {
508 2282 : if(impl_)
509 902 : return impl_->cs_ +
510 902 : impl_->offset(id_frag);
511 1380 : return data_ + size_;
512 : }
513 :
514 : std::size_t
515 8885 : query_ref::
516 : nparam() const noexcept
517 : {
518 8885 : if(impl_)
519 3134 : return impl_->nparam_;
520 5751 : return nparam_;
521 : }
522 :
523 : #if defined(__GNUC__) && ! defined(__clang__) && defined(__MINGW32__)
524 : #pragma GCC diagnostic pop
525 : #endif
526 :
527 : } // detail
528 : } // urls
529 : } // boost
530 :
|