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