SNAP Library, Developer Reference  2012-10-15 15:06:59
SNAP, a general purpose network analysis and graph mining library
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines
http.cpp
Go to the documentation of this file.
00001 
00002 // Http-General
00003 
00004 // general strings
00005 const TStr THttp::HttpStr="http";
00006 const TStr THttp::SlashStr="/";
00007 const TStr THttp::ColonStr=":";
00008 
00009 // fields names
00010 const TStr THttp::ContTypeFldNm="Content-Type";
00011 const TStr THttp::ContLenFldNm="Content-Length";
00012 const TStr THttp::HostFldNm="Host";
00013 const TStr THttp::AcceptRangesFldNm="Accept-Ranges";
00014 const TStr THttp::CacheCtrlFldNm="Cache-Control";
00015 const TStr THttp::AcceptFldNm="Accept";
00016 const TStr THttp::SrvFldNm="Server";
00017 const TStr THttp::ConnFldNm="Connection";
00018 const TStr THttp::FetchIdFldNm="FetchId";
00019 const TStr THttp::LocFldNm="Location";
00020 const TStr THttp::SetCookieFldNm="Set-Cookie";
00021 const TStr THttp::CookieFldNm="Cookie";
00022 
00023 // content-type field-values
00024 const TStr THttp::TextFldVal="text/";
00025 const TStr THttp::TextPlainFldVal="text/plain";
00026 const TStr THttp::TextHtmlFldVal="text/html";
00027 const TStr THttp::TextXmlFldVal="text/xml";
00028 const TStr THttp::TextWmlFldVal="text/vnd.wap.wml";
00029 const TStr THttp::TextJavaScriptFldVal="text/javascript";
00030 const TStr THttp::TextCssFldVal="text/css";
00031 const TStr THttp::ImagePngFldVal="image/png";
00032 const TStr THttp::ImageGifFldVal="image/gif";
00033 const TStr THttp::ImageJpgFldVal="image/jpg";
00034 const TStr THttp::AppOctetFldVal="application/octet-stream";
00035 const TStr THttp::AppSoapXmlFldVal="application/soap+xml";
00036 const TStr THttp::AppW3FormFldVal="application/x-www-form-urlencoded";
00037 const TStr THttp::AppJSonFldVal = "application/json";
00038 const TStr THttp::ConnKeepAliveFldVal="keep-alive";
00039 
00040 // file extensions
00041 bool THttp::IsHtmlFExt(const TStr& FExt){
00042   TStr UcFExt=FExt.GetUc();
00043   return ((UcFExt==TFile::HtmlFExt.GetUc())||(UcFExt==TFile::HtmFExt.GetUc()));
00044 }
00045 
00046 bool THttp::IsGifFExt(const TStr& FExt){
00047   return (FExt.GetUc()==TFile::GifFExt.GetUc());
00048 }
00049 
00050 // port number
00051 const int THttp::DfPortN=80;
00052 
00053 // status codes
00054 const int THttp::OkStatusCd=200;
00055 const int THttp::RedirStatusCd=300;
00056 const int THttp::BadRqStatusCd=400;
00057 const int THttp::ErrStatusCd=400;
00058 const int THttp::ErrNotFoundStatusCd=404;
00059 const int THttp::InternalErrStatusCd=500;
00060 
00061 TStr THttp::GetReasonPhrase(const int& StatusCd){
00062   switch (StatusCd){
00063     case 200: return "OK";
00064     case 201: return "Created";
00065     case 202: return "Accepted";
00066     case 204: return "No Content";
00067     case 300: return "Multiple Choices";
00068     case 301: return "Moved Permanently";
00069     case 302: return "Moved Temporarily";
00070     case 304: return "Not Modified";
00071     case 400: return "Bad Request";
00072     case 401: return "Unauthorized";
00073     case 403: return "Forbidden";
00074     case 404: return "Not Found";
00075     case 500: return "Internal Server Error";
00076     case 501: return "Not Implemented";
00077     case 502: return "Bad Gateway";
00078     case 503: return "Service Unavailable";
00079     default: return TStr("Unknown Status Code ")+TInt::GetStr(StatusCd);
00080   }
00081 }
00082 
00083 // method names
00084 const TStr THttp::GetMethodNm="GET";
00085 const TStr THttp::HeadMethodNm="HEAD";
00086 const TStr THttp::PostMethodNm="POST";
00087 const TStr THttp::UndefMethodNm="UndefinedMethod";
00088 
00090 // Http-Chars
00091 typedef enum {hpctUndef, hpctAlpha, hpctDigit, hpctCtl, hpctSpec} THttpChTy;
00092 
00093 class THttpChDef{
00094 private:
00095   TIntV ChTyV;
00096   TChV LcChV;
00097   void SetLcCh(const TStr& Str);
00098   void SetChTy(const THttpChTy& ChTy, const char& Ch);
00099   void SetChTy(const THttpChTy& ChTy, const TStr& Str);
00100 public:
00101   THttpChDef();
00102 
00103   THttpChDef& operator=(const THttpChDef&){Fail; return *this;}
00104 
00105   int GetChTy(const char& Ch){return ChTyV[Ch-TCh::Mn];}
00106   bool IsAlpha(const char& Ch){return ChTyV[Ch-TCh::Mn]==int(hpctAlpha);}
00107   bool IsDigit(const char& Ch){return ChTyV[Ch-TCh::Mn]==int(hpctDigit);}
00108   bool IsCtl(const char& Ch){return ChTyV[Ch-TCh::Mn]==int(hpctCtl);}
00109   bool IsLws(const char& Ch){
00110     return (Ch==' ')||(Ch==TCh::TabCh)||(Ch==TCh::CrCh)||(Ch==TCh::LfCh);}
00111   bool IsText(const char& Ch){return !IsCtl(Ch)||IsLws(Ch);}
00112   bool IsSpec(const char& Ch){
00113     return (ChTyV[Ch-TCh::Mn]==int(hpctSpec))||(Ch==9)||(Ch==32);}
00114   bool IsCr(const char& Ch){return Ch==13;}
00115   bool IsLf(const char& Ch){return Ch==10;}
00116   bool IsSp(const char& Ch){return Ch==32;}
00117   bool IsHt(const char& Ch){return Ch==9;}
00118   bool IsDQuote(const char& Ch){return Ch=='"';}
00119 
00120   char GetLcCh(const char& Ch){return LcChV[Ch-TCh::Mn];}
00121   TStr GetLcStr(const TStr& Str);
00122 };
00123 
00124 void THttpChDef::SetChTy(const THttpChTy& ChTy, const char& Ch){
00125   IAssert(ChTyV[Ch-TCh::Mn]==int(hpctUndef)); ChTyV[Ch-TCh::Mn]=TInt(ChTy);}
00126 
00127 void THttpChDef::SetChTy(const THttpChTy& ChTy, const TStr& Str){
00128   for (int ChN=0; ChN<Str.Len(); ChN++){SetChTy(ChTy, Str[ChN]);}}
00129 
00130 void THttpChDef::SetLcCh(const TStr& Str){
00131   for (int ChN=1; ChN<Str.Len(); ChN++){LcChV[Str[ChN]-TCh::Mn]=TCh(Str[0]);}}
00132 
00133 THttpChDef::THttpChDef():
00134   ChTyV(TCh::Vals), LcChV(TCh::Vals){
00135 
00136   // Character-Types
00137   ChTyV.PutAll(TInt(hpctUndef));
00138   SetChTy(hpctAlpha, "ABCDEFGHIJKLMNOPQRSTUVWXYZ");
00139   SetChTy(hpctAlpha, "abcdefghijklmnopqrstuvwxyz");
00140   SetChTy(hpctDigit, "0123456789");
00141   for (char Ch=0; Ch<=31; Ch++){SetChTy(hpctCtl, Ch);}
00142   SetChTy(hpctCtl, 127);
00143   SetChTy(hpctSpec, "()<>@,;:\\\"/[]?={}"); // +char(9)+char(32)
00144 
00145   // Lower-Case
00146   {for (int Ch=TCh::Mn; Ch<=TCh::Mx; Ch++){LcChV[Ch-TCh::Mn]=TCh(char(Ch));}}
00147   SetLcCh("aA"); SetLcCh("bB"); SetLcCh("cC"); SetLcCh("dD"); SetLcCh("eE");
00148   SetLcCh("fF"); SetLcCh("gG"); SetLcCh("hH"); SetLcCh("iI"); SetLcCh("jJ");
00149   SetLcCh("kK"); SetLcCh("lL"); SetLcCh("mM"); SetLcCh("nN"); SetLcCh("oO");
00150   SetLcCh("pP"); SetLcCh("qQ"); SetLcCh("rR"); SetLcCh("sS"); SetLcCh("tT");
00151   SetLcCh("uU"); SetLcCh("vV"); SetLcCh("wW"); SetLcCh("xX"); SetLcCh("yY");
00152   SetLcCh("zZ");
00153 }
00154 
00155 TStr THttpChDef::GetLcStr(const TStr& Str){
00156   TChA LcStr;
00157   for (int ChN=0; ChN<Str.Len(); ChN++){LcStr+=GetLcCh(Str[ChN]);}
00158   return LcStr;
00159 }
00160 
00162 // Http-Exception
00163 typedef enum {
00164   heUnexpectedEof, hePeriodExpected, heTokenExpected, heInvalidToken,
00165   heTSpecExpected, heInvalidTSpec, heNumExpected, heInvalidNumPlaces,
00166   heCrLfExpected, heMethodNmExpected, heUrlEmpty, heBadUrl,
00167   heBadSearchStr} THttpExCd;
00168 
00169 class THttpEx{
00170 private:
00171   THttpExCd HttpExCd;
00172 public:
00173   THttpEx(const THttpExCd& _HttpExCd): HttpExCd(_HttpExCd){}
00174 };
00175 
00177 // Http-Lexical
00178 class THttpLx{
00179 private:
00180   static THttpChDef ChDef;
00181   PSIn SIn;
00182   //TChA ChStack;
00183   TBoolChS EofChPrS;
00184   char Ch;
00185   bool AtEof;
00186   TMem SfMem;
00187 public:
00188   THttpLx(const PSIn& _SIn):
00189     SIn(_SIn), EofChPrS(), Ch(' '), AtEof(false), SfMem(50000){
00190     GetFirstCh();}
00191 
00192   THttpLx& operator=(const THttpLx&){Fail; return *this;}
00193 
00194   // basic
00195   bool Eof(){return AtEof;}
00196   int Len(){return EofChPrS.Len()+SIn->Len();}
00197   char GetFirstCh();
00198   char GetCh();
00199   void GetRest();
00200   void PutCh(const char& _Ch){
00201     EofChPrS.Push(TBoolChPr(AtEof, Ch)); Ch=_Ch; AtEof=false; SfMem.Pop();}
00202   void ClrMemSf(){SfMem.Clr();}
00203   TMem& GetMemSf(){return SfMem;}
00204 
00205   // http request
00206   THttpRqMethod GetRqMethod();
00207   PUrl GetUrl();
00208   TStr GetUrlStr();
00209   // http response
00210   bool IsRespStatusLn();
00211   TStr GetRespReasonPhrase();
00212   // spacing
00213   void GetWs();
00214   bool IsLws();
00215   void GetLws();
00216   bool IsCrLf();
00217   void GetCrLf();
00218   // tokens
00219   void GetPeriod();
00220   TStr GetToken(const TStr& ExpectStr=TStr());
00221   TStr GetSpec(const TStr& ExpectStr=TStr());
00222   int GetInt(const int& RqPlaces=-1);
00223   TStr GetFldVal();
00224 
00225   static TStr GetNrStr(const TStr& Str){return ChDef.GetLcStr(Str);}
00226 };
00227 THttpChDef THttpLx::ChDef;
00228 
00229 char THttpLx::GetFirstCh(){
00230   if (SIn->Eof()){
00231     if (AtEof){throw THttpEx(heUnexpectedEof);}
00232     AtEof=true; return 0;
00233   } else {
00234     Ch=SIn->GetCh(); return Ch;
00235   }
00236 }
00237 
00238 char THttpLx::GetCh(){
00239   if (EofChPrS.Empty()){
00240     if (SIn->Eof()){
00241       if (AtEof){throw THttpEx(heUnexpectedEof);}
00242       AtEof=true; SfMem+=Ch; Ch=TCh::NullCh; return Ch;
00243     } else {
00244       SfMem+=Ch; Ch=SIn->GetCh(); return Ch;
00245     }
00246   } else {
00247     SfMem+=Ch;
00248     AtEof=EofChPrS.Top().Val1; Ch=EofChPrS.Top().Val2; EofChPrS.Pop();
00249     return Ch;
00250   }
00251 }
00252 
00253 void THttpLx::GetRest(){
00254   while ((!SIn->Eof())&&(!EofChPrS.Empty())){GetCh();}
00255   if (!SIn->Eof()){SfMem+=Ch;}
00256   TMem RestMem; TMem::LoadMem(SIn, RestMem);
00257   SfMem+=RestMem;
00258 }
00259 
00260 THttpRqMethod THttpLx::GetRqMethod(){
00261   TChA MethodNm;
00262   while (!Eof() && ChDef.IsAlpha(Ch)){
00263     MethodNm+=Ch; GetCh();}
00264   THttpRqMethod Method=hrmUndef;
00265   if (MethodNm==THttp::GetMethodNm){Method=hrmGet;}
00266   else if (MethodNm==THttp::HeadMethodNm){Method=hrmHead;}
00267   else if (MethodNm==THttp::PostMethodNm){Method=hrmPost;}
00268   if (Method==hrmUndef){throw THttpEx(heMethodNmExpected);}
00269   return Method;
00270 }
00271 
00272 PUrl THttpLx::GetUrl(){
00273   TChA UrlChA;
00274   while ((!Eof())&&(!ChDef.IsSp(Ch))){
00275     UrlChA+=Ch; GetCh();}
00276   if (UrlChA.Empty()){
00277     throw THttpEx(heUrlEmpty);}
00278   static TStr LocalBaseUrlStr="http://localhost/";
00279   PUrl Url=PUrl(new TUrl(UrlChA, LocalBaseUrlStr));
00280   if (!Url->IsOk()){
00281     throw THttpEx(heBadUrl);}
00282   return Url;
00283 }
00284 
00285 TStr THttpLx::GetUrlStr(){
00286   TChA UrlChA;
00287   while ((!Eof())&&(!ChDef.IsSp(Ch))){
00288     UrlChA+=Ch; GetCh();}
00289   if (UrlChA.Empty()){
00290     throw THttpEx(heUrlEmpty);}
00291   return UrlChA;
00292 }
00293 
00294 bool THttpLx::IsRespStatusLn(){
00295   static const TChA MouldChA="http/N.N NNN ";
00296   TChA TestChA(MouldChA);
00297   int TestLen=TestChA.Len();
00298   if (1+Len()<TestLen){return false;}
00299   TestChA.PutCh(0, ChDef.GetLcCh(Ch));
00300   {for (int ChN=1; ChN<TestLen; ChN++){
00301     TestChA.PutCh(ChN, ChDef.GetLcCh(GetCh()));}}
00302   {for (int ChN=1; ChN<TestLen; ChN++){
00303     PutCh(TestChA[TestLen-ChN-1]);}}
00304   {for (int ChN=0; ChN<MouldChA.Len(); ChN++){
00305     if (MouldChA[ChN]=='N'){
00306       if (!ChDef.IsDigit(TestChA[ChN])){return false;}
00307     } else {
00308       if (MouldChA[ChN]!=TestChA[ChN]){return false;}
00309     }
00310   }}
00311   return true;
00312 }
00313 
00314 TStr THttpLx::GetRespReasonPhrase(){
00315   GetLws();
00316   TChA RPStr;
00317   while (!Eof()&&ChDef.IsText(Ch)&&(Ch!=TCh::CrCh)&&(Ch!=TCh::LfCh)){
00318     RPStr+=Ch; GetCh();}
00319   return RPStr;
00320 }
00321 
00322 void THttpLx::GetWs(){
00323   while (!Eof()&&((Ch==' ')||(Ch==TCh::TabCh))){GetCh();}
00324 }
00325 
00326 bool THttpLx::IsLws(){
00327   if ((Ch==' ')||(Ch==TCh::TabCh)){
00328     return true;
00329   } else
00330   if (Ch==TCh::CrCh){
00331     GetCh();
00332     if (Ch==TCh::LfCh){
00333       GetCh(); bool Ok=(Ch==' ')||(Ch==TCh::TabCh);
00334       PutCh(TCh::LfCh); PutCh(TCh::CrCh); return Ok;
00335     } else {
00336       PutCh(TCh::CrCh); return false;
00337     }
00338   } else
00339   if (Ch==TCh::LfCh){
00340     GetCh(); bool Ok=(Ch==' ')||(Ch==TCh::TabCh);
00341     PutCh(TCh::LfCh); return Ok;
00342   } else {
00343     return false;
00344   }
00345 }
00346 
00347 void THttpLx::GetLws(){
00348   forever {
00349     while ((Ch==' ')||(Ch==TCh::TabCh)){GetCh();}
00350     if (Ch==TCh::CrCh){
00351       GetCh();
00352       if (Ch==TCh::LfCh){
00353         GetCh();
00354         if ((Ch==' ')||(Ch==TCh::TabCh)){GetCh();}
00355         else {PutCh(TCh::LfCh); PutCh(TCh::CrCh); break;}
00356       } else {
00357         PutCh(TCh::CrCh); break;
00358       }
00359     } else
00360     if (Ch==TCh::LfCh){
00361       GetCh();
00362       if ((Ch==' ')||(Ch==TCh::TabCh)){GetCh();}
00363       else {PutCh(TCh::LfCh); break;}
00364     } else {
00365       break;
00366     }
00367   }
00368 }
00369 
00370 bool THttpLx::IsCrLf(){
00371   if (Ch==TCh::CrCh){
00372     GetCh(); bool Ok=(Ch==TCh::LfCh); PutCh(TCh::CrCh); return Ok;
00373   } else
00374   if (Ch==TCh::LfCh){
00375     return true;
00376   } else {
00377     return false;
00378   }
00379 }
00380 
00381 void THttpLx::GetCrLf(){
00382   if (Ch==TCh::CrCh){
00383     GetCh();
00384     if (Ch==TCh::LfCh){GetCh();} else {throw THttpEx(heCrLfExpected);}
00385   } else
00386   if (Ch==TCh::LfCh){
00387     GetCh();
00388   } else {
00389     throw THttpEx(heCrLfExpected);
00390   }
00391 }
00392 
00393 void THttpLx::GetPeriod(){
00394   GetWs();
00395   if (Ch!='.'){throw THttpEx(hePeriodExpected);}
00396   GetCh();
00397 }
00398 
00399 TStr THttpLx::GetToken(const TStr& ExpectStr){
00400   GetLws();
00401   TChA TokenStr;
00402   while (!Eof() && !ChDef.IsCtl(Ch) && !ChDef.IsSpec(Ch)){
00403     TokenStr+=Ch; GetCh();}
00404   if (TokenStr.Empty()){throw THttpEx(heTokenExpected);}
00405   if (!ExpectStr.Empty()){
00406     if (GetNrStr(ExpectStr)!=GetNrStr(TokenStr)){
00407       throw THttpEx(heInvalidToken);}
00408   }
00409   return TokenStr;
00410 }
00411 
00412 TStr THttpLx::GetSpec(const TStr& ExpectStr){
00413   GetLws();
00414   if (!ChDef.IsSpec(Ch)){throw THttpEx(heTSpecExpected);}
00415   TStr SpecStr(Ch); GetCh();
00416   if (!ExpectStr.Empty()){
00417     if (ExpectStr!=SpecStr){throw THttpEx(heInvalidTSpec);}}
00418   return SpecStr;
00419 }
00420 
00421 int THttpLx::GetInt(const int& RqPlaces){
00422   GetLws();
00423   if (!ChDef.IsDigit(Ch)){throw THttpEx(heNumExpected);}
00424   int Int=0; int CurPlaces=0;
00425   do {Int=Int*10+Ch-'0'; CurPlaces++; GetCh();
00426   } while ((CurPlaces<RqPlaces)&&(ChDef.IsDigit(Ch)));
00427   if (RqPlaces!=-1){
00428     if (CurPlaces!=RqPlaces){throw THttpEx(heInvalidNumPlaces);}}
00429   return Int;
00430 }
00431 
00432 TStr THttpLx::GetFldVal(){
00433   TChA FldValStr;
00434   do {
00435     GetLws();
00436     while (!Eof()&&ChDef.IsText(Ch)&&(Ch!=TCh::CrCh)&&(Ch!=TCh::LfCh)){
00437       FldValStr+=Ch; GetCh();}
00438     if (IsLws()){FldValStr+=' ';}
00439   } while (IsLws());
00440   return FldValStr;
00441 }
00442 
00444 // Http-Character-Returner
00445 class THttpChRet{
00446   PSIn SIn;
00447   int Chs, ChN;
00448   THttpExCd HttpExCd;
00449 public:
00450   THttpChRet(const PSIn& _SIn, const THttpExCd& _HttpExCd):
00451     SIn(_SIn), Chs(SIn->Len()), ChN(0), HttpExCd(_HttpExCd){}
00452   THttpChRet& operator=(const THttpChRet&){Fail; return *this;}
00453   bool Eof(){return ChN==Chs;}
00454   char GetCh(){
00455     if (ChN>=Chs){throw THttpEx(HttpExCd);}
00456     ChN++; return SIn->GetCh();}
00457 };
00458 
00460 // Http-Request
00461 void THttpRq::ParseSearch(const TStr& SearchStr){
00462   PSIn SIn=TStrIn::New(SearchStr);
00463   THttpChRet ChRet(SIn, heBadSearchStr);
00464   try {
00465   // check empty search string
00466   if (ChRet.Eof()){return;}
00467   // require '?' at the beginning
00468   if (ChRet.GetCh()!='?'){
00469     throw THttpEx(heBadSearchStr);}
00470   // parse key=val{&...} pairs
00471   TChA KeyNm; TChA ValStr;
00472   while (!ChRet.Eof()){
00473     char Ch; KeyNm.Clr(); ValStr.Clr();
00474     // key
00475     while ((Ch=ChRet.GetCh())!='='){
00476       switch (Ch){
00477         case '%':{
00478           char Ch1=ChRet.GetCh();
00479                   if (!TCh::IsHex(Ch1)) { throw THttpEx(heBadSearchStr); }
00480                   char Ch2=ChRet.GetCh();
00481                   if (!TCh::IsHex(Ch2)) { throw THttpEx(heBadSearchStr); }
00482           KeyNm.AddCh(char(16*TCh::GetHex(Ch1)+TCh::GetHex(Ch2)));} break;
00483         case '+': KeyNm.AddCh(' '); break;
00484         case '&': throw THttpEx(heBadSearchStr);
00485         default: KeyNm.AddCh(Ch);
00486       }
00487     }
00488     // equals
00489     if (Ch!='='){
00490       throw THttpEx(heBadSearchStr);}
00491     // value
00492     while ((!ChRet.Eof())&&((Ch=ChRet.GetCh())!='&')){
00493       switch (Ch){
00494         case '%':{
00495           char Ch1=ChRet.GetCh();
00496                   if (!TCh::IsHex(Ch1)) { throw THttpEx(heBadSearchStr); }
00497           char Ch2=ChRet.GetCh();
00498                   if (!TCh::IsHex(Ch2)) { throw THttpEx(heBadSearchStr); }
00499           ValStr.AddCh(char(16*TCh::GetHex(Ch1)+TCh::GetHex(Ch2)));} break;
00500         case '+': ValStr.AddCh(' '); break;
00501         case '&': throw THttpEx(heBadSearchStr);
00502         default: ValStr.AddCh(Ch);
00503       }
00504     }
00505     // save key-value pair
00506     UrlEnv->AddToKeyVal(KeyNm, ValStr);
00507     }
00508   }
00509   catch (THttpEx){Ok=false;}
00510 }
00511 
00512 void THttpRq::ParseHttpRq(const PSIn& SIn){
00513   THttpLx Lx(SIn);
00514   // initial status
00515   Ok=false;
00516   CompleteP=false;
00517   // request-line
00518   Method=Lx.GetRqMethod();
00519   Lx.GetWs();
00520   //Url=Lx.GetUrl();
00521   TStr UrlStr=Lx.GetUrlStr();
00522   Lx.GetWs();
00523   Lx.GetToken(THttp::HttpStr); Lx.GetSpec(THttp::SlashStr);
00524   MajorVerN=Lx.GetInt(1); Lx.GetPeriod(); MinorVerN=Lx.GetInt(1);
00525   Lx.GetCrLf();
00526   // header fields & values
00527   while ((!Lx.Eof())&&(!Lx.IsCrLf())){
00528     TStr FldNm=Lx.GetToken(); Lx.GetSpec(THttp::ColonStr);
00529     TStr FldVal=Lx.GetFldVal();
00530     Lx.GetCrLf();
00531     TStr NrFldNm=THttpLx::GetNrStr(FldNm);
00532     FldNmToValH.AddDat(NrFldNm, FldVal);
00533   }
00534   // separator CrLf
00535   if (!Lx.IsCrLf()){return;} // to avoid exceptions
00536   Lx.GetCrLf();
00537   // header & body strings
00538   HdStr=Lx.GetMemSf().GetAsStr();
00539   Lx.ClrMemSf();
00540   Lx.GetRest();
00541   BodyMem=Lx.GetMemSf();
00542   // completeness
00543   int ContLen=GetFldVal(THttp::ContLenFldNm).GetInt(-1);
00544   if (ContLen==-1){
00545     // if not content-len is given we assume http-request is ok
00546     CompleteP=true;
00547   } else {
00548     if (ContLen<=BodyMem.Len()){
00549       // if we read enough data, we claim completeness
00550       CompleteP=true;
00551       BodyMem.Trunc(ContLen);
00552     } else {
00553       // if we read not enough data we claim incompleteness
00554       CompleteP=false;
00555     }
00556   }
00557   // url
00558   if (CompleteP){
00559     const TStr LocalBaseUrlStr="http://localhost/";
00560     Url=TUrl::New(UrlStr, LocalBaseUrlStr);
00561     if (!Url->IsOk()){
00562       throw THttpEx(heBadUrl);}
00563   }
00564   // search string
00565   TStr SearchStr;
00566   if (Method==hrmGet){
00567     SearchStr=Url->GetSearchStr();
00568   } else
00569   if ((Method==hrmPost)&&(
00570    (!IsFldNm(THttp::ContTypeFldNm))||
00571    (GetFldVal(THttp::ContTypeFldNm)==THttp::TextHtmlFldVal)||
00572    (GetFldVal(THttp::ContTypeFldNm)==THttp::AppW3FormFldVal))){
00573     SearchStr=TStr("?")+BodyMem.GetAsStr();
00574   }
00575   ParseSearch(SearchStr);
00576   // at this point ok=true
00577   Ok=true;
00578 }
00579 
00580 THttpRq::THttpRq(const PSIn& SIn):
00581   Ok(false), MajorVerN(0), MinorVerN(0), Method(hrmUndef),
00582   FldNmToValH(), UrlEnv(TUrlEnv::New()),
00583   HdStr(), BodyMem(){
00584   try {
00585     ParseHttpRq(SIn);
00586   }
00587   catch (THttpEx){Ok=false;}
00588 }
00589 
00590 THttpRq::THttpRq(
00591  const THttpRqMethod& _Method, const PUrl& _Url,
00592  const TStr& ContTypeFldVal, const TMem& _BodyMem, const int& FetchId):
00593   Ok(false),
00594   MajorVerN(1), MinorVerN(0),
00595   Method(_Method),
00596   Url(_Url),
00597   FldNmToValH(),
00598   UrlEnv(TUrlEnv::New()),
00599   HdStr(), BodyMem(_BodyMem){
00600   // compose head-http-request
00601   TChA HdChA;
00602   if (Url->IsOk()){
00603     TStr AbsPath=Url->GetPathStr()+Url->GetSearchStr();
00604     HdChA+=GetMethodNm(); HdChA+=' '; HdChA+=AbsPath; HdChA+=" HTTP/1.0\r\n";
00605   }
00606   // add content-type
00607   if (!ContTypeFldVal.Empty()){
00608     FldNmToValH.AddDat(THttpLx::GetNrStr(THttp::ContTypeFldNm), ContTypeFldVal);
00609     HdChA+=THttpLx::GetNrStr(THttp::ContTypeFldNm); HdChA+=": ";
00610     HdChA+=ContTypeFldVal; HdChA+="\r\n";
00611   }
00612   // add host
00613   if (Url->IsOk()){
00614     TStr HostNm=Url->GetHostNm();
00615     FldNmToValH.AddDat(THttpLx::GetNrStr(THttp::HostFldNm), HostNm);
00616     HdChA+=THttpLx::GetNrStr(THttp::HostFldNm); HdChA+=": ";
00617     HdChA+=HostNm; HdChA+="\r\n";
00618     ParseSearch(Url->GetSearchStr());
00619   }
00620   // add fetch-id
00621   if (Url->IsOk()&&(FetchId!=-1)){
00622     TStr FetchIdStr=TInt::GetStr(FetchId);
00623     FldNmToValH.AddDat(THttpLx::GetNrStr(THttp::FetchIdFldNm), FetchIdStr);
00624     HdChA+=THttpLx::GetNrStr(THttp::FetchIdFldNm); HdChA+=": ";
00625     HdChA+=FetchIdStr; HdChA+="\r\n";
00626   }
00627   // finish head-http-request
00628   if (Url->IsOk()){
00629     HdChA+="\r\n";
00630     HdStr=HdChA;
00631   }
00632   // set http-request ok
00633   Ok=true;
00634 }
00635 
00636 const TStr& THttpRq::GetMethodNm() const {
00637   switch (Method){
00638     case hrmGet: return THttp::GetMethodNm;
00639     case hrmHead: return THttp::HeadMethodNm;
00640     case hrmPost: return THttp::PostMethodNm;
00641     default: return  THttp::UndefMethodNm;
00642   }
00643 }
00644 
00645 bool THttpRq::IsFldNm(const TStr& FldNm) const {
00646   return FldNmToValH.IsKey(THttpLx::GetNrStr(FldNm));
00647 }
00648 
00649 TStr THttpRq::GetFldVal(const TStr& FldNm) const {
00650   TStr NrFldNm=THttpLx::GetNrStr(FldNm);
00651   if (FldNmToValH.IsKey(NrFldNm)){
00652     return FldNmToValH.GetDat(NrFldNm);
00653   } else {
00654     return TStr();
00655   }
00656 }
00657 
00658 bool THttpRq::IsFldVal(const TStr& FldNm, const TStr& FldVal) const {
00659   return THttpLx::GetNrStr(FldVal)==THttpLx::GetNrStr(GetFldVal(FldNm));
00660 }
00661 
00662 
00663 void THttpRq::AddFldVal(const TStr& FldNm, const TStr& FldVal){
00664   TStr NrFldNm=THttpLx::GetNrStr(FldNm);
00665   FldNmToValH.AddDat(NrFldNm, FldVal);
00666 }
00667 
00668 const TStrStrH& THttpRq::GetFldValH() const {
00669         return FldNmToValH;
00670 }
00671 
00672 TStr THttpRq::GetStr() const {
00673   TChA ChA;
00674   ChA+=GetMethodNm(); ChA+=' ';
00675   ChA+=Url->GetUrlStr(); ChA+=' ';
00676   ChA+="HTTP/1.0\r\n";
00677   for (int FldN=0; FldN<FldNmToValH.Len(); FldN++){
00678     ChA+=FldNmToValH.GetKey(FldN); ChA+=": ";
00679     ChA+=FldNmToValH[FldN]; ChA+="\r\n";
00680   }
00681   if (!BodyMem.Empty()) {
00682     ChA+=THttp::ContLenFldNm; ChA+=": ";
00683     ChA+=TInt::GetStr(BodyMem.Len()); ChA+="\r\n";
00684   }
00685   ChA+="\r\n";
00686   ChA+=BodyMem.GetAsStr();
00687   return ChA;
00688 }
00689 
00691 // Http-Response
00692 void THttpResp::AddHdFld(const TStr& FldNm, const TStr& FldVal, TChA& HdChA){
00693   TStr NrFldNm=THttpLx::GetNrStr(FldNm);
00694   FldNmToValVH.AddDat(NrFldNm).Add(FldVal);
00695   HdChA+=FldNm; HdChA+=": "; HdChA+=FldVal; HdChA+="\r\n";
00696 }
00697 
00698 void THttpResp::ParseHttpResp(const PSIn& SIn){
00699   THttpLx Lx(SIn);
00700   if (Lx.Eof()){
00701     // no content
00702     MajorVerN=0; MinorVerN=9; StatusCd=204;
00703     HdStr.Clr(); BodyMem.Clr();
00704   } else {
00705     if (Lx.IsRespStatusLn()){
00706       // status-line
00707       Lx.GetToken(THttp::HttpStr); Lx.GetSpec(THttp::SlashStr);
00708       MajorVerN=Lx.GetInt(1); Lx.GetPeriod(); MinorVerN=Lx.GetInt(1);
00709       StatusCd=Lx.GetInt(3);
00710       ReasonPhrase=Lx.GetRespReasonPhrase();
00711       Lx.GetCrLf();
00712       // header fields & values
00713       while (!Lx.IsCrLf()){
00714         TStr FldNm=Lx.GetToken(); Lx.GetSpec(THttp::ColonStr);
00715         TStr FldVal=Lx.GetFldVal();
00716         Lx.GetCrLf();
00717         TStr NrFldNm=THttpLx::GetNrStr(FldNm);
00718         FldNmToValVH.AddDat(NrFldNm).Add(FldVal);
00719       }
00720       // separator CrLf
00721       Lx.GetCrLf();
00722       // header & body strings
00723       HdStr=Lx.GetMemSf().GetAsStr();
00724       Lx.ClrMemSf();
00725       Lx.GetRest();
00726       BodyMem=Lx.GetMemSf();
00727     } else {
00728       // old fashion format
00729       MajorVerN=0; MinorVerN=9; StatusCd=200;
00730       HdStr.Clr();
00731       Lx.ClrMemSf();
00732       Lx.GetRest();
00733       BodyMem=Lx.GetMemSf();
00734     }
00735   }
00736   Ok=true;
00737 }
00738 
00739 THttpResp::THttpResp(const int& _StatusCd, const TStr& ContTypeVal,
00740  const bool& CacheCtrlP, const PSIn& BodySIn, const TStr LocStr):
00741   Ok(true), MajorVerN(1), MinorVerN(0), StatusCd(_StatusCd), ReasonPhrase(),
00742   FldNmToValVH(20), HdStr(), BodyMem(){
00743   ReasonPhrase=THttp::GetReasonPhrase(StatusCd);
00744   TChA HdChA;
00745   // first line
00746   HdChA+="HTTP/"; HdChA+=TInt::GetStr(MajorVerN); HdChA+=".";
00747   HdChA+=TInt::GetStr(MinorVerN); HdChA+=' ';
00748   HdChA+=TInt::GetStr(StatusCd); HdChA+=' ';
00749   HdChA+=ReasonPhrase;
00750   HdChA+="\r\n";
00751   // header fields
00752   // server
00753   //AddHdFld(THttp::SrvFldNm, "Tralala", HdChA);
00754   if (!LocStr.Empty()){
00755     AddHdFld("Location", LocStr, HdChA);}
00756   if (!BodySIn.Empty()){
00757     // content-type
00758     AddHdFld(THttp::ContTypeFldNm, ContTypeVal, HdChA);
00759     // accept-ranges
00760     AddHdFld(THttp::AcceptRangesFldNm, "bytes", HdChA);
00761     // content-length
00762     TStr ContLenVal=TInt::GetStr(BodySIn->Len());
00763     AddHdFld(THttp::ContLenFldNm, ContLenVal, HdChA);
00764     // cache-control
00765     if (!CacheCtrlP){
00766       AddHdFld(THttp::CacheCtrlFldNm, "no-cache", HdChA);}
00767   }
00768   // header/body separator
00769   HdChA+="\r\n";
00770   // header/body data
00771   HdStr=HdChA;
00772   if (!BodySIn.Empty()){
00773     TMem::LoadMem(BodySIn, BodyMem);}
00774 }
00775 
00776 THttpResp::THttpResp(const PSIn& SIn):
00777   Ok(false), MajorVerN(0), MinorVerN(0), StatusCd(-1), ReasonPhrase(),
00778   FldNmToValVH(20), HdStr(), BodyMem(){
00779   try {
00780     ParseHttpResp(SIn);
00781   }
00782   catch (THttpEx){Ok=false;}
00783 }
00784 
00785 bool THttpResp::IsFldNm(const TStr& FldNm) const {
00786   return FldNmToValVH.IsKey(THttpLx::GetNrStr(FldNm));
00787 }
00788 
00789 TStr THttpResp::GetFldVal(const TStr& FldNm, const int& ValN) const {
00790   TStr NrFldNm=THttpLx::GetNrStr(FldNm);
00791   if (FldNmToValVH.IsKey(NrFldNm)){
00792     const TStrV& ValV=FldNmToValVH.GetDat(NrFldNm);
00793     if (ValV.Len()>0){return ValV[ValN];} else {return TStr();}
00794   } else {
00795     return TStr();
00796   }
00797 }
00798 
00799 void THttpResp::GetFldValV(const TStr& FldNm, TStrV& FldValV) const {
00800   TStr NrFldNm=THttpLx::GetNrStr(FldNm);
00801   if (FldNmToValVH.IsKey(NrFldNm)){
00802     FldValV=FldNmToValVH.GetDat(NrFldNm);
00803   } else {
00804     FldValV.Clr();
00805   }
00806 }
00807 
00808 bool THttpResp::IsFldVal(const TStr& FldNm, const TStr& FldVal) const {
00809   return THttpLx::GetNrStr(FldVal)==THttpLx::GetNrStr(GetFldVal(FldNm));
00810 }
00811 
00812 void THttpResp::AddFldVal(const TStr& FldNm, const TStr& FldVal){
00813   TStr NrFldNm=THttpLx::GetNrStr(FldNm);
00814   FldNmToValVH.AddDat(NrFldNm).Add(FldVal);
00815   if (HdStr.IsSuffix("\r\n\r\n")){
00816     TChA HdChA=HdStr;
00817     HdChA.Pop(); HdChA.Pop(); 
00818     HdChA+=NrFldNm; HdChA+=": "; HdChA+=FldVal;
00819     HdChA+="\r\n\r\n";
00820     HdStr=HdChA;
00821   }
00822 }
00823 
00824 void THttpResp::GetCookieKeyValDmPathQuV(TStrQuV& CookieKeyValDmPathQuV){
00825   CookieKeyValDmPathQuV.Clr();
00826   TStrV CookieFldValV; GetFldValV(THttp::SetCookieFldNm, CookieFldValV);
00827   for (int CookieN=0; CookieN<CookieFldValV.Len(); CookieN++){
00828     TStr CookieFldVal=CookieFldValV[CookieN];
00829     TStrV KeyValStrV;
00830     CookieFldVal.SplitOnAllCh(';', KeyValStrV, true);
00831     TStrPrV KeyValPrV; TStr DmNm; TStr PathStr;
00832     for (int KeyValStrN=0; KeyValStrN<KeyValStrV.Len(); KeyValStrN++){
00833       TStr KeyValStr=KeyValStrV[KeyValStrN];
00834       TStr KeyNm; TStr ValStr; 
00835       if (KeyValStr.IsChIn('=')){
00836         KeyValStrV[KeyValStrN].SplitOnCh(KeyNm, '=', ValStr);
00837         KeyNm.ToTrunc(); ValStr.ToTrunc();
00838       } else {
00839         KeyNm=KeyValStr.GetTrunc();
00840       }
00841       if (KeyNm=="expires"){}
00842       else if (KeyNm=="domain"){DmNm=ValStr;}
00843       else if (KeyNm=="path"){PathStr=ValStr;}
00844       else if (KeyNm=="expires"){}
00845       else if (KeyNm=="secure"){}
00846       else if (KeyNm=="httponly"){}
00847       else if (!KeyNm.Empty()){
00848         KeyValPrV.Add(TStrPr(KeyNm, ValStr));
00849       }
00850     }
00851     for (int KeyValPrN=0; KeyValPrN<KeyValPrV.Len(); KeyValPrN++){
00852       TStr KeyNm=KeyValPrV[KeyValPrN].Val1;
00853       TStr ValStr=KeyValPrV[KeyValPrN].Val2;
00854       CookieKeyValDmPathQuV.Add(TStrQu(KeyNm, ValStr, DmNm, PathStr));
00855     }
00856   }
00857 }
00858 
00859 PSIn THttpResp::GetSIn() const {
00860   TMOut MOut(HdStr.Len()+BodyMem.Len());
00861   MOut.PutStr(HdStr); MOut.PutMem(BodyMem);
00862   return MOut.GetSIn();
00863 }
00864