LCOV - code coverage report
Current view: top level - core/core/utils - SPUrl.cc (source / functions) Hit Total Coverage
Test: coverage.info Lines: 341 381 89.5 %
Date: 2024-05-12 00:16:13 Functions: 19 22 86.4 %

          Line data    Source code
       1             : /**
       2             : Copyright (c) 2016-2019 Roman Katuntsev <sbkarr@stappler.org>
       3             : Copyright (c) 2023 Stappler LLC <admin@stappler.dev>
       4             : 
       5             : Permission is hereby granted, free of charge, to any person obtaining a copy
       6             : of this software and associated documentation files (the "Software"), to deal
       7             : in the Software without restriction, including without limitation the rights
       8             : to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
       9             : copies of the Software, and to permit persons to whom the Software is
      10             : furnished to do so, subject to the following conditions:
      11             : 
      12             : The above copyright notice and this permission notice shall be included in
      13             : all copies or substantial portions of the Software.
      14             : 
      15             : THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
      16             : IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      17             : FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
      18             : AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      19             : LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
      20             : OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
      21             : THE SOFTWARE.
      22             : **/
      23             : 
      24             : #include "SPUrl.h"
      25             : #include "SPString.h"
      26             : #include "SPStringView.h"
      27             : #include "SPUrlTld.hpp"
      28             : 
      29             : namespace STAPPLER_VERSIONIZED stappler {
      30             : 
      31             : using Scheme =  chars::Compose<char, chars::CharGroup<char, CharGroupId::Alphanumeric>, chars::Chars<char, '+', '-', '.'>>;
      32             : using Ipv6 =  chars::Compose<char, chars::CharGroup<char, CharGroupId::Hexadecimial>, chars::Chars<char, ':'>>;
      33             : 
      34             : using Unreserved = chars::Compose<char, chars::CharGroup<char, CharGroupId::Alphanumeric>, chars::Chars<char, '-', '.', '_', '~', '%'>>;
      35             : using SubDelim = chars::Chars<char, '!', '$', '&', '\'', '(', ')', '*', '+', ',', ';', '='>;
      36             : using GenDelim = chars::Chars<char, ':', '/', '?', '#', '[', ']', '@'>;
      37             : 
      38             : using UnreservedUni = chars::Compose<char, Unreserved, chars::UniChar>;
      39             : 
      40        1050 : static bool validateScheme(const StringView &r) {
      41        1050 :         auto cpy = r;
      42        1050 :         if (cpy.is<StringView::Compose<StringView::CharGroup<CharGroupId::Alphanumeric>, StringView::Chars<'.'>>>()) {
      43        1050 :                 cpy ++;
      44        1050 :                 cpy.skipChars<Scheme>();
      45        1050 :                 if (cpy.empty()) {
      46        1050 :                         return true;
      47             :                 }
      48             :         }
      49           0 :         return false;
      50             : }
      51             : 
      52        4200 : static bool validateHost(StringView &r) {
      53        4200 :         if (r.empty()) {
      54         125 :                 return false;
      55             :         }
      56        4075 :         auto cpy = r;
      57        4075 :         if (cpy.is('[')) {
      58             :                 // check ipv6
      59         100 :                 ++ cpy;
      60         100 :                 cpy.skipChars<Ipv6>();
      61         100 :                 if (cpy.is(']')) {
      62         100 :                         cpy ++;
      63         100 :                         if (cpy.empty()) {
      64         100 :                                 return true;
      65             :                         }
      66             :                 }
      67             :         } else {
      68        3975 :                 cpy.skipChars<Unreserved, SubDelim, chars::UniChar>();
      69        3975 :                 if (cpy.empty()) {
      70        3950 :                         auto c = r.sub(r.size() - 1, 1);
      71        3975 :                         while (c.is(',') || c.is('.') || c.is(';')) {
      72          25 :                                 r = r.sub(0, r.size() - 1);
      73          25 :                                 c = r.sub(r.size() - 1, 1);
      74             :                         }
      75        3950 :                         if (c.is<StringView::Compose<StringView::CharGroup<CharGroupId::Alphanumeric>, chars::UniChar>>()) {
      76        3900 :                                 StringView h(r);
      77             : 
      78        3900 :                                 if (!h.empty()) {
      79        3900 :                                         StringView domain;
      80       10525 :                                         while (!h.empty()) {
      81        6650 :                                                 domain = h.readUntil<StringView::Chars<'.'>>();
      82        6650 :                                                 if (h.is('.')) {
      83        2775 :                                                         ++ h;
      84             :                                                 }
      85             : 
      86        6650 :                                                 if (domain.empty()) {
      87        3600 :                                                         return false;
      88             :                                                 }
      89             :                                         }
      90             : 
      91        3875 :                                         if (!domain.empty()) {
      92        3875 :                                                 auto tmp = domain;
      93        3875 :                                                 tmp.skipChars<StringView::CharGroup<CharGroupId::Alphanumeric>>();
      94        3875 :                                                 if (!tmp.empty()) {
      95         500 :                                                         if (UrlView::isValidIdnTld(domain)) {
      96        3575 :                                                                 return true;
      97             :                                                         }
      98             :                                                 } else {
      99        3375 :                                                         return true;
     100             :                                                 }
     101             :                                         }
     102             :                                 } else {
     103           0 :                                         return true;
     104             :                                 }
     105             :                         }
     106             :                 }
     107             :         }
     108         375 :         return false;
     109             : }
     110             : 
     111         900 : static bool validateUserOrPassword(const StringView &r) {
     112         900 :         auto cpy = r;
     113         900 :         cpy.skipChars<Unreserved, SubDelim, chars::UniChar>();
     114         900 :         if (cpy.empty()) {
     115         900 :                 return true;
     116             :         }
     117           0 :         return false;
     118             : }
     119             : 
     120        7375 : bool UrlView::parseUrl(StringView &s, const Callback<void(StringViewUtf8, UrlView::UrlToken)> &cb) {
     121        7375 :         UrlView::UrlToken state = UrlView::UrlToken::Scheme;
     122             : 
     123        7375 :         StringView tmp;
     124        7375 :         if (s.is('[')) {
     125          25 :                 state = UrlView::UrlToken::Host;
     126        7350 :         } else if (s.is("mailto:")) {
     127          75 :                 cb(StringView(s, 6), UrlView::UrlToken::Scheme);
     128          75 :                 s += 6;
     129          75 :                 cb(StringView(s, 1), UrlView::UrlToken::Blank);
     130          75 :                 ++ s;
     131          75 :                 state = UrlView::UrlToken::User;
     132             :         } else {
     133        7275 :                 tmp = s.readChars<UnreservedUni>();
     134             :         }
     135             : 
     136        7375 :         if (state == UrlView::UrlToken::Scheme) {
     137        7275 :                 if (s.is(':')) {
     138             :                         // scheme or host+port
     139        1300 :                         if (tmp.empty()) {
     140           0 :                                 return false; // error
     141             :                         }
     142             : 
     143        1300 :                         if (s.is("://")) {
     144         950 :                                 if (!validateScheme(tmp)) {
     145           0 :                                         return false;
     146             :                                 }
     147             : 
     148         950 :                                 cb(tmp, UrlView::UrlToken::Scheme);
     149         950 :                                 cb(StringView(s, 3), UrlView::UrlToken::Blank);
     150         950 :                                 s += 3;
     151             : 
     152         950 :                                 if (s.is('[')) {
     153          25 :                                         state = UrlView::UrlToken::Host;
     154             :                                 } else {
     155         925 :                                         state = UrlView::UrlToken::User;
     156             :                                 }
     157             :                         } else {
     158             :                                 // if it's port, next chars will be numbers only
     159         350 :                                 auto tmpS = s;
     160         350 :                                 tmpS ++;
     161         350 :                                 auto port = tmpS.readChars<StringView::CharGroup<CharGroupId::Numbers>>();
     162         350 :                                 if (!port.empty() && !tmpS.is<UnreservedUni>() && !tmpS.is('@')) {
     163             :                                         // host + port
     164         175 :                                         if (!validateHost(tmp)) {
     165         100 :                                                 return true;
     166             :                                         }
     167             : 
     168         175 :                                         cb(tmp, UrlView::UrlToken::Host);
     169         175 :                                         cb(StringView(port.data() - 1, 1), UrlView::UrlToken::Blank);
     170         175 :                                         cb(port, UrlView::UrlToken::Port);
     171         175 :                                         s = tmpS;
     172             : 
     173         175 :                                         if (s.is('/')) {
     174          25 :                                                 state = UrlView::UrlToken::Path;
     175         150 :                                         } else if (s.is<StringView::Chars<'?'>>()) {
     176          25 :                                                 state = UrlView::UrlToken::Query;
     177         125 :                                         } else if (s.is('#')) {
     178          25 :                                                 state = UrlView::UrlToken::Fragment;
     179             :                                         } else {
     180         100 :                                                 return true;
     181             :                                         }
     182             :                                 } else {
     183         175 :                                         tmpS = s;
     184         175 :                                         ++ tmpS;
     185         175 :                                         auto arg = tmpS.readChars<UnreservedUni, SubDelim>();
     186         175 :                                         if (tmpS.is('@')) {
     187             :                                                 // username + password
     188          75 :                                                 if (!validateUserOrPassword(tmp) || !validateUserOrPassword(arg)) {
     189           0 :                                                         return false;
     190             :                                                 }
     191             : 
     192          75 :                                                 cb(tmp, UrlView::UrlToken::User);
     193          75 :                                                 cb(StringView(arg.data() - 1, 1), UrlView::UrlToken::Blank);
     194          75 :                                                 cb(arg, UrlView::UrlToken::Password);
     195          75 :                                                 cb(StringView(tmpS, 1), UrlView::UrlToken::Blank);
     196          75 :                                                 state = UrlView::UrlToken::Host;
     197          75 :                                                 ++ tmpS;
     198          75 :                                                 s = tmpS;
     199             :                                         } else {
     200             :                                                 // scheme without authority segment
     201         100 :                                                 if (!validateScheme(tmp)) {
     202           0 :                                                         return false;
     203             :                                                 }
     204         100 :                                                 cb(tmp, UrlView::UrlToken::Scheme);
     205         100 :                                                 state = UrlView::UrlToken::Path;
     206         100 :                                                 cb(s.sub(0, 1), UrlView::UrlToken::Blank);
     207         100 :                                                 ++ s;
     208             :                                         }
     209             :                                 }
     210             :                         }
     211        5975 :                 } else if (s.is('@')) {
     212         425 :                         if (tmp.empty() || !validateUserOrPassword(tmp)) {
     213           0 :                                 return false;
     214             :                         }
     215         425 :                         cb(tmp, UrlView::UrlToken::User);
     216         425 :                         state = UrlView::UrlToken::Host;
     217         425 :                         cb(StringView(s, 1), UrlView::UrlToken::Blank);
     218         425 :                         ++ s;
     219        5550 :                 } else if (s.is('/')) {
     220             :                         // host + path
     221        4900 :                         if (!tmp.empty()) {
     222         850 :                                 if (!validateHost(tmp)) {
     223         300 :                                         return false;
     224             :                                 }
     225         550 :                                 cb(tmp, UrlView::UrlToken::Host);
     226             :                         }
     227        4600 :                         state = UrlView::UrlToken::Path;
     228         650 :                 } else if (s.is('?')) {
     229             :                         // host + query
     230          25 :                         if (tmp.empty()) {
     231           0 :                                 return false;
     232             :                         }
     233          25 :                         if (!validateHost(tmp)) {
     234           0 :                                 return false;
     235             :                         }
     236          25 :                         cb(tmp, UrlView::UrlToken::Host);
     237          25 :                         state = UrlView::UrlToken::Query;
     238         625 :                 } else if (s.is('#')) {
     239             :                         // host + fragment
     240          25 :                         if (tmp.empty()) {
     241           0 :                                 return false;
     242             :                         }
     243          25 :                         if (!validateHost(tmp)) {
     244           0 :                                 return false;
     245             :                         }
     246          25 :                         cb(tmp, UrlView::UrlToken::Host);
     247          25 :                         state = UrlView::UrlToken::Fragment;
     248             :                 } else {
     249             :                         // assume host-only
     250         600 :                         if (!tmp.empty()) {
     251         600 :                                 if (!validateHost(tmp)) {
     252           0 :                                         return false;
     253             :                                 }
     254         600 :                                 cb(tmp, UrlView::UrlToken::Host);
     255         600 :                                 return true;
     256             :                         }
     257           0 :                         return false;
     258             :                 }
     259             :         }
     260             : 
     261        6375 :         if (state == UrlView::UrlToken::User) {
     262        1000 :                 auto tmp_s = s;
     263        1000 :                 tmp = tmp_s.readChars<UnreservedUni, SubDelim>();
     264             : 
     265        1000 :                 if (tmp_s.is('@')) {
     266             :                         // user only part
     267         250 :                         if (!validateUserOrPassword(tmp)) {
     268          75 :                                 return false;
     269             :                         }
     270         250 :                         cb(tmp, UrlView::UrlToken::User);
     271         250 :                         state = UrlView::UrlToken::Host;
     272         250 :                         cb(StringView(tmp_s, 1), UrlView::UrlToken::Blank);
     273         250 :                         ++ tmp_s;
     274         250 :                         s = tmp_s;
     275         750 :                 } else if (tmp_s.is(':')) {
     276             :                         // user + password or host + port
     277         125 :                         tmp_s ++;
     278         125 :                         auto tmpS = tmp_s;
     279             : 
     280             :                         // if it's port, next chars will be numbers only
     281         125 :                         auto port = tmpS.readChars<StringView::CharGroup<CharGroupId::Numbers>>();
     282         125 :                         if (!port.empty() && !tmpS.is('@')) {
     283             :                                 // host + port
     284          75 :                                 if (!validateHost(tmp)) {
     285           0 :                                         return true;
     286             :                                 }
     287             : 
     288          75 :                                 cb(tmp, UrlView::UrlToken::Host);
     289          75 :                                 cb(StringView(port.data() - 1, 1), UrlView::UrlToken::Blank);
     290          75 :                                 cb(port, UrlView::UrlToken::Port);
     291          75 :                                 s = tmpS;
     292             : 
     293          75 :                                 if (s.is('/')) {
     294          25 :                                         state = UrlView::UrlToken::Path;
     295          50 :                                 } else if (s.is('?')) {
     296          25 :                                         state = UrlView::UrlToken::Query;
     297          25 :                                 } else if (s.is('#')) {
     298          25 :                                         state = UrlView::UrlToken::Fragment;
     299             :                                 } else {
     300           0 :                                         return true;
     301             :                                 }
     302             :                         } else {
     303             :                                 // user + password
     304          50 :                                 if (!validateUserOrPassword(tmp)) {
     305           0 :                                         return false;
     306             :                                 }
     307          50 :                                 cb(tmp, UrlView::UrlToken::User);
     308             : 
     309          50 :                                 if (tmpS.is('@')) {
     310          25 :                                         cb(StringView(port.data() - 1, 1), UrlView::UrlToken::Blank);
     311          25 :                                         cb(port, UrlView::UrlToken::Password);
     312          25 :                                         ++ tmpS;
     313          25 :                                         state = UrlView::UrlToken::Host;
     314          25 :                                         s = tmpS;
     315             :                                 } else {
     316          25 :                                         tmp = tmp_s.readChars<UnreservedUni, SubDelim>();
     317          25 :                                         if (!tmp_s.is('@')) {
     318           0 :                                                 return false;
     319             :                                         }
     320          25 :                                         ++ tmp_s;
     321          25 :                                         if (!validateUserOrPassword(tmp)) {
     322           0 :                                                 return false;
     323             :                                         }
     324          25 :                                         cb(StringView(tmp.data() - 1, 1), UrlView::UrlToken::Blank);
     325          25 :                                         cb(tmp, UrlView::UrlToken::Password);
     326          25 :                                         s = tmp_s;
     327          25 :                                         cb(StringView(s.data() - 1, 1), UrlView::UrlToken::Blank);
     328          25 :                                         state = UrlView::UrlToken::Host;
     329             :                                 }
     330             :                         }
     331             :                 } else {
     332             :                         // host
     333         625 :                         if (!validateHost(tmp)) {
     334           0 :                                 return false;
     335             :                         }
     336             : 
     337         625 :                         cb(tmp, UrlView::UrlToken::Host);
     338         625 :                         s = tmp_s;
     339             : 
     340         625 :                         if (tmp_s.is('/')) {
     341         525 :                                 state = UrlView::UrlToken::Path;
     342         100 :                         } else if (tmp_s.is('?')) {
     343          25 :                                 state = UrlView::UrlToken::Query;
     344          75 :                         } else if (tmp_s.is('#')) {
     345           0 :                                 state = UrlView::UrlToken::Fragment;
     346             :                         } else {
     347          75 :                                 return true;
     348             :                         }
     349             :                 }
     350             :         }
     351             : 
     352        6300 :         if (state == UrlView::UrlToken::Host) {
     353         850 :                 bool stop = false;
     354         850 :                 if (s.is('[')) {
     355         100 :                         auto t = s;
     356         100 :                         ++ t;
     357         100 :                         tmp = t.readChars<UnreservedUni, SubDelim, StringView::Chars<':'>>();
     358         100 :                         if (t.is(']')) {
     359         100 :                                 ++ t;
     360         100 :                                 tmp = StringView(s.data(), t.data() - s.data());
     361         100 :                                 s = t;
     362             :                         } else {
     363           0 :                                 return false;
     364             :                         }
     365             :                 } else {
     366         750 :                         tmp = s.readChars<UnreservedUni, SubDelim, StringView::Chars<'[', ']'>>();
     367             :                 }
     368         850 :                 if (!validateHost(tmp)) {
     369         125 :                         return false;
     370             :                 }
     371         725 :                 cb(tmp, UrlView::UrlToken::Host);
     372         725 :                 if (s.is(':')) {
     373         375 :                         auto tmp2 = s;
     374         375 :                         ++ tmp2;
     375         375 :                         auto port = tmp2.readChars<StringView::CharGroup<CharGroupId::Numbers>>();
     376         375 :                         if (port.empty() || s.is<UnreservedUni>()) {
     377          50 :                                 state = UrlView::UrlToken::Path;
     378          50 :                                 stop = true;
     379             :                         } else {
     380         325 :                                 cb(StringView(port.data() - 1, 1), UrlView::UrlToken::Blank);
     381         325 :                                 cb(port, UrlView::UrlToken::Port);
     382         325 :                                 s = tmp2;
     383             :                         }
     384             :                 }
     385         725 :                 if (stop) {
     386             :                         // do nothing
     387         675 :                 } else if (s.is('/')) {
     388         150 :                         state = UrlView::UrlToken::Path;
     389         525 :                 } else if (s.is('?')) {
     390          25 :                         state = UrlView::UrlToken::Query;
     391         500 :                 } else if (s.is('#')) {
     392         125 :                         state = UrlView::UrlToken::Fragment;
     393             :                 } else {
     394         375 :                         return true;
     395             :                 }
     396             :         }
     397             : 
     398        5800 :         if (state == UrlView::UrlToken::Path) {
     399        5475 :                 tmp = s.readChars<UnreservedUni, SubDelim, StringView::Chars<'/', ':', '@'>>();
     400        5475 :                 if (!tmp.empty()) {
     401        5475 :                         cb(tmp, UrlView::UrlToken::Path);
     402             :                 }
     403             : 
     404        5475 :                 if (s.is('?')) {
     405        1400 :                         state = UrlView::UrlToken::Query;
     406        4075 :                 } else if (s.is('#')) {
     407           0 :                         state = UrlView::UrlToken::Fragment;
     408             :                 } else {
     409        4075 :                         return true;
     410             :                 }
     411             :         }
     412             : 
     413        1725 :         if (state == UrlView::UrlToken::Query) {
     414        1525 :                 tmp = s.readChars<UnreservedUni, SubDelim, StringView::Chars<'/', ':', '@', '?', '[', ']'>>();
     415        1525 :                 if (!tmp.empty()) {
     416        1525 :                         if (tmp.is('?')) {
     417        1525 :                                 cb(StringView(tmp, 1), UrlView::UrlToken::Blank);
     418        1525 :                                 ++ tmp;
     419             :                         }
     420        1525 :                         if (!tmp.empty()) {
     421        1525 :                                 cb(tmp, UrlView::UrlToken::Query);
     422             :                         }
     423             :                 }
     424             : 
     425        1525 :                 if (s.is('#')) {
     426         375 :                         state = UrlView::UrlToken::Fragment;
     427             :                 } else {
     428        1150 :                         return true;
     429             :                 }
     430             :         }
     431             : 
     432         575 :         if (state == UrlView::UrlToken::Fragment) {
     433         575 :                 tmp = s.readChars<UnreservedUni, SubDelim, StringView::Chars<'/', ':', '@', '?', '#', '[', ']'>>();
     434         575 :                 if (!tmp.empty()) {
     435         575 :                         if (tmp.is('#')) {
     436         575 :                                 cb(StringView(tmp, 1), UrlView::UrlToken::Blank);
     437         575 :                                 ++ tmp;
     438             :                         }
     439         575 :                         if (!tmp.empty()) {
     440         575 :                                 cb(tmp, UrlView::UrlToken::Fragment);
     441             :                         }
     442             :                 }
     443             :         }
     444             : 
     445         575 :         return true;
     446             : }
     447             : 
     448             : template <typename Vector>
     449        6175 : auto _parsePath(StringView str, Vector &ret) {
     450        6175 :         StringView s(str);
     451             :         do {
     452       14350 :                 if (s.is('/')) {
     453       13425 :                         s ++;
     454             :                 }
     455       14350 :                 auto path = s.readUntil<StringView::Chars<'/', '?', ';', '&', '#'>>();
     456       14350 :                 if (path == "..") {
     457           0 :                         if (!ret.empty()) {
     458           0 :                                 ret.pop_back();
     459             :                         }
     460       14350 :                 } else if (path == ".") {
     461             :                         // skip this component
     462             :                 } else {
     463       14350 :                         if (!path.empty()) {
     464       13400 :                                 ret.push_back(str);
     465             :                         }
     466             :                 }
     467       14350 :         } while (!s.empty() && s.is('/'));
     468        6175 : }
     469             : 
     470             : template <>
     471           0 : auto UrlView::parsePath<memory::StandartInterface>(StringView str) -> memory::StandartInterface::VectorType<StringView> {
     472           0 :         memory::StandartInterface::VectorType<StringView> ret;
     473           0 :         _parsePath(str, ret);
     474           0 :         return ret;
     475           0 : }
     476             : 
     477             : template <>
     478        6175 : auto UrlView::parsePath<memory::PoolInterface>(StringView str) -> memory::PoolInterface::VectorType<StringView> {
     479        6175 :         memory::PoolInterface::VectorType<StringView> ret;
     480        6175 :         _parsePath(str, ret);
     481        6175 :         return ret;
     482           0 : }
     483             : 
     484         550 : bool UrlView::isValidIdnTld(StringView str) {
     485         550 :         auto p = s_IdnTld;
     486       61850 :         while (*p) {
     487       61550 :                 if (str == *p) {
     488         250 :                         return true;
     489             :                 }
     490       61300 :                 ++ p;
     491             :         }
     492         300 :         return false;
     493             : }
     494             : 
     495        6375 : UrlView::UrlView() { }
     496             : 
     497        1000 : UrlView::UrlView(StringView str) {
     498        1000 :         parse(str);
     499        1000 : }
     500             : 
     501         425 : void UrlView::clear() {
     502         425 :         scheme.clear();
     503         425 :         user.clear();
     504         425 :         password.clear();
     505         425 :         host.clear();
     506         425 :         port.clear();
     507         425 :         path.clear();
     508         425 :         query.clear();
     509         425 :         fragment.clear();
     510         425 :         url.clear();
     511         425 : }
     512             : 
     513        1050 : bool UrlView::parse(const StringView &str) {
     514        1050 :         StringView r(str);
     515        2100 :         return parse(r);
     516             : }
     517             : 
     518        7375 : bool UrlView::parse(StringView &str) {
     519        7375 :         auto tmp = str;
     520        7375 :         if (parseUrl(str, [this] (StringView str, UrlToken tok) {
     521       17700 :                 switch (tok) {
     522        1125 :                 case UrlToken::Scheme: scheme = str; break;
     523         800 :                 case UrlToken::User: user = str; break;
     524         125 :                 case UrlToken::Password: password = str; break;
     525        2800 :                 case UrlToken::Host: host = str; break;
     526         575 :                 case UrlToken::Port: port = str; break;
     527        5475 :                 case UrlToken::Path: path = str; break;
     528        1525 :                 case UrlToken::Query: query = str; break;
     529         575 :                 case UrlToken::Fragment: fragment = str; break;
     530        4700 :                 case UrlToken::Blank: break;
     531             :                 }
     532       17700 :         })) {
     533        6950 :                 url = StringView(tmp.data(), str.data() - tmp.data());
     534        6950 :                 return true;
     535             :         } else {
     536         425 :                 clear();
     537         425 :                 return false;
     538             :         }
     539             : }
     540             : 
     541        2000 : static void UrlView_get(std::ostream &stream, const UrlView &view) {
     542        2000 :         if (!view.scheme.empty()) {
     543         900 :                 stream << view.scheme << ":";
     544             :         }
     545        2000 :         if (!view.scheme.empty() && !view.host.empty() && view.scheme != "mailto") {
     546         750 :                 stream << "//";
     547             :         }
     548        2000 :         if (!view.host.empty()) {
     549        1825 :                 if (!view.user.empty()) {
     550         425 :                         stream << view.user;
     551         425 :                         if (!view.password.empty()) {
     552         125 :                                 stream << ":" << view.password;
     553             :                         }
     554         425 :                         stream << "@";
     555             :                 }
     556        1825 :                 stream << view.host;
     557        1825 :                 if (!view.port.empty()) {
     558         525 :                         stream << ":" << view.port;
     559             :                 }
     560             :         }
     561        2000 :         if (!view.path.empty()) {
     562        1050 :                 stream << view.path;
     563             :         }
     564        2000 :         if (!view.query.empty()) {
     565         425 :                 stream << "?" << view.query;
     566             :         }
     567        2000 :         if (!view.fragment.empty()) {
     568         575 :                 stream << "#" << view.fragment;
     569             :         }
     570        2000 : }
     571             : 
     572             : template <>
     573        1775 : auto UrlView::get<memory::PoolInterface>() const -> memory::PoolInterface::StringType {
     574        1775 :         memory::PoolInterface::StringStreamType stream;
     575        1775 :         UrlView_get(stream, *this);
     576        3550 :         return stream.str();
     577        1775 : }
     578             : 
     579             : template <>
     580         225 : auto UrlView::get<memory::StandartInterface>() const -> memory::StandartInterface::StringType {
     581         225 :         memory::StandartInterface::StringStreamType stream;
     582         225 :         UrlView_get(stream, *this);
     583         450 :         return stream.str();
     584         225 : }
     585             : 
     586        1775 : bool UrlView::isEmail() const {
     587        1775 :         return (!user.empty() && !host.empty()) && (scheme.empty() && password.empty() && port.empty() && path.empty() && query.empty() && fragment.empty());
     588             : }
     589             : 
     590        1575 : bool UrlView::isPath() const {
     591        1575 :         return !path.empty() && (scheme.empty() && user.empty() && password.empty() && host.empty() && port.empty() && query.empty() && fragment.empty());
     592             : }
     593             : 
     594             : 
     595             : #if MODULE_STAPPLER_DATA
     596             : 
     597             : template <>
     598         500 : auto UrlView::parseArgs<memory::PoolInterface>(StringView str, size_t maxVarSize) -> data::ValueTemplate<memory::PoolInterface> {
     599         500 :         if (str.empty()) {
     600           0 :                 data::ValueTemplate<memory::PoolInterface>();
     601             :         }
     602         500 :         StringView r(str);
     603         500 :         if (r.front() == '?' || r.front() == '&' || r.front() == ';') {
     604           0 :                 ++ r;
     605             :         }
     606        1000 :         return data::readUrlencoded<memory::PoolInterface>(str);
     607             : }
     608             : 
     609             : template <>
     610           0 : auto UrlView::parseArgs<memory::StandartInterface>(StringView str, size_t maxVarSize) -> data::ValueTemplate<memory::StandartInterface> {
     611           0 :         if (str.empty()) {
     612           0 :                 data::ValueTemplate<memory::StandartInterface>();
     613             :         }
     614           0 :         StringView r(str);
     615           0 :         if (r.front() == '?' || r.front() == '&' || r.front() == ';') {
     616           0 :                 ++ r;
     617             :         }
     618           0 :         return data::readUrlencoded<memory::StandartInterface>(str);
     619             : }
     620             : 
     621             : #endif
     622             : 
     623             : 
     624             : }

Generated by: LCOV version 1.14