SNAP Library 2.0, Developer Reference  2013-05-13 16:33:57
SNAP, a general purpose, high performance system for analysis and manipulation of large networks
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines
url.cpp
Go to the documentation of this file.
00001 
00002 // Url-Lexical-Chars
00003 class TUrlLxChDef{
00004 private:
00005   TBoolV IsLoAlphaV, IsHiAlphaV, IsAlphaV;
00006   TBoolV IsDigitV, IsSafeV, IsExtraV;
00007   TBoolV IsNationalV, IsPunctuationV;
00008   TBoolV IsReservedV, IsHexV;
00009   TBoolV IsUnreservedV, IsUCharV, IsXCharV;
00010   TBoolV IsSchemeV, IsHostV, IsHSegmentV;
00011   void InclCh(TBoolV& BoolV, const char& Ch);
00012   void InclStr(TBoolV& BoolV, const TStr& Str);
00013   void InclBoolV(TBoolV& BoolV, const TBoolV& OrBoolV);
00014 public:
00015   static const char EofCh;
00016   static const char EscCh;
00017   TUrlLxChDef();
00018 
00019   bool IsDigitCh(const char& Ch) const {return (Ch>=0)&&IsDigitV[Ch];}
00020   bool IsSchemeCh(const char& Ch) const {return (Ch>=0)&&IsSchemeV[Ch];}
00021   bool IsHostCh(const char& Ch) const {return (Ch>=0)&&IsHostV[Ch];}
00022   bool IsHSegmentCh(const char& Ch) const {
00023     return (Ch<0)||((Ch>=0)&&IsHSegmentV[Ch]);}
00024 };
00025 const char TUrlLxChDef::EofCh=0;
00026 const char TUrlLxChDef::EscCh='%';
00027 
00028 void TUrlLxChDef::InclCh(TBoolV& BoolV, const char& Ch){BoolV[Ch]=true;}
00029 
00030 void TUrlLxChDef::InclStr(TBoolV& BoolV, const TStr& Str){
00031   for (int CC=0; CC<Str.Len(); CC++){BoolV[Str.GetCh(CC)]=true;}}
00032 
00033 void TUrlLxChDef::InclBoolV(TBoolV& BoolV, const TBoolV& OrBoolV){
00034   for (int BoolN=0; BoolN<BoolV.Len(); BoolN++){
00035     BoolV[BoolN]=BoolV[BoolN]||OrBoolV[BoolN];}}
00036 
00037 TUrlLxChDef::TUrlLxChDef():
00038   IsLoAlphaV(TCh::Vals), IsHiAlphaV(TCh::Vals), IsAlphaV(TCh::Vals),
00039   IsDigitV(TCh::Vals), IsSafeV(TCh::Vals), IsExtraV(TCh::Vals),
00040   IsNationalV(TCh::Vals), IsPunctuationV(TCh::Vals),
00041   IsReservedV(TCh::Vals), IsHexV(TCh::Vals),
00042   IsUnreservedV(TCh::Vals), IsUCharV(TCh::Vals), IsXCharV(TCh::Vals),
00043   IsSchemeV(TCh::Vals), IsHostV(TCh::Vals), IsHSegmentV(TCh::Vals){
00044 
00045   InclStr(IsLoAlphaV, "abcdefghijklmnopqrstuvwxyz");
00046   InclStr(IsHiAlphaV, "ABCDEFGHIJKLMNOPQRSTUVWXYZ");
00047   InclBoolV(IsAlphaV, IsLoAlphaV); InclBoolV(IsAlphaV, IsHiAlphaV);
00048   InclStr(IsDigitV, "0123456789");
00049   InclStr(IsSafeV, "$-_.+");
00050   InclStr(IsExtraV, "!*'(),");
00051   InclStr(IsNationalV, "{}|\\^~[]`");
00052   InclStr(IsPunctuationV, "<>#%\"");
00053   InclStr(IsReservedV, ";/?:@&=");
00054   InclBoolV(IsHexV, IsDigitV); InclStr(IsHexV, "ABCDEFabcdef");
00055 
00056   InclBoolV(IsUnreservedV, IsAlphaV); InclBoolV(IsUnreservedV, IsDigitV);
00057   InclBoolV(IsUnreservedV, IsSafeV); InclBoolV(IsUnreservedV, IsExtraV);
00058 
00059   InclBoolV(IsUCharV, IsUnreservedV); InclStr(IsUCharV, TStr(EscCh));
00060 
00061   InclBoolV(IsXCharV, IsUnreservedV); InclBoolV(IsXCharV, IsReservedV);
00062   InclStr(IsXCharV, TStr(EscCh));
00063 
00064   InclBoolV(IsSchemeV, IsAlphaV); InclBoolV(IsSchemeV, IsDigitV);
00065   InclStr(IsSchemeV, "+-.");
00066 
00067   InclBoolV(IsHostV, IsAlphaV); InclBoolV(IsHostV, IsDigitV);
00068   InclStr(IsHostV, "-_");
00069 
00070   InclBoolV(IsHSegmentV, IsUCharV); InclStr(IsHSegmentV, ";:@&=");
00071   InclBoolV(IsHSegmentV, IsNationalV); InclStr(IsHSegmentV, " ");
00072 }
00073 
00075 // Url-Lexical
00076 class TUrlLx{
00077 private:
00078   static const char EofCh;
00079   TChA Bf;
00080   int BfC;
00081 public:
00082   static const TUrlLxChDef ChDef;
00083   TUrlLx(const TStr& _Str): Bf(_Str), BfC(0){}
00084   bool Eof() const {return BfC==Bf.Len();};
00085   char GetCh(){if (Eof()){return EofCh;} else {return Bf[BfC++];}}
00086   char PeekCh() const {if (Eof()){return EofCh;} else {return Bf[BfC];}}
00087   char GetCh(const char& Ch){EAssertR(GetCh()==Ch, ""); return Ch;}
00088   TStr GetStr(const TStr& Str){
00089     for (int ChN=0; ChN<Str.Len(); ChN++){GetCh(Str[ChN]);} return Str;}
00090   const char* GetStr(const char *Str){
00091         int Len = (int) strlen(Str);
00092     for (int ChN=0; ChN<Len; ChN++){GetCh(Str[ChN]);} 
00093         return Str;
00094   }
00095 
00096   bool IsSchemeCh() const {return ChDef.IsSchemeCh(PeekCh());}
00097   char GetSchemeCh(){EAssertR(IsSchemeCh(), ""); return GetCh();}
00098   bool IsDigitCh() const {return ChDef.IsDigitCh(PeekCh());}
00099   char GetDigitCh(){EAssertR(IsDigitCh(), ""); return GetCh();}
00100   bool IsHSegmentCh() const {return ChDef.IsHSegmentCh(PeekCh());}
00101   char GetHSegmentCh(){EAssertR(IsHSegmentCh(), ""); return GetCh();}
00102   TStr GetToCh(const char& Ch=TUrlLxChDef::EofCh){TChA Str;
00103     while ((PeekCh()!=EofCh)&&(PeekCh()!=Ch)){Str+=GetCh();} return Str;}
00104 
00105   TStr GetScheme(){TChA Str;
00106     Str+=GetSchemeCh(); while (IsSchemeCh()){Str+=GetCh();}
00107     Str.ToLc(); return Str;}
00108   TStr GetHost();
00109   TStr GetDigits(){TChA Str;
00110     do {Str+=GetDigitCh();} while (IsDigitCh()); return Str;}
00111   TStr GetHostPort(TStr& HostNm, TStr& PortStr, int& PortN);
00112   TStr GetHPath(TStrV& PathSegV);
00113   TStr GetSearch(){return GetToCh('#');}
00114 };
00115 
00116 const TUrlLxChDef TUrlLx::ChDef;
00117 const char TUrlLx::EofCh=TUrlLxChDef::EofCh;
00118 
00119 TStr TUrlLx::GetHost(){TChA Str;
00120   EAssertR(ChDef.IsHostCh(PeekCh()), "");
00121   do {
00122     while (ChDef.IsHostCh(PeekCh())){Str+=GetCh();}
00123     if (PeekCh()=='.'){Str+=GetCh('.');}
00124     else if (PeekCh()=='@'){GetCh('@'); Str.Clr();} // still unexplained
00125   } while (ChDef.IsHostCh(PeekCh()));
00126   Str.ToLc();
00127   return Str;
00128 }
00129 
00130 TStr TUrlLx::GetHostPort(TStr& HostNm, TStr& PortStr, int& PortN){TChA Str;
00131   Str+=HostNm=GetHost();
00132   if (PeekCh()==':'){
00133     Str+=GetCh(':');
00134     if (IsDigitCh()){Str+=PortStr=GetDigits(); PortN=PortStr.GetInt();}
00135   }
00136   return Str;
00137 }
00138 
00139 TStr TUrlLx::GetHPath(TStrV& PathSegV){TChA Str; TChA HSegStr; bool Cont;
00140   do {
00141     while (PeekCh()=='/'){GetCh('/');} // prevent multiple '/'
00142     HSegStr.Clr(); while (IsHSegmentCh()){HSegStr+=GetHSegmentCh();}
00143     Str+=HSegStr; PathSegV.Add(HSegStr);
00144     Cont=(PeekCh()=='/'); if (Cont){Str+=GetCh('/');}
00145   } while (Cont);
00146   return Str;
00147 }
00148 
00150 // Url
00151 const TStr TUrl::UrlHttpPrefixStr="http:";
00152 const TStr TUrl::UrlHttpAbsPrefixStr="http://";
00153 
00154 void TUrl::GetAbs(const TStr& AbsUrlStr){
00155   EAssertR(IsAbs(AbsUrlStr), AbsUrlStr);
00156   TUrlLx Lx(AbsUrlStr); TChA Str;
00157   Str+=SchemeNm=Lx.GetScheme(); Str+=Lx.GetCh(':');
00158   if (SchemeNm=="http"){
00159     Scheme=usHttp;
00160     const char *DbSlashStr="//";
00161     Str+=Lx.GetStr(DbSlashStr);
00162     Str+=Lx.GetHostPort(HostNm, PortStr, PortN);
00163     if (PortN==-1){PortN=THttp::DfPortN; PortStr.Clr();}
00164     else if (PortN==THttp::DfPortN){PortStr.Clr();}
00165     //**if (!PortStr.Empty()){Str+=':'; Str+=PortStr;}
00166     if (Lx.PeekCh()=='/'){
00167       PathStr=Lx.GetCh('/'); PathStr+=Lx.GetHPath(PathSegV); Str+=PathStr;}
00168     if (PathStr.Empty()){PathStr="/"; Str+=PathStr;}
00169     if (Lx.PeekCh()=='?'){
00170       SearchStr=Lx.GetCh('?'); SearchStr+=Lx.GetSearch(); Str+=SearchStr;}
00171   } else {
00172     Scheme=usOther; Str+=Lx.GetToCh();
00173   }
00174   while (Lx.PeekCh()==' '){Lx.GetCh();}
00175   if (Lx.PeekCh()=='#'){
00176     FragIdStr=Lx.GetCh('#'); FragIdStr+=Lx.GetToCh();
00177   }
00178   EAssertR(Lx.Eof(), "");
00179   UrlStr=Str;
00180 }
00181 
00182 void TUrl::GetAbsFromBase(const TStr& RelUrlStr, const TStr& BaseUrlStr){
00183   EAssertR(!BaseUrlStr.Empty(), "");
00184   PUrl Url=TUrl::New(BaseUrlStr); EAssertR(Url->IsOk(), "");
00185   EAssertR(IsAbs(BaseUrlStr), "");
00186   TStr AbsUrlStr=BaseUrlStr;
00187   TStr NrRelUrlStr=RelUrlStr;
00188   if (NrRelUrlStr.GetLc().IsPrefix(UrlHttpPrefixStr)){
00189     NrRelUrlStr.DelSubStr(0, UrlHttpPrefixStr.Len()-1);}
00190   if (NrRelUrlStr.Len()>0){
00191     if (NrRelUrlStr[0]=='/'){
00192       TStr SlashStr; int SlashChN=0;
00193       while ((SlashChN<NrRelUrlStr.Len())&&(NrRelUrlStr[SlashChN]=='/')){
00194         SlashChN++; SlashStr+="/";}
00195       int ChN=0; bool Found=false;
00196       while ((!Found)&&((ChN=AbsUrlStr.SearchStr(SlashStr, ChN))!=-1)){
00197         TStr Str=AbsUrlStr.GetSubStr(ChN-1, ChN+SlashStr.Len()-1+1);
00198         Found=((ChN==0)||(Str[0]!='/'))&&
00199          ((ChN+SlashStr.Len()-1==AbsUrlStr.Len()-1)||(Str[Str.Len()-1]!='/'));
00200         if (!Found){ChN++;}
00201       }
00202       if (Found){
00203         AbsUrlStr.DelSubStr(ChN, AbsUrlStr.Len()-1);
00204         AbsUrlStr+=NrRelUrlStr;
00205       }
00206     } else {
00207       int ChN=AbsUrlStr.Len()-1;
00208       while ((ChN>=0)&&(AbsUrlStr[ChN]!='/')){ChN--;}
00209       AbsUrlStr.DelSubStr(ChN+1, AbsUrlStr.Len()-1);
00210       AbsUrlStr+=NrRelUrlStr;
00211     }
00212   }
00213 
00214   const char *PrevDirStr="/../";
00215   {int ChN;
00216   while ((ChN=AbsUrlStr.SearchStr(PrevDirStr))!=-1){
00217     int BChN=ChN; int EChN=ChN+(int) strlen(PrevDirStr)-1;
00218     while ((BChN-1>=0)&&(AbsUrlStr[BChN-1]!='/')){BChN--;}
00219     AbsUrlStr.DelSubStr(BChN, EChN);
00220   }}
00221 
00222   const char *CurDirStr="/.";
00223   while (AbsUrlStr.DelStr(CurDirStr)){}
00224 
00225   GetAbs(AbsUrlStr);
00226 }
00227 
00228 TUrl::TUrl(const TStr& _RelUrlStr, const TStr& _BaseUrlStr):
00229   Scheme(usUndef),
00230   UrlStr(), RelUrlStr(_RelUrlStr), BaseUrlStr(_BaseUrlStr),
00231   SchemeNm(), HostNm(),
00232   PortStr(), PathStr(), SearchStr(), FragIdStr(),
00233   PortN(-1), PathSegV(),
00234   IpNum(),
00235   FinalUrlStr(), FinalHostNm(),
00236   HttpRqStr(){
00237   RelUrlStr.ToTrunc();
00238   RelUrlStr.ChangeStrAll(" ", "%20");
00239   try {
00240     if (IsAbs(RelUrlStr)){
00241       GetAbs(RelUrlStr);
00242     } else
00243     if (IsAbs(BaseUrlStr)){
00244       GetAbsFromBase(RelUrlStr, BaseUrlStr);
00245     } else {
00246       Scheme=usUndef;
00247     }
00248   }
00249   catch (PExcept&){Scheme=usUndef;}
00250 
00251   //** old version
00252   /*
00253   PUrl BaseUrl;
00254   if (!BaseUrlStr.Empty()){ // must be outside try-block (CBuilder3.0 bug)
00255     BaseUrl=TUrl::New(BaseUrlStr);}
00256   try {
00257     if (!BaseUrlStr.Empty()){
00258       EAssertR(BaseUrl->IsOk(), "");}
00259     if (IsAbs(RelUrlStr)){
00260       GetAbs(RelUrlStr);
00261     } else {
00262       GetAbsFromBase(RelUrlStr, BaseUrlStr);
00263     }
00264   }
00265   catch (PExcept&){Scheme=usUndef;}
00266   */
00267 }
00268 
00269 TStr TUrl::GetDmNm(const int& MxDmSegs) const {
00270   EAssert(IsOk());
00271   TChA DmChA; int DmSegs=0;
00272   for (int ChN=HostNm.Len()-1; ChN>=0; ChN--){
00273     if (HostNm[ChN]=='.'){
00274       DmSegs++;
00275       if (DmSegs==MxDmSegs){break;} else {DmChA+='.';}
00276     } else {
00277       DmChA+=HostNm[ChN];
00278     }
00279   }
00280   DmChA.Reverse();
00281   return DmChA;
00282 }
00283 
00284 void TUrl::DefFinalUrl(const TStr& _FinalHostNm){
00285   EAssert(IsOk(usHttp));
00286   EAssert(!IsDefFinalUrl());
00287   FinalHostNm=_FinalHostNm.GetLc();
00288   if (HostNm==FinalHostNm){
00289     FinalUrlStr=UrlStr;
00290   } else {
00291     TChA FinalUrlChA;
00292     FinalUrlChA+=SchemeNm; FinalUrlChA+="://";
00293     FinalUrlChA+=FinalHostNm;
00294     if (!PortStr.Empty()){
00295       FinalUrlChA+=":"; FinalUrlChA+=PortStr;}
00296     FinalUrlChA+=PathStr;
00297     FinalUrlChA+=SearchStr;
00298     FinalUrlStr=FinalUrlChA;
00299   }
00300 }
00301 
00302 void TUrl::ToLcPath(){
00303   // test if the conversion is needed
00304   if (!PathStr.IsLc()){
00305     // convert path strings to lower-case
00306     PathStr.ToLc();
00307     for (int PathSegN=0; PathSegN<PathSegV.Len(); PathSegN++){
00308       PathSegV[PathSegN].ToLc();}
00309     // recompose url
00310     TChA UrlChA;
00311     UrlChA+=SchemeNm; UrlChA+="://";
00312     UrlChA+=HostNm;
00313     if (!PortStr.Empty()){
00314       UrlChA+=":"; UrlChA+=PortStr;}
00315     UrlChA+=PathStr;
00316     UrlChA+=SearchStr;
00317     UrlStr=UrlChA;
00318     // recompose final-url
00319     if (IsDefFinalUrl()){
00320       FinalUrlStr.Clr(); DefFinalUrl(FinalHostNm);}
00321   }
00322 }
00323 
00324 bool TUrl::IsAbs(const TStr& UrlStr){
00325   if (UrlStr.GetLc().IsPrefix(UrlHttpPrefixStr)){
00326     return UrlStr.GetLc().IsPrefix(UrlHttpAbsPrefixStr);
00327   } else {
00328     int ColonChN=UrlStr.SearchCh(':'); int SlashChN=UrlStr.SearchCh('/');
00329     return (ColonChN!=-1)&&((SlashChN==-1)||((SlashChN!=-1)&&(ColonChN<SlashChN)));
00330   }
00331 }
00332 
00333 bool TUrl::IsScript(const TStr& UrlStr){
00334   return UrlStr.IsChIn('?');
00335 }
00336 
00337 bool TUrl::IsSite(const TStr& UrlStr){
00338   PUrl Url=TUrl::New(UrlStr);
00339   return Url->IsOk(usHttp) && (Url->GetPathStr()=="/") &&
00340    Url->GetSearchStr().Empty() && Url->GetFragIdStr().Empty();
00341 }
00342 
00343 PUrl TUrl::GetUrlFromShortcut(const TStr& ShortcutUrlStr,
00344  const TStr& DfHostNmPrefix, const TStr& DfHostNmSufix){
00345   // shortcut is already correct url
00346   TStr UrlStr=ShortcutUrlStr;
00347   PUrl Url=TUrl::New(UrlStr);
00348   if (Url->IsOk()){return Url;}
00349   // add 'http://' to shortcut (if shortcut is from more segments)
00350   if (ShortcutUrlStr.IsChIn('.')){
00351     UrlStr=TUrl::UrlHttpAbsPrefixStr+ShortcutUrlStr;
00352     Url=TUrl::New(UrlStr);
00353     if (Url->IsOk()){return Url;}
00354   }
00355   // add 'http://' and '/' to shortcut (if shortcut is from more segments)
00356   if (ShortcutUrlStr.IsChIn('.')){
00357     UrlStr=TUrl::UrlHttpAbsPrefixStr+ShortcutUrlStr+"/";
00358     Url=TUrl::New(UrlStr);
00359     if (Url->IsOk()){return Url;}
00360   }
00361   // add 'http://', prefix, postfix and '/' to shortcut
00362   UrlStr=UrlHttpAbsPrefixStr+
00363    DfHostNmPrefix+"."+ShortcutUrlStr+"."+DfHostNmSufix+"/";
00364   Url=TUrl::New(UrlStr);
00365   return Url;
00366 }
00367 
00368 TStr TUrl::GetUrlSearchStr(const TStr& Str){
00369   TChA InChA=Str; TChA OutChA;
00370   for (int ChN=0; ChN<InChA.Len(); ChN++){
00371     char Ch=InChA[ChN];
00372     if (Ch==' '){
00373       OutChA+='+';
00374     } else
00375     if ((' '<Ch)&&(Ch<='~')&&(Ch!='+')&&(Ch!='&')&&(Ch!='%')){
00376       OutChA+=Ch;
00377     } else {
00378       OutChA+='%';
00379       OutChA+=TInt::GetHexStr(uchar(Ch)/16);
00380       OutChA+=TInt::GetHexStr(uchar(Ch)%16);
00381     }
00382   }
00383   return OutChA;
00384 }
00385 
00386 TStr TUrl::DecodeUrlStr(const TStr& UrlStr) {
00387   TChA InChA=UrlStr; TChA OutChA;
00388   for (int ChN=0; ChN<InChA.Len(); ChN++){
00389     char Ch=InChA[ChN];
00390     if (Ch=='+'){
00391       OutChA+=' ';
00392     } else if (Ch=='%') {
00393       ChN++; if (ChN==InChA.Len()) { break; }
00394       char FirstCh = InChA[ChN];
00395       if (!TCh::IsHex(FirstCh)) { break; }
00396       ChN++; if (ChN==InChA.Len()) { break; }
00397       char SecondCh = InChA[ChN];
00398       if (!TCh::IsHex(SecondCh)) { break; }
00399       OutChA+=char(TCh::GetHex(FirstCh)*16 + TCh::GetHex(SecondCh));
00400     } else {
00401       OutChA+=Ch;
00402     }
00403   }
00404   return OutChA;
00405 }
00406 
00407 TStr TUrl::GetDocStrFromUrlStr(const TStr& UrlStr, const int& Copies){
00408   TStrV StrV; UrlStr.SplitOnNonAlNum(StrV);
00409   TChA DocChA;
00410   for (int StrN=0; StrN<StrV.Len(); StrN++){
00411     TStr UcStr=StrV[StrN].GetUc();
00412     if ((UcStr.Len()>3)&&(UcStr!="HTTP")&&(UcStr!="HTML")&&(UcStr!="INDEX")&&(UcStr!="DEFAULT")){
00413       for (int CopyN=0; CopyN<Copies; CopyN++){
00414         if (!DocChA.Empty()){DocChA+=' ';} DocChA+=StrV[StrN];
00415       }
00416     }
00417   }
00418   return DocChA;
00419 }
00420 
00421 TStr TUrl::GetTopDownDocNm(
00422  const TStr& UrlStr, const int& MxLen, const bool& HostOnlyP){
00423   PUrl Url=TUrl::New(UrlStr);
00424   TChA DocNm;
00425   if (Url->IsOk()){
00426     TStr HostNm=Url->GetHostNm().GetLc();
00427     TStrV HostNmSegV; HostNm.SplitOnAllCh('.', HostNmSegV, false);
00428     for (int HostNmSegN=0; HostNmSegN<HostNmSegV.Len(); HostNmSegN++){
00429       if (HostNmSegN>0){DocNm+='.';}
00430       DocNm+=HostNmSegV[HostNmSegV.Len()-HostNmSegN-1];
00431     }
00432     if (!HostOnlyP){
00433       DocNm+=Url->GetPathStr().GetLc();
00434     }
00435   } else {
00436     DocNm=UrlStr.GetLc();
00437   }
00438   if (MxLen!=-1){
00439     DocNm.Trunc(MxLen);}
00440   return DocNm;
00441 }
00442 
00444 // Url-Search-Environment
00445 TStr TUrlEnv::GetFullUrlStr() const {
00446   if (GetKeys()==0){return TStr();}
00447   TChA SearchChA;
00448   SearchChA+=BaseUrlStr;
00449   SearchChA+="?";
00450   int KeyVals=0;
00451   for (int KeyN=0; KeyN<GetKeys(); KeyN++){
00452     TStr KeyNm=GetKeyNm(KeyN);
00453     TStrV ValStrV=KeyNmToValH.GetDat(KeyNm);
00454     for (int ValStrN=0; ValStrN<ValStrV.Len(); ValStrN++){
00455       if (KeyVals>0){SearchChA+="&";}
00456       SearchChA+=TUrl::GetUrlSearchStr(KeyNm);
00457       SearchChA+='=';
00458       SearchChA+=TUrl::GetUrlSearchStr(ValStrV[ValStrN]);
00459       KeyVals++;
00460     }
00461   }
00462   return SearchChA;
00463 }
00464 
00465 PUrlEnv TUrlEnv::MkClone(const PUrlEnv& UrlEnv){
00466   PUrlEnv CloneUrlEnv=
00467    PUrlEnv(new TUrlEnv(*UrlEnv));
00468   return CloneUrlEnv;
00469 }
00470