SNAP Library 2.2, Developer Reference
2014-03-11 19:15:55
SNAP, a general purpose, high performance system for analysis and manipulation of large networks
|
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