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