SNAP Library , Developer Reference  2013-01-07 14:03:36
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::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