SNAP Library, Developer Reference  2012-10-02 12:56:23
SNAP, a general purpose network analysis and graph mining library
 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