cgiapp.pp 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884
  1. {
  2. This file is part of the Free Pascal run time library.
  3. Copyright (c) 1999-2000 by the Free Pascal development team
  4. TCGIApplication class.
  5. See the file COPYING.FPC, included in this distribution,
  6. for details about the copyright.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  10. **********************************************************************}
  11. {$mode objfpc}
  12. {$H+}
  13. unit cgiapp;
  14. Interface
  15. uses
  16. CustApp,Classes,SysUtils;
  17. Const
  18. CGIVarCount = 23;
  19. Type
  20. TCGIVarArray = Array[1..CGIVarCount] of String;
  21. Const
  22. CgiVarNames : TCGIVarArray =
  23. ('AUTH_TYPE',
  24. 'CONTENT_LENGTH',
  25. 'CONTENT_TYPE',
  26. 'GATEWAY_INTERFACE',
  27. 'PATH_INFO',
  28. 'PATH_TRANSLATED',
  29. 'QUERY_STRING', 'REMOTE_ADDR',
  30. 'REMOTE_HOST',
  31. 'REMOTE_IDENT',
  32. 'REMOTE_USER',
  33. 'REQUEST_METHOD',
  34. 'SCRIPT_NAME',
  35. 'SERVER_NAME',
  36. 'SERVER_PORT',
  37. 'SERVER_PROTOCOL',
  38. 'SERVER_SOFTWARE',
  39. 'HTTP_ACCEPT',
  40. 'HTTP_ACCEPT_CHARSET',
  41. 'HTTP_ACCEPT_ENCODING',
  42. 'HTTP_IF_MODIFIED_SINCE',
  43. 'HTTP_REFERER',
  44. 'HTTP_USER_AGENT');
  45. Type
  46. TCgiApplication = Class(TCustomApplication)
  47. Private
  48. FResponse : TStream;
  49. FEmail : String;
  50. FAdministrator : String;
  51. FContentTypeEmitted : Boolean;
  52. FCGIVars : TCGIVarArray;
  53. FRequestVars,
  54. FFormFiles : TStrings;
  55. Function GetCGIVar (Index : Integer) : String;
  56. Procedure InitCGIVars;
  57. Procedure InitRequestVars;
  58. Procedure InitPostVars;
  59. Procedure InitGetVars;
  60. Procedure SetContentLength (Value : Integer);
  61. Procedure SetCGIVar(Index : Integer; Value : String);
  62. Function GetContentLength : Integer;
  63. Function GetServerPort : Word;
  64. Function GetEmail : String;
  65. Function GetAdministrator : String;
  66. Procedure ProcessQueryString(Const FQueryString : String);
  67. Function GetRequestVariable(Const VarName : String) : String;
  68. Function GetRequestVariableCount : Integer;
  69. Procedure ProcessURLEncoded(M : TMemoryStream);
  70. Procedure ProcessMultiPart(M : TMemoryStream; Const Boundary : String);
  71. Public
  72. Constructor Create(AOwner : TComponent); override;
  73. Destructor Destroy; override;
  74. Procedure AddResponse(Const S : String);
  75. Procedure AddResponse(Const Fmt : String; Args : Array of const);
  76. Procedure AddResponseLn(Const S : String);
  77. Procedure AddResponseLn(Const Fmt : String; Args : Array of const);
  78. Procedure Initialize; override;
  79. Procedure GetCGIVarList(List : TStrings);
  80. Procedure GetRequestVarList(List : TStrings);
  81. Procedure GetRequestVarList(List : TStrings; NamesOnly : Boolean);
  82. Procedure ShowException(E: Exception);override;
  83. Procedure DeleteFormFiles;
  84. Function EmitContentType : Boolean;
  85. Function GetTempCGIFileName : String;
  86. Function VariableIsUploadedFile(Const VarName : String) : boolean;
  87. Function UploadedFileName(Const VarName : String) : String;
  88. Property AuthType : String Index 1 Read GetCGIVar;
  89. Property ContentLength : Integer Read GetContentLength Write SetContentLength; // Index 2
  90. Property ContentType : String Index 3 Read GetCGIVar Write SetCGIVar;
  91. Property GatewayInterface : String Index 4 Read GetCGIVar;
  92. Property PathInfo : String index 5 read GetCGIvar;
  93. Property PathTranslated : String Index 6 read getCGIVar;
  94. Property QueryString : String Index 7 read getcgivar;
  95. Property RemoteAddress : String Index 8 read GetCGIVar;
  96. Property RemoteHost : String Index 9 read GetCGIVar;
  97. Property RemoteIdent : String Index 10 read GetCGIVar;
  98. Property RemoteUser : String Index 11 read GetCGIVar;
  99. Property RequestMethod : String Index 12 read GetCGIVar;
  100. Property ScriptName : String Index 13 read GetCGIVar;
  101. Property ServerName : String Index 14 read GetCGIVar;
  102. Property ServerPort : Word Read GetServerPort; // Index 15
  103. Property ServerProtocol : String Index 16 read GetCGIVar;
  104. Property ServerSoftware : String Index 17 read GetCGIVar;
  105. Property HTTPAccept : String Index 18 read GetCGIVar;
  106. Property HTTPAcceptCharset : String Index 19 read GetCGIVar;
  107. Property HTTPAcceptEncoding : String Index 20 read GetCGIVar;
  108. Property HTTPIfModifiedSince : String Index 21 read GetCGIVar; // Maybe change to TDateTime ??
  109. Property HTTPReferer : String Index 22 read GetCGIVar;
  110. Property HTTPUserAgent : String Index 23 read GetCGIVar;
  111. Property Email : String Read GetEmail Write FEmail;
  112. Property Administrator : String Read GetAdministrator Write FAdministrator;
  113. Property RequestVariables[VarName : String] : String Read GetRequestVariable;
  114. Property RequestVariableCount : Integer Read GetRequestVariableCount;
  115. Property Response : TStream Read FResponse;
  116. end;
  117. ResourceString
  118. SWebMaster = 'webmaster';
  119. SCGIError = 'CGI Error';
  120. SAppEncounteredError = 'The application encountered the following error:';
  121. SError = 'Error: ';
  122. SNotify = 'Notify: ';
  123. SErrNoContentLength = 'No content length passed from server!';
  124. SErrUnsupportedContentType = 'Unsupported content type: "%s"';
  125. SErrNoRequestMethod = 'No REQUEST_METHOD passed from server.';
  126. SErrInvalidRequestMethod = 'Invalid REQUEST_METHOD passed from server.';
  127. Implementation
  128. uses
  129. iostream;
  130. {$ifdef cgidebug}
  131. Var
  132. flog : Text;
  133. Procedure Log(Msg : String);
  134. begin
  135. Writeln(flog,Msg);
  136. end;
  137. Procedure Log(Msg : String;Args : Array of const);
  138. begin
  139. Writeln(flog,Format(Msg,Args));
  140. end;
  141. Procedure InitLog;
  142. begin
  143. Assign(flog,'/tmp/cgi.log');
  144. Rewrite(flog);
  145. Log('---- Start of log session ---- ');
  146. end;
  147. Procedure DoneLog;
  148. begin
  149. Close(Flog);
  150. end;
  151. {$endif}
  152. Constructor TCgiApplication.Create(AOwner : TComponent);
  153. begin
  154. Inherited Create(AOwner);
  155. FRequestVars:=TStringList.Create;
  156. FFormFiles:=TStringList.Create;
  157. end;
  158. Destructor TCgiApplication.Destroy;
  159. begin
  160. DeleteFormFiles;
  161. FFormFiles.Free;
  162. FRequestVars.Free;
  163. Inherited;
  164. end;
  165. Function TCgiApplication.GetCGIVar (Index : Integer) : String;
  166. begin
  167. Result:=FCGIVars[Index];
  168. end;
  169. Procedure TCgiApplication.InitCGIVars;
  170. Var
  171. I : Integer;
  172. L : TStrings;
  173. begin
  174. L:=TStringList.Create;
  175. Try
  176. GetEnvironmentList(L);
  177. For I:=1 to CGIVarCount do
  178. FCGIVars[i]:=L.Values[CGIVarNames[i]];
  179. Finally
  180. L.Free;
  181. end;
  182. end;
  183. Function TCgiApplication.GetTempCGIFileName : String;
  184. begin
  185. Result:=GetTempFileName('/tmp/','CGI')
  186. end;
  187. Procedure TCgiApplication.DeleteFormFiles;
  188. Var
  189. I,P : Integer;
  190. FN : String;
  191. begin
  192. For I:=0 to FFormFiles.Count-1 do
  193. begin
  194. FN:=FFormFiles[i];
  195. P:=Pos('=',FN);
  196. Delete(FN,1,P);
  197. If FileExists(FN) then
  198. DeleteFile(FN);
  199. end;
  200. end;
  201. Procedure TCgiApplication.Initialize;
  202. begin
  203. StopOnException:=True;
  204. Inherited;
  205. InitCGIVars;
  206. InitRequestVars;
  207. FResponse:=TIOStream.Create(iosOutput);
  208. end;
  209. Procedure TCgiApplication.GetCGIVarList(List : TStrings);
  210. Var
  211. I : Integer;
  212. begin
  213. List.Clear;
  214. For I:=1 to cgiVarCount do
  215. List.Add(CGIVarNames[i]+'='+FCGIVars[i]);
  216. end;
  217. Procedure TCgiApplication.GetRequestVarList(List : TStrings);
  218. begin
  219. GetRequestVarList(List,False);
  220. end;
  221. Procedure TCgiApplication.GetRequestVarList(List : TStrings; NamesOnly : Boolean);
  222. Var
  223. I,J : Integer;
  224. S : String;
  225. begin
  226. List.BeginUpdate;
  227. Try
  228. List.Clear;
  229. // Copy one by one, there may be CR/LF in the variables, causing 'Text' to go wrong.
  230. If Assigned(FRequestVars) then
  231. For I:=0 to FRequestVars.Count-1 do
  232. begin
  233. S:=FRequestVars[i];
  234. If NamesOnly then
  235. begin
  236. J:=Pos('=',S);
  237. If (J>0) then
  238. S:=Copy(S,1,J-1);
  239. end;
  240. List.Add(S);
  241. end;
  242. finally
  243. List.EndUpdate;
  244. end;
  245. end;
  246. Function TCgiApplication.GetContentLength : Integer;
  247. begin
  248. Result:=StrToIntDef(GetCGIVar(2),-1);
  249. end;
  250. Procedure TCgiApplication.SetContentLength (Value : Integer);
  251. begin
  252. SetCGIVar(2,IntToStr(Value));
  253. end;
  254. Procedure TCgiApplication.SetCGIVar(Index : Integer; Value : String);
  255. begin
  256. If Index in [1..cgiVarCount] then
  257. FCGIVars[Index]:=Value;
  258. end;
  259. Function TCgiApplication.GetServerPort : Word;
  260. begin
  261. Result:=StrToIntDef(GetCGIVar(15),0);
  262. end;
  263. Function TCgiApplication.EmitContentType : Boolean;
  264. Var
  265. S: String;
  266. begin
  267. Result:=Not FContentTypeEmitted;
  268. If result then
  269. begin
  270. S:=ContentType;
  271. If (S='') then
  272. S:='text/html';
  273. AddResponseLn('Content-Type: '+ContentType);
  274. AddResponseLn('');
  275. FContentTypeEmitted:=True;
  276. end;
  277. end;
  278. Procedure TCgiApplication.ShowException(E: Exception);
  279. Var
  280. TheEmail : String;
  281. FrameCount: integer;
  282. Frames: PPointer;
  283. FrameNumber:Integer;
  284. begin
  285. If not FContentTypeEmitted then
  286. begin
  287. ContentType:='text/html';
  288. EmitContentType;
  289. end;
  290. If (ContentType='text/html') then
  291. begin
  292. AddResponseLN('<html><head><title>'+Title+': '+SCGIError+'</title></head>');
  293. AddResponseLN('<body>');
  294. AddResponseLN('<center><hr><h1>'+Title+': ERROR</h1><hr></center><br><br>');
  295. AddResponseLN(SAppEncounteredError+'<br>');
  296. AddResponseLN('<ul>');
  297. AddResponseLN('<li>'+SError+' <b>'+E.Message+'</b>');
  298. AddResponseLn('<li> Stack trace:<br>');
  299. AddResponseLn(BackTraceStrFunc(ExceptAddr)+'<br>');
  300. FrameCount:=ExceptFrameCount;
  301. Frames:=ExceptFrames;
  302. for FrameNumber := 0 to FrameCount-1 do
  303. AddResponseLn(BackTraceStrFunc(Frames[FrameNumber])+'<br>');
  304. AddResponseLn('</ul><hr>');
  305. TheEmail:=Email;
  306. If (TheEmail<>'') then
  307. AddResponseLN('<h5><p><i>'+SNotify+Administrator+': <a href="mailto:'+TheEmail+'">'+TheEmail+'</a></i></p></h5>');
  308. AddResponseLN('</body></html>');
  309. end;
  310. end;
  311. Function TCgiApplication.GetEmail : String;
  312. Var
  313. H : String;
  314. begin
  315. If (FEmail='') then
  316. begin
  317. H:=ServerName;
  318. If (H<>'') then
  319. Result:=Administrator+'@'+H
  320. else
  321. Result:='';
  322. end
  323. else
  324. Result:=Email;
  325. end;
  326. Function TCgiApplication.GetAdministrator : String;
  327. begin
  328. If (FADministrator<>'') then
  329. Result:=FAdministrator
  330. else
  331. Result:=SWebMaster;
  332. end;
  333. Procedure TCgiApplication.InitRequestVars;
  334. var
  335. R : String;
  336. begin
  337. R:=RequestMethod;
  338. if (R='') then
  339. Raise Exception.Create(SErrNoRequestMethod);
  340. if CompareText(R,'POST')=0 then
  341. InitPostVars
  342. else if CompareText(R,'GET')=0 then
  343. InitGetVars
  344. else
  345. Raise Exception.CreateFmt(SErrInvalidRequestMethod,[R]);
  346. end;
  347. Procedure TCgiApplication.ProcessURLEncoded(M : TMemoryStream);
  348. var
  349. FQueryString : String;
  350. begin
  351. SetLength(FQueryString,M.Size); // Skip added Null.
  352. M.Read(FQueryString[1],M.Size);
  353. ProcessQueryString(FQueryString);
  354. end;
  355. Type
  356. TFormItem = Class(TObject)
  357. DisPosition : String;
  358. Name : String;
  359. isFile : Boolean;
  360. FileName : String;
  361. ContentType : String;
  362. DLen : Integer;
  363. Data : String;
  364. Procedure Process;
  365. end;
  366. Procedure TFormItem.Process;
  367. Function GetLine(Var S : String) : String;
  368. Var
  369. P : Integer;
  370. begin
  371. P:=Pos(#13#10,S);
  372. If (P<>0) then
  373. begin
  374. Result:=Copy(S,1,P-1);
  375. Delete(S,1,P+1);
  376. end;
  377. end;
  378. Function GetWord(Var S : String) : String;
  379. Var
  380. I,len : Integer;
  381. Quoted : Boolean;
  382. C : Char;
  383. begin
  384. len:=length(S);
  385. quoted:=false;
  386. Result:='';
  387. for i:=1 to len do
  388. Begin
  389. c:=S[i];
  390. if (c='"') then
  391. Quoted:=Not Quoted
  392. else
  393. begin
  394. if not (c in [' ','=',';',':']) or Quoted then
  395. Result:=Result+C;
  396. if (c in [';',':','=']) and (not quoted) then
  397. begin
  398. Delete(S,1,I);
  399. Exit;
  400. end;
  401. end;
  402. end;
  403. S:='';
  404. end;
  405. Var
  406. Line : String;
  407. Words : TStringList;
  408. i,len : integer;
  409. c : char;
  410. S : string;
  411. quoted : boolean;
  412. begin
  413. Line:=GetLine(Data);
  414. While (Line<>'') do
  415. begin
  416. S:=GetWord(Line);
  417. While (S<>'') do
  418. begin
  419. If CompareText(S,'Content-Disposition')=0 then
  420. Disposition:=GetWord(Line)
  421. else if CompareText(S,'name')=0 Then
  422. Name:=GetWord(Line)
  423. else if CompareText(S,'filename')=0 then
  424. begin
  425. FileName:=GetWord(Line);
  426. isFile:=True;
  427. end
  428. else if CompareText(S,'Content-Type')=0 then
  429. ContentType:=GetWord(Line);
  430. S:=GetWord(Line);
  431. end;
  432. Line:=GetLine(Data);
  433. end;
  434. // Now Data contains the rest of the data, plus a CR/LF. Strip the CR/LF
  435. Len:=Length(Data);
  436. If (len>2) then
  437. Data:=Copy(Data,1,Len-2);
  438. end;
  439. Function MakeString(PStart,PEnd : Pchar) : String;
  440. begin
  441. SetLength(Result,PEnd-PStart);
  442. If Length(Result)>0 then
  443. Move(PStart^,Result[1],Length(Result));
  444. end;
  445. procedure FormSplit(var Cnt : String; boundary: String; List : TList);
  446. // Splits the form into items
  447. var
  448. Sep : string;
  449. Clen,slen, p:longint;
  450. FI : TFormItem;
  451. begin
  452. Sep:='--'+boundary+#13+#10;
  453. Slen:=length(Sep);
  454. CLen:=Pos('--'+Boundary+'--',Cnt);
  455. // Cut last marker
  456. Cnt:=Copy(Cnt,1,Clen-1);
  457. // Cut first marker
  458. Delete(Cnt,1,Slen);
  459. Clen:=Length(Cnt);
  460. While Clen>0 do
  461. begin
  462. Fi:=TFormItem.Create;
  463. List.Add(Fi);
  464. P:=pos(Sep,Cnt);
  465. If (P=0) then
  466. P:=CLen+1;
  467. FI.Data:=Copy(Cnt,1,P-1);
  468. delete(Cnt,1,P+SLen-1);
  469. CLen:=Length(Cnt);
  470. end;
  471. end;
  472. function GetNextLine(Var Data: String):string;
  473. Var
  474. p : Integer;
  475. begin
  476. P:=Pos(#13#10,Data);
  477. If (P<>0) then
  478. begin
  479. Result:=Copy(Data,1,P-1);
  480. Delete(Data,1,P+1);
  481. end;
  482. end;
  483. Procedure TCgiApplication.ProcessMultiPart(M : TMemoryStream; Const Boundary : String);
  484. Var
  485. L : TList;
  486. B : String;
  487. I,Index : Integer;
  488. S,FF,key, Value : String;
  489. FI : TFormItem;
  490. F : TStream;
  491. begin
  492. i:=Pos('=',Boundary);
  493. B:=Copy(Boundary,I+1,Length(Boundary)-I);
  494. I:=Length(B);
  495. If (I>0) and (B[1]='"') then
  496. B:=Copy(B,2,I-2);
  497. L:=TList.Create;
  498. Try
  499. SetLength(S,M.Size);
  500. If Length(S)>0 then
  501. Move(M.Memory^,S[1],M.Size);
  502. FormSplit(S,B,L);
  503. For I:=L.Count-1 downto 0 do
  504. begin
  505. FI:=TFormItem(L[i]);
  506. FI.Process;
  507. If (FI.Name='') then
  508. Raise Exception.CreateFmt('Invalid multipart encoding: %s',[FI.Data]);
  509. Key:=FI.Name;
  510. If Not FI.IsFile Then
  511. begin
  512. Value:=FI.Data
  513. end
  514. else
  515. begin
  516. Value:=FI.FileName;
  517. FF:=GetTempCGIFileName;
  518. FFormFiles.Add(Key+'='+FF);
  519. F:=TFileStream.Create(FF,fmCreate);
  520. Try
  521. if Length(FI.Data)>0 then
  522. F.Write(FI.Data[1],Length(FI.Data));
  523. finally
  524. F.Free;
  525. end;
  526. FI.Free;
  527. L[i]:=Nil;
  528. end;
  529. FRequestVars.Add(Key+'='+Value)
  530. end;
  531. Finally
  532. For I:=0 to L.Count-1 do
  533. TObject(L[i]).Free;
  534. L.Free;
  535. end;
  536. end;
  537. Type
  538. TCapacityStream = Class(TMemoryStream)
  539. Public
  540. Property Capacity;
  541. end;
  542. Procedure TCgiApplication.InitPostVars;
  543. Var
  544. M : TCapacityStream;
  545. I : TIOStream;
  546. Cl : Integer;
  547. B : Byte;
  548. begin
  549. CL:=ContentLength;
  550. M:=TCapacityStream.Create;
  551. Try
  552. I:=TIOStream.Create(iosInput);
  553. Try
  554. if (CL<>0) then
  555. begin
  556. M.Capacity:=(Cl);
  557. M.CopyFrom(I,Cl);
  558. end
  559. else
  560. begin
  561. While (I.Read(B,1)>0) do
  562. M.Write(B,1)
  563. end;
  564. Finally
  565. I.Free;
  566. end;
  567. if Pos(ContentType,'MULTIPART/FORM-DATA')=0 then
  568. ProcessMultiPart(M,ContentType)
  569. else if CompareText(ContentType,'APPLICATION/X-WWW-FORM-URLENCODED')=0 then
  570. ProcessUrlEncoded(M)
  571. else
  572. Raise Exception.CreateFmt(SErrUnsupportedContentType,[ContentType]);
  573. finally
  574. M.Free;
  575. end;
  576. end;
  577. Procedure TCgiApplication.InitGetVars;
  578. Var
  579. FQueryString : String;
  580. begin
  581. FQueryString:=QueryString;
  582. If (FQueryString<>'') then
  583. ProcessQueryString(FQueryString);
  584. end;
  585. const
  586. hexTable = '0123456789ABCDEF';
  587. Procedure TCgiApplication.ProcessQueryString(Const FQueryString : String);
  588. var
  589. queryItem : String;
  590. delimiter : Char;
  591. aString : String;
  592. aSepStr : String;
  593. aPos : Integer;
  594. aLenStr : Integer;
  595. aLenSep : Integer;
  596. function hexConverter(h1, h2 : Char) : Char;
  597. var
  598. B : Byte;
  599. begin
  600. B:=(Pos(upcase(h1),hexTable)-1)*16;
  601. B:=B+Pos(upcase(h2),hexTable)-1;
  602. Result:=chr(B);
  603. end;
  604. procedure Convert_ESC_Chars;
  605. var
  606. index : Integer;
  607. begin
  608. Index:=Length(QueryItem);
  609. While (Index>0) do
  610. begin
  611. If QueryItem[Index]='+' then
  612. QueryItem[Index]:=' '
  613. else If (QueryItem[Index]='%') and (Index<Length(QueryItem)-1) then
  614. begin
  615. QueryItem[Index]:=hexConverter(QueryItem[Index+1],QueryItem[index+2]);
  616. System.Delete(QueryItem,Index+1,2);
  617. end;
  618. dec(Index);
  619. end;
  620. end;
  621. procedure InitToken(aStr, aSep : String);
  622. begin
  623. aString := aStr;
  624. aSepStr := aSep;
  625. aPos := 1;
  626. aLenStr := Length(aString);
  627. aLenSep := Length(aSepStr);
  628. end;
  629. function NextToken(var aToken : String; var aSepChar : Char) : Boolean;
  630. var
  631. i : Integer;
  632. j : Integer;
  633. BoT : Integer;
  634. EoT : Integer;
  635. isSep : Boolean;
  636. begin
  637. BoT:=aPos;
  638. EoT:=aPos;
  639. for i:=aPos to aLenStr do
  640. begin
  641. IsSep := false;
  642. for j := 1 to aLenSep do
  643. begin
  644. if aString[i] = aSepStr[j] then
  645. begin
  646. IsSep := true;
  647. Break;
  648. end;
  649. end;
  650. if IsSep then
  651. begin
  652. EoT := i;
  653. aPos := i + 1;
  654. aSepChar := aString[i];
  655. Break;
  656. end
  657. else
  658. begin
  659. if i = aLenStr then
  660. begin
  661. EoT := i;
  662. aPos := i;
  663. Break;
  664. end;
  665. end;
  666. end;
  667. if aPos < aLenStr then
  668. begin
  669. aToken := Copy(aString, BoT, EoT - BoT);
  670. Result := true;
  671. end
  672. else
  673. begin
  674. if aPos = aLenStr then
  675. begin
  676. aToken := Copy(aString, BoT, EoT - BoT + 1);
  677. Result := true;
  678. aPos := aPos + 1;
  679. end
  680. else
  681. begin
  682. Result := false;
  683. end;
  684. end;
  685. end;
  686. begin
  687. InitToken(FQueryString, '&');
  688. while NextToken(QueryItem, delimiter) do
  689. begin
  690. if (QueryItem<>'') then
  691. begin
  692. Convert_ESC_Chars;
  693. FRequestVars.Add(QueryItem);
  694. end;
  695. end;
  696. end;
  697. Function TCGIApplication.GetRequestVariable(Const VarName : String) : String;
  698. begin
  699. If Assigned(FRequestVars) then
  700. Result:=FRequestVars.Values[VarName];
  701. end;
  702. Function TCGIApplication.GetRequestVariableCount : Integer;
  703. begin
  704. If Assigned(FRequestVars) then
  705. Result:=FRequestVars.Count
  706. else
  707. Result:=0;
  708. end;
  709. Procedure TCGIApplication.AddResponse(Const S : String);
  710. Var
  711. L : Integer;
  712. begin
  713. L:=Length(S);
  714. If L>0 then
  715. FResponse.Write(S[1],L);
  716. end;
  717. Procedure TCGIApplication.AddResponse(Const Fmt : String; Args : Array of const);
  718. begin
  719. AddResponse(Format(Fmt,Args));
  720. end;
  721. Procedure TCGIApplication.AddResponseLN(Const S : String);
  722. begin
  723. AddResponse(S+LineEnding);
  724. end;
  725. Procedure TCGIApplication.AddResponseLN(Const Fmt : String; Args : Array of const);
  726. begin
  727. AddResponseLN(Format(Fmt,Args));
  728. end;
  729. Function TCGIApplication.VariableIsUploadedFile(Const VarName : String) : boolean;
  730. begin
  731. Result:=FFormFiles.IndexOfName(VarName)<>-1;
  732. end;
  733. Function TCGIApplication.UploadedFileName(Const VarName : String) : String;
  734. begin
  735. Result:=FFormFiles.Values[VarName];
  736. end;
  737. {$ifdef cgidebug}
  738. Initialization
  739. initLog;
  740. Finalization
  741. DoneLog;
  742. {$endif}
  743. end.