BrookURLEntryPoints.pas 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746
  1. (* _ _
  2. * | |__ _ __ ___ ___ | | __
  3. * | '_ \| '__/ _ \ / _ \| |/ /
  4. * | |_) | | | (_) | (_) | <
  5. * |_.__/|_| \___/ \___/|_|\_\
  6. *
  7. * Microframework which helps to develop web Pascal applications.
  8. *
  9. * Copyright (c) 2012-2021 Silvio Clecio <[email protected]>
  10. *
  11. * Brook framework is free software; you can redistribute it and/or
  12. * modify it under the terms of the GNU Lesser General Public
  13. * License as published by the Free Software Foundation; either
  14. * version 2.1 of the License, or (at your option) any later version.
  15. *
  16. * Brook framework is distributed in the hope that it will be useful,
  17. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  18. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  19. * Lesser General Public License for more details.
  20. *
  21. * You should have received a copy of the GNU Lesser General Public
  22. * License along with Brook framework; if not, write to the Free Software
  23. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  24. *)
  25. { Contains classes for handling URL entry-points. }
  26. unit BrookURLEntryPoints;
  27. {$I BrookDefines.inc}
  28. interface
  29. uses
  30. RTLConsts,
  31. SysUtils,
  32. Classes,
  33. Platform,
  34. Marshalling,
  35. libsagui,
  36. BrookUtility,
  37. BrookHandledClasses,
  38. BrookExtra,
  39. BrookHTTPRequest,
  40. BrookHTTPResponse,
  41. BrookURLRouter;
  42. resourcestring
  43. { Error message @code('Entry-point list not prepared.'). }
  44. SBrookEntryPointListUnprepared = 'Entry-point list not prepared.';
  45. { Error message @code('Inactive entry-points.'). }
  46. SBrookInactiveEntryPoints = 'Inactive entry-points.';
  47. { Error message @code('No entry-points defined.'). }
  48. SBrookNoEntryPointsDefined = 'No entry-points defined.';
  49. { Error message @code('<new-class>: entry-point <entry-point> already
  50. exists in <existing-class>.'). }
  51. SBrookEntryPointAlreadyExists =
  52. '%s: entry-point ''%s'' already exists in ''%s''.';
  53. { Error message @code('<new-class>: entry-point cannot be empty.'). }
  54. SBrookEmptyEntryPointName = '%s: entry-point cannot be empty.';
  55. { Error message @code('Entry-point not found: <entry-point>.'). }
  56. SBrookEntryPointNotFound = 'Entry-point not found: %s.';
  57. { Error message @code('Router not assigned for entry-point <entry-point>.'). }
  58. SBrookRouterNotAssigned = 'Router not assigned for entry-point ''%s''.';
  59. type
  60. TBrookURLEntryPointList = class;
  61. { Handles exceptions related to entry-point classes. }
  62. EBrookURLEntryPoint = class(Exception);
  63. { Class to represent a URL entry-point item. }
  64. TBrookURLEntryPoint = class(TBrookHandledCollectionItem)
  65. private
  66. FList: TBrookURLEntryPointList;
  67. FHandle: Psg_entrypoint;
  68. FName: string;
  69. FUserData: Pointer;
  70. function GetName: string;
  71. procedure SetName(const AValue: string);
  72. function GetUserData: Pointer;
  73. protected
  74. function GetHandle: Pointer; override;
  75. function GetRouter: TBrookURLRouter; virtual;
  76. procedure SetRouter(AValue: TBrookURLRouter); virtual;
  77. public
  78. { Creates an instance of @code(TBrookURLEntryPoint).
  79. @param(ACollection[in] Entry-point list.) }
  80. constructor Create(ACollection: TCollection); override;
  81. { Checks if the entry-point name is valid. }
  82. procedure Validate; {$IFNDEF DEBUG}inline;{$ENDIF}
  83. { User-defined data to be stored temporarily in the entry-point object. }
  84. property UserData: Pointer read GetUserData write FUserData;
  85. published
  86. { Entry-point item name. }
  87. property Name: string read GetName write SetName;
  88. { Referenced router to the entry-point. }
  89. property Router: TBrookURLRouter read GetRouter write SetRouter;
  90. end;
  91. { Class-reference for @code(TBrookURLEntryPoint). }
  92. TBrookURLEntryPointClass = class of TBrookURLEntryPoint;
  93. { List enumerator for @code(TBrookURLEntryPointList). }
  94. TBrookURLEntryPointListEnumerator = class(TCollectionEnumerator)
  95. public
  96. { Get current entry-point item. }
  97. function GetCurrent: TBrookURLEntryPoint;
  98. { Current entry-point item. }
  99. property Current: TBrookURLEntryPoint read GetCurrent;
  100. end;
  101. { Handles exceptions related to URL entry-point list. }
  102. EBrookURLEntryPointList = class(Exception);
  103. { Class to represent an list of URL entry-points. }
  104. TBrookURLEntryPointList = class(TBrookHandledOwnedCollection)
  105. private
  106. FHandle: Psg_entrypoints;
  107. procedure InternalLibUnloadEvent(ASender: TObject);
  108. protected
  109. class function GetEntryPointLabel: string; virtual;
  110. class function GetEntryPointName(
  111. AEntryPoint: TBrookURLEntryPoint): string; virtual;
  112. function GetHandle: Pointer; override;
  113. function GetItem(AIndex: Integer): TBrookURLEntryPoint; virtual;
  114. procedure SetItem(AIndex: Integer; AValue: TBrookURLEntryPoint); virtual;
  115. procedure InternalAdd(AEntryPoint: TBrookURLEntryPoint); virtual;
  116. procedure CheckPrepared; {$IFNDEF DEBUG}inline;{$ENDIF}
  117. public
  118. { Creates an instance of @code(TBrookURLEntryPointList).
  119. @param(AOwner[in] Entry-points persistent.) }
  120. constructor Create(AOwner: TPersistent); virtual;
  121. { Frees an instance of @code(TBrookURLEntryPointList). }
  122. destructor Destroy; override;
  123. { Gets the default class for entry-point item creation. }
  124. class function GetEntryPointClass: TBrookURLEntryPointClass; virtual;
  125. { Creates an enumerator to iterate the entry-points though @code(for..in). }
  126. function GetEnumerator: TBrookURLEntryPointListEnumerator;
  127. { Prepares entry-points handle. }
  128. procedure Prepare; virtual;
  129. { Unprepares entry-points handle. }
  130. procedure Unprepare; virtual;
  131. { Checks if entry-points handle is prepared. }
  132. function IsPrepared: Boolean; virtual;
  133. { Creates a new entry-point name. }
  134. function NewName: string; virtual;
  135. { Adds a new item to the entry-point list.
  136. @returns(Entry-point item.) }
  137. function Add: TBrookURLEntryPoint; virtual;
  138. { Removes an item from the entry-point list by its name.
  139. @param(AName[in] Entry-point name.)
  140. @returns(@True if an entry-point is removed.) }
  141. function Remove(const AName: string): Boolean; virtual;
  142. { Gets the entry-point index by its name. }
  143. function IndexOf(const AName: string): Integer; virtual;
  144. { Finds an entry-point in the entry-point list by its name.
  145. @param(AName[in] Entry-point name.)
  146. @returns(Entry-point item.) }
  147. function FindInList(const AName: string): TBrookURLEntryPoint; virtual;
  148. { Finds an user-data in the entry-point list by entry-point path.
  149. @param(APath[in] Entry-point path.)
  150. @param(AUserData[out] User-defined data.)
  151. @returns(@True if user-data is found.) }
  152. function Find(const APath: string; out AUserData): Boolean; virtual;
  153. { Clears the entry-point list. }
  154. procedure Clear; virtual;
  155. { Gets/sets an entry-point from/to the entry-point list by its index. }
  156. property Items[AIndex: Integer]: TBrookURLEntryPoint read GetItem
  157. write SetItem; default;
  158. { @True if entry-points handle is prepared. }
  159. property Prepared: Boolean read IsPrepared; //FI:C110
  160. end;
  161. { Event signature used by @code(TBrookURLEntryPoints) to notify a not found
  162. entry-point items. }
  163. TBrookURLEntryPointsNotFoundEvent = procedure(ASender: TObject;
  164. const AEntryPoint, APath: string; ARequest: TBrookHTTPRequest;
  165. AResponse: TBrookHTTPResponse) of object;
  166. { URL entry-points component. }
  167. TBrookURLEntryPoints = class(TBrookHandledComponent)
  168. private
  169. FActive: Boolean;
  170. FList: TBrookURLEntryPointList;
  171. FStreamedActive: Boolean;
  172. FOnNotFound: TBrookURLEntryPointsNotFoundEvent;
  173. FOnActivate: TNotifyEvent;
  174. FOnDeactivate: TNotifyEvent;
  175. function IsActiveStored: Boolean;
  176. procedure SetActive(AValue: Boolean);
  177. function GetItem(AIndex: Integer): TBrookURLEntryPoint;
  178. procedure SetItem(AIndex: Integer; AValue: TBrookURLEntryPoint);
  179. procedure SetList(AValue: TBrookURLEntryPointList);
  180. procedure InternalLibUnloadEvent(ASender: TObject);
  181. protected
  182. function CreateList: TBrookURLEntryPointList; virtual;
  183. procedure Loaded; override;
  184. function GetHandle: Pointer; override;
  185. procedure DoRoute(ASender: TObject; const AEntryPoint, APath: string;
  186. ARouter: TBrookURLRouter; ARequest: TBrookHTTPRequest;
  187. AResponse: TBrookHTTPResponse); virtual;
  188. procedure DoNotFound(ASender: TObject; const AEntryPoint, APath: string;
  189. ARequest: TBrookHTTPRequest; AResponse: TBrookHTTPResponse); virtual;
  190. procedure DoOpen; virtual;
  191. procedure DoClose; virtual;
  192. procedure CheckItems; {$IFNDEF DEBUG}inline;{$ENDIF}
  193. procedure CheckActive; {$IFNDEF DEBUG}inline;{$ENDIF}
  194. public
  195. { Creates an instance of @code(TBrookURLEntryPoints).
  196. @param(AOwner[in] Owner component.) }
  197. constructor Create(AOwner: TComponent); override;
  198. { Destroys an instance of @code(TBrookURLEntryPoints). }
  199. destructor Destroy; override;
  200. { Creates an enumerator to iterate the entry-points though @code(for..in). }
  201. function GetEnumerator: TBrookURLEntryPointListEnumerator;
  202. { Adds a new item to the entry-point list.
  203. @returns(Entry-point item.) }
  204. function Add: TBrookURLEntryPoint; {$IFNDEF DEBUG}inline;{$ENDIF}
  205. { Removes an item from the entry-point list by its name.
  206. @param(AName[in] Entry-point name.) }
  207. procedure Remove(const AName: string); {$IFNDEF DEBUG}inline;{$ENDIF}
  208. { Clears the entry-point list. }
  209. procedure Clear; {$IFNDEF DEBUG}inline;{$ENDIF}
  210. { Enabled the entry-point component. }
  211. procedure Open;
  212. { Disables the entry-point component. }
  213. procedure Close;
  214. { Enters into entry-points routing them.
  215. @param(ASender[in] Sender object.)
  216. @param(APath[in] Entry-point path.)
  217. @param(ARequest[in] Request object to pass to the entry-point found.)
  218. @param(AResponse: Response object to pass to the entry-point found.) }
  219. procedure Enter(ASender: TObject; const APath: string;
  220. ARequest: TBrookHTTPRequest;
  221. AResponse: TBrookHTTPResponse); overload; virtual;
  222. { Enters into entry-points routing them.
  223. @param(ASender[in] Sender object.)
  224. @param(ARequest[in] Request object to pass to the entry-point found.)
  225. @param(AResponse: Response object to pass to the entry-point found.) }
  226. procedure Enter(ASender: TObject; ARequest: TBrookHTTPRequest;
  227. AResponse: TBrookHTTPResponse); overload; virtual;
  228. { Gets/sets an entry-point from/to the entry-point list by its index. }
  229. property Items[AIndex: Integer]: TBrookURLEntryPoint read GetItem
  230. write SetItem; default;
  231. published
  232. { Enabled/disables the entry-point component. }
  233. property Active: Boolean read FActive write SetActive stored IsActiveStored;
  234. { Available entry-point list. }
  235. property List: TBrookURLEntryPointList read FList write SetList;
  236. { Event triggered when an entry-point is not found. }
  237. property OnNotFound: TBrookURLEntryPointsNotFoundEvent read FOnNotFound
  238. write FOnNotFound;
  239. { Event triggered when the component is enabled. }
  240. property OnActivate: TNotifyEvent read FOnActivate write FOnActivate;
  241. { Event triggered when the component is disabled. }
  242. property OnDeactivate: TNotifyEvent read FOnDeactivate write FOnDeactivate;
  243. end;
  244. implementation
  245. { TBrookURLEntryPoint }
  246. constructor TBrookURLEntryPoint.Create(ACollection: TCollection);
  247. begin
  248. inherited Create(ACollection);
  249. if Assigned(ACollection) and (ACollection is TBrookURLEntryPointList) then
  250. begin
  251. FList := ACollection as TBrookURLEntryPointList;
  252. FName := FList.NewName;
  253. end
  254. else
  255. FName := '/';
  256. end;
  257. function TBrookURLEntryPoint.GetHandle: Pointer;
  258. begin
  259. Result := FHandle;
  260. end;
  261. procedure TBrookURLEntryPoint.Validate;
  262. begin
  263. if FName.IsEmpty then
  264. raise EBrookURLEntryPoint.CreateFmt(SBrookEmptyEntryPointName,
  265. [GetNamePath]);
  266. end;
  267. function TBrookURLEntryPoint.GetName: string;
  268. var
  269. P: Pcchar;
  270. begin
  271. if not Assigned(FHandle) then
  272. Exit(FName);
  273. SgLib.Check;
  274. P := sg_entrypoint_name(FHandle);
  275. try
  276. Result := TMarshal.ToString(P);
  277. finally
  278. sg_free(P);
  279. end;
  280. end;
  281. function TBrookURLEntryPoint.GetRouter: TBrookURLRouter;
  282. begin
  283. Result := GetUserData;
  284. end;
  285. function TBrookURLEntryPoint.GetUserData: Pointer;
  286. begin
  287. if not Assigned(FHandle) then
  288. Exit(FUserData);
  289. SgLib.Check;
  290. Result := sg_entrypoint_user_data(FHandle);
  291. end;
  292. procedure TBrookURLEntryPoint.SetName(const AValue: string);
  293. var
  294. EP: TBrookURLEntryPoint;
  295. NN: string;
  296. begin
  297. if (AValue = FName) or (not Assigned(FList)) then
  298. Exit;
  299. NN := Brook.FixEntryPoint(AValue);
  300. EP := FList.FindInList(NN);
  301. if Assigned(EP) and (EP <> Self) then
  302. raise EBrookURLEntryPoint.CreateFmt(SBrookEntryPointAlreadyExists,
  303. [GetNamePath, NN, EP.GetNamePath]);
  304. FName := NN;
  305. if Assigned(FList.FHandle) then
  306. begin
  307. SgLib.Check;
  308. FList.InternalAdd(Self);
  309. end;
  310. end;
  311. procedure TBrookURLEntryPoint.SetRouter(AValue: TBrookURLRouter);
  312. var
  313. M: TMarshaller;
  314. EP: Psg_entrypoint;
  315. begin
  316. FUserData := AValue;
  317. if not Assigned(FList.FHandle) then
  318. Exit;
  319. SgLib.Check;
  320. if sg_entrypoints_find(FList.FHandle, @EP, M.ToCString(FName)) = 0 then
  321. SgLib.CheckLastError(sg_entrypoint_set_user_data(EP, FUserData));
  322. end;
  323. { TBrookURLEntryPointListEnumerator }
  324. function TBrookURLEntryPointListEnumerator.GetCurrent: TBrookURLEntryPoint;
  325. begin
  326. Result := TBrookURLEntryPoint(inherited GetCurrent);
  327. end;
  328. { TBrookURLEntryPointList }
  329. constructor TBrookURLEntryPointList.Create(AOwner: TPersistent);
  330. begin
  331. inherited Create(AOwner, GetEntryPointClass);
  332. SgLib.UnloadEvents.Add(InternalLibUnloadEvent, Self);
  333. end;
  334. destructor TBrookURLEntryPointList.Destroy;
  335. begin
  336. Unprepare;
  337. SgLib.UnloadEvents.Remove(InternalLibUnloadEvent);
  338. inherited Destroy;
  339. end;
  340. class function TBrookURLEntryPointList.GetEntryPointClass: TBrookURLEntryPointClass;
  341. begin
  342. Result := TBrookURLEntryPoint;
  343. end;
  344. class function TBrookURLEntryPointList.GetEntryPointLabel: string;
  345. begin
  346. Result := '/api';
  347. end;
  348. class function TBrookURLEntryPointList.GetEntryPointName(
  349. AEntryPoint: TBrookURLEntryPoint): string;
  350. begin
  351. Result := AEntryPoint.FName;
  352. end;
  353. procedure TBrookURLEntryPointList.CheckPrepared;
  354. begin
  355. if not Assigned(FHandle) then
  356. raise EBrookURLEntryPointList.Create(SBrookEntryPointListUnprepared);
  357. end;
  358. procedure TBrookURLEntryPointList.InternalLibUnloadEvent(ASender: TObject);
  359. begin
  360. if Assigned(ASender) then
  361. TBrookURLEntryPointList(ASender).Unprepare;
  362. end;
  363. function TBrookURLEntryPointList.GetHandle: Pointer;
  364. begin
  365. Result := FHandle;
  366. end;
  367. function TBrookURLEntryPointList.GetEnumerator: TBrookURLEntryPointListEnumerator;
  368. begin
  369. Result := TBrookURLEntryPointListEnumerator.Create(Self);
  370. end;
  371. procedure TBrookURLEntryPointList.InternalAdd(AEntryPoint: TBrookURLEntryPoint);
  372. var
  373. M: TMarshaller;
  374. R: cint;
  375. begin
  376. R := sg_entrypoints_add(FHandle, M.ToCString(GetEntryPointName(AEntryPoint)),
  377. AEntryPoint.FUserData);
  378. if R = 0 then
  379. Exit;
  380. if R = EALREADY then
  381. raise EBrookURLEntryPointList.CreateFmt(SBrookEntryPointAlreadyExists,
  382. [AEntryPoint.GetNamePath, AEntryPoint.Name]);
  383. SgLib.CheckLastError(R);
  384. end;
  385. function TBrookURLEntryPointList.NewName: string;
  386. var
  387. I: Integer;
  388. begin
  389. I := 1;
  390. repeat
  391. Result := Concat(GetEntryPointLabel, I.ToString);
  392. Inc(I);
  393. until IndexOf(Result) < 0;
  394. end;
  395. procedure TBrookURLEntryPointList.Prepare;
  396. var
  397. EP: TBrookURLEntryPoint;
  398. begin
  399. if Assigned(FHandle) or (Count = 0) then
  400. Exit;
  401. SgLib.Check;
  402. FHandle := sg_entrypoints_new;
  403. SgLib.CheckLastError(sg_entrypoints_clear(FHandle));
  404. for EP in Self do
  405. begin
  406. EP.Validate;
  407. InternalAdd(EP);
  408. end;
  409. end;
  410. procedure TBrookURLEntryPointList.Unprepare;
  411. begin
  412. if not Assigned(FHandle) then
  413. Exit;
  414. SgLib.Check;
  415. sg_entrypoints_free(FHandle);
  416. FHandle := nil;
  417. end;
  418. function TBrookURLEntryPointList.IsPrepared: Boolean;
  419. begin
  420. Result := Assigned(FHandle);
  421. end;
  422. function TBrookURLEntryPointList.GetItem(AIndex: Integer): TBrookURLEntryPoint;
  423. begin
  424. Result := TBrookURLEntryPoint(inherited GetItem(AIndex));
  425. end;
  426. procedure TBrookURLEntryPointList.SetItem(AIndex: Integer;
  427. AValue: TBrookURLEntryPoint);
  428. begin
  429. inherited SetItem(AIndex, AValue);
  430. end;
  431. function TBrookURLEntryPointList.Add: TBrookURLEntryPoint;
  432. begin
  433. Result := TBrookURLEntryPoint(inherited Add);
  434. end;
  435. function TBrookURLEntryPointList.Remove(const AName: string): Boolean;
  436. var
  437. M: TMarshaller;
  438. I: Integer;
  439. begin
  440. I := IndexOf(AName);
  441. Result := I > -1;
  442. if Result then
  443. begin
  444. if Assigned(FHandle) then
  445. SgLib.CheckLastError(sg_entrypoints_rm(FHandle, M.ToCString(AName)));
  446. inherited Delete(I);
  447. end;
  448. end;
  449. function TBrookURLEntryPointList.IndexOf(const AName: string): Integer;
  450. begin
  451. for Result := 0 to Pred(Count) do
  452. if SameText(GetItem(Result).Name, AName) then
  453. Exit;
  454. Result := -1;
  455. end;
  456. function TBrookURLEntryPointList.FindInList(
  457. const AName: string): TBrookURLEntryPoint;
  458. var
  459. EP: TBrookURLEntryPoint;
  460. begin
  461. for EP in Self do
  462. if SameText(EP.Name, AName) then
  463. Exit(EP);
  464. Result := nil;
  465. end;
  466. function TBrookURLEntryPointList.Find(const APath: string;
  467. out AUserData): Boolean;
  468. var
  469. M: TMarshaller;
  470. EP: Psg_entrypoint;
  471. R: cint;
  472. begin
  473. CheckPrepared;
  474. SgLib.Check;
  475. R := sg_entrypoints_find(FHandle, @EP, M.ToCString(APath));
  476. Result := R = 0;
  477. if Result then
  478. Pointer(AUserData) := sg_entrypoint_user_data(EP)
  479. else
  480. if (R <> ENOENT) then
  481. SgLib.CheckLastError(R);
  482. end;
  483. procedure TBrookURLEntryPointList.Clear;
  484. begin
  485. inherited Clear;
  486. if not Assigned(FHandle) then
  487. Exit;
  488. SgLib.Check;
  489. SgLib.CheckLastError(sg_entrypoints_clear(FHandle));
  490. end;
  491. { TBrookURLEntryPoints }
  492. constructor TBrookURLEntryPoints.Create(AOwner: TComponent);
  493. begin
  494. inherited Create(AOwner);
  495. FList := CreateList;
  496. SgLib.UnloadEvents.Add(InternalLibUnloadEvent, Self);
  497. end;
  498. destructor TBrookURLEntryPoints.Destroy;
  499. begin
  500. SetActive(False);
  501. FList.Free;
  502. SgLib.UnloadEvents.Remove(InternalLibUnloadEvent);
  503. inherited Destroy;
  504. end;
  505. function TBrookURLEntryPoints.CreateList: TBrookURLEntryPointList;
  506. begin
  507. Result := TBrookURLEntryPointList.Create(Self);
  508. end;
  509. procedure TBrookURLEntryPoints.CheckItems;
  510. begin
  511. if FList.Count = 0 then
  512. raise EBrookURLEntryPointList.Create(SBrookNoEntryPointsDefined);
  513. end;
  514. procedure TBrookURLEntryPoints.CheckActive;
  515. begin
  516. if (not (csLoading in ComponentState)) and (not Active) then
  517. raise EInvalidOpException.Create(SBrookInactiveEntryPoints);
  518. end;
  519. procedure TBrookURLEntryPoints.Loaded;
  520. begin
  521. inherited Loaded;
  522. try
  523. if FStreamedActive then
  524. SetActive(True);
  525. except
  526. if csDesigning in ComponentState then
  527. begin
  528. if Assigned(ApplicationHandleException) then
  529. ApplicationHandleException(ExceptObject)
  530. else
  531. ShowException(ExceptObject, ExceptAddr);
  532. end
  533. else
  534. raise;
  535. end;
  536. end;
  537. procedure TBrookURLEntryPoints.InternalLibUnloadEvent(ASender: TObject);
  538. begin
  539. if Assigned(ASender) then
  540. TBrookURLEntryPoints(ASender).Close;
  541. end;
  542. function TBrookURLEntryPoints.GetEnumerator: TBrookURLEntryPointListEnumerator;
  543. begin
  544. Result := TBrookURLEntryPointListEnumerator.Create(FList);
  545. end;
  546. function TBrookURLEntryPoints.Add: TBrookURLEntryPoint;
  547. begin
  548. Result := FList.Add;
  549. end;
  550. procedure TBrookURLEntryPoints.Remove(const AName: string);
  551. begin
  552. FList.Remove(AName);
  553. end;
  554. procedure TBrookURLEntryPoints.Clear;
  555. begin
  556. FList.Clear;
  557. end;
  558. function TBrookURLEntryPoints.GetHandle: Pointer;
  559. begin
  560. Result := FList.FHandle;
  561. end;
  562. procedure TBrookURLEntryPoints.DoOpen;
  563. begin
  564. FList.Prepare;
  565. FActive := FList.IsPrepared;
  566. if Assigned(FOnActivate) then
  567. FOnActivate(Self);
  568. end;
  569. procedure TBrookURLEntryPoints.DoClose;
  570. begin
  571. FList.Unprepare;
  572. FActive := False;
  573. if Assigned(FOnDeactivate) then
  574. FOnDeactivate(Self);
  575. end;
  576. procedure TBrookURLEntryPoints.SetList(AValue: TBrookURLEntryPointList);
  577. begin
  578. if AValue = FList then
  579. Exit;
  580. if Assigned(AValue) then
  581. FList.Assign(AValue)
  582. else
  583. FList.Clear;
  584. end;
  585. function TBrookURLEntryPoints.IsActiveStored: Boolean;
  586. begin
  587. Result := FActive;
  588. end;
  589. function TBrookURLEntryPoints.GetItem(AIndex: Integer): TBrookURLEntryPoint;
  590. begin
  591. Result := FList.GetItem(AIndex);
  592. end;
  593. procedure TBrookURLEntryPoints.SetActive(AValue: Boolean);
  594. begin
  595. if AValue = FActive then
  596. Exit;
  597. if csDesigning in ComponentState then
  598. begin
  599. if not (csLoading in ComponentState) then
  600. SgLib.Check;
  601. FActive := AValue;
  602. end
  603. else
  604. if AValue then
  605. begin
  606. if csReading in ComponentState then
  607. FStreamedActive := True
  608. else
  609. DoOpen;
  610. end
  611. else
  612. DoClose;
  613. end;
  614. procedure TBrookURLEntryPoints.SetItem(AIndex: Integer;
  615. AValue: TBrookURLEntryPoint);
  616. begin
  617. FList.SetItem(AIndex, AValue);
  618. end;
  619. procedure TBrookURLEntryPoints.Open;
  620. begin
  621. SetActive(True);
  622. end;
  623. procedure TBrookURLEntryPoints.Close;
  624. begin
  625. SetActive(False);
  626. end;
  627. procedure TBrookURLEntryPoints.DoRoute(ASender: TObject; const AEntryPoint,
  628. APath: string; ARouter: TBrookURLRouter; ARequest: TBrookHTTPRequest;
  629. AResponse: TBrookHTTPResponse);
  630. begin
  631. if Assigned(ARouter) then
  632. ARouter.Route(ASender, APath, ARequest, AResponse)
  633. else
  634. AResponse.SendFmt(SBrookRouterNotAssigned, [AEntryPoint],
  635. BROOK_CT_TEXT_PLAIN, 500);
  636. end;
  637. procedure TBrookURLEntryPoints.DoNotFound(ASender: TObject;
  638. const AEntryPoint, APath: string; ARequest: TBrookHTTPRequest;
  639. AResponse: TBrookHTTPResponse);
  640. begin
  641. if Assigned(FOnNotFound) then
  642. FOnNotFound(ASender, AEntryPoint, APath, ARequest, AResponse)
  643. else
  644. AResponse.SendFmt(SBrookEntryPointNotFound, [AEntryPoint],
  645. BROOK_CT_TEXT_PLAIN, 404);
  646. end;
  647. procedure TBrookURLEntryPoints.Enter(ASender: TObject; const APath: string;
  648. ARequest: TBrookHTTPRequest; AResponse: TBrookHTTPResponse);
  649. var
  650. RT: TBrookURLRouter;
  651. EP, P: string;
  652. begin
  653. CheckItems;
  654. CheckActive;
  655. EP := Brook.FixEntryPoint(APath);
  656. P := Brook.FixPath(APath.SubString(EP.Length));
  657. if FList.Find(EP, RT) then
  658. DoRoute(ASender, EP, P, RT, ARequest, AResponse)
  659. else
  660. DoNotFound(ASender, EP, P, ARequest, AResponse);
  661. end;
  662. procedure TBrookURLEntryPoints.Enter(ASender: TObject;
  663. ARequest: TBrookHTTPRequest; AResponse: TBrookHTTPResponse);
  664. begin
  665. if not Assigned(ARequest) then
  666. raise EArgumentNilException.CreateFmt(SParamIsNil, ['ARequest']);
  667. Enter(ASender, ARequest.Path, ARequest, AResponse);
  668. end;
  669. end.