#include <stdlib.h>
#include "TUrl.h"
#include "THashList.h"
#include "TObjArray.h"
#include "TObjString.h"
#include "TEnv.h"
#include "TSystem.h"
TObjArray *TUrl::fgSpecialProtocols = 0;
THashList *TUrl::fgHostFQDNs = 0;
ClassImp(TUrl)
TUrl::TUrl(const char *url, Bool_t defaultIsFile)
{
SetUrl(url, defaultIsFile);
}
void TUrl::SetUrl(const char *url, Bool_t defaultIsFile)
{
if (!url || !strlen(url)) {
fPort = -1;
return;
}
fUrl = "";
fProtocol = "http";
fUser = "";
fPasswd = "";
fHost = "";
fPort = 80;
fFile = "";
fAnchor = "";
fOptions = "";
if (url[0] == '/')
defaultIsFile = kTRUE;
char *s, sav;
char *u, *u0 = Strip(url);
tryfile:
u = u0;
for (int i = 0; i < GetSpecialProtocols()->GetEntriesFast(); i++) {
TObjString *os = (TObjString*) GetSpecialProtocols()->UncheckedAt(i);
TString s1 = os->GetString();
int l = s1.Length();
Bool_t stripoff = kFALSE;
if (s1.EndsWith("/-")) {
stripoff = kTRUE;
s1 = s1.Strip(TString::kTrailing, '-');
l--;
}
if (!strncmp(u, s1, l)) {
if (s1(0) == '/' && s1(l-1) == '/') {
fProtocol = s1(1, l-2);
if (stripoff)
l--;
else
l = 0;
} else {
fProtocol = s1(0, l-1);
}
if (!strncmp(u+l, "//", 2))
u += l+2;
else
u += l;
fPort = 0;
FindFile(u, kFALSE);
delete [] u0;
return;
}
}
u = u0;
char *t, *s2;
if ((s = strstr(u, ":/")) && u+1 != s) {
if (*(s+2) != '/') {
Error("TUrl", "%s malformed, URL must contain \"://\"", u0);
fPort = -1;
goto cleanup;
}
sav = *s;
*s = 0;
SetProtocol(u, kTRUE);
*s = sav;
s += 3;
if (!*s) {
fPort = -1;
goto cleanup;
}
} else {
if (defaultIsFile) {
char *newu = new char [strlen("file:") + strlen(u0) + 1];
sprintf(newu, "file:%s", u0);
delete [] u0;
u0 = newu;
goto tryfile;
}
s = u;
}
u = s;
t = s;
again:
if ((s = strchr(t, '@'))) {
if (*(s-1) == '\\') {
t = s+1;
goto again;
}
sav = *s;
*s = 0;
if ((s2 = strchr(u, ':'))) {
*s2 = 0;
fUser = u;
*s2 = ':';
s2++;
if (*s2) {
fPasswd = s2;
fPasswd.ReplaceAll("\\@", "@");
}
} else
fUser = u;
*s = sav;
s++;
} else
s = u;
u = s;
if ((s = strchr(u, ':')) || (s = strchr(u, '/'))) {
if ((strchr (u, ':') > strchr(u, '/')) && (strchr (u, '/')))
s = strchr(u, '/');
sav = *s;
*s = 0;
fHost = u;
*s = sav;
if (sav == ':') {
s++;
if (!*s) {
fPort = -1;
goto cleanup;
}
u = s;
if ((s = strchr(u, '/'))) {
sav = *s;
*s = 0;
fPort = atoi(u);
*s = sav;
} else {
fPort = atoi(u);
goto cleanup;
}
}
} else {
fHost = u;
goto cleanup;
}
if (!*s) goto cleanup;
u = s;
if (*u == '/' && fHost.Length())
u++;
FindFile(u);
cleanup:
delete [] u0;
}
void TUrl::FindFile(char *u, Bool_t stripDoubleSlash)
{
char *s, sav;
char *opt = strchr(u, '?');
char *anc = strchr(u, '#');
if (opt && anc && opt > anc) {
fPort = -1;
return;
}
if ((s = opt) || (s = anc)) {
sav = *s;
*s = 0;
fFile = u;
if (stripDoubleSlash)
fFile.ReplaceAll("//", "/");
*s = sav;
s++;
if (sav == '?') {
if (!*s) {
return;
}
u = s;
if ((s = strchr(u, '#'))) {
sav = *s;
*s = 0;
fOptions = u;
*s = sav;
s++;
} else {
fOptions = u;
return;
}
}
if (!*s) {
return;
}
} else {
fFile = u;
if (stripDoubleSlash)
fFile.ReplaceAll("//", "/");
return;
}
fAnchor = s;
}
TUrl::TUrl(const TUrl &url) : TObject(url)
{
fUrl = url.fUrl;
fProtocol = url.fProtocol;
fUser = url.fUser;
fPasswd = url.fPasswd;
fHost = url.fHost;
fFile = url.fFile;
fAnchor = url.fAnchor;
fOptions = url.fOptions;
fPort = url.fPort;
fFileOA = url.fFileOA;
fHostFQ = url.fHostFQ;
}
TUrl &TUrl::operator=(const TUrl &rhs)
{
if (this != &rhs) {
TObject::operator=(rhs);
fUrl = rhs.fUrl;
fProtocol = rhs.fProtocol;
fUser = rhs.fUser;
fPasswd = rhs.fPasswd;
fHost = rhs.fHost;
fFile = rhs.fFile;
fAnchor = rhs.fAnchor;
fOptions = rhs.fOptions;
fPort = rhs.fPort;
fFileOA = rhs.fFileOA;
fHostFQ = rhs.fHostFQ;
}
return *this;
}
const char *TUrl::GetUrl(Bool_t withDeflt)
{
if (IsValid() && fUrl == "") {
for (int i = 0; i < GetSpecialProtocols()->GetEntriesFast(); i++) {
TObjString *os = (TObjString*) GetSpecialProtocols()->UncheckedAt(i);
TString &s = os->String();
int l = s.Length();
if (fProtocol == s(0, l-1)) {
if (fFile[0] == '/')
fUrl = fProtocol + "://" + fFile;
else
fUrl = fProtocol + ":" + fFile;
if (fOptions != "") {
fUrl += "?";
fUrl += fOptions;
}
if (fAnchor != "") {
fUrl += "#";
fUrl += fAnchor;
}
return fUrl;
}
}
Bool_t deflt = kFALSE;
if ((!fProtocol.CompareTo("http") && fPort == 80) ||
(fProtocol.BeginsWith("proof") && fPort == 1093) ||
(fProtocol.BeginsWith("root") && fPort == 1094) ||
(!fProtocol.CompareTo("ftp") && fPort == 20) ||
(!fProtocol.CompareTo("news") && fPort == 119) ||
fPort == 0)
deflt = kTRUE;
fUrl = fProtocol + "://";
if (fUser != "") {
fUrl += fUser;
if (fPasswd != "") {
fUrl += ":";
TString passwd = fPasswd;
passwd.ReplaceAll("@", "\\@");
fUrl += passwd;
}
fUrl += "@";
}
if (!deflt || withDeflt) {
char p[10];
sprintf(p, "%d", fPort);
fUrl = fUrl + fHost + ":" + p + "/" + fFile;
} else
fUrl = fUrl + fHost + "/" + fFile;
if (fOptions != "") {
fUrl += "?";
fUrl += fOptions;
}
if (fAnchor != "") {
fUrl += "#";
fUrl += fAnchor;
}
}
fUrl.ReplaceAll("////", "///");
return fUrl;
}
const char *TUrl::GetHostFQDN() const
{
if (fHostFQ == "") {
TNamed *fqdn = fgHostFQDNs ? (TNamed *) fgHostFQDNs->FindObject(fHost) : 0;
if (!fqdn) {
TInetAddress adr(gSystem->GetHostByName(fHost));
if (adr.IsValid()) {
fHostFQ = adr.GetHostName();
} else
fHostFQ = "-";
if (!fgHostFQDNs) {
fgHostFQDNs = new THashList;
fgHostFQDNs->SetOwner();
}
if (fgHostFQDNs)
fgHostFQDNs->Add(new TNamed(fHost,fHostFQ));
} else {
fHostFQ = fqdn->GetTitle();
}
}
if (fHostFQ == "-")
return fHost;
return fHostFQ;
}
const char *TUrl::GetFileAndOptions() const
{
if (fFileOA == "") {
fFileOA = fFile;
if (fOptions != "") {
fFileOA += "?";
fFileOA += fOptions;
}
if (fAnchor != "") {
fFileOA += "#";
fFileOA += fAnchor;
}
}
return fFileOA;
}
void TUrl::SetProtocol(const char *proto, Bool_t setDefaultPort)
{
fProtocol = proto;
if (setDefaultPort) {
if (!fProtocol.CompareTo("http"))
fPort = 80;
else if (fProtocol.BeginsWith("proof"))
fPort = 1093;
else if (fProtocol.BeginsWith("root"))
fPort = 1094;
else if (!fProtocol.CompareTo("ftp"))
fPort = 20;
else if (!fProtocol.CompareTo("news"))
fPort = 119;
else {
fPort = 0;
}
}
fUrl = "";
}
Int_t TUrl::Compare(const TObject *obj) const
{
if (this == obj) return 0;
if (TUrl::Class() != obj->IsA()) return -1;
return TString(((TUrl*)this)->GetUrl()).CompareTo(((TUrl*)obj)->GetUrl(),
TString::kExact);
}
void TUrl::Print(Option_t *) const
{
if (fPort == -1)
Printf("Illegal URL");
Printf("%s", ((TUrl*)this)->GetUrl());
}
TObjArray *TUrl::GetSpecialProtocols()
{
static Bool_t usedEnv = kFALSE;
if (!fgSpecialProtocols)
fgSpecialProtocols = new TObjArray;
if (!gEnv) {
if (fgSpecialProtocols->GetEntriesFast() == 0)
fgSpecialProtocols->Add(new TObjString("file:"));
return fgSpecialProtocols;
}
if (fgSpecialProtocols->GetEntriesFast() > 0 && usedEnv)
return fgSpecialProtocols;
fgSpecialProtocols->Delete();
const char *protos = gEnv->GetValue("Url.Special", "file: rfio: hpss: castor: dcache: dcap:");
usedEnv = kTRUE;
if (protos) {
Int_t cnt = 0;
char *p = StrDup(protos);
while (1) {
TObjString *proto = new TObjString(strtok(!cnt ? p : 0, " "));
if (proto->String().IsNull()) {
delete proto;
break;
}
fgSpecialProtocols->Add(proto);
cnt++;
}
delete [] p;
}
return fgSpecialProtocols;
}