brookfclhttpclientbroker.pas 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395
  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. { FCL HTTP client broker. }
  11. unit BrookFCLHttpClientBroker;
  12. {$mode objfpc}{$H+}
  13. interface
  14. uses
  15. BrookHttpClient, BrookConsts, FPHttpClient, Classes, SysUtils;
  16. type
  17. TBrookFPHttpClientDef = class(TBrookHttpDef)
  18. private
  19. FHttp: TFPHttpClient;
  20. FContents: TStrings;
  21. FDocument: TMemoryStream;
  22. FMethod: string;
  23. FUrl: string;
  24. class function InternalRequest(AHttp: TFPHttpClient; AResponse: TStream;
  25. const AMethod, AUrl: string): Boolean;
  26. protected
  27. function GetClient: TObject; override;
  28. function GetContents: TStrings; override;
  29. function GetCookies: TStrings; override;
  30. function GetDocument: TStream; override;
  31. function GetHeaders: TStrings; override;
  32. function GetContentType: string; override;
  33. procedure SetContentType(AValue: string); override;
  34. function GetStatusCode: Integer; override;
  35. function GetReasonPhrase: string; override;
  36. function GetMethod: string; override;
  37. function GetUrl: string; override;
  38. procedure SetMethod(AValue: string); override;
  39. procedure SetUrl(AValue: string); override;
  40. public
  41. constructor Create; override;
  42. destructor Destroy; override;
  43. class function GetLibrary: string; override;
  44. class function Get(const AUrl: string; AResponse: TStream): Boolean; override;
  45. class function Post(const AUrl: string; AResponse: TStream): Boolean; override;
  46. class function Put(const AUrl: string; AResponse: TStream): Boolean; override;
  47. class function Delete(const AUrl: string; AResponse: TStream): Boolean; override;
  48. class function Options(const AUrl: string; AResponse: TStream): Boolean; override;
  49. class function Head(const AUrl: string; AHeaders: TStrings): Boolean; override;
  50. class function PostForm(const AUrl, AFormData: string; AResponse: TStream): Boolean; override;
  51. class function PostForm(const AUrl: string; AFormData, AResponse: TStream): Boolean; override;
  52. class function PutForm(const AUrl, AFormData: string; AResponse: TStream): Boolean; override;
  53. class function PutForm(const AUrl: string; AFormData, AResponse: TStream): Boolean; override;
  54. class function PostFile(const AUrl, AFieldName, AFileName: string;
  55. AResponse: TStream): Boolean; override;
  56. class function PostFile(const AUrl, AFieldName, AFileName: string;
  57. AFile, AResponse: TStream): Boolean; override;
  58. procedure AddHeader(const AName, AValue: string); override;
  59. function Request: Boolean; override;
  60. end;
  61. implementation
  62. constructor TBrookFPHttpClientDef.Create;
  63. begin
  64. FHttp := TFPHttpClient.Create(nil);
  65. FContents := TStringList.Create;
  66. FDocument := TMemoryStream.Create;
  67. FHttp.AddHeader('User-Agent', 'Brook for Free Pascal and FCL-Web.');
  68. FMethod := 'GET';
  69. end;
  70. destructor TBrookFPHttpClientDef.Destroy;
  71. begin
  72. FContents.Free;
  73. FDocument.Free;
  74. FHttp.Free;
  75. inherited Destroy;
  76. end;
  77. function TBrookFPHttpClientDef.GetClient: TObject;
  78. begin
  79. Result := FHttp;
  80. end;
  81. function TBrookFPHttpClientDef.GetContents: TStrings;
  82. begin
  83. FDocument.Seek(0, 0);
  84. FContents.LoadFromStream(FDocument);
  85. Result := FContents;
  86. end;
  87. function TBrookFPHttpClientDef.GetCookies: TStrings;
  88. begin
  89. Result := FHttp.Cookies;
  90. end;
  91. function TBrookFPHttpClientDef.GetDocument: TStream;
  92. begin
  93. Result := FDocument;
  94. end;
  95. function TBrookFPHttpClientDef.GetHeaders: TStrings;
  96. begin
  97. Result := FHttp.ResponseHeaders;
  98. end;
  99. function TBrookFPHttpClientDef.GetContentType: string;
  100. begin
  101. Result := FHttp.GetHeader('Content-Type');
  102. end;
  103. procedure TBrookFPHttpClientDef.SetContentType(AValue: string);
  104. begin
  105. FHttp.AddHeader('Content-Type', AValue);
  106. end;
  107. function TBrookFPHttpClientDef.GetStatusCode: Integer;
  108. begin
  109. Result := FHttp.ResponseStatusCode;
  110. end;
  111. function TBrookFPHttpClientDef.GetReasonPhrase: string;
  112. begin
  113. Result := FHttp.ResponseStatusText;
  114. end;
  115. function TBrookFPHttpClientDef.GetMethod: string;
  116. begin
  117. Result := FMethod;
  118. end;
  119. function TBrookFPHttpClientDef.GetUrl: string;
  120. begin
  121. Result := FUrl;
  122. end;
  123. procedure TBrookFPHttpClientDef.SetMethod(AValue: string);
  124. begin
  125. FMethod := AValue;
  126. end;
  127. procedure TBrookFPHttpClientDef.SetUrl(AValue: string);
  128. begin
  129. FUrl := AValue;
  130. end;
  131. class function TBrookFPHttpClientDef.InternalRequest(AHttp: TFPHttpClient;
  132. AResponse: TStream; const AMethod, AUrl: string): Boolean;
  133. begin
  134. AHttp.RequestHeaders.Add('Connection: Close');
  135. if Assigned(AResponse) then
  136. begin
  137. AHttp.HttpMethod(AMethod, AUrl, AResponse, []);
  138. Result := AHttp.ResponseStatusCode = 200;
  139. end
  140. else
  141. begin
  142. AResponse := TMemoryStream.Create;
  143. try
  144. AHttp.HttpMethod(AMethod, AUrl, AResponse, []);
  145. Result := AHttp.ResponseStatusCode = 200;
  146. finally
  147. FreeAndNil(AResponse);
  148. end;
  149. end;
  150. end;
  151. class function TBrookFPHttpClientDef.GetLibrary: string;
  152. begin
  153. Result := 'FCLWeb';
  154. end;
  155. class function TBrookFPHttpClientDef.Get(const AUrl: string;
  156. AResponse: TStream): Boolean;
  157. var
  158. VHttp: TFPHttpClient;
  159. begin
  160. VHttp := TFPHttpClient.Create(nil);
  161. try
  162. Result := InternalRequest(VHttp, AResponse, 'GET', AUrl);
  163. finally
  164. VHttp.Free;
  165. end;
  166. end;
  167. class function TBrookFPHttpClientDef.Post(const AUrl: string;
  168. AResponse: TStream): Boolean;
  169. var
  170. VHttp: TFPHttpClient;
  171. begin
  172. VHttp := TFPHttpClient.Create(nil);
  173. try
  174. Result := InternalRequest(VHttp, AResponse, 'POST', AUrl);
  175. finally
  176. VHttp.Free;
  177. end;
  178. end;
  179. class function TBrookFPHttpClientDef.Put(const AUrl: string;
  180. AResponse: TStream): Boolean;
  181. var
  182. VHttp: TFPHttpClient;
  183. begin
  184. VHttp := TFPHttpClient.Create(nil);
  185. try
  186. Result := InternalRequest(VHttp, AResponse, 'PUT', AUrl);
  187. finally
  188. VHttp.Free;
  189. end;
  190. end;
  191. class function TBrookFPHttpClientDef.Delete(const AUrl: string;
  192. AResponse: TStream): Boolean;
  193. var
  194. VHttp: TFPHttpClient;
  195. begin
  196. VHttp := TFPHttpClient.Create(nil);
  197. try
  198. Result := InternalRequest(VHttp, AResponse, 'DELETE', AUrl);
  199. finally
  200. VHttp.Free;
  201. end;
  202. end;
  203. class function TBrookFPHttpClientDef.Options(const AUrl: string;
  204. AResponse: TStream): Boolean;
  205. var
  206. VHttp: TFPHttpClient;
  207. begin
  208. VHttp := TFPHttpClient.Create(nil);
  209. try
  210. Result := InternalRequest(VHttp, AResponse, 'OPTIONS', AUrl);
  211. finally
  212. VHttp.Free;
  213. end;
  214. end;
  215. class function TBrookFPHttpClientDef.Head(const AUrl: string;
  216. AHeaders: TStrings): Boolean;
  217. var
  218. VHttp: TFPHttpClient;
  219. begin
  220. VHttp := TFPHttpClient.Create(nil);
  221. try
  222. VHttp.RequestHeaders.Add('Connection: Close');
  223. VHttp.HttpMethod('HEAD', AUrl, nil, []);
  224. AHeaders.Assign(VHttp.ResponseHeaders);
  225. Result := VHttp.ResponseStatusCode = 200;
  226. finally
  227. VHttp.Free;
  228. end;
  229. end;
  230. class function TBrookFPHttpClientDef.PostForm(const AUrl: string; AFormData,
  231. AResponse: TStream): Boolean;
  232. var
  233. VHttp: TFPHttpClient;
  234. begin
  235. VHttp := TFPHttpClient.Create(nil);
  236. try
  237. VHttp.RequestBody := AFormData;
  238. VHttp.AddHeader('Content-Type', 'application/x-www-form-urlencoded');
  239. Result := InternalRequest(VHttp, AResponse, 'POST', AUrl);
  240. finally
  241. VHttp.Free;
  242. end;
  243. end;
  244. class function TBrookFPHttpClientDef.PostForm(const AUrl, AFormData: string;
  245. AResponse: TStream): Boolean;
  246. var
  247. VFormData: TStringStream;
  248. begin
  249. VFormData := TStringStream.Create(AFormData);
  250. try
  251. Result := PostForm(AUrl, VFormData, AResponse);
  252. finally
  253. VFormData.Free;
  254. VFormData := nil;
  255. end;
  256. end;
  257. class function TBrookFPHttpClientDef.PutForm(const AUrl: string; AFormData,
  258. AResponse: TStream): Boolean;
  259. var
  260. VHttp: TFPHttpClient;
  261. begin
  262. VHttp := TFPHttpClient.Create(nil);
  263. try
  264. VHttp.RequestBody := AFormData;
  265. VHttp.AddHeader('Content-Type', 'application/x-www-form-urlencoded');
  266. Result := InternalRequest(VHttp, AResponse, 'PUT', AUrl);
  267. finally
  268. VHttp.Free;
  269. end;
  270. end;
  271. class function TBrookFPHttpClientDef.PutForm(const AUrl, AFormData: string;
  272. AResponse: TStream): Boolean;
  273. var
  274. VFormData: TStringStream;
  275. begin
  276. VFormData := TStringStream.Create(AFormData);
  277. try
  278. Result := PutForm(AUrl, VFormData, AResponse);
  279. finally
  280. VFormData.Free;
  281. VFormData := nil;
  282. end;
  283. end;
  284. class function TBrookFPHttpClientDef.PostFile(const AUrl, AFieldName,
  285. AFileName: string; AFile, AResponse: TStream): Boolean;
  286. var
  287. S, VSep: string;
  288. VData: TMemoryStream;
  289. VHttp: TFPHttpClient;
  290. begin
  291. VData := TMemoryStream.Create;
  292. VHttp := TFPHttpClient.Create(nil);
  293. try
  294. VSep := Format('%.8x_multipart_boundary', [Random($FFFFFF)]);
  295. S := '--' + VSep + CRLF;
  296. S := S + Format('Content-Disposition: form-data; name="%s"; filename="%s"' +
  297. CRLF, [AFieldName, ExtractFileName(AFileName)]);
  298. S := S + 'Content-Type: application/octet-string' + CRLF + CRLF;
  299. VData.Write(Pointer(S)^, Length(S));
  300. VData.CopyFrom(AFile, 0);
  301. S := CRLF + '--' + VSep + '--' + CRLF;
  302. VData.Write(Pointer(S)^, Length(S));
  303. VHttp.AddHeader('Content-Type', 'multipart/form-data; boundary=' + VSep);
  304. VData.Seek(0, 0);
  305. VHttp.RequestBody := VData;
  306. Result := InternalRequest(VHttp, AResponse, 'POST', AUrl);
  307. finally
  308. VData.Free;
  309. VHttp.RequestBody := nil;
  310. VHttp.Free;
  311. end;
  312. end;
  313. class function TBrookFPHttpClientDef.PostFile(const AUrl, AFieldName,
  314. AFileName: string; AResponse: TStream): Boolean;
  315. var
  316. VFile: TFileStream;
  317. begin
  318. VFile := TFileStream.Create(AFileName, fmOpenRead or fmShareDenyWrite);
  319. try
  320. Result := PostFile(AUrl, AFieldName, AFileName, VFile, AResponse);
  321. finally
  322. VFile.Free;
  323. end;
  324. end;
  325. procedure TBrookFPHttpClientDef.AddHeader(const AName, AValue: string);
  326. begin
  327. FHttp.AddHeader(AName, AValue);
  328. end;
  329. function TBrookFPHttpClientDef.Request: Boolean;
  330. begin
  331. try
  332. if FHttp.ResponseHeaders.Count > 0 then
  333. FHttp.RequestHeaders.AddStrings(FHttp.ResponseHeaders);
  334. if FDocument.Size > 0 then
  335. begin
  336. FHttp.RequestBody := TMemoryStream.Create;
  337. FHttp.RequestBody.CopyFrom(FDocument, 0);
  338. FHttp.RequestBody.Seek(0, 0);
  339. FDocument.Clear;
  340. end;
  341. FHttp.RequestHeaders.Add('Connection: Close');
  342. FHttp.HttpMethod(FMethod, FUrl, FDocument, []);
  343. Result := FHttp.ResponseStatusCode = 200;
  344. finally
  345. FHttp.RequestBody.Free;
  346. FHttp.RequestBody := nil;
  347. end;
  348. end;
  349. initialization
  350. TBrookFPHttpClientDef.Register;
  351. end.