00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #include <stdlib.h>
00024 #include "TUrl.h"
00025 #include "THashList.h"
00026 #include "TObjArray.h"
00027 #include "TObjString.h"
00028 #include "TEnv.h"
00029 #include "TSystem.h"
00030 #include "TMap.h"
00031 #include "TVirtualMutex.h"
00032
00033 TObjArray *TUrl::fgSpecialProtocols = 0;
00034 THashList *TUrl::fgHostFQDNs = 0;
00035
00036 TVirtualMutex *gURLMutex = 0;
00037
00038 #ifdef R__COMPLETE_MEM_TERMINATION
00039 namespace {
00040 class TUrlCleanup {
00041 TObjArray **fSpecialProtocols;
00042 THashList **fHostFQDNs;
00043 public:
00044 TUrlCleanup(TObjArray **protocols, THashList **hosts) : fSpecialProtocols(protocols),fHostFQDNs(hosts) {}
00045 ~TUrlCleanup() {
00046 if (*fSpecialProtocols) (*fSpecialProtocols)->Delete();
00047 delete *fSpecialProtocols;
00048 *fSpecialProtocols = 0;
00049 if (*fHostFQDNs) (*fHostFQDNs)->Delete();
00050 delete *fHostFQDNs;
00051 *fHostFQDNs = 0;
00052 }
00053 };
00054 }
00055 #endif
00056
00057 ClassImp(TUrl)
00058
00059
00060 TUrl::TUrl(const char *url, Bool_t defaultIsFile)
00061 {
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076
00077
00078 SetUrl(url, defaultIsFile);
00079
00080 #ifdef R__COMPLETE_MEM_TERMINATION
00081 static TUrlCleanup cleanup(&fgSpecialProtocols,&fgHostFQDNs);
00082 #endif
00083 }
00084
00085
00086 TUrl::~TUrl()
00087 {
00088
00089
00090 delete fOptionsMap;
00091 }
00092
00093
00094 void TUrl::SetUrl(const char *url, Bool_t defaultIsFile)
00095 {
00096
00097
00098
00099
00100
00101
00102
00103
00104
00105
00106
00107
00108
00109
00110
00111
00112 fOptionsMap = 0;
00113
00114 if (!url || !strlen(url)) {
00115 fPort = -1;
00116 return;
00117 }
00118
00119
00120 fUrl = "";
00121 fProtocol = "http";
00122 fUser = "";
00123 fPasswd = "";
00124 fHost = "";
00125 fPort = 80;
00126 fFile = "";
00127 fAnchor = "";
00128 fOptions = "";
00129
00130
00131 if (url[0] == '/')
00132 defaultIsFile = kTRUE;
00133
00134
00135 char *s, sav;
00136
00137 char *u, *u0 = Strip(url);
00138 tryfile:
00139 u = u0;
00140
00141
00142 for (int i = 0; i < GetSpecialProtocols()->GetEntriesFast(); i++) {
00143 TObjString *os = (TObjString*) GetSpecialProtocols()->UncheckedAt(i);
00144 TString s1 = os->GetString();
00145 int l = s1.Length();
00146 Bool_t stripoff = kFALSE;
00147 if (s1.EndsWith("/-")) {
00148 stripoff = kTRUE;
00149 s1 = s1.Strip(TString::kTrailing, '-');
00150 l--;
00151 }
00152 if (!strncmp(u, s1, l)) {
00153 if (s1(0) == '/' && s1(l-1) == '/') {
00154
00155 fProtocol = s1(1, l-2);
00156 if (stripoff)
00157 l--;
00158 else
00159 l = 0;
00160 } else {
00161
00162 fProtocol = s1(0, l-1);
00163 }
00164 if (!strncmp(u+l, "//", 2))
00165 u += l+2;
00166 else
00167 u += l;
00168 fPort = 0;
00169
00170 FindFile(u, kFALSE);
00171
00172 delete [] u0;
00173 return;
00174 }
00175 }
00176
00177 u = u0;
00178
00179 char *t, *s2;
00180
00181 if ((s = strstr(u, ":/")) && u+1 != s) {
00182 if (*(s+2) != '/') {
00183 Error("TUrl", "%s malformed, URL must contain \"://\"", u0);
00184 fPort = -1;
00185 goto cleanup;
00186 }
00187 sav = *s;
00188 *s = 0;
00189 SetProtocol(u, kTRUE);
00190 *s = sav;
00191 s += 3;
00192 if (!*s) {
00193
00194 fPort = -1;
00195 goto cleanup;
00196 }
00197 } else {
00198 if (defaultIsFile) {
00199 char *newu = new char [strlen("file:") + strlen(u0) + 1];
00200 sprintf(newu, "file:%s", u0);
00201 delete [] u0;
00202 u0 = newu;
00203 goto tryfile;
00204 }
00205 s = u;
00206 }
00207
00208
00209 u = s;
00210 t = s;
00211 again:
00212 if ((s = strchr(t, '@'))) {
00213 if (*(s-1) == '\\') {
00214 t = s+1;
00215 goto again;
00216 }
00217 sav = *s;
00218 *s = 0;
00219 if ((s2 = strchr(u, ':'))) {
00220 *s2 = 0;
00221 fUser = u;
00222 *s2 = ':';
00223 s2++;
00224 if (*s2) {
00225 fPasswd = s2;
00226 fPasswd.ReplaceAll("\\@", "@");
00227 }
00228 } else
00229 fUser = u;
00230 *s = sav;
00231 s++;
00232 } else
00233 s = u;
00234
00235
00236 u = s;
00237 if ((s = strchr(u, ':')) || (s = strchr(u, '/'))) {
00238 if ((strchr (u, ':') > strchr(u, '/')) && (strchr (u, '/')))
00239 s = strchr(u, '/');
00240 sav = *s;
00241 *s = 0;
00242 fHost = u;
00243 *s = sav;
00244 if (sav == ':') {
00245 s++;
00246
00247 if (!*s) {
00248 fPort = -1;
00249 goto cleanup;
00250 }
00251 u = s;
00252 if ((s = strchr(u, '/'))) {
00253 sav = *s;
00254 *s = 0;
00255 fPort = atoi(u);
00256 *s = sav;
00257 } else {
00258 fPort = atoi(u);
00259 goto cleanup;
00260 }
00261 }
00262 } else {
00263 fHost = u;
00264 goto cleanup;
00265 }
00266
00267 if (!*s) goto cleanup;
00268
00269
00270 u = s;
00271 if (*u == '/' && fHost.Length())
00272 u++;
00273
00274 FindFile(u);
00275
00276 cleanup:
00277 delete [] u0;
00278 }
00279
00280
00281 void TUrl::FindFile(char *u, Bool_t stripDoubleSlash)
00282 {
00283
00284
00285 char *s, sav;
00286
00287
00288 char *opt = strchr(u, '?');
00289 char *anc = strchr(u, '#');
00290
00291
00292 if (opt && anc && opt > anc) {
00293 fPort = -1;
00294 return;
00295 }
00296
00297 if ((s = opt) || (s = anc)) {
00298 sav = *s;
00299 *s = 0;
00300 fFile = u;
00301 if (stripDoubleSlash)
00302 fFile.ReplaceAll("//", "/");
00303 *s = sav;
00304 s++;
00305 if (sav == '?') {
00306
00307 if (!*s) {
00308
00309 return;
00310 }
00311 u = s;
00312 if ((s = strchr(u, '#'))) {
00313 sav = *s;
00314 *s = 0;
00315 fOptions = u;
00316 *s = sav;
00317 s++;
00318 } else {
00319 fOptions = u;
00320 return;
00321 }
00322 }
00323 if (!*s) {
00324
00325 return;
00326 }
00327 } else {
00328 fFile = u;
00329 if (stripDoubleSlash)
00330 fFile.ReplaceAll("//", "/");
00331 return;
00332 }
00333
00334
00335 fAnchor = s;
00336 }
00337
00338
00339 TUrl::TUrl(const TUrl &url) : TObject(url)
00340 {
00341
00342
00343 fUrl = url.fUrl;
00344 fProtocol = url.fProtocol;
00345 fUser = url.fUser;
00346 fPasswd = url.fPasswd;
00347 fHost = url.fHost;
00348 fFile = url.fFile;
00349 fAnchor = url.fAnchor;
00350 fOptions = url.fOptions;
00351 fPort = url.fPort;
00352 fFileOA = url.fFileOA;
00353 fHostFQ = url.fHostFQ;
00354 fOptionsMap = 0;
00355 }
00356
00357
00358 TUrl &TUrl::operator=(const TUrl &rhs)
00359 {
00360
00361
00362 if (this != &rhs) {
00363 TObject::operator=(rhs);
00364 fUrl = rhs.fUrl;
00365 fProtocol = rhs.fProtocol;
00366 fUser = rhs.fUser;
00367 fPasswd = rhs.fPasswd;
00368 fHost = rhs.fHost;
00369 fFile = rhs.fFile;
00370 fAnchor = rhs.fAnchor;
00371 fOptions = rhs.fOptions;
00372 fPort = rhs.fPort;
00373 fFileOA = rhs.fFileOA;
00374 fHostFQ = rhs.fHostFQ;
00375 fOptionsMap = 0;
00376 }
00377 return *this;
00378 }
00379
00380
00381 const char *TUrl::GetUrl(Bool_t withDeflt) const
00382 {
00383
00384
00385
00386 if (((TestBit(kUrlWithDefaultPort) && !withDeflt) ||
00387 (!TestBit(kUrlWithDefaultPort) && withDeflt)) &&
00388 TestBit(kUrlHasDefaultPort))
00389 fUrl = "";
00390
00391 if (IsValid() && fUrl == "") {
00392
00393 for (int i = 0; i < GetSpecialProtocols()->GetEntriesFast(); i++) {
00394 TObjString *os = (TObjString*) GetSpecialProtocols()->UncheckedAt(i);
00395 TString &s = os->String();
00396 int l = s.Length();
00397 if (fProtocol == s(0, l-1)) {
00398 if (fFile[0] == '/')
00399 fUrl = fProtocol + "://" + fFile;
00400 else
00401 fUrl = fProtocol + ":" + fFile;
00402 if (fOptions != "") {
00403 fUrl += "?";
00404 fUrl += fOptions;
00405 }
00406 if (fAnchor != "") {
00407 fUrl += "#";
00408 fUrl += fAnchor;
00409 }
00410 return fUrl;
00411 }
00412 }
00413
00414 Bool_t deflt = kFALSE;
00415 if ((!fProtocol.CompareTo("http") && fPort == 80) ||
00416 (fProtocol.BeginsWith("proof") && fPort == 1093) ||
00417 (fProtocol.BeginsWith("root") && fPort == 1094) ||
00418 (!fProtocol.CompareTo("ftp") && fPort == 20) ||
00419 (!fProtocol.CompareTo("news") && fPort == 119) ||
00420 fPort == 0) {
00421 deflt = kTRUE;
00422 ((TUrl *)this)->SetBit(kUrlHasDefaultPort);
00423 }
00424
00425 fUrl = fProtocol + "://";
00426 if (fUser != "") {
00427 fUrl += fUser;
00428 if (fPasswd != "") {
00429 fUrl += ":";
00430 TString passwd = fPasswd;
00431 passwd.ReplaceAll("@", "\\@");
00432 fUrl += passwd;
00433 }
00434 fUrl += "@";
00435 }
00436 if (withDeflt)
00437 ((TUrl*)this)->SetBit(kUrlWithDefaultPort);
00438 else
00439 ((TUrl*)this)->ResetBit(kUrlWithDefaultPort);
00440
00441 if (!deflt || withDeflt) {
00442 char p[10];
00443 sprintf(p, "%d", fPort);
00444 fUrl = fUrl + fHost + ":" + p + "/" + fFile;
00445 } else
00446 fUrl = fUrl + fHost + "/" + fFile;
00447 if (fOptions != "") {
00448 fUrl += "?";
00449 fUrl += fOptions;
00450 }
00451 if (fAnchor != "") {
00452 fUrl += "#";
00453 fUrl += fAnchor;
00454 }
00455 }
00456
00457 fUrl.ReplaceAll("////", "///");
00458 return fUrl;
00459 }
00460
00461
00462 const char *TUrl::GetHostFQDN() const
00463 {
00464
00465
00466
00467 if (fHostFQ == "") {
00468
00469 TNamed *fqdn = fgHostFQDNs ? (TNamed *) fgHostFQDNs->FindObject(fHost) : 0;
00470 if (!fqdn) {
00471 TInetAddress adr(gSystem->GetHostByName(fHost));
00472 if (adr.IsValid()) {
00473 fHostFQ = adr.GetHostName();
00474 } else
00475 fHostFQ = "-";
00476 R__LOCKGUARD2(gURLMutex);
00477 if (!fgHostFQDNs) {
00478 fgHostFQDNs = new THashList;
00479 fgHostFQDNs->SetOwner();
00480 }
00481 if (fgHostFQDNs && !fgHostFQDNs->FindObject(fHost))
00482 fgHostFQDNs->Add(new TNamed(fHost,fHostFQ));
00483 } else {
00484 fHostFQ = fqdn->GetTitle();
00485 }
00486 }
00487 if (fHostFQ == "-")
00488 return fHost;
00489 return fHostFQ;
00490 }
00491
00492
00493 const char *TUrl::GetFileAndOptions() const
00494 {
00495
00496
00497
00498
00499 if (fFileOA == "") {
00500 fFileOA = fFile;
00501 if (fOptions != "") {
00502 fFileOA += "?";
00503 fFileOA += fOptions;
00504 }
00505 if (fAnchor != "") {
00506 fFileOA += "#";
00507 fFileOA += fAnchor;
00508 }
00509 }
00510 return fFileOA;
00511 }
00512
00513
00514 void TUrl::SetProtocol(const char *proto, Bool_t setDefaultPort)
00515 {
00516
00517
00518 fProtocol = proto;
00519 if (setDefaultPort) {
00520 if (!fProtocol.CompareTo("http"))
00521 fPort = 80;
00522 else if (fProtocol.BeginsWith("proof"))
00523 fPort = 1093;
00524 else if (fProtocol.BeginsWith("root"))
00525 fPort = 1094;
00526 else if (!fProtocol.CompareTo("ftp"))
00527 fPort = 20;
00528 else if (!fProtocol.CompareTo("news"))
00529 fPort = 119;
00530 else {
00531
00532 fPort = 0;
00533 }
00534 }
00535 fUrl = "";
00536 }
00537
00538
00539 Int_t TUrl::Compare(const TObject *obj) const
00540 {
00541
00542
00543 if (this == obj) return 0;
00544 if (TUrl::Class() != obj->IsA()) return -1;
00545 return TString(GetUrl()).CompareTo(((TUrl*)obj)->GetUrl(), TString::kExact);
00546 }
00547
00548
00549 void TUrl::Print(Option_t *) const
00550 {
00551
00552
00553 if (fPort == -1)
00554 Printf("Illegal URL");
00555
00556 Printf("%s", GetUrl());
00557 }
00558
00559
00560 TObjArray *TUrl::GetSpecialProtocols()
00561 {
00562
00563
00564
00565
00566
00567 static Bool_t usedEnv = kFALSE;
00568
00569 if (!gEnv) {
00570 R__LOCKGUARD2(gURLMutex);
00571 if (!fgSpecialProtocols)
00572 fgSpecialProtocols = new TObjArray;
00573 if (fgSpecialProtocols->GetEntriesFast() == 0)
00574 fgSpecialProtocols->Add(new TObjString("file:"));
00575 return fgSpecialProtocols;
00576 }
00577
00578 if (usedEnv)
00579 return fgSpecialProtocols;
00580
00581 R__LOCKGUARD2(gURLMutex);
00582 if (fgSpecialProtocols)
00583 fgSpecialProtocols->Delete();
00584
00585 if (!fgSpecialProtocols)
00586 fgSpecialProtocols = new TObjArray;
00587
00588 const char *protos = gEnv->GetValue("Url.Special", "file: rfio: hpss: castor: dcache: dcap:");
00589 usedEnv = kTRUE;
00590
00591 if (protos) {
00592 Int_t cnt = 0;
00593 char *p = StrDup(protos);
00594 while (1) {
00595 TObjString *proto = new TObjString(strtok(!cnt ? p : 0, " "));
00596 if (proto->String().IsNull()) {
00597 delete proto;
00598 break;
00599 }
00600 fgSpecialProtocols->Add(proto);
00601 cnt++;
00602 }
00603 delete [] p;
00604 }
00605 return fgSpecialProtocols;
00606 }
00607
00608
00609
00610 void TUrl::ParseOptions() const
00611 {
00612
00613
00614 if (fOptionsMap) return;
00615
00616 TString urloptions = GetOptions();
00617 TObjArray *objOptions = urloptions.Tokenize("&");
00618 for (Int_t n = 0; n < objOptions->GetEntries(); n++) {
00619 TString loption = ((TObjString *) objOptions->At(n))->GetName();
00620 TObjArray *objTags = loption.Tokenize("=");
00621 if (objTags->GetEntries() == 2) {
00622 TString key = ((TObjString *) objTags->At(0))->GetName();
00623 TString value = ((TObjString *) objTags->At(1))->GetName();
00624 if (!fOptionsMap) {
00625 fOptionsMap = new TMap;
00626 fOptionsMap->SetOwnerKeyValue();
00627 }
00628 fOptionsMap->Add(new TObjString(key), new TObjString(value));
00629 }
00630 delete objTags;
00631 }
00632 delete objOptions;
00633 }
00634
00635
00636
00637 const char *TUrl::GetValueFromOptions(const char *key) const
00638 {
00639
00640
00641
00642 if (!key) return 0;
00643 ParseOptions();
00644 TObject *option = fOptionsMap ? fOptionsMap->GetValue(key) : 0;
00645 return (option ? ((TObjString*)fOptionsMap->GetValue(key))->GetName(): 0);
00646 }
00647
00648
00649 Int_t TUrl::GetIntValueFromOptions(const char *key) const
00650 {
00651
00652
00653
00654 if (!key) return -1;
00655 ParseOptions();
00656 TObject *option = fOptionsMap ? fOptionsMap->GetValue(key) : 0;
00657 return (option ? (atoi(((TObjString*)fOptionsMap->GetValue(key))->GetName())) : -1);
00658 }
00659
00660
00661 void TUrl::CleanRelativePath()
00662 {
00663
00664
00665 Ssiz_t slash = 0;
00666 while ( (slash = fFile.Index("/..") ) != kNPOS) {
00667
00668 Bool_t found = kFALSE;
00669 for (int l = slash-1; l >=0; l--) {
00670 if (fFile[l] == '/') {
00671
00672 fFile.Remove(l, slash+3-l);
00673 found = kTRUE;
00674 break;
00675 }
00676 }
00677 if (!found)
00678 break;
00679 }
00680 }