TUrl.cxx

Go to the documentation of this file.
00001 // @(#)root/base:$Id: TUrl.cxx 37531 2010-12-10 20:38:06Z pcanal $
00002 // Author: Fons Rademakers   17/01/97
00003 
00004 /*************************************************************************
00005  * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers.               *
00006  * All rights reserved.                                                  *
00007  *                                                                       *
00008  * For the licensing terms see $ROOTSYS/LICENSE.                         *
00009  * For the list of contributors see $ROOTSYS/README/CREDITS.             *
00010  *************************************************************************/
00011 
00012 //////////////////////////////////////////////////////////////////////////
00013 //                                                                      //
00014 // TUrl                                                                 //
00015 //                                                                      //
00016 // This class represents a WWW compatible URL.                          //
00017 // It provides member functions to return the different parts of        //
00018 // an URL. The supported url format is:                                 //
00019 //  [proto://][user[:passwd]@]host[:port]/file.ext[#anchor][?options]   //
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; // local mutex
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    // Parse url character string and split in its different subcomponents.
00063    // Use IsValid() to check if URL is legal.
00064    //
00065    // url: [proto://][user[:passwd]@]host[:port]/file.ext[?options][#anchor]
00066    //
00067    // Known protocols: http, root, proof, ftp, news and any special protocols
00068    // defined in the rootrc Url.Special key.
00069    // The default protocol is "http", unless defaultIsFile is true in which
00070    // case the url is assumed to be of type "file".
00071    // If a passwd contains a @ it must be escaped by a \\, e.g.
00072    // "pip@" becomes "pip\\@".
00073    //
00074    // Default ports: http=80, root=1094, proof=1093, ftp=20, news=119.
00075    // Port #1093 has been assigned by IANA (www.iana.org) to proofd.
00076    // Port #1094 has been assigned by IANA (www.iana.org) to rootd.
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    // Cleanup.
00089 
00090    delete fOptionsMap;
00091 }
00092 
00093 //______________________________________________________________________________
00094 void TUrl::SetUrl(const char *url, Bool_t defaultIsFile)
00095 {
00096    // Parse url character string and split in its different subcomponents.
00097    // Use IsValid() to check if URL is legal.
00098    //
00099    // url: [proto://][user[:passwd]@]host[:port]/file.ext[?options][#anchor]
00100    //
00101    // Known protocols: http, root, proof, ftp, news and any special protocols
00102    // defined in the rootrc Url.Special key.
00103    // The default protocol is "http", unless defaultIsFile is true in which
00104    // case the url is assumed to be of type "file".
00105    // If a passwd contains a @ it must be escaped by a \\, e.g.
00106    // "pip@" becomes "pip\\@".
00107    //
00108    // Default ports: http=80, root=1094, proof=1093, ftp=20, news=119.
00109    // Port #1093 has been assigned by IANA (www.iana.org) to proofd.
00110    // Port #1094 has been assigned by IANA (www.iana.org) to rootd.
00111 
00112    fOptionsMap = 0;
00113 
00114    if (!url || !strlen(url)) {
00115       fPort = -1;
00116       return;
00117    }
00118 
00119    // Set defaults
00120    fUrl        = "";
00121    fProtocol   = "http";
00122    fUser       = "";
00123    fPasswd     = "";
00124    fHost       = "";
00125    fPort       = 80;
00126    fFile       = "";
00127    fAnchor     = "";
00128    fOptions    = "";
00129 
00130    // if url starts with a / consider it as a file url
00131    if (url[0] == '/')
00132       defaultIsFile = kTRUE;
00133 
00134    // Find protocol
00135    char *s, sav;
00136 
00137    char *u, *u0 = Strip(url);
00138 tryfile:
00139    u = u0;
00140 
00141    // Handle special protocol cases: "file:", "rfio:", etc.
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             // case whith file namespace like: /alien/user/file.root
00155             fProtocol = s1(1, l-2);
00156             if (stripoff)
00157                l--;    // strip off namespace prefix from file name
00158             else
00159                l = 0;  // leave namespace prefix as part of file name
00160          } else {
00161             // case with protocol, like: rfio:machine:/data/file.root
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    // allow x:/path as Windows filename
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          // error if we are at end of string
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    // Find user and passwd
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    // Find host
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          // Get port #
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    // Find file
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    // Find file and optionally anchor and options.
00284 
00285    char *s, sav;
00286 
00287    // Locate anchor and options, if any
00288    char *opt = strchr(u, '?');
00289    char *anc = strchr(u, '#');
00290 
00291    // URL invalid if anchor is coming before the options
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          // Get options
00307          if (!*s) {
00308             // options string is empty
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          // anchor string is empty
00325          return;
00326       }
00327    } else {
00328       fFile = u;
00329       if (stripDoubleSlash)
00330          fFile.ReplaceAll("//", "/");
00331       return;
00332    }
00333 
00334    // Set anchor
00335    fAnchor = s;
00336 }
00337 
00338 //______________________________________________________________________________
00339 TUrl::TUrl(const TUrl &url) : TObject(url)
00340 {
00341    // TUrl copt ctor.
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    // TUrl assignment operator.
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    // Return full URL. If withDflt is kTRUE, explicitly add the port even
00384    // if it matches the default value for the URL protocol.
00385 
00386    if (((TestBit(kUrlWithDefaultPort) && !withDeflt) ||
00387        (!TestBit(kUrlWithDefaultPort) && withDeflt)) &&
00388        TestBit(kUrlHasDefaultPort))
00389       fUrl = "";
00390 
00391    if (IsValid() && fUrl == "") {
00392       // Handle special protocol cases: file:, rfio:, etc.
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    // Return fully qualified domain name of url host. If host cannot be
00465    // resolved or not valid return the host name as originally specified.
00466 
00467    if (fHostFQ == "") {
00468       // Check if we already resolved it
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    // Return the file and its options (the string specified behind the ?).
00496    // Convenience function useful when the option is used to pass
00497    // authetication/access information for the specified file.
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    // Set protocol and, optionally, change the port accordingly.
00517 
00518    fProtocol = proto;
00519    if (setDefaultPort) {
00520       if (!fProtocol.CompareTo("http"))
00521          fPort = 80;
00522       else if (fProtocol.BeginsWith("proof"))  // can also be proofs or proofk
00523          fPort = 1093;
00524       else if (fProtocol.BeginsWith("root"))   // can also be roots or rootk
00525          fPort = 1094;
00526       else if (!fProtocol.CompareTo("ftp"))
00527          fPort = 20;
00528       else if (!fProtocol.CompareTo("news"))
00529          fPort = 119;
00530       else {
00531          // generic protocol (no default port)
00532          fPort = 0;
00533       }
00534    }
00535    fUrl = "";
00536 }
00537 
00538 //______________________________________________________________________________
00539 Int_t TUrl::Compare(const TObject *obj) const
00540 {
00541    // Compare two urls as strings.
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    // Print URL on stdout.
00552 
00553    if (fPort == -1)
00554       Printf("Illegal URL");
00555 
00556    Printf("%s", GetUrl());
00557 }
00558 
00559 //______________________________________________________________________________
00560 TObjArray *TUrl::GetSpecialProtocols()
00561 {
00562    // Read the list of special protocols from the rootrc files.
00563    // These protocols will be parsed in a protocol and a file part,
00564    // no host or other info will be determined. This is typically
00565    // used for legacy file descriptions like: rfio:host:/path/file.root.
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    // Parse URL options into a key/value map.
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    // Return a value for a given key from the URL options.
00640    // Returns 0 in case key is not found.
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    // Return a value for a given key from the URL options as an Int_t,
00652    // a missing key returns -1.
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    // Recompute the path removing all relative directory jumps via '..'.
00664 
00665    Ssiz_t slash = 0;
00666    while ( (slash = fFile.Index("/..") ) != kNPOS) {
00667       // find backwards the next '/'
00668       Bool_t found = kFALSE;
00669       for (int l = slash-1; l >=0; l--) {
00670          if (fFile[l] == '/') {
00671             // found previous '/'
00672             fFile.Remove(l, slash+3-l);
00673             found = kTRUE;
00674             break;
00675          }
00676       }
00677       if (!found)
00678         break;
00679    }
00680 }

Generated on Tue Jul 5 14:11:24 2011 for ROOT_528-00b_version by  doxygen 1.5.1