4#include "Stroika/Foundation/StroikaPreComp.h"
9#include "Stroika/Foundation/Characters/String2Int.h"
12#include "Stroika/Foundation/Execution/Exceptions.h"
13#include "Stroika/Foundation/Execution/Throw.h"
23using namespace Stroika::Foundation::IO;
34 String PatchOldStroikaURLPath2NewPath_ (
const optional<URI::Authority>& a,
const String& s)
53#if USE_NOISY_TRACE_IN_THIS_MODULE_
57 vector<String> segments;
60 if (c ==
'/' and not accumulatingSegment.
empty ()) {
61 segments.push_back (accumulatingSegment.
str ());
62 accumulatingSegment.clear ();
64 accumulatingSegment << c;
66 if (not accumulatingSegment.
empty ()) {
67 segments.push_back (accumulatingSegment.
str ());
69 vector<String> segments2;
70 bool lastSegmentShouldHaveSlash{
false};
71 for (
const String& segment : segments) {
72 lastSegmentShouldHaveSlash =
false;
73 if (segment ==
"."sv or segment ==
"/."sv) {
75 if (segment[0] ==
'/') {
76 lastSegmentShouldHaveSlash =
true;
79 else if (segment ==
".."sv or segment ==
"/.."sv) {
80 if (not segments2.empty ()) {
81 segments2.pop_back ();
83 if (segment[0] ==
'/') {
84 lastSegmentShouldHaveSlash =
true;
88 segments2.push_back (segment);
93 bool soFarEndsWithSlash =
false;
94 for (
const String& segment : segments2) {
95 if (normalization == URI::NormalizationStyle::eAggressive) {
96 if (segment.StartsWith (
'/') and soFarEndsWithSlash) {
98 if (not add.empty ()) {
100 soFarEndsWithSlash = add.
EndsWith (
'/');
105 soFarEndsWithSlash = segment.EndsWith (
'/');
112 if (lastSegmentShouldHaveSlash and not result.
str ().
EndsWith (
"/"sv)) {
121#if USE_NOISY_TRACE_IN_THIS_MODULE_
125 static const RegularExpression kParseURLRegExp_{
"^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\\?([^#]*))?(#(.*))?"_RegEx};
126 optional<String> scheme;
127 optional<String> authority;
128 optional<String> path;
129 optional<String> query;
130 optional<String> fragment;
131 auto emptyStr2Missing = [] (
const optional<String>& s) -> optional<String> {
133 if (not s->empty ()) {
140 if (rawURL.
Matches (kParseURLRegExp_,
nullptr, &scheme,
nullptr, &authority, &path,
nullptr, &query,
nullptr, &fragment)) {
142 UniformResourceIdentification::PCTDecode2String (path.value_or (
String{})), emptyStr2Missing (query), emptyStr2Missing (fragment)};
152#if USE_NOISY_TRACE_IN_THIS_MODULE_
156 static const RegularExpression kParseRelativeURLRegExp_{
"([^?#]*)(\\?([^#]*))?(#(.*))?"_RegEx};
157 optional<String> scheme;
158 optional<String> authority;
159 optional<String> path;
160 optional<String> query;
161 optional<String> fragment;
162 auto emptyStr2Missing = [] (
const optional<String>& s) -> optional<String> {
164 if (not s->empty ()) {
170 (void)rawRelativeURL.
AsASCII ();
171 if (rawRelativeURL.
Matches (kParseRelativeURLRegExp_, &path,
nullptr, &query,
nullptr, &fragment)) {
172 return URI{nullopt, nullopt, UniformResourceIdentification::PCTDecode2String (path.value_or (
String{})), emptyStr2Missing (query),
173 emptyStr2Missing (fragment)};
181String URI::AsString_ (optional<StringPCTEncodedFlag> pctEncode)
const
184 StringPCTEncodedFlag usingPCTEncodeFlag = pctEncode.value_or (eDecoded);
185 AssertExternallySynchronizedMutex::ReadContext declareContext{fThisAssertExternallySynchronized_};
191 Assert (fScheme_->All ([] (
Character c) { return c.IsASCII (); }));
192 result << *fScheme_ <<
":"sv;
195 Assert (fAuthority_->As<
String> (usingPCTEncodeFlag).
All ([] (
Character c) { return c.IsASCII (); }));
196 result <<
"//"sv << fAuthority_->As<
String> (usingPCTEncodeFlag);
199 if (fAuthority_ and not(fPath_.empty () or fPath_.
StartsWith (
"/"sv))) {
205 if (usingPCTEncodeFlag == eDecoded) {
210 .allowSubDelims =
false, .allowGenDelims =
false, .allowPChar =
true, .allowFragOrQueryChars =
false, .allowPathCharacters =
true};
211 result << UniformResourceIdentification::PCTEncode2String (fPath_, kPathEncodeOptions_);
216 .allowSubDelims =
false, .allowGenDelims =
false, .allowPChar =
false, .allowFragOrQueryChars =
true};
217 if (usingPCTEncodeFlag == eDecoded) {
218 result <<
"?"sv << *fQuery_;
221 result <<
"?"sv << UniformResourceIdentification::PCTEncode2String (*fQuery_, kQueryEncodeOptions_);
225 if (usingPCTEncodeFlag == eDecoded) {
226 result <<
"#"sv + *fFragment_;
230 result <<
"#"sv + UniformResourceIdentification::PCTEncode2String (*fFragment_, kFragmentEncodeOptions_);
233 Ensure (result.
str ().
All ([] (
Character c) { return c.IsASCII (); }));
234 return result.
str ();
237URI::operator bool ()
const
239 AssertExternallySynchronizedMutex::ReadContext declareContext{fThisAssertExternallySynchronized_};
246 if (not fPath_.empty ()) {
260 AssertExternallySynchronizedMutex::ReadContext declareContext{fThisAssertExternallySynchronized_};
262 optional<String> baseDir;
263 (void)fPath_.
Matches (kSelectDir_, &baseDir);
264 return baseDir.value_or (
String{});
269 AssertExternallySynchronizedMutex::ReadContext declareContext{fThisAssertExternallySynchronized_};
270 optional<SchemeType> scheme = fScheme_;
272 scheme = scheme->Normalize ();
274 optional<Authority> authority = fAuthority_;
276 authority = authority->Normalize ();
278 String path = remove_dot_segments_ (fPath_, normalization);
279 return URI{scheme, authority, path, fQuery_, fFragment_};
285 AssertExternallySynchronizedMutex::ReadContext declareContext{fThisAssertExternallySynchronized_};
288 result << *fScheme_ <<
":"sv;
291 result <<
"//"sv << fAuthority_->As<
String> ();
295 result <<
"?"sv << *fQuery_;
298 result <<
"#"sv << *fFragment_;
303void URI::CheckValidPathForAuthority_ (
const optional<Authority>& authority,
const String& path)
310 if (authority and (not path.empty () and not path.
StartsWith (
"/"sv))) {
318 AssertExternallySynchronizedMutex::ReadContext declareContext{fThisAssertExternallySynchronized_};
331 return overridingURI;
349 optional<String> baseDir;
350 (void)base.
Matches (kSelectDir_, &baseDir);
351 return baseDir.value_or (
String{}) + rhs;
354 Assert (remove_dot_segments_ (
"/a/b/c/./../../g") ==
"/a/g");
355 Assert (remove_dot_segments_ (
"mid/content=5/../6") ==
"mid/6");
372 result.
SetPath (remove_dot_segments_ (overridingURI.GetPath ()));
373 result.SetQuery (overridingURI.GetQuery<
String> ());
379 result.
SetPath (remove_dot_segments_ (overridingURI.GetPath ()));
380 result.SetQuery (overridingURI.GetQuery<
String> ());
384 if (overridingURI.GetPath ().empty ()) {
385 result.
SetPath (baseURI.GetPath ());
386 result.SetQuery (overridingURI.GetQuery<
String> () ? overridingURI.GetQuery<
String> () : baseURI.GetQuery<
String> ());
389 if (overridingURI.GetPath ().
StartsWith (
"/"sv)) {
390 result.
SetPath (remove_dot_segments_ (overridingURI.GetPath ()));
393 result.
SetPath (remove_dot_segments_ (merge (baseURI.GetPath (), overridingURI.GetPath ())));
395 result.SetQuery (overridingURI.GetQuery<
String> ());
399 result.SetFragment (overridingURI.GetFragment ());
403strong_ordering URI::TWC_ (
const URI& lhs,
const URI& rhs)
405 using namespace UniformResourceIdentification;
406 if (
auto cmp = Common::StdCompat::compare_three_way{}(lhs.
GetScheme (), rhs.
GetScheme ()); cmp != strong_ordering::equal) {
409 if (
auto cmp = Common::StdCompat::compare_three_way{}(lhs.
GetAuthority (), rhs.
GetAuthority ()); cmp != strong_ordering::equal) {
412 if (
auto cmp = Common::StdCompat::compare_three_way{}(lhs.GetPath (), rhs.GetPath ()); cmp != strong_ordering::equal) {
415 if (
auto cmp = Common::StdCompat::compare_three_way{}(lhs.GetQuery (), rhs.GetQuery ()); cmp != strong_ordering::equal) {
418 if (
auto cmp = Common::StdCompat::compare_three_way{}(lhs.GetFragment (), rhs.GetFragment ()); cmp != strong_ordering::equal) {
421 return strong_ordering::equal;
RegularExpression is a compiled regular expression which can be used to match on a String class.
Similar to String, but intended to more efficiently construct a String. Mutable type (String is large...
nonvirtual bool empty() const noexcept
nonvirtual String str() const
String is like std::u32string, except it is much easier to use, often much more space efficient,...
nonvirtual bool Matches(const RegularExpression ®Ex) const
nonvirtual bool EndsWith(const Character &c, CompareOptions co=eWithCase) const
nonvirtual String SubString(SZ from) const
nonvirtual bool StartsWith(const Character &c, CompareOptions co=eWithCase) const
nonvirtual T AsASCII() const
NOT a real mutex - just a debugging infrastructure support tool so in debug builds can be assured thr...
nonvirtual String GetAuthorityRelativeResourceDir() const
Return the path component, excluding any text after the final /.
static URI Parse(const String &rawURL)
nonvirtual String ToString() const
nonvirtual T As(optional< StringPCTEncodedFlag > pctEncoded={}) const
nonvirtual optional< SchemeType > GetScheme() const
nonvirtual void SetPath(const String &path)
nonvirtual URI Combine(const URI &overridingURI) const
Combine overridingURI possibly relative url with this base url, to produce a new URI.
static URI ParseRelative(const String &rawRelativeURL)
nonvirtual optional< Authority > GetAuthority() const
nonvirtual URI Normalize(NormalizationStyle normalization=NormalizationStyle::eDefault) const
Produce a normalized representation of the URI.
nonvirtual void SetScheme(const optional< SchemeType > &scheme)
nonvirtual bool All(const function< bool(ArgByValueType< T >)> &testEachElt) const
return true iff argument predicate returns true for each element of the iterable
void Throw(T &&e2Throw)
identical to builtin C++ 'throw' except that it does helpful, type dependent DbgTrace() messages firs...