brookaction.pas 22 KB

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