4#include "Stroika/Foundation/StroikaPreComp.h"
9#include "Stroika/Foundation/Characters/String2Int.h"
11#include "Stroika/Foundation/Containers/Support/ReserveTweaks.h"
12#include "Stroika/Foundation/Execution/Exceptions.h"
13#include "Stroika/Foundation/Execution/Throw.h"
23using namespace Stroika::Foundation::IO;
25using namespace Stroika::Foundation::IO::Network::UniformResourceIdentification;
28 inline uint8_t ConvertReadSingleHexDigit_ (
char digit)
31 if (isupper (digit)) {
32 digit =
static_cast<char> (tolower (digit));
34 if (isdigit (digit)) {
35 return static_cast<uint8_t
> (digit -
'0');
37 else if (islower (digit)) {
41 return static_cast<uint8_t
> (10 + (digit -
'a'));
60void SchemeType::Validate ()
const
64 if (not c.IsASCII () or not(c.IsAlphabetic () or c.IsDigit () or c ==
'-' or c ==
'.' or c ==
'+')) [[unlikely]] {
74 return ns ==
"https"sv or ns ==
"ftps"sv or ns ==
"ldaps"sv or ns ==
"ssh"sv;
77optional<PortType> SchemeType::GetDefaultPort ()
const
82 {
"http"sv,
static_cast<PortType
> (80)},
83 {
"https"sv,
static_cast<PortType
> (443)},
84 {
"ldap"sv,
static_cast<PortType
> (389)},
85 {
"ldaps"sv,
static_cast<PortType
> (636)},
86 {
"ftp"sv,
static_cast<PortType
> (21)},
87 {
"ftps"sv,
static_cast<PortType
> (990)},
89 return kPredefined_.Lookup (*
this);
94 using namespace Characters;
95 return String::ThreeWayComparer{eCaseInsensitive}(lhs, rhs);
103pair<optional<String>, optional<InternetAddress>> Host::ParseRaw_ (
const String& raw)
105 Require (not raw.empty ());
108 if (raw[0].IsDigit ()) {
110 return pair<optional<String>, optional<InternetAddress>>{nullopt,
InternetAddress{raw, InternetAddress::AddressFamily::V4}};
112 else if (raw[0] ==
'[') {
115 if (raw.
Last () !=
']') {
119 return pair<optional<String>, optional<InternetAddress>>{nullopt,
InternetAddress{raw.
SubString (1, -1), InternetAddress::AddressFamily::V6}};
122 return pair<optional<String>, optional<InternetAddress>>{PCTDecode2String (raw.
AsUTF8<
string> ()), nullopt};
128 if (fRegisteredName_) {
129 return Host{fRegisteredName_->ToLowerCase ()};
131 Assert (fInternetAddress_);
132 return Host{*fInternetAddress_};
135String Host::EncodeAsRawURL_ (
const String& registeredName)
140 return UniformResourceIdentification::PCTEncode2String (registeredName, kHostEncodeOptions_);
147 case InternetAddress::AddressFamily::V4: {
150 case InternetAddress::AddressFamily::V6: {
151 return "["sv + ipAddr.
As<
String> () +
"]"sv;
173 Require (not raw.empty ());
175 return PCTDecode2String (raw);
178String UserInfo::EncodeAsRawURL_ (
const String& decodedName)
180 Require (not decodedName.empty ());
184 return UniformResourceIdentification::PCTEncode2String (decodedName, kUserInfoEncodeOptions_);
199 if (rawURLAuthorityText.empty ()) {
202 optional<UserInfo> userInfo;
211 String remainingString2Parse = rawURLAuthorityText;
213 if (
auto oat = remainingString2Parse.
Find (
'@')) {
214 optional<String> encodedUserInfo = remainingString2Parse.
SubString (0, *oat);
215 if (encodedUserInfo) {
218 remainingString2Parse = remainingString2Parse.
SubString (*oat + 1);
227 if (remainingString2Parse.
size () >= 2 and remainingString2Parse[0] ==
'[') {
228 auto closeBracket = remainingString2Parse.
Find (
']');
230 hostString = remainingString2Parse.
SubString (0, *closeBracket + 1);
231 remainingString2Parse = remainingString2Parse.
SubString (*closeBracket + 1);
241 if (
auto oPortColon = remainingString2Parse.
Find (
':')) {
242 hostString = remainingString2Parse.
SubString (0, *oPortColon);
243 remainingString2Parse = remainingString2Parse.
SubString (*oPortColon);
246 hostString = remainingString2Parse;
247 remainingString2Parse =
String{};
250 host = hostString.empty () ? optional<Host>{} :
Host::Parse (hostString);
252 optional<uint16_t> port;
253 if (
auto oPortColon = remainingString2Parse.
Find (
':')) {
254 port = Characters::String2Int<uint16_t> (remainingString2Parse.
SubString (*oPortColon + 1));
261 return Authority{fHost_ ? fHost_->Normalize () : optional<Host>{}, fPort_, fUserInfo_};
269 sb << fUserInfo_->As<
String> (pctEncode) <<
"@"sv;
272 sb << fHost_->As<
String> (pctEncode);
275 sb <<
":"sv << static_cast<unsigned int> (*fPort_);
296 size_t utfqLen = utf8Query.length ();
297 for (
size_t i = 0; i < utfqLen;) {
298 size_t e = utf8Query.find (
'&', i);
299 u8string elt = utf8Query.substr (i, e - i);
300 size_t brk = elt.find (
'=');
301 if (brk != string::npos) {
302 u8string val = elt.substr (brk + 1);
303 for (
auto p = val.begin (); p != val.end (); ++p) {
309 if (p + 2 < val.end ()) {
310 unsigned char newC = (ConvertReadSingleHexDigit_ (*(p + 1)) << 4) + ConvertReadSingleHexDigit_ (*(p + 2));
311 p = val.erase (p, p + 2);
312 *p =
static_cast<char> (newC);
327Query::Query (
const String& query)
329 InitURLQueryDecoder_ (&fMap_, query.
AsASCII<u8string> ());
332Query::Query (
const u8string& query)
334 InitURLQueryDecoder_ (&fMap_, query);
337void Query::RemoveFieldIfAny (
const String& idx)
342String Query::ComputeQueryString ()
const
345 for (
auto i = fMap_.begin (); i != fMap_.end (); ++i) {
346 Containers::Support::ReserveTweaks::Reserve4Add1 (result);
347 if (not result.empty ()) {
351 result += EncodeURLQueryStringField (i->fKey) + u8
"=" + EncodeURLQueryStringField (i->fValue);
363strong_ordering Query::TWC_ (
const Query& lhs,
const Query& rhs)
370 optional<String> lhsVal = lhs.GetMap ().Lookup (i);
371 optional<String> rhsVal = rhs.GetMap ().Lookup (i);
372 strong_ordering cmp = Common::StdCompat::compare_three_way{}(lhsVal, rhsVal);
373 if (cmp != strong_ordering::equal) {
377 return strong_ordering::equal;
385u8string UniformResourceIdentification::EncodeURLQueryStringField (
const String& s)
393 u8string utf8Query = s.
AsUTF8 ();
395 size_t sLength = utf8Query.length ();
396 result.reserve (sLength);
397 for (
size_t i = 0; i < sLength; ++i) {
398 Containers::Support::ReserveTweaks::Reserve4Add1 (result);
399 switch (utf8Query[i]) {
404 char8_t ccode = utf8Query[i];
405 if (isascii (ccode) and (isalnum (ccode) or (ccode ==
'-') or (ccode ==
'.') or (ccode ==
'_') or (ccode ==
'~'))) {
406 result +=
static_cast<char> (utf8Query[i]);
409 result += CString::Format (u8
"%%%.2x", ccode);
422u8string UniformResourceIdentification::PCTEncode (
const u8string& s,
const PCTEncodeOptions& options)
425 size_t sLength = s.length ();
426 result.reserve (sLength);
429 if (useOptions.allowFragOrQueryChars) {
430 useOptions.allowPChar =
true;
432 if (useOptions.allowPChar) {
433 useOptions.allowSubDelims =
true;
435 if (useOptions.allowPathCharacters) {
436 useOptions.allowSubDelims =
true;
443 if (isalpha (c) or isdigit (c)) {
454 if (useOptions.allowFragOrQueryChars) {
461 if (useOptions.allowPChar) {
468 if (useOptions.allowPathCharacters) {
474 if (useOptions.allowGenDelims) {
485 if (useOptions.allowSubDelims) {
502 Containers::Support::ReserveTweaks::Reserve4AddN (result, 3);
503 result += CString::Format (u8
"%%%.2x", c);
506 Containers::Support::ReserveTweaks::Reserve4Add1 (result);
515 return PCTEncode (s.
AsUTF8<u8string> (), options);
528u8string UniformResourceIdentification::PCTDecode (
const u8string& s)
531 result.reserve (s.length ());
532 for (
auto p = s.begin (); p != s.end (); ++p) {
535 if (p + 2 < s.end ()) {
536 unsigned char newC = (ConvertReadSingleHexDigit_ (*(p + 1)) << 4) + ConvertReadSingleHexDigit_ (*(p + 2));
558String UniformResourceIdentification::PCTDecode2String (
const u8string& s)
563String UniformResourceIdentification::PCTDecode2String (
const String& s)
573size_t std::hash<Stroika::Foundation::IO::Network::UniformResourceIdentification::Host>::operator() (
576 return hash<Characters::String>{}(arg.
As<
Characters::String> (UniformResourceIdentification::Host::eDecoded));
#define WeakAssertNotImplemented()
Similar to String, but intended to more efficiently construct a String. Mutable type (String is large...
String is like std::u32string, except it is much easier to use, often much more space efficient,...
nonvirtual T AsUTF8() const
nonvirtual size_t size() const noexcept
nonvirtual String ToLowerCase() const
static constexpr size_t npos
nonvirtual String SubString(SZ from) const
nonvirtual T AsASCII() const
static String FromUTF8(span< CHAR_T > from)
nonvirtual optional< size_t > Find(Character c, CompareOptions co=eWithCase) const
nonvirtual bool Add(ArgByValueType< key_type > key, ArgByValueType< mapped_type > newElt, AddReplaceMode addReplaceMode=AddReplaceMode::eAddReplaces)
Set<T> is a container of T, where once an item is added, additionally adds () do nothing.
nonvirtual constexpr AddressFamily GetAddressFamily() const
nonvirtual optional< T > Last() const
return last element in iterable, or if 'that' specified, last where 'that' is true,...
String ToString(T &&t, ARGS... args)
Return a debug-friendly, display version of the argument: not guaranteed parsable or usable except fo...
void Throw(T &&e2Throw)
identical to builtin C++ 'throw' except that it does helpful, type dependent DbgTrace() messages firs...