brookaction.pas 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739
  1. (*
  2. Brook framework, Action Classes
  3. Copyright (C) 2014 Silvio Clecio
  4. See the file LICENSE.txt, included in this distribution,
  5. for details about the copyright.
  6. This library is distributed in the hope that it will be useful,
  7. but WITHOUT ANY WARRANTY; without even the implied warranty of
  8. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  9. *)
  10. unit BrookAction;
  11. {$i brook.inc}
  12. interface
  13. uses
  14. BrookClasses, BrookHttpDefs, BrookException, BrookMessages, BrookUtils,
  15. BrookConsts, BrookHTTPUtils, BrookHTTPConsts, Classes, SysUtils;
  16. type
  17. { Handles exceptions for @link(TBrookAction). }
  18. EBrookAction = class(EBrook);
  19. { Is a metaclass for @link(TBrookAction) class. }
  20. TBrookActionClass = class of TBrookAction;
  21. { Provides features to handle HTTP requests and responses. }
  22. TBrookAction = class(TBrookPersistent)
  23. private
  24. FFields: TStrings;
  25. FFiles: TBrookUploadedFiles;
  26. FParams: TStrings;
  27. FHttpRequest: TBrookRequest;
  28. FHttpResponse: TBrookResponse;
  29. FVariables: TStrings;
  30. function GetField(const AName: string): string;
  31. function GetMethod: string;
  32. function GetParam(const AName: string): string;
  33. function GetVariable(const AName: string): string;
  34. procedure SetField(const AName: string; const AValue: string);
  35. procedure SetParam(const AName: string; const AValue: string);
  36. procedure SetVariable(const AName: string; const AValue: string);
  37. public
  38. { Creates an instance of a @link(TBrookAction) class. }
  39. constructor Create; overload; virtual;
  40. { Creates an instance of a @link(TBrookAction) class passing params to
  41. request/response. }
  42. constructor Create(ARequest: TBrookRequest;
  43. AResponse: TBrookResponse); overload; virtual;
  44. { Frees an instance of @link(TBrookAction) class. }
  45. destructor Destroy; override;
  46. { Registers an action.
  47. @param(APattern Is an expression defining which URLs is used to call
  48. an action. It is possible to use variables inside URLs:
  49. @definitionList(
  50. @itemLabel(@bold(:name) -- Represents a variable that spans single URL
  51. component between slashes.)
  52. @item(Examples:
  53. @code(TMyAction.Register('/foo/:myvar');)
  54. Value of a variable @code("myvar") can be read from the property
  55. @link(Variables) or @link(Variable), e.g.:
  56. @code(Write(Variables.Values['myvar']);)
  57. @code(Write(Variable['myvar']);)
  58. Any number of variables can be combined:
  59. @code(TMyAction.Register('/foo/:cat/:id');)
  60. )
  61. @itemLabel(@bold(*name) -- Represents a variable that spans one or more
  62. levels between slashes in the current URL.)
  63. @item(Examples:
  64. @code(TMyAction.Register('/home/*path');)
  65. Any of the following URLs will match:
  66. http://localhost/cgi-bin/cgi1/home/file @br
  67. http://localhost/cgi-bin/cgi1/home/dir/file @br
  68. http://localhost/cgi-bin/cgi1/home/dir/subdir/file etc.
  69. Variable @code(Variables.Values['path']) will receive @code('file'),
  70. @code('dir/file') or @code('dir/subdir/file') correspondingly.
  71. You can also add static text after variable part:
  72. @code(TMyAction.Register('/home/*path/download');)
  73. http://localhost/cgi-bin/cgi1/home/dir/file/download -- This will match, @br
  74. http://localhost/cgi-bin/cgi1/home/dir/file/info -- but not this, because ending is different.
  75. Multi-level variable can be combined with any number of single-level
  76. variables in any order:
  77. @code(TMyAction.Register('/home/user/:uid/file/*fpath/version/:vid/info');)
  78. @bold(@italic(NOTE:)) Only one multi-level variable can be specified per URL.
  79. )
  80. @itemLabel(@bold(url/) -- Adds a slash to the end of the URL if does not exist.)
  81. @item(Example:
  82. @code(TMyAction.Register('/foo/');)
  83. An action can be accessed as
  84. http://localhost/cgi-bin/cgi1/foo or http://localhost/cgi-bin/cgi1/foo/.
  85. When called as http://localhost/cgi-bin/cgi1/foo, it will be automatically
  86. redirected to http://localhost/cgi-bin/cgi1/foo/.
  87. If the pathinfo is different from @code(/foo) a 404 page is returned;
  88. )
  89. )
  90. @bold(@italic(NOTE:)) Two actions can't be registered with the same
  91. pattern except when they are called by means of different HTTP methods.
  92. )
  93. @param(ADefault A action registered as @italic(Default) will be called
  94. automatically if the URL does not match with @italic(Pattern) of any
  95. registered actions. It is not allowed to register more than one action
  96. as default. A typical example of use is:
  97. @code(TMyAction.Register('*', True);)) }
  98. class procedure Register(const APattern: string;
  99. const ADefault: Boolean = False); overload;
  100. { Registers an action specifying the HTTP request method.
  101. @param(AMethod Informs the HTTP request method being valid the following
  102. options: @code(rmAll, rmGet, rmHead, rmOptions, rmPost, rmPut) or
  103. @code(rmDelete). The only way to register two actions with the same
  104. pattern is differentiating the value of this parameter.
  105. If at least one action has this parameter changed, the route mapping is
  106. enabled in @link(TBrookSettings.Mapped).
  107. A typical example of use is:
  108. @longCode(
  109. procedure TMyAction1.Get;
  110. begin
  111. Write('GET');
  112. end;
  113. procedure TMyAction1.Put;
  114. begin
  115. Write('PUT');
  116. end;
  117. procedure TMyAction2.Post;
  118. begin
  119. Write('POST');
  120. end;
  121. initialization
  122. TMyAction1.Register('/foo1', rmGet);
  123. TMyAction1.Register('/foo1', rmPut);
  124. TMyAction2.Register('/foo1', rmPost);)) }
  125. class procedure Register(const APattern: string;
  126. const AMethod: TBrookRequestMethod;
  127. const ADefault: Boolean = False); overload;
  128. { Returns the path of action. Exemple:
  129. @code(/cgi-bin/cgi1/myaction). }
  130. class function GetPath: string;
  131. { Fills the @link(Variables) with the registered variables passed through
  132. the URL. }
  133. procedure DoFillVariables(const ANames,
  134. AValues: TBrookArrayOfString); virtual;
  135. { Fills the @link(Variables) with the registered variables passed one by one
  136. through the URL. }
  137. procedure DoFillingVariables(const AIndex: Integer; const ANames,
  138. AValues: TBrookArrayOfString); virtual;
  139. { Creates a cookie. }
  140. procedure SetCookie(const AName, AValue: string;
  141. const AExpires: TDateTime = NullDate; const APath: string = ES;
  142. const ADomain: string = ES; const ASecure: Boolean = False;
  143. const AHttpOnly: Boolean = False);
  144. { Get a cookie value. }
  145. function GetCookie(const AName: string): string;
  146. { Deletes a cookie. }
  147. procedure DeleteCookie(const AName: string; const APath: string = ES;
  148. const ADomain: string = ES);
  149. { Calls the method @link(TBrookAction.Request). }
  150. procedure DoRequest(ARequest: TBrookRequest;
  151. AResponse: TBrookResponse); virtual;
  152. { Is triggered by a request of any HTTP method. }
  153. procedure Request(ARequest: TBrookRequest;
  154. AResponse: TBrookResponse); virtual;
  155. { Get an object with the fields coming from a
  156. @code(x-www-form-urlencoded) form. }
  157. procedure GetFields(AObject: TObject);
  158. { Get an object with the params coming from a @code(QUERY_STRING). }
  159. procedure GetParams(AObject: TObject);
  160. { Get an object with the variables coming from an URL. }
  161. procedure GetVariables(AObject: TObject);
  162. { Creates an URL for action. }
  163. function UrlFor(AActionClass: TBrookActionClass): string; overload;
  164. { Creates an URL for an action informing an array of parameters. Exemple:
  165. @longCode(
  166. procedure TMyAction.Get;
  167. begin
  168. // When calling with http://localhost/cgi-bin/cgi1/foo/myvalue
  169. // the output will be /cgi-bin/cgi1/foo/myvalue
  170. Write(UrlFor(TMyAction, ['myvalue']));
  171. end;
  172. initialization
  173. TMyAction.Register('/foo/:myvar');) }
  174. function UrlFor(AActionClass: TBrookActionClass;
  175. const AParams: array of string): string; overload;
  176. { Creates an URL for an action passing an array of parameters however
  177. informing the class name as string. }
  178. function UrlFor(AClassName: string;
  179. const AParams: array of string): string; overload;
  180. { Creates an URL for an action informing the class name as string. }
  181. function UrlFor(AClassName: string): string; overload;
  182. { Is triggered by a GET HTTP request method. }
  183. procedure Get; virtual;
  184. { Is triggered by a POST HTTP request method. }
  185. procedure Post; virtual;
  186. { Is triggered by a PUT HTTP request method. }
  187. procedure Put; virtual;
  188. { Is triggered by a PATCH HTTP request method. }
  189. procedure Patch; virtual;
  190. { Is triggered by a DELETE HTTP request method. }
  191. procedure Delete; virtual;
  192. { Is triggered by a HEAD HTTP request method. }
  193. procedure Head; virtual;
  194. { Is triggered by an OPTIONS HTTP request method. }
  195. procedure Options; virtual;
  196. { Redirects to an URL. }
  197. procedure Redirect(const AUrl: string); overload;
  198. { Redirects to an URL informing the (302, 307) status code. }
  199. procedure Redirect(const AUrl: string; const AStatusCode: Word); overload;
  200. { Redirects to an URL informing the root URL. }
  201. procedure Redirect(const AUrl: string; const AUseRootUrl: Boolean); overload;
  202. { Redirects to an URL informing the (302, 307) status code and the
  203. @code(ScriptName). }
  204. procedure Redirect(const AUrl: string; const AUseRootUrl: Boolean;
  205. const AStatusCode: Word); overload;
  206. { Raises a message for action exceptions. }
  207. procedure Error(const AMsg: string); overload;
  208. { Raises a formated message for action exceptions. }
  209. procedure Error(const AMsg: string; const AArgs: array of const); overload;
  210. { Stops the action showing an exception message. }
  211. procedure Stop(const AMsg: string); overload;
  212. { Stops the action showing a formatted exception message. }
  213. procedure Stop(const AMsg: string; const AArgs: array of const); overload;
  214. { Writes the content of a file. }
  215. procedure Render(const AFileName: TFileName); overload; virtual;
  216. { Writes the content of a file passing parameters to the output. }
  217. procedure Render(const AFileName: TFileName;
  218. const AArgs: array of const); overload; virtual;
  219. { Clears all written content with @code(Write(), WriteLn(), Render()) etc. }
  220. procedure Clear;
  221. { Checks if a name exists in fields. }
  222. function Exists(const AName: string): Boolean;
  223. { Writes a string. }
  224. procedure Write(const AString: string); overload;
  225. { Writes a boolean. }
  226. procedure Write(const ABoolean: Boolean); overload;
  227. { Writes an integer. }
  228. procedure Write(const AInteger: Integer); overload;
  229. { Writes a float. }
  230. procedure Write(const AFloat: Double); overload;
  231. { Writes an object. }
  232. procedure Write(AObject: TObject); overload;
  233. { Writes an object allowing to ignore properties via an array of strings. }
  234. procedure Write(AObject: TObject; const AIgnoredProps: TStrings); overload;
  235. { Writes an object allowing to ignore properties via a list of strings. }
  236. procedure Write(AObject: TObject;
  237. const AIgnoredProps: array of string); overload;
  238. { Writes a content of stream. }
  239. procedure Write(AStream: TStream); overload;
  240. { Writes a formatted string. }
  241. procedure Write(const AFmt: string; const AArgs: array of const); overload;
  242. { Handles the fields of a form. }
  243. property Field[const AName: string]: string read GetField write SetField;
  244. { Handles the Query_String parameters of a URL. }
  245. property Param[const AName: string]: string read GetParam write SetParam;
  246. { Handles variables from a parametrized URL. }
  247. property Variable[const AName: string]: string read GetVariable
  248. write SetVariable;
  249. { Handles a file list of fields of a form. }
  250. property Files: TBrookUploadedFiles read FFiles;
  251. { Handles a string list of fields of a form. }
  252. property Fields: TStrings read FFields;
  253. { Handles a string list of the Query_String parameters of a URL. }
  254. property Params: TStrings read FParams;
  255. { Handles a string list of variables from a parametrized URL. }
  256. property Variables: TStrings read FVariables;
  257. { Returns the HTTP request method. }
  258. property Method: string read GetMethod;
  259. { Provides services related to HTTP requests drived to a webserver. }
  260. property HttpRequest: TBrookRequest read FHttpRequest;
  261. { Provides services related to the HTTP responses comming back from a
  262. webserver. }
  263. property HttpResponse: TBrookResponse read FHttpResponse;
  264. end;
  265. { Provides features to handle HTTP requests and responses mapping URIs to
  266. object. }
  267. generic TBrookGAction<T> = class(TBrookAction)
  268. private
  269. FEntity: T;
  270. protected
  271. procedure FillEntity; virtual;
  272. function CreateEntity: T; virtual;
  273. procedure FreeEntity; virtual;
  274. public
  275. { Creates an instance of a @link(TBrookGAction) class. }
  276. constructor Create; overload; override;
  277. { Frees an instance of @link(TBrookGAction) class. }
  278. destructor Destroy; override;
  279. { Is triggered by a request of any HTTP method. }
  280. procedure Request(ARequest: TBrookRequest;
  281. AResponse: TBrookResponse); override;
  282. { Maps URI to object. }
  283. property Entity: T read FEntity write FEntity;
  284. end;
  285. implementation
  286. uses
  287. BrookRouter;
  288. { TBrookAction }
  289. constructor TBrookAction.Create;
  290. begin
  291. inherited Create;
  292. FVariables := TStringList.Create;
  293. end;
  294. constructor TBrookAction.Create(ARequest: TBrookRequest;
  295. AResponse: TBrookResponse);
  296. begin
  297. Create;
  298. FHttpRequest := ARequest;
  299. FHttpResponse := AResponse;
  300. FFields := FHttpRequest.ContentFields;
  301. FParams := FHttpRequest.QueryFields;
  302. FFiles := FHttpRequest.Files;
  303. end;
  304. destructor TBrookAction.Destroy;
  305. begin
  306. FVariables.Free;
  307. inherited Destroy;
  308. end;
  309. function TBrookAction.GetMethod: string;
  310. begin
  311. Result := FHttpRequest.Method;
  312. end;
  313. function TBrookAction.GetField(const AName: string): string;
  314. begin
  315. Result := FFields.Values[AName];
  316. end;
  317. function TBrookAction.GetParam(const AName: string): string;
  318. begin
  319. Result := FParams.Values[AName];
  320. end;
  321. function TBrookAction.GetVariable(const AName: string): string;
  322. begin
  323. Result := FVariables.Values[AName];
  324. end;
  325. procedure TBrookAction.SetField(const AName: string; const AValue: string);
  326. begin
  327. FFields.Values[AName] := AValue;
  328. end;
  329. procedure TBrookAction.SetParam(const AName: string; const AValue: string);
  330. begin
  331. FParams.Values[AName] := AValue;
  332. end;
  333. procedure TBrookAction.SetVariable(const AName: string; const AValue: string);
  334. begin
  335. FVariables.Values[AName] := AValue;
  336. end;
  337. procedure TBrookAction.DoRequest(ARequest: TBrookRequest;
  338. AResponse: TBrookResponse);
  339. begin
  340. Request(ARequest, AResponse);
  341. end;
  342. procedure TBrookAction.GetFields(AObject: TObject);
  343. begin
  344. BrookSafeStringsToObject(AObject, FHttpRequest.ContentFields);
  345. end;
  346. procedure TBrookAction.GetParams(AObject: TObject);
  347. begin
  348. BrookSafeStringsToObject(AObject, FHttpRequest.QueryFields);
  349. end;
  350. procedure TBrookAction.GetVariables(AObject: TObject);
  351. begin
  352. BrookSafeStringsToObject(AObject, FVariables);
  353. end;
  354. class procedure TBrookAction.Register(const APattern: string;
  355. const ADefault: Boolean);
  356. begin
  357. Register(APattern, rmAll, ADefault);
  358. end;
  359. class procedure TBrookAction.Register(const APattern: string;
  360. const AMethod: TBrookRequestMethod; const ADefault: Boolean);
  361. begin
  362. if Self = TBrookAction then
  363. raise EBrookAction.Create(Self, SBrookRegiterTBrookActionError);
  364. if AMethod <> rmAll then
  365. BrookSettings.Mapped := True;
  366. TBrookRouter.Service.Routes.Add(Self, LowerCase(APattern), AMethod, ADefault);
  367. end;
  368. class function TBrookAction.GetPath: string;
  369. begin
  370. Result := BrookIncludeTrailingUrlDelimiter(TBrookRouter.RootUrl) +
  371. LowerCase(Copy(ClassName, 2, MaxInt));
  372. end;
  373. procedure TBrookAction.DoFillVariables(const ANames,
  374. AValues: TBrookArrayOfString);
  375. var
  376. I: Integer;
  377. begin
  378. FVariables.Clear;
  379. for I := Low(ANames) to High(ANames) do
  380. DoFillingVariables(I, ANames, AValues);
  381. end;
  382. procedure TBrookAction.DoFillingVariables(const AIndex: Integer; const ANames,
  383. AValues: TBrookArrayOfString);
  384. begin
  385. FVariables.Add(ANames[AIndex] + EQ + AValues[AIndex]);
  386. end;
  387. procedure TBrookAction.SetCookie(const AName, AValue: string;
  388. const AExpires: TDateTime; const APath: string; const ADomain: string;
  389. const ASecure: Boolean; const AHttpOnly: Boolean);
  390. var
  391. VCookie: TBrookCookie;
  392. begin
  393. VCookie := FHttpResponse.Cookies.Add;
  394. VCookie.Name := AName;
  395. VCookie.Value := AValue;
  396. if AExpires <> NullDate then
  397. VCookie.Expires := AExpires;
  398. VCookie.Path := APath;
  399. VCookie.Domain := ADomain;
  400. VCookie.Secure := ASecure;
  401. VCookie.HttpOnly := AHTTPOnly;
  402. end;
  403. function TBrookAction.GetCookie(const AName: string): string;
  404. begin
  405. Result := FHttpRequest.CookieFields.Values[AName];
  406. end;
  407. procedure TBrookAction.DeleteCookie(const AName: string; const APath: string;
  408. const ADomain: string);
  409. var
  410. VCookie: TBrookCookie;
  411. begin
  412. VCookie := FHttpResponse.Cookies.Add;
  413. VCookie.Name := AName;
  414. VCookie.Path := APath;
  415. VCookie.Domain := ADomain;
  416. VCookie.Expire;
  417. end;
  418. function TBrookAction.UrlFor(AActionClass: TBrookActionClass;
  419. const AParams: array of string): string;
  420. begin
  421. Result := TBrookRouter.Service.UrlFor(AActionClass, AParams);
  422. end;
  423. function TBrookAction.UrlFor(AActionClass: TBrookActionClass): string;
  424. begin
  425. Result := UrlFor(AActionClass, []);
  426. end;
  427. function TBrookAction.UrlFor(AClassName: string;
  428. const AParams: array of string): string;
  429. begin
  430. Result := TBrookRouter.Service.UrlFor(AClassName, AParams);
  431. end;
  432. function TBrookAction.UrlFor(AClassName: string): string;
  433. begin
  434. Result := UrlFor(AClassName, []);
  435. end;
  436. {$PUSH}{$WARN 5024 OFF}
  437. procedure TBrookAction.Request(ARequest: TBrookRequest;
  438. AResponse: TBrookResponse);
  439. begin
  440. case ARequest.Method of
  441. BROOK_HTTP_REQUEST_METHOD_GET: Get;
  442. BROOK_HTTP_REQUEST_METHOD_POST: Post;
  443. BROOK_HTTP_REQUEST_METHOD_PUT: Put;
  444. BROOK_HTTP_REQUEST_METHOD_PATCH: Patch;
  445. BROOK_HTTP_REQUEST_METHOD_DELETE: Delete;
  446. BROOK_HTTP_REQUEST_METHOD_HEAD: Head;
  447. BROOK_HTTP_REQUEST_METHOD_OPTIONS: Options;
  448. end;
  449. end;
  450. {$POP}
  451. procedure TBrookAction.Get;
  452. begin
  453. TBrookRouter.MethodNotAllowed(FHttpResponse);
  454. end;
  455. procedure TBrookAction.Post;
  456. begin
  457. TBrookRouter.MethodNotAllowed(FHttpResponse);
  458. end;
  459. procedure TBrookAction.Put;
  460. begin
  461. TBrookRouter.MethodNotAllowed(FHttpResponse);
  462. end;
  463. procedure TBrookAction.Patch;
  464. begin
  465. TBrookRouter.MethodNotAllowed(FHttpResponse);
  466. end;
  467. procedure TBrookAction.Delete;
  468. begin
  469. TBrookRouter.MethodNotAllowed(FHttpResponse);
  470. end;
  471. procedure TBrookAction.Head;
  472. begin
  473. TBrookRouter.MethodNotAllowed(FHttpResponse);
  474. end;
  475. procedure TBrookAction.Options;
  476. begin
  477. TBrookRouter.MethodNotAllowed(FHttpResponse);
  478. end;
  479. procedure TBrookAction.Redirect(const AUrl: string);
  480. begin
  481. FHttpResponse.SendRedirect(AUrl);
  482. end;
  483. procedure TBrookAction.Redirect(const AUrl: string; const AStatusCode: Word);
  484. begin
  485. FHttpResponse.Code := AStatusCode;
  486. FHttpResponse.CodeText := BrookStatusCodeToReasonPhrase(AStatusCode);
  487. FHttpResponse.SetCustomHeader('Location', AUrl);
  488. end;
  489. procedure TBrookAction.Redirect(const AUrl: string; const AUseRootUrl: Boolean);
  490. begin
  491. if AUseRootUrl then
  492. FHttpResponse.SendRedirect(TBrookRouter.RootUrl + AUrl)
  493. else
  494. FHttpResponse.SendRedirect(AUrl);
  495. end;
  496. procedure TBrookAction.Redirect(const AUrl: string;
  497. const AUseRootUrl: Boolean; const AStatusCode: Word);
  498. begin
  499. FHttpResponse.Code := AStatusCode;
  500. FHttpResponse.CodeText := BrookStatusCodeToReasonPhrase(AStatusCode);
  501. if AUseRootUrl then
  502. FHttpResponse.SetCustomHeader('Location',
  503. TBrookRouter.RootUrl(FHttpRequest) + AUrl)
  504. else
  505. FHttpResponse.SetCustomHeader('Location', AUrl);
  506. end;
  507. procedure TBrookAction.Error(const AMsg: string);
  508. begin
  509. raise EBrookAction.Create(Self, AMsg);
  510. end;
  511. procedure TBrookAction.Error(const AMsg: string; const AArgs: array of const);
  512. begin
  513. raise EBrookAction.CreateFmt(Self, AMsg, AArgs);
  514. end;
  515. procedure TBrookAction.Stop(const AMsg: string);
  516. begin
  517. raise EBrookAction.Create(AMsg);
  518. end;
  519. procedure TBrookAction.Stop(const AMsg: string; const AArgs: array of const);
  520. begin
  521. raise EBrookAction.CreateFmt(AMsg, AArgs);
  522. end;
  523. procedure TBrookAction.Render(const AFileName: TFileName);
  524. begin
  525. FHttpResponse.Contents.LoadFromFile(AFileName);
  526. end;
  527. procedure TBrookAction.Render(const AFileName: TFileName;
  528. const AArgs: array of const);
  529. begin
  530. FHttpResponse.Contents.LoadFromFile(AFileName);
  531. FHttpResponse.Contents.Text := Format(FHttpResponse.Contents.Text, AArgs);
  532. end;
  533. procedure TBrookAction.Clear;
  534. begin
  535. FHttpResponse.Contents.Clear;
  536. end;
  537. function TBrookAction.Exists(const AName: string): Boolean;
  538. begin
  539. Result := FFields.IndexOfName(AName) > -1;
  540. end;
  541. procedure TBrookAction.Write(const AString: string);
  542. begin
  543. FHttpResponse.Contents.Add(AString);
  544. end;
  545. procedure TBrookAction.Write(const ABoolean: Boolean);
  546. begin
  547. Write(BoolToStr(ABoolean));
  548. end;
  549. procedure TBrookAction.Write(const AInteger: Integer);
  550. begin
  551. Write(IntToStr(AInteger));
  552. end;
  553. procedure TBrookAction.Write(const AFloat: Double);
  554. begin
  555. Write(FloatToStr(AFloat));
  556. end;
  557. procedure TBrookAction.Write(AObject: TObject);
  558. begin
  559. BrookObjectToStrings(AObject, FHttpResponse.Contents);
  560. end;
  561. procedure TBrookAction.Write(AObject: TObject; const AIgnoredProps: TStrings);
  562. begin
  563. BrookObjectToStrings(AObject, FHttpResponse.Contents, AIgnoredProps);
  564. end;
  565. procedure TBrookAction.Write(AObject: TObject;
  566. const AIgnoredProps: array of string);
  567. begin
  568. BrookObjectToStrings(AObject, FHttpResponse.Contents, AIgnoredProps);
  569. end;
  570. procedure TBrookAction.Write(AStream: TStream);
  571. begin
  572. FHttpResponse.Contents.LoadFromStream(AStream);
  573. end;
  574. procedure TBrookAction.Write(const AFmt: string; const AArgs: array of const);
  575. begin
  576. Write(Format(AFmt, AArgs));
  577. end;
  578. { TBrookGAction }
  579. constructor TBrookGAction.Create;
  580. begin
  581. inherited Create;
  582. FEntity := CreateEntity;
  583. end;
  584. destructor TBrookGAction.Destroy;
  585. begin
  586. FreeEntity;
  587. inherited Destroy;
  588. end;
  589. function TBrookGAction.CreateEntity: T;
  590. begin
  591. Result := T.Create;
  592. end;
  593. procedure TBrookGAction.FreeEntity;
  594. begin
  595. FreeAndNil(FEntity);
  596. end;
  597. procedure TBrookGAction.Request(ARequest: TBrookRequest;
  598. AResponse: TBrookResponse);
  599. begin
  600. case ARequest.Method of
  601. BROOK_HTTP_REQUEST_METHOD_GET: Get;
  602. BROOK_HTTP_REQUEST_METHOD_POST:
  603. begin
  604. FillEntity;
  605. Post;
  606. end;
  607. BROOK_HTTP_REQUEST_METHOD_PUT:
  608. begin
  609. FillEntity;
  610. Put;
  611. end;
  612. BROOK_HTTP_REQUEST_METHOD_PATCH:
  613. begin
  614. FillEntity;
  615. Patch;
  616. end;
  617. BROOK_HTTP_REQUEST_METHOD_DELETE:
  618. begin
  619. FillEntity;
  620. Delete;
  621. end;
  622. BROOK_HTTP_REQUEST_METHOD_HEAD: Head;
  623. BROOK_HTTP_REQUEST_METHOD_OPTIONS: Options;
  624. end;
  625. end;
  626. procedure TBrookGAction.FillEntity;
  627. begin
  628. GetFields(FEntity);
  629. end;
  630. end.