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 2265 : url_impl::
35 : apply_scheme(
36 : core::string_view s) noexcept
37 : {
38 2265 : scheme_ = string_to_scheme(s);
39 2265 : set_size(id_scheme, s.size() + 1);
40 2265 : }
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 1866 : 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 1866 : BOOST_ASSERT(from_ == from::authority);
80 :
81 : // host, port
82 1866 : host_type_ = ht;
83 1866 : set_size(id_host, s.size());
84 1866 : decoded_[id_host] =
85 1866 : s.decoded_size();
86 1866 : std::memcpy(
87 1866 : ip_addr_,
88 : addr,
89 : sizeof(ip_addr_));
90 1866 : }
91 :
92 : void
93 260 : 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 260 : BOOST_ASSERT(from_ == from::authority);
101 :
102 260 : port_number_ = pn;
103 260 : set_size(id_port, 1 + s.size());
104 260 : }
105 :
106 : void
107 1808 : url_impl::
108 : apply_authority(
109 : authority_view const& a) noexcept
110 : {
111 1808 : BOOST_ASSERT(from_ != from::authority);
112 :
113 : // userinfo
114 1808 : set_size(id_user,
115 1808 : a.u_.len(id_user) +
116 1808 : (from_ == from::authority ? 0 : 2));
117 1808 : set_size(id_pass, a.u_.len(id_pass));
118 1808 : decoded_[id_user] = a.u_.decoded_[id_user];
119 1808 : decoded_[id_pass] = a.u_.decoded_[id_pass];
120 :
121 : // host, port
122 1808 : host_type_ = a.u_.host_type_;
123 1808 : port_number_ = a.u_.port_number_;
124 1808 : set_size(id_host, a.u_.len(id_host));
125 1808 : set_size(id_port, a.u_.len(id_port));
126 1808 : std::memcpy(
127 1808 : ip_addr_,
128 1808 : a.u_.ip_addr_,
129 : sizeof(ip_addr_));
130 1808 : decoded_[id_host] = a.u_.decoded_[id_host];
131 1808 : }
132 :
133 : void
134 3540 : url_impl::
135 : apply_path(
136 : pct_string_view s,
137 : std::size_t nseg) noexcept
138 : {
139 3540 : set_size(id_path, s.size());
140 3540 : decoded_[id_path] = s.decoded_size();
141 3540 : nseg_ = detail::path_segments(s, nseg);
142 3540 : }
143 :
144 : void
145 430 : url_impl::
146 : apply_query(
147 : pct_string_view s,
148 : std::size_t n) noexcept
149 : {
150 430 : nparam_ = n;
151 430 : set_size(id_query, 1 + s.size());
152 430 : decoded_[id_query] = s.decoded_size();
153 430 : }
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 20207 : url_impl::
167 : len(
168 : int first,
169 : int last) const noexcept ->
170 : std::size_t
171 : {
172 20207 : BOOST_ASSERT(first <= last);
173 20207 : BOOST_ASSERT(last <= id_end);
174 20207 : return offset(last) - offset(first);
175 : }
176 :
177 : // return length of part
178 : auto
179 265467 : url_impl::
180 : len(int id) const noexcept ->
181 : std::size_t
182 : {
183 : return id == id_end
184 530934 : ? zero_
185 265467 : : ( offset(id + 1) -
186 530934 : offset(id) );
187 : }
188 :
189 : // return offset of id
190 : auto
191 695348 : url_impl::
192 : offset(int id) const noexcept ->
193 : std::size_t
194 : {
195 : return
196 : id == id_scheme
197 695348 : ? zero_
198 695348 : : offset_[id];
199 : }
200 :
201 : // return id as string
202 : core::string_view
203 47265 : url_impl::
204 : get(int id) const noexcept
205 : {
206 : return {
207 47265 : cs_ + offset(id), len(id) };
208 : }
209 :
210 : // return [first, last) as string
211 : core::string_view
212 873 : url_impl::
213 : get(int first,
214 : int last) const noexcept
215 : {
216 873 : return { cs_ + offset(first),
217 873 : offset(last) - offset(first) };
218 : }
219 :
220 : // return id as pct-string
221 : pct_string_view
222 2167 : url_impl::
223 : pct_get(
224 : int id) const noexcept
225 : {
226 : return make_pct_string_view_unsafe(
227 2167 : cs_ + offset(id),
228 : len(id),
229 4334 : 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 : 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 19212 : url_impl::
254 : set_size(
255 : int id,
256 : std::size_t n) noexcept
257 : {
258 19212 : auto d = n - len(id);
259 19212 : for(auto i = id + 1;
260 116719 : i <= id_end; ++i)
261 97507 : offset_[i] += d;
262 19212 : }
263 :
264 : // trim id to size n,
265 : // moving excess into id+1
266 : void
267 811 : url_impl::
268 : split(
269 : int id,
270 : std::size_t n) noexcept
271 : {
272 811 : BOOST_ASSERT(id < id_end - 1);
273 : //BOOST_ASSERT(n <= len(id));
274 811 : offset_[id + 1] = offset(id) + n;
275 811 : }
276 :
277 : // add n to [first, last]
278 : void
279 911 : url_impl::
280 : adjust_right(
281 : int first,
282 : int last,
283 : std::size_t n) noexcept
284 : {
285 911 : for(int i = first;
286 5305 : i <= last; ++i)
287 4394 : offset_[i] += n;
288 911 : }
289 :
290 : // remove n from [first, last]
291 : void
292 676 : url_impl::
293 : adjust_left(
294 : int first,
295 : int last,
296 : std::size_t n) noexcept
297 : {
298 676 : for(int i = first;
299 3333 : i <= last; ++i)
300 2657 : offset_[i] -= n;
301 676 : }
302 :
303 : // set [first, last) offset
304 : void
305 1568 : url_impl::
306 : collapse(
307 : int first,
308 : int last,
309 : std::size_t n) noexcept
310 : {
311 1568 : for(int i = first + 1;
312 2113 : i < last; ++i)
313 545 : offset_[i] = n;
314 1568 : }
315 :
316 :
317 : //------------------------------------------------
318 : //
319 : // path_ref
320 : //
321 : //------------------------------------------------
322 :
323 2027 : path_ref::
324 : path_ref(
325 2027 : url_impl const& impl) noexcept
326 : {
327 2027 : if(impl.from_ == url_impl::from::url)
328 : {
329 1571 : impl_ = &impl;
330 : }
331 : else
332 : {
333 456 : core::string_view s = impl.get(id_path);
334 456 : data_ = s.data();
335 456 : size_ = s.size();
336 456 : nseg_ = impl.nseg_;
337 456 : dn_ = impl.decoded_[id_path];
338 : }
339 2027 : }
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 141 : : data_(s.data())
347 141 : , size_(s.size())
348 : , nseg_(nseg)
349 141 : , dn_(dn)
350 : {
351 141 : }
352 :
353 : pct_string_view
354 4517 : path_ref::
355 : buffer() const noexcept
356 : {
357 4517 : if(impl_)
358 : return make_pct_string_view_unsafe(
359 2333 : impl_->cs_ +
360 2333 : impl_->offset(id_path),
361 2333 : impl_->len(id_path),
362 4666 : impl_->decoded_[id_path]);
363 : return make_pct_string_view_unsafe(
364 2184 : data_, size_, dn_);
365 : }
366 :
367 : std::size_t
368 3927 : path_ref::
369 : size() const noexcept
370 : {
371 3927 : if(impl_)
372 2665 : return impl_->len(id_path);
373 1262 : return size_;
374 : }
375 :
376 : char const*
377 12658 : path_ref::
378 : data() const noexcept
379 : {
380 12658 : if(impl_)
381 7463 : return impl_->cs_ +
382 7463 : impl_->offset(id_path);
383 5195 : return data_;
384 : }
385 :
386 : char const*
387 4421 : path_ref::
388 : end() const noexcept
389 : {
390 4421 : if(impl_)
391 2951 : return impl_->cs_ +
392 2951 : impl_->offset(id_query);
393 1470 : return data_ + size_;
394 : }
395 :
396 : std::size_t
397 8654 : path_ref::
398 : nseg() const noexcept
399 : {
400 8654 : if(impl_)
401 5514 : return impl_->nseg_;
402 3140 : return nseg_;
403 : }
404 :
405 : //------------------------------------------------
406 : //
407 : // query_ref
408 : //
409 : //------------------------------------------------
410 :
411 674 : query_ref::
412 : query_ref(
413 : core::string_view s,
414 : std::size_t dn,
415 674 : std::size_t nparam) noexcept
416 674 : : data_(s.data())
417 674 : , size_(s.size())
418 : , nparam_(nparam)
419 674 : , dn_(dn)
420 : {
421 674 : }
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 454 : query_ref::
448 : buffer() const noexcept
449 : {
450 454 : 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 : return make_pct_string_view_unsafe(
458 0 : impl_->cs_ + pos,
459 : pos1 - pos,
460 0 : impl_->decoded_[id_query]);
461 : }
462 : // empty
463 : return make_pct_string_view_unsafe(
464 2 : impl_->cs_ + pos,
465 : 0,
466 2 : 0);
467 : }
468 : // no '?'
469 : return make_pct_string_view_unsafe(
470 452 : 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 8886 : query_ref::
516 : nparam() const noexcept
517 : {
518 8886 : if(impl_)
519 3134 : return impl_->nparam_;
520 5752 : 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 :
|