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