lfastcgi.pp 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910
  1. { FastCGI requester support for lNet
  2. Copyright (C) 2006-2008 Micha Nelissen
  3. This library is Free software; you can redistribute it and/or modify it
  4. under the terms of the GNU Library General Public License as published by
  5. the Free Software Foundation; either version 2 of the License, or (at your
  6. option) any later version.
  7. This program is diStributed in the hope that it will be useful, but WITHOUT
  8. ANY WARRANTY; withOut even the implied warranty of MERCHANTABILITY or
  9. FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License
  10. for more details.
  11. You should have received a Copy of the GNU Library General Public License
  12. along with This library; if not, Write to the Free Software Foundation,
  13. Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  14. This license has been modified. See file LICENSE.ADDON for more information.
  15. Should you find these sources without a LICENSE File, please contact
  16. me at [email protected]
  17. }
  18. unit lfastcgi;
  19. {$mode objfpc}{$h+}
  20. interface
  21. uses
  22. classes, sysutils, fastcgi_base, lnet, levents, lstrbuffer, ltimer;
  23. type
  24. TLFastCGIClient = class;
  25. TLFastCGIRequest = class;
  26. TLFastCGIPool = class;
  27. TLFastCGIRequestEvent = procedure(ARequest: TLFastCGIRequest) of object;
  28. PLFastCGIRequest = ^TLFastCGIRequest;
  29. TLFastCGIRequest = class(TObject)
  30. protected
  31. FID: integer;
  32. FClient: TLFastCGIClient;
  33. FBuffer: TStringBuffer;
  34. FBufferSendPos: integer;
  35. FHeader: FCGI_Header;
  36. FHeaderPos: integer;
  37. FContentLength: integer;
  38. FInputBuffer: pchar;
  39. FInputSize: integer;
  40. FOutputDone: boolean;
  41. FStderrDone: boolean;
  42. FOutputPending: boolean;
  43. FNextFree: TLFastCGIRequest;
  44. FNextSend: TLFastCGIRequest;
  45. FOnEndRequest: TLFastCGIRequestEvent;
  46. FOnInput: TLFastCGIRequestEvent;
  47. FOnOutput: TLFastCGIRequestEvent;
  48. FOnStderr: TLFastCGIRequestEvent;
  49. procedure HandleReceive;
  50. procedure HandleReceiveEnd;
  51. function HandleSend: boolean;
  52. procedure DoEndRequest;
  53. procedure DoOutput;
  54. procedure DoStderr;
  55. procedure EndRequest;
  56. procedure RewindBuffer;
  57. procedure SetContentLength(NewLength: integer);
  58. procedure SendEmptyRec(AType: integer);
  59. procedure SendGetValues;
  60. procedure SetID(const NewID: integer);
  61. public
  62. constructor Create;
  63. destructor Destroy; override;
  64. procedure AbortRequest;
  65. function Get(ABuffer: pchar; ASize: integer): integer;
  66. procedure ParseClientBuffer;
  67. function SendBuffer: integer;
  68. function SendPrivateBuffer: boolean;
  69. procedure SendBeginRequest(AType: integer);
  70. procedure SendParam(const AName, AValue: string; AReqType: integer = FCGI_PARAMS);
  71. function SendInput(const ABuffer: pchar; ASize: integer): integer;
  72. procedure DoneParams;
  73. procedure DoneInput;
  74. property ID: integer read FID write SetID;
  75. property StderrDone: boolean read FStderrDone;
  76. property OutputDone: boolean read FOutputDone;
  77. property OutputPending: boolean read FOutputPending;
  78. property OnEndRequest: TLFastCGIRequestEvent read FOnEndRequest write FOnEndRequest;
  79. property OnInput: TLFastCGIRequestEvent read FOnInput write FOnInput;
  80. property OnOutput: TLFastCGIRequestEvent read FOnOutput write FOnOutput;
  81. property OnStderr: TLFastCGIRequestEvent read FOnStderr write FOnStderr;
  82. end;
  83. TFastCGIClientState = (fsIdle, fsConnecting, fsConnectingAgain,
  84. fsStartingServer, fsHeader, fsData, fsFlush);
  85. PLFastCGIClient = ^TLFastCGIClient;
  86. TLFastCGIClient = class(TLTcp)
  87. protected
  88. FRequests: PLFastCGIRequest;
  89. FRequestsCount: integer;
  90. FNextRequestID: integer;
  91. FRequestsSent: integer;
  92. FFreeRequest: TLFastCGIRequest;
  93. FSendRequest: TLFastCGIRequest;
  94. FRequest: TLFastCGIRequest;
  95. FState: TFastCGIClientState;
  96. FNextFree: TLFastCGIClient;
  97. FPool: TLFastCGIPool;
  98. FBuffer: pchar;
  99. FBufferEnd: pchar;
  100. FBufferPos: pchar;
  101. FBufferSize: dword;
  102. FReqType: byte;
  103. FContentLength: integer;
  104. FPaddingLength: integer;
  105. function Connect: Boolean; override;
  106. procedure ConnectEvent(ASocket: TLHandle); override;
  107. procedure DisconnectEvent(ASocket: TLHandle); override;
  108. procedure ErrorEvent(ASocket: TLHandle; const msg: string); override;
  109. function CreateRequester: TLFastCGIRequest;
  110. procedure HandleGetValuesResult;
  111. procedure HandleReceive(ASocket: TLSocket);
  112. procedure HandleSend(ASocket: TLSocket);
  113. procedure ParseBuffer;
  114. public
  115. constructor Create(AOwner: TComponent); override;
  116. destructor Destroy; override;
  117. procedure AddToSendQueue(ARequest: TLFastCGIRequest);
  118. function BeginRequest(AType: integer): TLFastCGIRequest;
  119. procedure EndRequest(ARequest: TLFastCGIRequest);
  120. procedure Flush;
  121. function GetBuffer(ABuffer: pchar; ASize: integer): integer;
  122. property ReqType: byte read FReqType;
  123. property RequestsSent: integer read FRequestsSent;
  124. end;
  125. TSpawnState = (ssNone, ssSpawning, ssSpawned);
  126. TLFastCGIPool = class(TObject)
  127. protected
  128. FClients: PLFastCGIClient;
  129. FClientsCount: integer;
  130. FClientsAvail: integer;
  131. FClientsMax: integer;
  132. FMaxRequestsConn: integer;
  133. FFreeClient: TLFastCGIClient;
  134. FTimer: TLTimer;
  135. FEventer: TLEventer;
  136. FAppName: string;
  137. FAppEnv: string;
  138. FHost: string;
  139. FPort: integer;
  140. FSpawnState: TSpawnState;
  141. procedure AddToFreeClients(AClient: TLFastCGIClient);
  142. function CreateClient: TLFastCGIClient;
  143. procedure ConnectClients(Sender: TObject);
  144. procedure StartServer;
  145. public
  146. constructor Create;
  147. destructor Destroy; override;
  148. function BeginRequest(AType: integer): TLFastCGIRequest;
  149. procedure EndRequest(AClient: TLFastCGIClient);
  150. property AppEnv: string read FAppEnv write FAppEnv;
  151. property AppName: string read FAppName write FAppName;
  152. property ClientsMax: integer read FClientsMax write FClientsMax;
  153. property Eventer: TLEventer read FEventer write FEventer;
  154. property MaxRequestsConn: integer read FMaxRequestsConn write FMaxRequestsConn;
  155. property Host: string read FHost write FHost;
  156. property Port: integer read FPort write FPort;
  157. property Timer: TLTimer read FTimer;
  158. end;
  159. implementation
  160. uses
  161. lSpawnFCGI;
  162. { TLFastCGIRequest }
  163. constructor TLFastCGIRequest.Create;
  164. begin
  165. inherited;
  166. FBuffer := InitStringBuffer(504);
  167. FHeader.Version := FCGI_VERSION_1;
  168. FHeaderPos := -1;
  169. end;
  170. destructor TLFastCGIRequest.Destroy;
  171. begin
  172. inherited;
  173. FreeMem(FBuffer.Memory);
  174. end;
  175. procedure TLFastCGIRequest.HandleReceive;
  176. begin
  177. case FClient.ReqType of
  178. FCGI_STDOUT: DoOutput;
  179. FCGI_STDERR: DoStderr;
  180. FCGI_END_REQUEST: EndRequest;
  181. FCGI_GET_VALUES_RESULT: FClient.HandleGetValuesResult;
  182. else
  183. FClient.Flush;
  184. end;
  185. end;
  186. procedure TLFastCGIRequest.HandleReceiveEnd;
  187. begin
  188. case FClient.ReqType of
  189. FCGI_STDOUT: FOutputDone := true;
  190. FCGI_STDERR: FStderrDone := true;
  191. end;
  192. end;
  193. function TLFastCGIRequest.HandleSend: boolean;
  194. begin
  195. if FOnInput <> nil then
  196. FOnInput(Self);
  197. Result := FInputBuffer = nil;
  198. end;
  199. procedure TLFastCGIRequest.DoOutput;
  200. begin
  201. if FOnOutput <> nil then
  202. FOnOutput(Self);
  203. end;
  204. procedure TLFastCGIRequest.DoStderr;
  205. begin
  206. if FOnStderr <> nil then
  207. FOnStderr(Self);
  208. end;
  209. procedure TLFastCGIRequest.DoEndRequest;
  210. begin
  211. if FOnEndRequest <> nil then
  212. FOnEndRequest(Self);
  213. end;
  214. procedure TLFastCGIRequest.EndRequest;
  215. begin
  216. FOutputDone := false;
  217. FStderrDone := false;
  218. FClient.EndRequest(Self);
  219. FClient.Flush;
  220. RewindBuffer;
  221. DoEndRequest;
  222. end;
  223. function TLFastCGIRequest.Get(ABuffer: pchar; ASize: integer): integer;
  224. begin
  225. Result := FClient.GetBuffer(ABuffer, ASize);
  226. end;
  227. procedure TLFastCGIRequest.ParseClientBuffer;
  228. begin
  229. FOutputPending := false;
  230. if (FClient.Iterator <> nil) and FClient.Iterator.IgnoreRead then
  231. FClient.HandleReceive(nil)
  232. else
  233. FClient.ParseBuffer;
  234. end;
  235. procedure TLFastCGIRequest.SetID(const NewID: integer);
  236. begin
  237. FID := NewID;
  238. FHeader.RequestIDB0 := byte(NewID and $FF);
  239. FHeader.RequestIDB1 := byte((NewID shr 8) and $FF);
  240. end;
  241. procedure TLFastCGIRequest.SetContentLength(NewLength: integer);
  242. begin
  243. FContentLength := NewLength;
  244. FHeader.ContentLengthB0 := byte(NewLength and $FF);
  245. FHeader.ContentLengthB1 := byte((NewLength shr 8) and $FF);
  246. FHeader.PaddingLength := byte(7-((NewLength+7) and 7));
  247. end;
  248. const
  249. PaddingBuffer: array[0..7] of char = (#0, #0, #0, #0, #0, #0, #0, #0);
  250. type
  251. TLFastCGIStringSize = record
  252. Size: integer;
  253. SizeBuf: array[0..3] of char;
  254. end;
  255. function GetFastCGIStringSize(ABufferPos: pbyte; var ASize: integer): integer;
  256. begin
  257. ASize := ABufferPos[0];
  258. if ASize >= 128 then
  259. begin
  260. ASize := ((ABufferPos[0] shl 24) and $7f) or (ABufferPos[1] shl 16)
  261. or (ABufferPos[2] shl 8) or ABufferPos[3];
  262. Result := 4;
  263. end else
  264. Result := 1;
  265. end;
  266. procedure FillFastCGIStringSize(const AStr: string; var AFastCGIStr: TLFastCGIStringSize);
  267. var
  268. lLen: dword;
  269. begin
  270. lLen := dword(Length(AStr));
  271. if lLen > 127 then
  272. begin
  273. AFastCGIStr.Size := 4;
  274. AFastCGIStr.SizeBuf[0] := char($80 + ((lLen shr 24) and $ff));
  275. AFastCGIStr.SizeBuf[1] := char((lLen shr 16) and $ff);
  276. AFastCGIStr.SizeBuf[2] := char((lLen shr 8) and $ff);
  277. AFastCGIStr.SizeBuf[3] := char(lLen and $ff);
  278. end else begin
  279. AFastCGIStr.Size := 1;
  280. AFastCGIStr.SizeBuf[0] := char(lLen);
  281. end;
  282. end;
  283. procedure TLFastCGIRequest.SendBeginRequest(AType: integer);
  284. var
  285. lBody: FCGI_BeginRequestBody;
  286. begin
  287. lBody.roleB1 := byte((AType shr 8) and $ff);
  288. lBody.roleB0 := byte(AType and $ff);
  289. lBody.flags := FCGI_KEEP_CONN;
  290. FHeader.ReqType := FCGI_BEGIN_REQUEST;
  291. SetContentLength(sizeof(lBody));
  292. AppendString(FBuffer, @FHeader, sizeof(FHeader));
  293. AppendString(FBuffer, @lBody, sizeof(lBody));
  294. end;
  295. procedure TLFastCGIRequest.SendParam(const AName, AValue: string; AReqType: integer = FCGI_PARAMS);
  296. var
  297. lNameLen: TLFastCGIStringSize;
  298. lValueLen: TLFastCGIStringSize;
  299. lTotalLen: integer;
  300. begin
  301. FillFastCGIStringSize(AName, lNameLen);
  302. FillFastCGIStringSize(AValue, lValueLen);
  303. lTotalLen := lNameLen.Size+lValueLen.Size+Length(AName)+Length(AValue);
  304. if (FHeader.ReqType = AReqType) and (FBufferSendPos = 0)
  305. and (0 <= FHeaderPos) and (FHeaderPos < FBuffer.Pos - FBuffer.Memory) then
  306. begin
  307. { undo padding }
  308. Dec(FBuffer.Pos, FHeader.PaddingLength);
  309. SetContentLength(FContentLength+lTotalLen);
  310. Move(FHeader, FBuffer.Memory[FHeaderPos], sizeof(FHeader));
  311. end else begin
  312. FHeader.ReqType := AReqType;
  313. SetContentLength(lTotalLen);
  314. FHeaderPos := FBuffer.Pos - FBuffer.Memory;
  315. AppendString(FBuffer, @FHeader, sizeof(FHeader));
  316. end;
  317. AppendString(FBuffer, @lNameLen.SizeBuf[0], lNameLen.Size);
  318. AppendString(FBuffer, @lValueLen.SizeBuf[0], lValueLen.Size);
  319. AppendString(FBuffer, AName);
  320. AppendString(FBuffer, AValue);
  321. AppendString(FBuffer, @PaddingBuffer[0], FHeader.PaddingLength);
  322. end;
  323. procedure TLFastCGIRequest.SendGetValues;
  324. var
  325. lRequestID: integer;
  326. begin
  327. { management record type has request id 0 }
  328. lRequestID := ID;
  329. ID := 0;
  330. SendParam('FCGI_MAX_REQS', '', FCGI_GET_VALUES);
  331. { if we're the first connection, ask max. # connections }
  332. if FClient.FPool.FClientsAvail = 1 then
  333. SendParam('FCGI_MAX_CONNS', '', FCGI_GET_VALUES);
  334. ID := lRequestID;
  335. end;
  336. function TLFastCGIRequest.SendInput(const ABuffer: pchar; ASize: integer): integer;
  337. begin
  338. { first send current buffer if any }
  339. if FInputBuffer <> nil then
  340. begin
  341. Result := SendBuffer;
  342. if FInputBuffer <> nil then exit;
  343. end else Result := 0;
  344. if Result >= ASize then exit;
  345. if FInputBuffer = nil then
  346. begin
  347. FInputBuffer := ABuffer+Result;
  348. FInputSize := ASize-Result;
  349. FHeader.ReqType := FCGI_STDIN;
  350. SetContentLength(FInputSize);
  351. AppendString(FBuffer, @FHeader, sizeof(FHeader));
  352. end;
  353. Inc(Result, SendBuffer);
  354. end;
  355. procedure TLFastCGIRequest.RewindBuffer;
  356. begin
  357. FBufferSendPos := 0;
  358. FHeaderPos := -1;
  359. { rewind stringbuffer }
  360. FBuffer.Pos := FBuffer.Memory;
  361. end;
  362. function TLFastCGIRequest.SendPrivateBuffer: boolean;
  363. var
  364. lWritten: integer;
  365. begin
  366. { nothing to send ? }
  367. if FBuffer.Pos-FBuffer.Memory = FBufferSendPos then
  368. exit(true);
  369. { already a queue and we are not first in line ? no use in trying to send then }
  370. if (FClient.FSendRequest = nil) or (FClient.FSendRequest = Self) then
  371. begin
  372. lWritten := FClient.Send(FBuffer.Memory[FBufferSendPos],
  373. FBuffer.Pos-FBuffer.Memory-FBufferSendPos);
  374. Inc(FBufferSendPos, lWritten);
  375. Result := FBufferSendPos = FBuffer.Pos-FBuffer.Memory;
  376. { do not rewind buffer, unless remote side has had chance to disconnect }
  377. if Result then
  378. RewindBuffer;
  379. end else
  380. Result := false;
  381. if not Result then
  382. FClient.AddToSendQueue(Self);
  383. end;
  384. function TLFastCGIRequest.SendBuffer: integer;
  385. var
  386. lWritten: integer;
  387. begin
  388. { already a queue and we are not first in line ? no use in trying to send then }
  389. if (FClient.FSendRequest <> nil) and (FClient.FSendRequest <> Self) then
  390. exit(0);
  391. { header to be sent? }
  392. if not SendPrivateBuffer then exit(0);
  393. { first write request header, then wait for possible disconnect }
  394. if FBufferSendPos > 0 then exit(0);
  395. if FInputBuffer = nil then exit(0);
  396. lWritten := FClient.Send(FInputBuffer^, FInputSize);
  397. Inc(FInputBuffer, lWritten);
  398. Dec(FInputSize, lWritten);
  399. if FInputSize = 0 then
  400. begin
  401. FInputBuffer := nil;
  402. AppendString(FBuffer, @PaddingBuffer[0], FHeader.PaddingLength);
  403. end else
  404. FClient.AddToSendQueue(Self);
  405. Result := lWritten;
  406. end;
  407. procedure TLFastCGIRequest.SendEmptyRec(AType: integer);
  408. begin
  409. FHeader.ReqType := AType;
  410. SetContentLength(0);
  411. AppendString(FBuffer, @FHeader, sizeof(FHeader));
  412. { no padding needed for empty string }
  413. end;
  414. procedure TLFastCGIRequest.DoneParams;
  415. begin
  416. SendEmptyRec(FCGI_PARAMS);
  417. end;
  418. procedure TLFastCGIRequest.DoneInput;
  419. begin
  420. SendEmptyRec(FCGI_STDIN);
  421. SendPrivateBuffer;
  422. end;
  423. procedure TLFastCGIRequest.AbortRequest;
  424. begin
  425. FHeader.ReqType := FCGI_ABORT_REQUEST;
  426. SetContentLength(0);
  427. AppendString(FBuffer, @FHeader, sizeof(FHeader));
  428. SendPrivateBuffer;
  429. end;
  430. { TLFastCGIClient }
  431. const
  432. DataBufferSize = 64*1024-1;
  433. constructor TLFastCGIClient.Create(AOwner: TComponent);
  434. begin
  435. inherited;
  436. FBuffer := GetMem(DataBufferSize+1);
  437. FBufferPos := FBuffer;
  438. FBufferEnd := FBuffer;
  439. FRequests := AllocMem(sizeof(TLFastCGIRequest));
  440. FRequestsCount := 1;
  441. FFreeRequest := nil;
  442. OnReceive := @HandleReceive;
  443. OnCanSend := @HandleSend;
  444. end;
  445. destructor TLFastCGIClient.Destroy;
  446. var
  447. I: integer;
  448. begin
  449. for I := 0 to FNextRequestID-1 do
  450. FRequests[I].Free;
  451. FreeMem(FRequests);
  452. FreeMem(FBuffer);
  453. inherited;
  454. end;
  455. function TLFastCGIClient.GetBuffer(ABuffer: pchar; ASize: integer): integer;
  456. begin
  457. Result := FBufferEnd - FBufferPos;
  458. if Result > FContentLength then
  459. Result := FContentLength;
  460. if Result > ASize then
  461. Result := ASize;
  462. Move(FBufferPos^, ABuffer^, Result);
  463. Inc(FBufferPos, Result);
  464. Dec(FContentLength, Result);
  465. { buffer empty? reset }
  466. if FBufferPos = FBufferEnd then
  467. begin
  468. FBufferPos := FBuffer;
  469. FBufferEnd := FBuffer;
  470. end;
  471. end;
  472. procedure TLFastCGIClient.ConnectEvent(ASocket: TLHandle);
  473. begin
  474. if FState = fsStartingServer then
  475. FPool.FSpawnState := ssSpawned;
  476. FState := fsHeader;
  477. if FPool <> nil then
  478. FPool.AddToFreeClients(Self);
  479. inherited;
  480. end;
  481. procedure TLFastCGIClient.DisconnectEvent(ASocket: TLHandle);
  482. var
  483. I: integer;
  484. needReconnect: boolean;
  485. begin
  486. inherited;
  487. FRequestsSent := 0;
  488. needReconnect := false;
  489. for I := 0 to FNextRequestID-1 do
  490. if FRequests[I].FNextFree = nil then
  491. begin
  492. { see if buffer contains request, then assume we can resend that }
  493. if FRequests[I].FBufferSendPos > 0 then
  494. begin
  495. needReconnect := true;
  496. FRequests[I].FBufferSendPos := 0;
  497. FRequests[I].SendPrivateBuffer;
  498. end else
  499. if FRequests[I].FBuffer.Memory = FRequests[I].FBuffer.Pos then
  500. needReconnect := true
  501. else
  502. FRequests[I].EndRequest;
  503. end;
  504. if needReconnect then
  505. Connect;
  506. end;
  507. procedure TLFastCGIClient.ErrorEvent(ASocket: TLHandle; const msg: string);
  508. begin
  509. if (FState = fsConnectingAgain)
  510. or ((FState = fsConnecting) and (FPool.FSpawnState = ssSpawned)) then
  511. begin
  512. FRequest.DoEndRequest;
  513. EndRequest(FRequest);
  514. FState := fsIdle;
  515. end else
  516. if FState = fsConnecting then
  517. begin
  518. FPool.StartServer;
  519. FState := fsStartingServer;
  520. end;
  521. end;
  522. procedure TLFastCGIClient.HandleGetValuesResult;
  523. var
  524. lNameLen, lValueLen, lIntVal, lCode: integer;
  525. lBufferPtr: pchar;
  526. lPrevChar: char;
  527. procedure GetIntVal;
  528. begin
  529. lPrevChar := lBufferPtr[lNameLen+lValueLen];
  530. lBufferPtr[lNameLen+lValueLen] := #0;
  531. Val(lBufferPtr+lNameLen, lIntVal, lCode);
  532. lBufferPtr[lNameLen+lValueLen] := lPrevChar;
  533. end;
  534. begin
  535. repeat
  536. lBufferPtr := FBufferPos;
  537. Inc(lBufferPtr, GetFastCGIStringSize(PByte(lBufferPtr), lNameLen));
  538. Inc(lBufferPtr, GetFastCGIStringSize(PByte(lBufferPtr), lValueLen));
  539. if lBufferPtr + lNameLen + lValueLen > FBufferEnd then exit;
  540. if StrLComp(lBufferPtr, 'FCGI_MAX_REQS', lNameLen) = 0 then
  541. begin
  542. GetIntVal;
  543. if (lCode = 0) and (FRequestsCount <> lIntVal) then
  544. begin
  545. FRequestsCount := lIntVal;
  546. ReallocMem(FRequests, sizeof(TLFastCGIRequest)*lIntVal);
  547. end;
  548. end else
  549. if StrLComp(lBufferPtr, 'FCGI_MAX_CONNS', lNameLen) = 0 then
  550. begin
  551. GetIntVal;
  552. if lCode = 0 then
  553. FPool.ClientsMax := lIntVal;
  554. end;
  555. Inc(lBufferPtr, lNameLen+lValueLen);
  556. Dec(FContentLength, lBufferPtr-FBufferPos);
  557. FBufferPos := lBufferPtr;
  558. until FContentLength = 0;
  559. end;
  560. procedure TLFastCGIClient.HandleReceive(ASocket: TLSocket);
  561. var
  562. lRead: integer;
  563. begin
  564. lRead := Get(FBufferEnd^, DataBufferSize-PtrUInt(FBufferEnd-FBuffer));
  565. if lRead = 0 then exit;
  566. { remote side has had chance to disconnect, clear buffer }
  567. Inc(FBufferEnd, lRead);
  568. ParseBuffer;
  569. end;
  570. procedure TLFastCGIClient.HandleSend(ASocket: TLSocket);
  571. var
  572. lRequest: TLFastCGIRequest;
  573. begin
  574. if FSendRequest = nil then exit;
  575. lRequest := FSendRequest.FNextSend;
  576. repeat
  577. if not lRequest.SendPrivateBuffer or not lRequest.HandleSend then
  578. exit;
  579. lRequest.FNextSend := nil;
  580. { only this one left in list ? }
  581. if FSendRequest = lRequest then
  582. begin
  583. FSendRequest := nil;
  584. exit;
  585. end else begin
  586. lRequest := lRequest.FNextSend;
  587. FSendRequest.FNextSend := lRequest;
  588. end;
  589. until false;
  590. end;
  591. procedure TLFastCGIClient.AddToSendQueue(ARequest: TLFastCGIRequest);
  592. begin
  593. if ARequest.FNextSend <> nil then exit;
  594. if FSendRequest = nil then
  595. FSendRequest := ARequest
  596. else
  597. ARequest.FNextSend := FSendRequest.FNextSend;
  598. FSendRequest.FNextSend := ARequest;
  599. end;
  600. procedure TLFastCGIClient.ParseBuffer;
  601. var
  602. lHeader: PFCGI_Header;
  603. lReqIndex: integer;
  604. begin
  605. repeat
  606. case FState of
  607. fsHeader:
  608. begin
  609. if FBufferEnd-FBufferPos < sizeof(FCGI_Header) then
  610. exit;
  611. lHeader := PFCGI_Header(FBufferPos);
  612. FReqType := lHeader^.ReqType;
  613. lReqIndex := (lHeader^.RequestIDB1 shl 8) or lHeader^.RequestIDB0;
  614. FContentLength := (lHeader^.ContentLengthB1 shl 8) or lHeader^.ContentLengthB0;
  615. FPaddingLength := lHeader^.PaddingLength;
  616. Inc(FBufferPos, sizeof(lHeader^));
  617. if lReqIndex > 0 then
  618. Dec(lReqIndex);
  619. if (lReqIndex < FRequestsCount) and (FRequests[lReqIndex] <> nil) then
  620. begin
  621. FRequest := FRequests[lReqIndex];
  622. if FContentLength > 0 then
  623. FState := fsData
  624. else begin
  625. FRequest.HandleReceiveEnd;
  626. Flush;
  627. end;
  628. end else
  629. Flush;
  630. end;
  631. fsData:
  632. begin
  633. FRequest.HandleReceive;
  634. if FContentLength = 0 then
  635. Flush
  636. else begin
  637. FRequest.FOutputPending := true;
  638. exit;
  639. end;
  640. end;
  641. fsFlush: Flush;
  642. end;
  643. until FBufferPos = FBufferEnd;
  644. end;
  645. procedure TLFastCGIClient.Flush;
  646. function FlushSize(var ANumBytes: integer): boolean;
  647. var
  648. lFlushBytes: integer;
  649. begin
  650. lFlushBytes := ANumBytes;
  651. if lFlushBytes > FBufferEnd - FBufferPos then
  652. lFlushBytes := FBufferEnd - FBufferPos;
  653. Dec(ANumBytes, lFlushBytes);
  654. Inc(FBufferPos, lFlushBytes);
  655. Result := ANumBytes = 0;
  656. end;
  657. begin
  658. FState := fsFlush;
  659. if FlushSize(FContentLength) and FlushSize(FPaddingLength) then
  660. begin
  661. { buffer empty? reset }
  662. if FBufferPos = FBufferEnd then
  663. begin
  664. FBufferPos := FBuffer;
  665. FBufferEnd := FBuffer;
  666. end;
  667. FState := fsHeader;
  668. FRequest := nil;
  669. end;
  670. end;
  671. function TLFastCGIClient.CreateRequester: TLFastCGIRequest;
  672. begin
  673. if FRequests[FNextRequestID] = nil then
  674. FRequests[FNextRequestID] := TLFastCGIRequest.Create;
  675. Result := FRequests[FNextRequestID];
  676. Inc(FNextRequestID);
  677. Result.FClient := Self;
  678. Result.ID := FNextRequestID; { request ids start at 1 }
  679. end;
  680. function TLFastCGIClient.Connect: Boolean;
  681. begin
  682. Result := inherited Connect(FPool.Host, FPool.Port);
  683. FRequest := FRequests[0];
  684. if FRequest.FBuffer.Pos = FRequest.FBuffer.Memory then
  685. FRequest.SendGetValues;
  686. if FState <> fsStartingServer then
  687. FState := fsConnecting
  688. else
  689. FState := fsConnectingAgain;
  690. end;
  691. function TLFastCGIClient.BeginRequest(AType: integer): TLFastCGIRequest;
  692. begin
  693. if FFreeRequest <> nil then
  694. begin
  695. Result := FFreeRequest.FNextFree;
  696. if FFreeRequest = FFreeRequest.FNextFree then
  697. FFreeRequest := nil
  698. else
  699. FFreeRequest.FNextFree := FFreeRequest.FNextFree.FNextFree;
  700. Result.FNextFree := nil;
  701. end else
  702. if FNextRequestID = FRequestsCount then
  703. exit(nil)
  704. else begin
  705. Result := CreateRequester;
  706. end;
  707. if not Connected then
  708. Connect;
  709. Result.SendBeginRequest(AType);
  710. Inc(FRequestsSent);
  711. end;
  712. procedure TLFastCGIClient.EndRequest(ARequest: TLFastCGIRequest);
  713. begin
  714. if FFreeRequest <> nil then
  715. ARequest.FNextFree := FFreeRequest.FNextFree
  716. else
  717. FFreeRequest := ARequest;
  718. FFreeRequest.FNextFree := ARequest;
  719. if FPool <> nil then
  720. FPool.EndRequest(Self);
  721. end;
  722. { TLFastCGIPool }
  723. constructor TLFastCGIPool.Create;
  724. begin
  725. FClientsMax := 1;
  726. FMaxRequestsConn := 1;
  727. inherited;
  728. end;
  729. destructor TLFastCGIPool.Destroy;
  730. var
  731. I: integer;
  732. begin
  733. for I := 0 to FClientsAvail-1 do
  734. FClients[I].Free;
  735. FreeMem(FClients);
  736. if FTimer <> nil then
  737. FTimer.Free;
  738. inherited;
  739. end;
  740. function TLFastCGIPool.CreateClient: TLFastCGIClient;
  741. begin
  742. if FClientsAvail = FClientsCount then
  743. begin
  744. Inc(FClientsCount, 64);
  745. ReallocMem(FClients, FClientsCount*sizeof(TLFastCGIRequest));
  746. end;
  747. Result := TLFastCGIClient.Create(nil);
  748. Result.FPool := Self;
  749. Result.Eventer := FEventer;
  750. FClients[FClientsAvail] := Result;
  751. Inc(FClientsAvail);
  752. end;
  753. function TLFastCGIPool.BeginRequest(AType: integer): TLFastCGIRequest;
  754. var
  755. lTempClient: TLFastCGIClient;
  756. begin
  757. Result := nil;
  758. while FFreeClient <> nil do
  759. begin
  760. lTempClient := FFreeClient.FNextFree;
  761. Result := lTempClient.BeginRequest(AType);
  762. if Result <> nil then break;
  763. { Result = nil -> no free requesters on next free client }
  764. if lTempClient = FFreeClient then
  765. FFreeClient := nil
  766. else
  767. FFreeClient.FNextFree := lTempClient.FNextFree;
  768. lTempClient.FNextFree := nil;
  769. end;
  770. { all clients busy }
  771. if Result = nil then
  772. if FClientsAvail < FClientsMax then
  773. Result := CreateClient.BeginRequest(AType);
  774. end;
  775. procedure TLFastCGIPool.EndRequest(AClient: TLFastCGIClient);
  776. begin
  777. { TODO: wait for other requests to be completed }
  778. if AClient.RequestsSent = FMaxRequestsConn then
  779. AClient.Disconnect;
  780. AddToFreeClients(AClient);
  781. end;
  782. procedure TLFastCGIPool.AddToFreeClients(AClient: TLFastCGIClient);
  783. begin
  784. if AClient.FNextFree <> nil then exit;
  785. if FFreeClient = nil then
  786. FFreeClient := AClient
  787. else
  788. AClient.FNextFree := FFreeClient.FNextFree;
  789. FFreeClient.FNextFree := AClient;
  790. end;
  791. procedure TLFastCGIPool.ConnectClients(Sender: TObject);
  792. var
  793. I: integer;
  794. begin
  795. for I := 0 to FClientsAvail-1 do
  796. if FClients[I].FState = fsStartingServer then
  797. FClients[I].Connect;
  798. end;
  799. procedure TLFastCGIPool.StartServer;
  800. begin
  801. if FSpawnState = ssNone then
  802. begin
  803. FSpawnState := ssSpawning;
  804. SpawnFCGIProcess(FAppName, FAppEnv, FPort);
  805. if FTimer = nil then
  806. FTimer := TLTimer.Create;
  807. FTimer.OneShot := true;
  808. FTimer.OnTimer := @ConnectClients;
  809. end;
  810. FTimer.Interval := 2000;
  811. end;
  812. end.