PageRenderTime 66ms CodeModel.GetById 29ms RepoModel.GetById 0ms app.codeStats 0ms

/fpcbuild-2.6.0/fpcsrc/packages/fcl-web/src/base/fphttpclient.pp

#
Puppet | 830 lines | 813 code | 17 blank | 0 comment | 11 complexity | 41b8d2b2a245c81376c7421d35a6a922 MD5 | raw file
Possible License(s): LGPL-3.0, BSD-3-Clause, GPL-2.0, LGPL-2.0, LGPL-2.1
  1. {
  2. This file is part of the Free Pascal run time library.
  3. Copyright (c) 2011 by the Free Pascal development team
  4. HTTP client component.
  5. See the file COPYING.FPC, included in this distribution,
  6. for details about the copyright.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  10. **********************************************************************}
  11. unit fphttpclient;
  12. { ---------------------------------------------------------------------
  13. Todo:
  14. * Proxy support ?
  15. * Easy calls for POST/DELETE/etc.
  16. ---------------------------------------------------------------------}
  17. {$mode objfpc}{$H+}
  18. interface
  19. uses
  20. Classes, SysUtils, ssockets, httpdefs, uriparser, base64;
  21. Const
  22. ReadBufLen = 4096;
  23. Type
  24. { TFPCustomHTTPClient }
  25. TFPCustomHTTPClient = Class(TComponent)
  26. private
  27. FCookies: TStrings;
  28. FHTTPVersion: String;
  29. FRequestBody: TStream;
  30. FRequestHeaders: TStrings;
  31. FResponseHeaders: TStrings;
  32. FResponseStatusCode: Integer;
  33. FResponseStatusText: String;
  34. FServerHTTPVersion: String;
  35. FSocket : TInetSocket;
  36. FBuffer : Ansistring;
  37. function CheckContentLength: Integer;
  38. function GetCookies: TStrings;
  39. procedure SetCookies(const AValue: TStrings);
  40. procedure SetRequestHeaders(const AValue: TStrings);
  41. protected
  42. // Parse response status line. Saves status text and protocol, returns numerical code. Exception if invalid line.
  43. Function ParseStatusLine(AStatusLine : String) : Integer;
  44. // Construct server URL for use in request line.
  45. function GetServerURL(URI: TURI): String;
  46. // Read 1 line of response. Fills FBuffer
  47. function ReadString: String;
  48. // Check if response code is in AllowedResponseCodes. if not, an exception is raised.
  49. function CheckResponseCode(ACode: Integer; const AllowedResponseCodes: array of Integer): Boolean; virtual;
  50. // Read response from server, and write any document to Stream.
  51. procedure ReadResponse(Stream: TStream; const AllowedResponseCodes: array of Integer); virtual;
  52. // Read server response line and headers. Returns status code.
  53. Function ReadResponseHeaders : integer; virtual;
  54. // Allow header in request ? (currently checks only if non-empty and contains : token)
  55. function AllowHeader(var AHeader: String): Boolean; virtual;
  56. // Connect to the server. Must initialize FSocket.
  57. procedure ConnectToServer(const AHost: String; APort: Integer); virtual;
  58. // Disconnect from server. Must free FSocket.
  59. procedure DisconnectFromServer; virtual;
  60. // Run method AMethod, using request URL AURL. Write Response to Stream, and headers in ResponseHeaders.
  61. // If non-empty, AllowedResponseCodes contains an array of response codes considered valid responses.
  62. Procedure DoMethod(Const AMethod,AURL : String; Stream : TStream; Const AllowedResponseCodes : Array of Integer); virtual;
  63. // Send request to server: construct request line and send headers and request body.
  64. procedure SendRequest(const AMethod: String; URI: TURI); virtual;
  65. Public
  66. Constructor Create(AOwner: TComponent); override;
  67. Destructor Destroy; override;
  68. // Request Header management
  69. // Return index of header, -1 if not present.
  70. Function IndexOfHeader(Const AHeader : String) : Integer;
  71. // Add header, replacing an existing one if it exists.
  72. Procedure AddHeader(Const AHeader,AValue : String);
  73. // Return header value, empty if not present.
  74. Function GetHeader(Const AHeader : String) : String;
  75. // General-purpose call.
  76. Procedure HTTPMethod(Const AMethod,AURL : String; Stream : TStream; Const AllowedResponseCodes : Array of Integer); virtual;
  77. // Execute GET on server, store result in Stream, File, StringList or string
  78. Procedure Get(Const AURL : String; Stream : TStream);
  79. Procedure Get(Const AURL : String; const LocalFileName : String);
  80. Procedure Get(Const AURL : String; Response : TStrings);
  81. Function Get(Const AURL : String) : String;
  82. // Simple post
  83. // Post URL, and Requestbody. Return response in Stream, File, TstringList or String;
  84. procedure Post(const URL: string; const Response: TStream);
  85. procedure Post(const URL: string; Response : TStrings);
  86. procedure Post(const URL: string; const LocalFileName: String);
  87. function Post(const URL: string) : String;
  88. // Post Form data (www-urlencoded).
  89. // Formdata in string (urlencoded) or TStrings (plain text) format.
  90. // Form data will be inserted in the requestbody.
  91. // Return response in Stream, File, TStringList or String;
  92. Procedure FormPost(const URL, FormData: string; const Response: TStream);
  93. Procedure FormPost(const URL : string; FormData: TStrings; const Response: TStream);
  94. Procedure FormPost(const URL, FormData: string; const Response: TStrings);
  95. Procedure FormPost(const URL : string; FormData: TStrings; const Response: TStrings);
  96. function FormPost(const URL, FormData: string): String;
  97. function FormPost(const URL: string; FormData : TStrings): String;
  98. // Post a file
  99. Procedure FileFormPost(const AURL, AFieldName, AFileName: string; const Response: TStream);
  100. Protected
  101. // Before request properties.
  102. // Additional headers for request. Host; and Authentication are automatically added.
  103. Property RequestHeaders : TStrings Read FRequestHeaders Write SetRequestHeaders;
  104. // Cookies. Set before request to send cookies to server.
  105. // After request the property is filled with the cookies sent by the server.
  106. Property Cookies : TStrings Read GetCookies Write SetCookies;
  107. // Optional body to send (mainly in POST request)
  108. Property RequestBody : TStream read FRequestBody Write FRequestBody;
  109. // used HTTP version when constructing the request.
  110. Property HTTPversion : String Read FHTTPVersion Write FHTTPVersion;
  111. // After request properties.
  112. // After request, this contains the headers sent by server.
  113. Property ResponseHeaders : TStrings Read FResponseHeaders;
  114. // After request, HTTP version of server reply.
  115. Property ServerHTTPVersion : String Read FServerHTTPVersion;
  116. // After request, HTTP response status of the server.
  117. Property ResponseStatusCode : Integer Read FResponseStatusCode;
  118. // After request, HTTP response status text of the server.
  119. Property ResponseStatusText : String Read FResponseStatusText;
  120. end;
  121. TFPHTTPClient = Class(TFPCustomHTTPClient)
  122. Public
  123. Property RequestHeaders;
  124. Property RequestBody;
  125. Property ResponseHeaders;
  126. Property HTTPversion;
  127. Property ServerHTTPVersion;
  128. Property ResponseStatusCode;
  129. Property ResponseStatusText;
  130. Property Cookies;
  131. end;
  132. EHTTPClient = Class(Exception);
  133. Function EncodeURLElement(S : String) : String;
  134. Function DecodeURLElement(Const S : String) : String;
  135. implementation
  136. resourcestring
  137. SErrInvalidProtocol = 'Invalid protocol : "%s"';
  138. SErrReadingSocket = 'Error reading data from socket';
  139. SErrInvalidProtocolVersion = 'Invalid protocol version in response: "%s"';
  140. SErrInvalidStatusCode = 'Invalid response status code: %s';
  141. SErrUnexpectedResponse = 'Unexpected response status code: %d';
  142. Const
  143. CRLF = #13#10;
  144. function EncodeURLElement(S: String): String;
  145. Const
  146. NotAllowed = [ ';', '/', '?', ':', '@', '=', '&', '#', '+', '_', '<', '>',
  147. '"', '%', '{', '}', '|', '\', '^', '~', '[', ']', '`' ];
  148. var
  149. i, o, l : Integer;
  150. h: string[2];
  151. P : PChar;
  152. c: AnsiChar;
  153. begin
  154. l:=Length(S);
  155. If (l=0) then Exit;
  156. SetLength(Result,l*3);
  157. P:=Pchar(Result);
  158. for I:=1 to L do
  159. begin
  160. C:=S[i];
  161. O:=Ord(c);
  162. if (O<=$20) or (O>=$7F) or (c in NotAllowed) then
  163. begin
  164. P^ := '%';
  165. Inc(P);
  166. h := IntToHex(Ord(c), 2);
  167. p^ := h[1];
  168. Inc(P);
  169. p^ := h[2];
  170. Inc(P);
  171. end
  172. else
  173. begin
  174. P^ := c;
  175. Inc(p);
  176. end;
  177. end;
  178. SetLength(Result,P-PChar(Result));
  179. end;
  180. function DecodeURLElement(Const S: AnsiString): AnsiString;
  181. var
  182. i,l,o : Integer;
  183. c: AnsiChar;
  184. p : pchar;
  185. h : string;
  186. begin
  187. l := Length(S);
  188. if l=0 then exit;
  189. SetLength(Result, l);
  190. P:=PChar(Result);
  191. i:=1;
  192. While (I<=L) do
  193. begin
  194. c := S[i];
  195. if (c<>'%') then
  196. begin
  197. P^:=c;
  198. Inc(P);
  199. end
  200. else if (I<L-1) then
  201. begin
  202. H:='$'+Copy(S,I+1,2);
  203. o:=StrToIntDef(H,-1);
  204. If (O>=0) and (O<=255) then
  205. begin
  206. P^:=char(O);
  207. Inc(P);
  208. Inc(I,2);
  209. end;
  210. end;
  211. Inc(i);
  212. end;
  213. SetLength(Result, P-Pchar(Result));
  214. end;
  215. { TFPCustomHTTPClient }
  216. procedure TFPCustomHTTPClient.SetRequestHeaders(const AValue: TStrings);
  217. begin
  218. if FRequestHeaders=AValue then exit;
  219. FRequestHeaders.Assign(AValue);
  220. end;
  221. function TFPCustomHTTPClient.IndexOfHeader(const AHeader: String): Integer;
  222. Var
  223. L : Integer;
  224. H : String;
  225. begin
  226. H:=LowerCase(Aheader);
  227. l:=Length(AHeader);
  228. Result:=Requestheaders.Count-1;
  229. While (Result>=0) and ((LowerCase(Copy(RequestHeaders[Result],1,l)))<>h) do
  230. Dec(Result);
  231. end;
  232. procedure TFPCustomHTTPClient.AddHeader(const AHeader, AValue: String);
  233. Var
  234. I,J,L : Integer;
  235. H : String;
  236. begin
  237. j:=IndexOfHeader(Aheader);
  238. if (J<>-1) then
  239. RequestHeaders.Delete(j);
  240. RequestHeaders.Add(AHeader+': '+Avalue);
  241. end;
  242. function TFPCustomHTTPClient.GetHeader(const AHeader: String): String;
  243. Var
  244. I : Integer;
  245. begin
  246. I:=indexOfHeader(AHeader);
  247. Result:=RequestHeaders[i];
  248. I:=Pos(':',Result);
  249. if (I=0) then
  250. I:=Length(Result);
  251. Delete(Result,1,I);
  252. end;
  253. Function TFPCustomHTTPClient.GetServerURL(URI : TURI) : String;
  254. Var
  255. D : String;
  256. begin
  257. D:=URI.Path;
  258. If (D[1]<>'/') then
  259. D:='/'+D;
  260. If (D[Length(D)]<>'/') then
  261. D:=D+'/';
  262. Result:=D+URI.Document;
  263. if (URI.Params<>'') then
  264. Result:=Result+'?'+URI.Params;
  265. end;
  266. procedure TFPCustomHTTPClient.ConnectToServer(Const AHost : String; APort : Integer);
  267. begin
  268. if Aport=0 then
  269. Aport:=80;
  270. FSocket:=TInetSocket.Create(AHost,APort);
  271. end;
  272. procedure TFPCustomHTTPClient.DisconnectFromServer;
  273. begin
  274. FreeAndNil(FSocket);
  275. end;
  276. function TFPCustomHTTPClient.AllowHeader(Var AHeader : String) : Boolean;
  277. begin
  278. Result:=(AHeader<>'') and (Pos(':',AHeader)<>0);
  279. end;
  280. procedure TFPCustomHTTPClient.SendRequest(Const AMethod : String; URI : TURI);
  281. Var
  282. S,L : String;
  283. I : Integer;
  284. begin
  285. S:=Uppercase(AMethod)+' '+GetServerURL(URI)+' '+'HTTP/'+FHTTPVersion+CRLF;
  286. If (URI.Username<>'') then
  287. S:=S+'Authorization: Basic ' + EncodeStringBase64(URI.UserName+ ':' + URI.Password)+CRLF;
  288. S:=S+'Host: '+URI.Host;
  289. If (URI.Port<>0) then
  290. S:=S+':'+IntToStr(URI.Port);
  291. S:=S+CRLF;
  292. If Assigned(RequestBody) and (IndexOfHeader('Content-length')=-1) then
  293. AddHeader('Content-length',IntToStr(RequestBody.Size));
  294. For I:=0 to FRequestHeaders.Count-1 do
  295. begin
  296. l:=FRequestHeaders[i];
  297. If AllowHeader(L) then
  298. S:=S+L+CRLF;
  299. end;
  300. if Assigned(FCookies) then
  301. begin
  302. L:='Cookie:';
  303. For I:=0 to FCookies.Count-1 do
  304. begin
  305. If (I>0) then
  306. L:=L+'; ';
  307. L:=L+FCookies[i];
  308. end;
  309. if AllowHeader(L) then
  310. S:=S+L+CRLF;
  311. end;
  312. S:=S+CRLF;
  313. FSocket.WriteBuffer(S[1],Length(S));
  314. If Assigned(FRequestBody) then
  315. FSocket.CopyFrom(FRequestBody,FRequestBody.Size);
  316. end;
  317. function TFPCustomHTTPClient.ReadString : String;
  318. Procedure FillBuffer;
  319. Var
  320. R : Integer;
  321. begin
  322. SetLength(FBuffer,ReadBufLen);
  323. r:=FSocket.Read(FBuffer[1],ReadBufLen);
  324. If r<0 then
  325. Raise EHTTPClient.Create(SErrReadingSocket);
  326. if (r<ReadBuflen) then
  327. SetLength(FBuffer,r);
  328. end;
  329. Var
  330. CheckLF,Done : Boolean;
  331. P,L : integer;
  332. begin
  333. Result:='';
  334. Done:=False;
  335. CheckLF:=False;
  336. Repeat
  337. if Length(FBuffer)=0 then
  338. FillBuffer;
  339. if Length(FBuffer)=0 then
  340. Done:=True
  341. else if CheckLF then
  342. begin
  343. If (FBuffer[1]<>#10) then
  344. Result:=Result+#13
  345. else
  346. begin
  347. Delete(FBuffer,1,1);
  348. Done:=True;
  349. end;
  350. end;
  351. if not Done then
  352. begin
  353. P:=Pos(#13#10,FBuffer);
  354. If P=0 then
  355. begin
  356. L:=Length(FBuffer);
  357. CheckLF:=FBuffer[L]=#13;
  358. if CheckLF then
  359. Result:=Result+Copy(FBuffer,1,L-1)
  360. else
  361. Result:=Result+FBuffer;
  362. FBuffer:='';
  363. end
  364. else
  365. begin
  366. Result:=Result+Copy(FBuffer,1,P-1);
  367. Delete(FBuffer,1,P+1);
  368. Done:=True;
  369. end;
  370. end;
  371. until Done;
  372. end;
  373. Function GetNextWord(Var S : String) : string;
  374. Const
  375. WhiteSpace = [' ',#9];
  376. Var
  377. P : Integer;
  378. begin
  379. While (Length(S)>0) and (S[1] in WhiteSpace) do
  380. Delete(S,1,1);
  381. P:=Pos(' ',S);
  382. If (P=0) then
  383. P:=Pos(#9,S);
  384. If (P=0) then
  385. P:=Length(S)+1;
  386. Result:=Copy(S,1,P-1);
  387. Delete(S,1,P);
  388. end;
  389. Function TFPCustomHTTPClient.ParseStatusLine(AStatusLine : String) : Integer;
  390. Var
  391. S : String;
  392. begin
  393. S:=Uppercase(GetNextWord(AStatusLine));
  394. If (Copy(S,1,5)<>'HTTP/') then
  395. Raise EHTTPClient.CreateFmt(SErrInvalidProtocolVersion,[S]);
  396. Delete(S,1,5);
  397. FServerHTTPVersion:=S;
  398. S:=GetNextWord(AStatusLine);
  399. Result:=StrToIntDef(S,-1);
  400. if Result=-1 then
  401. Raise EHTTPClient.CreateFmt(SErrInvalidStatusCode,[S]);
  402. FResponseStatusText:=AStatusLine;
  403. end;
  404. Function TFPCustomHTTPClient.ReadResponseHeaders : Integer;
  405. Procedure DoCookies(S : String);
  406. Var
  407. P : Integer;
  408. C : String;
  409. begin
  410. If Assigned(FCookies) then
  411. FCookies.Clear;
  412. P:=Pos(':',S);
  413. Delete(S,1,P);
  414. Repeat
  415. P:=Pos(';',S);
  416. If (P=0) then
  417. P:=Length(S)+1;
  418. C:=Trim(Copy(S,1,P-1));
  419. Cookies.Add(C);
  420. Delete(S,1,P);
  421. Until (S='');
  422. end;
  423. Const
  424. SetCookie = 'set-cookie';
  425. Var
  426. StatusLine,S : String;
  427. begin
  428. StatusLine:=ReadString;
  429. Result:=ParseStatusLine(StatusLine);
  430. Repeat
  431. S:=ReadString;
  432. if (S<>'') then
  433. begin
  434. ResponseHeaders.Add(S);
  435. If (LowerCase(Copy(S,1,Length(SetCookie)))=SetCookie) then
  436. DoCookies(S);
  437. end
  438. Until (S='');
  439. end;
  440. Function TFPCustomHTTPClient.CheckResponseCode(ACode : Integer; Const AllowedResponseCodes : Array of Integer) : Boolean;
  441. Var
  442. I : Integer;
  443. begin
  444. Result:=(High(AllowedResponseCodes)=-1);
  445. if not Result then
  446. begin
  447. I:=Low(AllowedResponseCodes);
  448. While (Not Result) and (I<=High(AllowedResponseCodes)) do
  449. begin
  450. Result:=(AllowedResponseCodes[i]=ACode);
  451. Inc(I);
  452. end
  453. end;
  454. end;
  455. Function TFPCustomHTTPClient.CheckContentLength: Integer;
  456. Const CL ='content-length:';
  457. Var
  458. S : String;
  459. I : integer;
  460. begin
  461. Result:=-1;
  462. I:=0;
  463. While (Result=-1) and (I<FResponseHeaders.Count) do
  464. begin
  465. S:=Trim(LowerCase(FResponseHeaders[i]));
  466. If (Copy(S,1,Length(Cl))=Cl) then
  467. begin
  468. Delete(S,1,Length(CL));
  469. Result:=StrToIntDef(Trim(S),-1);
  470. end;
  471. Inc(I);
  472. end;
  473. end;
  474. function TFPCustomHTTPClient.GetCookies: TStrings;
  475. begin
  476. If (FCookies=Nil) then
  477. FCookies:=TStringList.Create;
  478. Result:=FCookies;
  479. end;
  480. procedure TFPCustomHTTPClient.SetCookies(const AValue: TStrings);
  481. begin
  482. if GetCookies=AValue then exit;
  483. GetCookies.Assign(AValue);
  484. end;
  485. procedure TFPCustomHTTPClient.ReadResponse(Stream: TStream; Const AllowedResponseCodes : Array of Integer);
  486. Function Transfer(LB : Integer) : Integer;
  487. begin
  488. Result:=FSocket.Read(FBuffer[1],LB);
  489. If Result<0 then
  490. Raise EHTTPClient.Create(SErrReadingSocket);
  491. if (Result>0) then
  492. Stream.Write(FBuffer[1],Result);
  493. end;
  494. Var
  495. L,LB,R : Integer;
  496. ResponseOK : Boolean;
  497. begin
  498. SetLength(FBuffer,0);
  499. FResponseStatusCode:=ReadResponseHeaders;
  500. if not CheckResponseCode(FResponseStatusCode,AllowedResponseCodes) then
  501. Raise EHTTPClient.CreateFmt(SErrUnexpectedResponse,[ResponseStatusCode]);
  502. // Write remains of buffer to output.
  503. LB:=Length(FBuffer);
  504. If (LB>0) then
  505. Stream.WriteBuffer(FBuffer[1],LB);
  506. // Now read the rest, if any.
  507. SetLength(FBuffer,ReadBuflen);
  508. L:=CheckContentLength;
  509. If (L>LB) then
  510. begin
  511. // We cannot use copyfrom, it uses ReadBuffer, and this is dangerous with sockets
  512. L:=L-LB;
  513. Repeat
  514. LB:=ReadBufLen;
  515. If (LB>L) then
  516. LB:=L;
  517. R:=Transfer(LB);
  518. L:=L-R;
  519. until (L=0) or (R=0);
  520. end
  521. else if L<0 then
  522. // No content-length, so we read till no more data available.
  523. Repeat
  524. R:=Transfer(ReadBufLen);
  525. until (R=0);
  526. end;
  527. procedure TFPCustomHTTPClient.DoMethod(Const AMethod,AURL: String; Stream: TStream; Const AllowedResponseCodes : Array of Integer);
  528. Var
  529. URI : TURI;
  530. begin
  531. FResponseHeaders.Clear;
  532. URI:=ParseURI(AURL);
  533. If (Lowercase(URI.Protocol)<>'http') then
  534. Raise EHTTPClient.CreateFmt(SErrInvalidProtocol,[URI.Protocol]);
  535. ConnectToServer(URI.Host,URI.Port);
  536. try
  537. SendRequest(AMethod,URI);
  538. ReadResponse(Stream,AllowedResponseCodes);
  539. finally
  540. DisconnectFromServer;
  541. end;
  542. end;
  543. constructor TFPCustomHTTPClient.Create(AOwner: TComponent);
  544. begin
  545. inherited Create(AOwner);
  546. FRequestHeaders:=TStringList.Create;
  547. FResponseHeaders:=TStringList.Create;
  548. FHTTPVersion:='1.1';
  549. end;
  550. destructor TFPCustomHTTPClient.Destroy;
  551. begin
  552. FreeAndNil(FRequestHeaders);
  553. FreeAndNil(FResponseHeaders);
  554. inherited Destroy;
  555. end;
  556. procedure TFPCustomHTTPClient.HTTPMethod(const AMethod, AURL: String;
  557. Stream: TStream; const AllowedResponseCodes: array of Integer);
  558. begin
  559. DoMethod(AMethod,AURL,Stream,AllowedResponseCodes);
  560. end;
  561. procedure TFPCustomHTTPClient.Get(Const AURL: String; Stream: TStream);
  562. begin
  563. DoMethod('GET',AURL,Stream,[200]);
  564. end;
  565. procedure TFPCustomHTTPClient.Get(Const AURL: String; const LocalFileName: String);
  566. Var
  567. F : TFileStream;
  568. begin
  569. F:=TFileStream.Create(LocalFileName,fmCreate);
  570. try
  571. Get(AURL,F);
  572. finally
  573. F.Free;
  574. end;
  575. end;
  576. procedure TFPCustomHTTPClient.Get(const AURL: String; Response: TStrings);
  577. begin
  578. Response.Text:=Get(AURL);
  579. end;
  580. function TFPCustomHTTPClient.Get(Const AURL: String): String;
  581. Var
  582. SS : TStringStream;
  583. begin
  584. SS:=TStringStream.Create('');
  585. try
  586. Get(AURL,SS);
  587. Result:=SS.Datastring;
  588. finally
  589. SS.Free;
  590. end;
  591. end;
  592. procedure TFPCustomHTTPClient.Post(const URL: string; const Response: TStream);
  593. begin
  594. DoMethod('POST',URL,Response,[]);
  595. end;
  596. procedure TFPCustomHTTPClient.Post(const URL: string; Response: TStrings);
  597. begin
  598. Response.Text:=Post(URL);
  599. end;
  600. procedure TFPCustomHTTPClient.Post(const URL: string;
  601. const LocalFileName: String);
  602. Var
  603. F : TFileStream;
  604. begin
  605. F:=TFileStream.Create(LocalFileName,fmCreate);
  606. try
  607. Post(URL,F);
  608. finally
  609. F.Free;
  610. end;
  611. end;
  612. function TFPCustomHTTPClient.Post(const URL: string): String;
  613. Var
  614. SS : TStringStream;
  615. begin
  616. SS:=TStringStream.Create('');
  617. try
  618. Post(URL,SS);
  619. Result:=SS.Datastring;
  620. finally
  621. SS.Free;
  622. end;
  623. end;
  624. procedure TFPCustomHTTPClient.FormPost(const URL, FormData: string;
  625. const Response: TStream);
  626. Var
  627. S : TStringStream;
  628. begin
  629. RequestBody:=TStringStream.Create(FormData);
  630. try
  631. AddHeader('Content-Type','application/x-www-form-urlencoded');
  632. Post(URL,Response);
  633. finally
  634. RequestBody.Free;
  635. RequestBody:=Nil;
  636. end;
  637. end;
  638. procedure TFPCustomHTTPClient.FormPost(const URL: string; FormData: TStrings;
  639. const Response: TStream);
  640. Var
  641. I : Integer;
  642. S,N,V : String;
  643. begin
  644. S:='';
  645. For I:=0 to FormData.Count-1 do
  646. begin
  647. If (S<>'') then
  648. S:=S+'&';
  649. FormData.GetNameValue(i,n,v);
  650. S:=S+EncodeURLElement(N)+'='+EncodeURLElement(V);
  651. end;
  652. FormPost(URL,S,Response);
  653. end;
  654. procedure TFPCustomHTTPClient.FormPost(const URL, FormData: string;
  655. const Response: TStrings);
  656. begin
  657. Response.Text:=FormPost(URL,FormData);
  658. end;
  659. procedure TFPCustomHTTPClient.FormPost(const URL: string; FormData: TStrings;
  660. const Response: TStrings);
  661. begin
  662. Response.Text:=FormPost(URL,FormData);
  663. end;
  664. function TFPCustomHTTPClient.FormPost(const URL, FormData: string): String;
  665. Var
  666. SS : TStringStream;
  667. begin
  668. SS:=TStringStream.Create('');
  669. try
  670. FormPost(URL,FormData,SS);
  671. Result:=SS.Datastring;
  672. finally
  673. SS.Free;
  674. end;
  675. end;
  676. function TFPCustomHTTPClient.FormPost(const URL: string; FormData: TStrings
  677. ): String;
  678. Var
  679. SS : TStringStream;
  680. begin
  681. SS:=TStringStream.Create('');
  682. try
  683. FormPost(URL,FormData,SS);
  684. Result:=SS.Datastring;
  685. finally
  686. SS.Free;
  687. end;
  688. end;
  689. procedure TFPCustomHTTPClient.FileFormPost(const AURL, AFieldName, AFileName: string; const Response: TStream);
  690. Var
  691. S, Sep : string;
  692. SS : TStringStream;
  693. F : TFileStream;
  694. DS : TBase64EncodingStream;
  695. begin
  696. Sep:=Format('%.8x_multipart_boundary',[Random($ffffff)]);
  697. AddHeader('Content-type','multipart/form-data; boundary='+Sep);
  698. S:='--'+Sep+CRLF;
  699. s:=s+Format('content-disposition: form-data; name="%s"; filename="%s"'+CRLF,[AFieldName,AFileName]);
  700. s:=s+'Content-Type: Application/octet-string'+CRLF+CRLF;
  701. SS:=TStringStream.Create(s);
  702. try
  703. SS.Seek(0,soFromEnd);
  704. F:=TFileStream.Create(AFileName,fmOpenRead);
  705. try
  706. SS.CopyFrom(F,F.Size);
  707. finally
  708. F.Free;
  709. end;
  710. S:=CRLF+'--'+Sep+'--'+CRLF;
  711. SS.WriteBuffer(S[1],Length(S));
  712. SS.Position:=0;
  713. RequestBody:=SS;
  714. Post(AURL,Response);
  715. finally
  716. RequestBody:=Nil;
  717. SS.Free;
  718. end;
  719. end;
  720. end.