30 const char*
const kURI_pchar =
"(?:[[:alpha:][:digit:]-._~!$&'()*+,;=:@]|%[0-9A-Fa-f][0-9A-Fa-f])";
33 const char*
const kURI_unreserved =
"[[:alpha:][:digit:]-._~]";
52 TUri::TUri(
const TString &uri)
60 TUri::TUri(
const char *uri)
68 TUri::TUri(
const TUri &uri) : TObject(uri)
70 fScheme = uri.fScheme;
71 fUserinfo = uri.fUserinfo;
76 fFragment = uri.fFragment;
77 fHasScheme = uri.fHasScheme;
78 fHasUserinfo = uri.fHasUserinfo;
79 fHasHost = uri.fHasHost;
80 fHasPort = uri.fHasPort;
81 fHasPath = uri.fHasPath;
82 fHasQuery = uri.fHasQuery;
83 fHasFragment = uri.fHasFragment;
89 TUri &TUri::operator= (
const TUri & rhs)
92 TObject::operator= (rhs);
93 fScheme = rhs.fScheme;
94 fUserinfo = rhs.fUserinfo;
99 fFragment = rhs.fFragment;
100 fHasScheme = rhs.fHasScheme;
101 fHasUserinfo = rhs.fHasUserinfo;
102 fHasHost = rhs.fHasHost;
103 fHasPort = rhs.fHasPort;
104 fHasPath = rhs.fHasPath;
105 fHasQuery = rhs.fHasQuery;
106 fHasFragment = rhs.fHasFragment;
116 Bool_t operator== (
const TUri &u1,
const TUri &u2)
125 return u11.GetUri() == u22.GetUri();
140 const TString TUri::GetUri()
const
144 result = fScheme +
":";
145 result += GetHierPart();
147 result += TString(
"?") + fQuery;
149 result += TString(
"#") + fFragment;
159 const TString TUri::RemoveDotSegments(
const TString &inp)
161 TString source = inp;
162 TString sink = TString(
"");
165 while (source.Length() > 0) {
167 if (TPRegexp(
"^\\.\\.?/(.*)$").Substitute(source,
"/$1") > 0)
171 if (TPRegexp(
"^/\\./(.*)$|^/\\.($)").Substitute(source,
"/$1") > 0)
175 if (TPRegexp(
"^/\\.\\./(.*)$|^/\\.\\.($)").Substitute(source,
"/$1") > 0) {
176 Ssiz_t last = sink.Last(
'/');
179 sink.Remove(last, sink.Length() - last);
184 if (source.CompareTo(
".") == 0 || source.CompareTo(
"..") == 0) {
185 source.Remove(0, source.Length() - 11);
190 TPRegexp regexp = TPRegexp(
"^(/?[^/]*)(?:/|$)");
191 TObjArray *tokens = regexp.MatchS(source);
192 TString segment = ((TObjString*) tokens->At(1))->GetString();
194 source.Remove(0, segment.Length());
207 Bool_t TUri::IsAbsolute()
const
209 return (HasScheme() && HasHierPart() && !HasFragment());
217 Bool_t TUri::IsRelative()
const
219 return (!HasScheme() && HasRelativePart());
227 Bool_t TUri::IsUri()
const
229 return (HasScheme() && HasHierPart());
237 Bool_t TUri::IsReference()
const
239 return (IsUri() || IsRelative());
248 Bool_t TUri::SetScheme(
const TString &scheme)
254 if (IsScheme(scheme)) {
259 Error(
"SetScheme",
"<scheme> component \"%s\" of URI is not compliant with RFC 3986.", scheme.Data());
270 Bool_t TUri::IsScheme(
const TString &
string)
273 "^[[:alpha:]][[:alpha:][:digit:]+-.]*$"
283 const TString TUri::GetAuthority()
const
285 TString authority = fHasUserinfo ? fUserinfo +
"@" + fHost : fHost;
286 if (fHasPort && !fPort.IsNull())
288 authority += TString(
":") + TString(fPort);
298 Bool_t TUri::SetQuery(
const TString &query)
304 if (IsQuery(query)) {
309 Error(
"SetQuery",
"<query> component \"%s\" of URI is not compliant with RFC 3986.", query.Data());
320 Bool_t TUri::IsQuery(
const TString &
string)
323 TString(
"^([/?]|") + kURI_pchar +
")*$"
338 Bool_t TUri::SetAuthority(
const TString &authority)
340 if (authority.IsNull()) {
341 fHasUserinfo = kFALSE;
346 TPRegexp regexp = TPRegexp(
"^(?:(.*@))?([^:]*)((?::.*)?)$");
347 TObjArray *tokens = regexp.MatchS(authority);
349 if (tokens->GetEntries() != 4) {
350 Error(
"SetAuthority",
"<authority> component \"%s\" of URI is not compliant with RFC 3986.", authority.Data());
354 Bool_t valid = kTRUE;
357 TString userinfo = ((TObjString*) tokens->At(1))->GetString();
358 if (userinfo.EndsWith(
"@")) {
359 userinfo.Remove(TString::kTrailing,
'@');
360 valid &= SetUserInfo(userinfo);
364 TString host = ((TObjString*) tokens->At(2))->GetString();
365 valid &= SetHost(host);
368 TString port = ((TObjString*) tokens->At(3))->GetString();
369 if (port.BeginsWith(
":")) {
370 port.Remove(TString::kLeading,
':');
371 valid &= SetPort(port);
383 Bool_t TUri::IsAuthority(
const TString &
string)
386 TPRegexp regexp = TPRegexp(
"^(?:(.*)@)?([^:]*)(?::(.*))?$");
387 TObjArray *tokens = regexp.MatchS(
string);
388 TString userinfo = ((TObjString*) tokens->At(1))->GetString();
389 TString host = ((TObjString*) tokens->At(2))->GetString();
392 if (tokens->GetEntries() == 4)
393 port = ((TObjString*) tokens->At(3))->GetString();
396 return (IsHost(host) && IsUserInfo(userinfo) && IsPort(port));
405 Bool_t TUri::SetUserInfo(
const TString &userinfo)
407 if (userinfo.IsNull()) {
408 fHasUserinfo = kFALSE;
411 if (IsUserInfo(userinfo)) {
412 fUserinfo = userinfo;
413 fHasUserinfo = kTRUE;
416 Error(
"SetUserInfo",
"<userinfo> component \"%s\" of URI is not compliant with RFC 3986.", userinfo.Data());
428 Bool_t TUri::IsUserInfo(
const TString &
string)
431 "^" + TString(kURI_pchar) +
"*$"
432 ).Match(
string) > 0 && !TString(
string).Contains(
"@"));
442 Bool_t TUri::SetHost(
const TString &host)
449 Error(
"SetHost",
"<host> component \"%s\" of URI is not compliant with RFC 3986.", host.Data());
460 Bool_t TUri::SetPort(
const TString &port)
467 Error(
"SetPort",
"<port> component \"%s\" of URI is not compliant with RFC 3986.", port.Data());
481 Bool_t TUri::SetPath(
const TString &path)
488 Error(
"SetPath",
"<path> component \"%s\" of URI is not compliant with RFC 3986.", path.Data());
498 Bool_t TUri::SetFragment(
const TString &fragment)
500 if (IsFragment(fragment)) {
501 fFragment = fragment;
502 fHasFragment = kTRUE;
505 Error(
"SetFragment",
"<fragment> component \"%s\" of URI is not compliant with RFC 3986.", fragment.Data());
516 Bool_t TUri::IsFragment(
const TString &
string)
519 "^(" + TString(kURI_pchar) +
"|[/?])*$"
520 ).Match(
string) > 0);
528 void TUri::Print(Option_t *option)
const
530 if (strcmp(option,
"d") != 0) {
531 Printf(
"%s", GetUri().Data());
535 Printf(
"URI: <%s>", GetUri().Data());
536 Printf(
"(%c) |--scheme---------<%s>", fHasScheme ?
't' :
'f', fScheme.Data());
537 Printf(
" |--hier-----------<%s>", GetHierPart().Data());
538 Printf(
"(%c) |--authority------<%s>", HasAuthority() ?
't' :
'f', GetAuthority().Data());
539 Printf(
"(%c) |--userinfo---<%s>", fHasUserinfo ?
't' :
'f', fUserinfo.Data());
540 Printf(
"(%c) |--host-------<%s>", fHasHost ?
't' :
'f', fHost.Data());
541 Printf(
"(%c) |--port-------<%s>", fHasPort ?
't' :
'f', fPort.Data());
542 Printf(
"(%c) |--path-------<%s>", fHasPath ?
't' :
'f', fPath.Data());
543 Printf(
"(%c) |--query------<%s>", fHasQuery ?
't' :
'f', fQuery.Data());
544 Printf(
"(%c) |--fragment---<%s>", fHasFragment ?
't' :
'f', fFragment.Data());
545 printf(
"path flags: ");
546 if (IsPathAbempty(fPath))
548 if (IsPathAbsolute(fPath))
550 if (IsPathRootless(fPath))
552 if (IsPathEmpty(fPath))
554 printf(
"\nURI flags: ");
556 printf(
"absolute-URI ");
558 printf(
"relative-ref ");
562 printf(
"URI-reference ");
582 fHasUserinfo = kFALSE;
587 fHasFragment = kFALSE;
601 Bool_t TUri::SetUri(
const TString &uri)
608 TPRegexp regexp = TPRegexp(
"^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)([?]([^#]*))?(#(.*))?");
609 TObjArray *tokens = regexp.MatchS(uri);
612 Bool_t valid = kTRUE;
614 switch (tokens->GetEntries()) {
617 valid &= SetFragment(((TObjString*) tokens->At(9))->GetString());
623 if (!((TString)((TObjString*) tokens->At(6))->GetString()).IsNull())
624 valid &= SetQuery(((TObjString*) tokens->At(7))->GetString());
629 valid &= SetPath(((TObjString*) tokens->At(5))->GetString());
631 if (!((TString)((TObjString*) tokens->At(3))->GetString()).IsNull())
632 valid &= SetAuthority(((TObjString*) tokens->At(4))->GetString());
634 if (!((TString)((TObjString*) tokens->At(1))->GetString()).IsNull())
635 valid &= SetScheme(((TObjString*) tokens->At(2))->GetString());
640 Error(
"SetUri",
"URI \"%s\" is not is not compliant with RFC 3986.", uri.Data());
660 const TString TUri::GetHierPart()
const
662 if (HasAuthority() && IsPathAbempty(fPath))
663 return (TString(
"//") + GetAuthority() + fPath);
676 const TString TUri::GetRelativePart()
const
678 if (HasAuthority() && IsPathAbempty(fPath))
679 return (TString(
"//") + GetAuthority() + fPath);
693 Bool_t TUri::SetHierPart(
const TString &hier)
702 TPRegexp regexp = TPRegexp(
"^(//([^/?#]*))?([^?#]*)$");
703 TObjArray *tokens = regexp.MatchS(hier);
705 if (tokens->GetEntries() == 0) {
706 Error(
"SetHierPart",
"<hier-part> component \"%s\" of URI is not compliant with RFC 3986.", hier.Data());
711 TString delm = ((TObjString*) tokens->At(1))->GetString();
712 TString auth = ((TObjString*) tokens->At(2))->GetString();
713 TString path = ((TObjString*) tokens->At(3))->GetString();
715 Bool_t valid = kTRUE;
717 if (!delm.IsNull() && IsPathAbempty(path)) {
719 valid &= SetAuthority(auth);
720 valid &= SetPath(path);
723 if (IsPathAbsolute(path) || IsPathRootless(path) || IsPathEmpty(path))
724 valid &= SetPath(path);
727 Error(
"SetHierPart",
"<hier-part> component \"%s\" of URI is not compliant with RFC 3986.", hier.Data());
743 Bool_t TUri::IsHierPart(
const TString &
string)
748 return (uri.SetHierPart(
string));
760 Bool_t TUri::IsRelativePart(
const TString &
string)
765 return (uri.SetRelativePart(
string));
777 Bool_t TUri::SetRelativePart(
const TString &relative)
780 TPRegexp regexp = TPRegexp(
"^(//([^/?#]*))?([^?#]*)$");
781 TObjArray *tokens = regexp.MatchS(relative);
783 if (tokens->GetEntries() == 0) {
784 Error(
"SetRelativePath",
"<relative-part> component \"%s\" of URI is not compliant with RFC 3986.", relative.Data());
788 TString delm = ((TObjString*) tokens->At(1))->GetString();
789 TString auth = ((TObjString*) tokens->At(2))->GetString();
790 TString path = ((TObjString*) tokens->At(3))->GetString();
792 Bool_t valid = kTRUE;
794 if (!delm.IsNull() && IsPathAbempty(path)) {
796 valid &= SetAuthority(auth);
797 valid &= SetPath(path);
800 if (IsPathAbsolute(path) || IsPathNoscheme(path) || IsPathEmpty(path))
801 valid &= SetPath(path);
804 Error(
"SetRelativePath",
"<relative-part> component \"%s\" of URI is not compliant with RFC 3986.", relative.Data());
815 const TString TUri::PctEncode(
const TString &source)
819 for (Int_t i = 0; i < source.Length(); i++) {
820 if (IsUnreserved(TString(source(i)))) {
822 sink = sink + source[i];
827 sprintf(buffer,
"%%%02X", source[i]);
828 sink = sink + buffer;
839 Bool_t TUri::IsHost(
const TString &
string)
841 return (IsRegName(
string) || IsIpv4(
string));
854 Bool_t TUri::IsPath(
const TString &
string)
856 return (IsPathAbempty(
string) ||
857 IsPathAbsolute(
string) ||
858 IsPathNoscheme(
string) ||
859 IsPathRootless(
string) ||
860 IsPathEmpty(
string));
870 Bool_t TUri::IsPathAbempty(
const TString &
string)
873 TString(
"^(/") + TString(kURI_pchar) +
"*)*$"
874 ).Match(
string) > 0);
885 Bool_t TUri::IsPathAbsolute(
const TString &
string)
888 TString(
"^/(") + TString(kURI_pchar) +
"+(/" + TString(kURI_pchar) +
"*)*)?$"
889 ).Match(
string) > 0);
900 Bool_t TUri::IsPathNoscheme(
const TString &
string)
903 TString(
"^(([[:alpha:][:digit:]-._~!$&'()*+,;=@]|%[0-9A-Fa-f][0-9A-Fa-f])+)(/") + TString(kURI_pchar) +
"*)*$"
904 ).Match(
string) > 0);
913 Bool_t TUri::IsPathRootless(
const TString &
string)
916 TString(
"^") + TString(kURI_pchar) +
"+(/" + TString(kURI_pchar) +
"*)*$"
926 Bool_t TUri::IsPathEmpty(
const TString &
string)
928 return TString(
string).IsNull();
937 Bool_t TUri::IsPort(
const TString &
string)
939 return (TPRegexp(
"^[[:digit:]]*$").Match(
string) > 0);
950 Bool_t TUri::IsRegName(
const TString &
string)
953 "^([[:alpha:][:digit:]-._~!$&'()*+,;=]|%[0-9A-Fa-f][0-9A-Fa-f])*$").Match(
string) > 0);
962 Bool_t TUri::IsIpv4(
const TString &
string)
965 "^([[:digit:]]{1,3}[.]){3}[[:digit:]]{1,3}$").Match(
string) > 0);
975 Bool_t TUri::IsUnreserved(
const TString &
string)
978 "^" + TString(kURI_unreserved) +
"*$").Match(
string) > 0);
985 void TUri::Normalise()
991 TString host = GetHost();
997 fUserinfo = PctNormalise(PctDecodeUnreserved(fUserinfo));
998 fHost = PctNormalise(PctDecodeUnreserved(fHost));
999 fPath = PctNormalise(PctDecodeUnreserved(fPath));
1000 fQuery = PctNormalise(PctDecodeUnreserved(fQuery));
1001 fFragment = PctNormalise(PctDecodeUnreserved(fFragment));
1005 SetPath(RemoveDotSegments(GetPath()));
1012 TString
const TUri::PctDecodeUnreserved(
const TString &source)
1016 while (i < source.Length()) {
1017 if (source[i] ==
'%') {
1018 if (source.Length() < i+2) {
1024 char c1 = tolower(source[i + 1]) -
'0';
1028 char c0 = tolower(source[i + 2]) -
'0';
1031 char decoded = c1 << 4 | c0;
1032 if (TPRegexp(kURI_unreserved).Match(decoded) > 0) {
1034 sink = sink + decoded;
1037 TString pct = source(i,3);
1045 sink = sink + source[i];
1057 TString
const TUri::PctNormalise(
const TString &source)
1061 while (i < source.Length()) {
1062 if (source[i] ==
'%') {
1063 if (source.Length() < i+2) {
1067 TString pct = source(i,3);
1075 sink = sink + source[i];
1086 TString
const TUri::PctDecode(
const TString &source)
1090 while (i < source.Length()) {
1091 if (source[i] ==
'%') {
1092 if (source.Length() < i+2) {
1098 char c1 = tolower(source[i + 1]) -
'0';
1102 char c0 = tolower(source[i + 2]) -
'0';
1105 sink = sink + (char)(c1 << 4 | c0);
1110 sink = sink + source[i];
1122 TUri TUri::Transform(
const TUri &reference,
const TUri &base)
1125 if (reference.HasScheme()) {
1126 target.SetScheme(reference.GetScheme());
1127 if (reference.HasAuthority())
1128 target.SetAuthority(reference.GetAuthority());
1129 if (reference.HasPath())
1130 target.SetPath(RemoveDotSegments(reference.GetPath()));
1131 if (reference.HasQuery())
1132 target.SetQuery(reference.GetQuery());
1134 if (reference.HasAuthority()) {
1135 target.SetAuthority(reference.GetAuthority());
1136 if (reference.HasPath())
1137 target.SetPath(RemoveDotSegments(reference.GetPath()));
1138 if (reference.HasQuery())
1139 target.SetQuery(reference.GetQuery());
1141 if (reference.GetPath().IsNull()) {
1142 target.SetPath(base.GetPath());
1143 if (reference.HasQuery()) {
1144 target.SetQuery(reference.GetQuery());
1146 if (base.HasQuery())
1147 target.SetQuery(base.GetQuery());
1150 if (reference.GetPath().BeginsWith(
"/")) {
1151 target.SetPath(RemoveDotSegments(reference.GetPath()));
1153 target.SetPath(RemoveDotSegments(MergePaths(reference, base)));
1155 if (reference.HasQuery())
1156 target.SetQuery(reference.GetQuery());
1158 if (base.HasAuthority())
1159 target.SetAuthority(base.GetAuthority());
1161 if (base.HasScheme())
1162 target.SetScheme(base.GetScheme());
1164 if (reference.HasFragment())
1165 target.SetFragment(reference.GetFragment());
1180 const TString TUri::MergePaths(
const TUri &reference,
const TUri &base)
1182 TString result =
"";
1183 if (base.HasAuthority() && base.GetPath().IsNull()) {
1184 result = TString(
"/") + reference.GetPath();
1186 TString basepath = base.GetPath();
1187 Ssiz_t last = basepath.Last(
'/');
1189 result = reference.GetPath();
1191 result = basepath(0, last + 1) + reference.GetPath();