brookhttpclient.pas 14 KB

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