cgiapp.pp 19 KB

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