brookhttpclient.pas 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466
  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. { HTTP client classes. }
  11. unit BrookHttpClient;
  12. {$i brook.inc}
  13. interface
  14. uses
  15. BrookClasses, BrookException, BrookMessages, BrookConsts, BrookHttpConsts,
  16. Classes, SysUtils, FGL;
  17. type
  18. { Handles exceptions for @link(TBrookHttpDef). }
  19. EBrookHttpDef = class(EBrook);
  20. { Handles exceptions for @link(TBrookHttpDefs). }
  21. EBrookHttpDefs = class(EBrook);
  22. { Handles exceptions for @link(EBrookHttpClient). }
  23. EBrookHttpClient = class(EBrook);
  24. { Is a metaclass for @link(TBrookHttpDef) class. }
  25. TBrookHttpDefClass = class of TBrookHttpDef;
  26. { Is a metaclass for @link(TBrookHttpDefs) class. }
  27. TBrookHttpDefsClass = class of TBrookHttpDefs;
  28. { Is a metaclass for @link(TBrookHttpClient) class. }
  29. TBrookHttpClientClass = class of TBrookHttpClient;
  30. { Information returned after a request. }
  31. TBrookHttpResult = record
  32. StatusCode: Integer;
  33. ReasonPhrase, Header, Content: string;
  34. end;
  35. { Offers general abstract features for HTTP handling. }
  36. TBrookHttpDef = class(TBrookObject)
  37. protected
  38. procedure SetContentType(AValue: string); virtual; abstract;
  39. function GetContentType: string; virtual; abstract;
  40. function GetClient: TObject; virtual; abstract;
  41. function GetContents: TStrings; virtual; abstract;
  42. function GetCookies: TStrings; virtual; abstract;
  43. function GetDocument: TStream; virtual; abstract;
  44. function GetHeaders: TStrings; virtual; abstract;
  45. function GetReasonPhrase: string; virtual; abstract;
  46. function GetStatusCode: Integer; virtual; abstract;
  47. function GetMethod: string; virtual; abstract;
  48. function GetUrl: string; virtual; abstract;
  49. procedure SetMethod(AValue: string); virtual; abstract;
  50. procedure SetUrl(AValue: string); virtual; abstract;
  51. public
  52. { Creates an instance of a @link(TBrookHttpDef) class. }
  53. constructor Create; virtual; abstract;
  54. { Register the broker class. }
  55. class procedure Register;
  56. { Unregister the broker class. }
  57. class procedure Unregister;
  58. { Get the broker library name, for example: FCLWeb, Synapse, LNet, Indy etc. }
  59. class function GetLibrary: string; virtual; abstract;
  60. { Adds header, replacing an existing one if it exists. }
  61. procedure AddHeader(const AName, AValue: string); virtual; abstract;
  62. { Sends request to server. }
  63. function Request: Boolean; virtual; abstract;
  64. { Sends request by a GET HTTP request method. }
  65. class function Get(const AUrl: string;
  66. AResponse: TStream): Boolean; virtual; abstract;
  67. { Sends request by a POST HTTP request method. }
  68. class function Post(const AUrl: string;
  69. AResponse: TStream): Boolean; virtual; abstract;
  70. { Sends request by a PUT HTTP request method. }
  71. class function Put(const AUrl: string;
  72. AResponse: TStream): Boolean; virtual; abstract;
  73. { Sends request by a DELETE HTTP request method. }
  74. class function Delete(const AUrl: string;
  75. AResponse: TStream): Boolean; virtual; abstract;
  76. { Sends request by an OPTIONS HTTP request method. }
  77. class function Options(const AUrl: string;
  78. AResponse: TStream): Boolean; virtual; abstract;
  79. { Sends request by a HEAD HTTP request method. }
  80. class function Head(const AUrl: string;
  81. AHeaders: TStrings): Boolean; virtual; abstract;
  82. { Sends request by a POST HTTP request method, passing a form-data as
  83. parameter. }
  84. class function PostForm(const AUrl: string;
  85. AFormData, AResponse: TStream): Boolean; virtual; abstract;
  86. { Sends request by a POST HTTP request method, passing a form-data as
  87. parameter. }
  88. class function PostForm(const AUrl, AFormData: string;
  89. AResponse: TStream): Boolean; virtual; abstract;
  90. { Sends request by a PUT HTTP request method, passing a form-data as
  91. parameter. }
  92. class function PutForm(const AUrl: string;
  93. AFormData, AResponse: TStream): Boolean; virtual; abstract;
  94. { Sends request by a PUT HTTP request method, passing a form-data as
  95. parameter. }
  96. class function PutForm(const AUrl, AFormData: string;
  97. AResponse: TStream): Boolean; virtual; abstract;
  98. { Sends request by a POST HTTP request method, passing a file as
  99. parameter. }
  100. class function PostFile(const AUrl, AFieldName, AFileName: string;
  101. AFile, AResponse: TStream): Boolean; virtual; abstract;
  102. { Sends request by a POST HTTP request method, passing a file as
  103. parameter. }
  104. class function PostFile(const AUrl, AFieldName, AFileName: string;
  105. AResponse: TStream): Boolean; virtual; abstract;
  106. { Content type of sending data. }
  107. property ContentType: string read GetContentType write SetContentType;
  108. { Strings received from the request. }
  109. property Contents: TStrings read GetContents;
  110. { Set cookies to be sent and/or received from the server. }
  111. property Cookies: TStrings read GetCookies;
  112. { Document received from the request. }
  113. property Document: TStream read GetDocument;
  114. { Request headers. }
  115. property Headers: TStrings read GetHeaders;
  116. { Result code after successful request. }
  117. property StatusCode: Integer read GetStatusCode;
  118. { Result text after successful request. }
  119. property ReasonPhrase: string read GetReasonPhrase;
  120. { Method for requests. }
  121. property Method: string read GetMethod write SetMethod;
  122. { URL that request is driven to. }
  123. property Url: string read GetUrl write SetUrl;
  124. { Is the instance of the HTTP client broker. }
  125. property Client: TObject read GetClient;
  126. end;
  127. { Registers HTTP definitions. }
  128. TBrookHttpDefs = class(specialize TFPGList<TBrookHttpDefClass>)
  129. private
  130. class var _List: TBrookHttpDefs;
  131. public
  132. { Registers the service provided by this class. }
  133. class function Service: TBrookHttpDefs;
  134. { Finds a database item by its library name. }
  135. function Find(const ALibrary: string): TBrookHttpDefClass;
  136. { Returns a database item by its library name. }
  137. function ItemByLibrary(const ALibrary: string): TBrookHttpDefClass;
  138. end;
  139. { Client to perform HTTP requests. }
  140. TBrookHttpClient = class(TBrookObject)
  141. private
  142. class var _Library: string;
  143. public
  144. { Creates an instance of a @link(TBrookHttpClient) class. }
  145. constructor Create(const ALibrary: string);
  146. { Specifies the library to be used by this class. }
  147. class procedure SetLibrary(const ALibrary: string);
  148. { Prepares an instance of @code(TBrookHttpDef). }
  149. class procedure Prepare(out AHttp: TBrookHttpDef);
  150. { Sends request by a GET HTTP request method. }
  151. class function Get(const AUrl: string; AResponse: TStream): Boolean;
  152. { Sends request by a POST HTTP request method. }
  153. class function Post(const AUrl: string; AResponse: TStream): Boolean;
  154. { Sends request by a PUT HTTP request method. }
  155. class function Put(const AUrl: string; AResponse: TStream): Boolean;
  156. { Sends request by a DELETE HTTP request method. }
  157. class function Delete(const AUrl: string; AResponse: TStream): Boolean;
  158. { Sends request by an OPTIONS HTTP request method. }
  159. class function Options(const AUrl: string; AResponse: TStream): Boolean;
  160. { Sends request by a HEAD HTTP request method. }
  161. class function Head(const AUrl: string; AHeaders: TStrings): Boolean;
  162. { Sends request by a POST HTTP request method, passing a form-data as
  163. parameter. }
  164. class function PostForm(const AUrl: string; AFormData,
  165. AResponse: TStream): Boolean;
  166. { Sends request by a POST HTTP request method, passing a form-data as
  167. parameter. }
  168. class function PostForm(const AUrl, AFormData: string;
  169. AResponse: TStream): Boolean;
  170. { Sends request by a PUT HTTP request method, passing a form-data as
  171. parameter. }
  172. class function PutForm(const AUrl: string; AFormData,
  173. AResponse: TStream): Boolean;
  174. { Sends request by a PUT HTTP request method, passing a form-data as
  175. parameter. }
  176. class function PutForm(const AUrl, AFormData: string;
  177. AResponse: TStream): Boolean;
  178. { Sends request by a POST HTTP request method, passing a file as
  179. parameter. }
  180. class function PostFile(const AUrl, AFieldName, AFileName: string;
  181. AFile, AResponse: TStream): Boolean;
  182. { Sends request by a POST HTTP request method, passing a file as
  183. parameter. }
  184. class function PostFile(const AUrl, AFieldName, AFileName: string;
  185. AResponse: TStream): Boolean;
  186. { Performs the request, passing a @code(TBrookHttpDef) as parameter. }
  187. function Request(AHttp: TBrookHttpDef): TBrookHttpResult;
  188. { Performs the request, passing the method and URL as parameter. }
  189. function Request(const AMethod, AUrl: string): TBrookHttpResult;
  190. { Performs the request, passing URL as parameter. }
  191. function Request(const AUrl: string): TBrookHttpResult;
  192. end;
  193. implementation
  194. { TBrookHttpDef }
  195. {$IFNDEF VER3_0}
  196. {$PUSH}{$WARN 6058 OFF}
  197. {$ENDIF}
  198. class procedure TBrookHttpDef.Register;
  199. begin
  200. TBrookHttpDefs.Service.Add(Self);
  201. BROOK_HTTP_CLIENT_DEFAULT_LIBRARY := GetLibrary;
  202. end;
  203. {$IFNDEF VER3_0}
  204. {$POP}
  205. {$ENDIF}
  206. class procedure TBrookHttpDef.Unregister;
  207. begin
  208. TBrookHttpDefs.Service.Remove(Self);
  209. end;
  210. { TBrookHttpDefs }
  211. class function TBrookHttpDefs.Service: TBrookHttpDefs;
  212. begin
  213. if not Assigned(TBrookHttpDefs._List) then
  214. TBrookHttpDefs._List := TBrookHttpDefs.Create;
  215. Result := TBrookHttpDefs._List;
  216. end;
  217. function TBrookHttpDefs.Find(const ALibrary: string): TBrookHttpDefClass;
  218. begin
  219. for Result in Self do
  220. if SameText(Result.GetLibrary, ALibrary) then
  221. Exit;
  222. Result := nil;
  223. end;
  224. function TBrookHttpDefs.ItemByLibrary(
  225. const ALibrary: string): TBrookHttpDefClass;
  226. begin
  227. if ALibrary = ES then
  228. raise EBrookHttpDefs.Create(Self, SBrookEmptyLibraryNameError);
  229. Result := Find(ALibrary);
  230. if not Assigned(Result) then
  231. raise EBrookHttpDefs.CreateFmt(Self, SBrookItemNotFoundError, [ALibrary]);
  232. end;
  233. { TBrookHttpClient }
  234. constructor TBrookHttpClient.Create(const ALibrary: string);
  235. begin
  236. _Library := ALibrary;
  237. end;
  238. class procedure TBrookHttpClient.SetLibrary(const ALibrary: string);
  239. begin
  240. _Library := ALibrary;
  241. end;
  242. class procedure TBrookHttpClient.Prepare(out AHttp: TBrookHttpDef);
  243. begin
  244. AHttp := TBrookHttpDefs.Service.ItemByLibrary(_Library).Create;
  245. end;
  246. class function TBrookHttpClient.Get(const AUrl: string;
  247. AResponse: TStream): Boolean;
  248. var
  249. VHttp: TBrookHttpDef = nil;
  250. begin
  251. Prepare(VHttp);
  252. try
  253. Result := VHttp.Get(AUrl, AResponse);
  254. finally
  255. VHttp.Free;
  256. end;
  257. end;
  258. class function TBrookHttpClient.Post(const AUrl: string;
  259. AResponse: TStream): Boolean;
  260. var
  261. VHttp: TBrookHttpDef = nil;
  262. begin
  263. Prepare(VHttp);
  264. try
  265. Result := VHttp.Post(AUrl, AResponse);
  266. finally
  267. VHttp.Free;
  268. end;
  269. end;
  270. class function TBrookHttpClient.Put(const AUrl: string;
  271. AResponse: TStream): Boolean;
  272. var
  273. VHttp: TBrookHttpDef = nil;
  274. begin
  275. Prepare(VHttp);
  276. try
  277. Result := VHttp.Put(AUrl, AResponse);
  278. finally
  279. VHttp.Free;
  280. end;
  281. end;
  282. class function TBrookHttpClient.Delete(const AUrl: string;
  283. AResponse: TStream): Boolean;
  284. var
  285. VHttp: TBrookHttpDef = nil;
  286. begin
  287. Prepare(VHttp);
  288. try
  289. Result := VHttp.Delete(AUrl, AResponse);
  290. finally
  291. VHttp.Free;
  292. end;
  293. end;
  294. class function TBrookHttpClient.Options(const AUrl: string;
  295. AResponse: TStream): Boolean;
  296. var
  297. VHttp: TBrookHttpDef = nil;
  298. begin
  299. Prepare(VHttp);
  300. try
  301. Result := VHttp.Options(AUrl, AResponse);
  302. finally
  303. VHttp.Free;
  304. end;
  305. end;
  306. class function TBrookHttpClient.Head(const AUrl: string;
  307. AHeaders: TStrings): Boolean;
  308. var
  309. VHttp: TBrookHttpDef = nil;
  310. begin
  311. Prepare(VHttp);
  312. try
  313. Result := VHttp.Head(AUrl, AHeaders);
  314. finally
  315. VHttp.Free;
  316. end;
  317. end;
  318. class function TBrookHttpClient.PostForm(const AUrl: string; AFormData,
  319. AResponse: TStream): Boolean;
  320. var
  321. VHttp: TBrookHttpDef = nil;
  322. begin
  323. Prepare(VHttp);
  324. try
  325. Result := VHttp.PostForm(AUrl, AFormData, AResponse);
  326. finally
  327. VHttp.Free;
  328. end;
  329. end;
  330. class function TBrookHttpClient.PostForm(const AUrl, AFormData: string;
  331. AResponse: TStream): Boolean;
  332. var
  333. VHttp: TBrookHttpDef = nil;
  334. begin
  335. Prepare(VHttp);
  336. try
  337. Result := VHttp.PostForm(AUrl, AFormData, AResponse);
  338. finally
  339. VHttp.Free;
  340. end;
  341. end;
  342. class function TBrookHttpClient.PutForm(const AUrl: string; AFormData,
  343. AResponse: TStream): Boolean;
  344. var
  345. VHttp: TBrookHttpDef = nil;
  346. begin
  347. Prepare(VHttp);
  348. try
  349. Result := VHttp.PutForm(AUrl, AFormData, AResponse);
  350. finally
  351. VHttp.Free;
  352. end;
  353. end;
  354. class function TBrookHttpClient.PutForm(const AUrl, AFormData: string;
  355. AResponse: TStream): Boolean;
  356. var
  357. VHttp: TBrookHttpDef = nil;
  358. begin
  359. Prepare(VHttp);
  360. try
  361. Result := VHttp.PutForm(AUrl, AFormData, AResponse);
  362. finally
  363. VHttp.Free;
  364. end;
  365. end;
  366. class function TBrookHttpClient.PostFile(const AUrl, AFieldName,
  367. AFileName: string; AFile, AResponse: TStream): Boolean;
  368. var
  369. VHttp: TBrookHttpDef = nil;
  370. begin
  371. Prepare(VHttp);
  372. try
  373. Result := VHttp.PostFile(AUrl, AFieldName, AFileName, AFile, AResponse);
  374. finally
  375. VHttp.Free;
  376. end;
  377. end;
  378. class function TBrookHttpClient.PostFile(const AUrl, AFieldName,
  379. AFileName: string; AResponse: TStream): Boolean;
  380. var
  381. VHttp: TBrookHttpDef = nil;
  382. begin
  383. Prepare(VHttp);
  384. try
  385. Result := VHttp.PostFile(AUrl, AFieldName, AFileName, AResponse);
  386. finally
  387. VHttp.Free;
  388. end;
  389. end;
  390. function TBrookHttpClient.Request(AHttp: TBrookHttpDef): TBrookHttpResult;
  391. begin
  392. AHttp.Request;
  393. Result.Content := AHttp.Contents.Text;
  394. Result.Header := AHttp.Headers.Text;
  395. Result.StatusCode := AHttp.StatusCode;
  396. Result.ReasonPhrase := AHttp.ReasonPhrase;
  397. end;
  398. function TBrookHttpClient.Request(const AMethod, AUrl: string): TBrookHttpResult;
  399. var
  400. VHttp: TBrookHttpDef = nil;
  401. begin
  402. Prepare(VHttp);
  403. try
  404. VHttp.Method := AMethod;
  405. VHttp.Url := AUrl;
  406. Result := Request(VHttp);
  407. finally
  408. VHttp.Free;
  409. end;
  410. end;
  411. function TBrookHttpClient.Request(const AUrl: string): TBrookHttpResult;
  412. begin
  413. Result := Request(BROOK_HTTP_REQUEST_METHOD_GET, AUrl);
  414. end;
  415. finalization
  416. FreeAndNil(TBrookHttpDefs._List);
  417. end.