Sign in Join
Wiki copytemporary

fphttpclient: what changed

Revision 1 to 2. Removed lines have a minus sign; added lines have a plus sign.

OldNewLine
11## Overview
22
3-fphttpclient is supplied with FPC as part of the [[fcl-web]] package, and can be used by itself as well.
3+fphttpclient is supplied with FPC as part of the [[fcl-web]] package, and can be used by itself as well.
44
55## HTTPS (TLS/SSL)
66
7-Since April 2014, the trunk/development fphttpclient supports SSL/TLS connections using the OpenSSL library (will ship with version 2.8.0 and above). This requires the OpenSSL .so/.dll/.dylib library/libraries to be installed (e.g. present in your application or system directory on Windows).
7+Since April 2014, the trunk/development fphttpclient supports SSL/TLS connections using the OpenSSL library (will ship with version 2.8.0 and above). This requires the OpenSSL .so/.dll/.dylib library/libraries to be installed (e.g. present in your application or system directory on Windows).
88
9-- If you do not use client side certificates, just specifying the proper port (e.g. 443 for https) is enough to enable TLS/SSL as long as you have [OpenSSL libraries](https://wiki.openssl.org/index.php/Binaries) installed (or e.g. in the application directory)
10-- If you want to use e.g. a client side certificate, do something like this:
9+ * If you do not use client side certificates, just specifying the proper port (e.g. 443 for https) is enough to enable TLS/SSL as long as you have [OpenSSL libraries](<https://wiki.openssl.org/index.php/Binaries>) installed (or e.g. in the application directory)
10+ * If you want to use e.g. a client side certificate, do something like this:
1111
12-``` pascal
12+```
1313uses ...ssockets, sslsockets..
14-// Callback for setting up SSL client certificate
15-procedure TSSLHelper.SSLClientCertSetup(Sender: TObject; const UseSSL: Boolean;
16- out AHandler: TSocketHandler);
17-begin
18- AHandler := nil;
19- if UseSSL and (FClientCertificate <> '') then
20- begin
21- // Only set up client certificate if needed.
22- // If not, let normal fphttpclient flow create
23- // required socket handler
24- AHandler := TSSLSocketHandler.Create;
25- // Example: use your own client certificate when communicating with the server:
26- (AHandler as TSSLSocketHandler).Certificate.FileName := FClientCertificate;
27- end;
28-end;
29-
30-//... and in your TFPHTTPClient creation:
31-myclient := TFPHTTPClient.Create(nil);
32-if FClientCertificate <> '' then
33- myclient.OnGetSocketHandler := @SSLClientCertSetup;
14+ // Callback for setting up SSL client certificate
15+ procedure TSSLHelper.SSLClientCertSetup(Sender: TObject; const UseSSL: Boolean;
16+ out AHandler: TSocketHandler);
17+ begin
18+ AHandler := nil;
19+ if UseSSL and (FClientCertificate <> '') then
20+ begin
21+ // Only set up client certificate if needed.
22+ // If not, let normal fphttpclient flow create
23+ // required socket handler
24+ AHandler := TSSLSocketHandler.Create;
25+ // Example: use your own client certificate when communicating with the server:
26+ (AHandler as TSSLSocketHandler).Certificate.FileName := FClientCertificate;
27+ end;
28+ end;
29+
30+ //... and in your TFPHTTPClient creation:
31+ myclient := TFPHTTPClient.Create(nil);
32+ if FClientCertificate <> '' then
33+ myclient.OnGetSocketHandler := @SSLClientCertSetup;
3434```
3535
3636## Examples
3737
38-Examples are included in your FPC directory: packages/fcl-web/examples/
38+Examples are included in your FPC directory: packages/fcl-web/examples/
3939
40-Apart from those, please see below:
40+Apart from those, please see below:
4141
4242### Get body of a web page via HTTP protocol
43-
44-``` pascal
43+```
4544{$mode delphi}
46-uses fphttpclient;
47-
48-Var
49- URL, S : String;
50-begin
51- URL := ParamStr(1);
52- with TFPHttpClient.Create(Nil) do
53- try
54- S := Get(URL);
55- finally
56- Free;
57- end;
58- Writeln('Content: ', S);
59-end.
45+ uses fphttpclient;
46+
47+ Var
48+ URL, S : String;
49+ begin
50+ URL := ParamStr(1);
51+ with TFPHttpClient.Create(Nil) do
52+ try
53+ S := Get(URL);
54+ finally
55+ Free;
56+ end;
57+ Writeln('Content: ', S);
58+ end.
6059```
6160
62-If you want to write even fewer lines of code, in FPC 2.7.1 you can use the class method:
63-
64-``` pascal
65- S := TFPCustomHTTPClient.SimpleGet('http://a_site/a_page');
61+If you want to write even fewer lines of code, in FPC 2.7.1 you can use the class method:
6662```
63+S := TFPCustomHTTPClient.SimpleGet('http://a_site/a_page');
64+```
6765
6866### Download a file via HTTP protocol
6967
70-Let's show you the simplest example using HTTP only. This example retrieves just an html page and writes it to the screen.
71-
72-It uses one of the class **Get** methods of TfpHttpClient. You don't need to create and free the class. There are several overloads for e.g. TStrings or TStream (file) as well:
68+Let's show you the simplest example using HTTP only. This example retrieves just an html page and writes it to the screen.
7369
74-``` pascal
70+It uses one of the class **Get** methods of TfpHttpClient. You don't need to create and free the class. There are several overloads for e.g. TStrings or TStream (file) as well:
71+```
7572program dl_fphttp_a;
76-{$mode delphi}{$ifdef windows}{$apptype console}{$endif}
77-uses
78- fphttpclient;
79-begin
80- writeln(TFPHttpClient.SimpleGet('http://example.com'));
81-end.
73+ {$mode delphi}{$ifdef windows}{$apptype console}{$endif}
74+ uses
75+ fphttpclient;
76+ begin
77+ writeln(TFPHttpClient.SimpleGet('http://example.com'));
78+ end.
8279```
8380
84-That's all! For simple purposes this will suffice. You can even use it for HTTPS, which needs just the inclusion of one additional unit:
85-
86-``` pascal
81+That's all! For simple purposes this will suffice. You can even use it for HTTPS, which needs just the inclusion of one additional unit:
82+```
8783program dl_fphttp_b;
88-
89-{$mode delphi}{$ifdef windows}{$apptype console}{$endif}
90-
91-uses
92- fphttpclient,
93- opensslsockets;
94-
95-begin
96- writeln(TFPHttpClient.SimpleGet('https://freepascal.org'));
97-end.
84+
85+ {$mode delphi}{$ifdef windows}{$apptype console}{$endif}
86+
87+ uses
88+ fphttpclient,
89+ opensslsockets;
90+
91+ begin
92+ writeln(TFPHttpClient.SimpleGet('https://freepascal.org'));
93+ end.
9894```
9995
100-This really is all there is to do in simple scenarios, usually if you have enough control.
101-
102-But there are some caveats with this code. The foremost one being that this code does not allow for redirects. Let me demo that:
96+This really is all there is to do in simple scenarios, usually if you have enough control.
10397
104-``` pascal
98+But there are some caveats with this code. The foremost one being that this code does not allow for redirects. Let me demo that:
99+```
105100program dl_fphttp_redirect_error;
106-{$mode delphi}{$ifdef windows}{$apptype console}{$endif}
107-uses
108- sysutils, fphttpclient, opensslsockets;
109-begin
110- try
111- writeln(TFPHttpClient.SimpleGet('https://google.com'));
112- except on E:EHttpClient do
113- writeln(e.message) else raise;
114- end;
115-end.
101+ {$mode delphi}{$ifdef windows}{$apptype console}{$endif}
102+ uses
103+ sysutils, fphttpclient, opensslsockets;
104+ begin
105+ try
106+ writeln(TFPHttpClient.SimpleGet('https://google.com'));
107+ except on E:EHttpClient do
108+ writeln(e.message) else raise;
109+ end;
110+ end.
116111```
117112
118-Because the Google URL uses redirects, there is an exception: **"Unexpected response status code: 301"**. In such a case we need more control, which I will show you in the next example:
119-
120-``` pascal
113+Because the Google URL uses redirects, there is an exception: **"Unexpected response status code: 301"**. In such a case we need more control, which I will show you in the next example:
114+```
121115program dl_fphttp_c;
122-
123-{$mode delphi}{$ifdef windows}{$apptype console}{$endif}
124-
125-uses
126- classes,
127- fphttpclient,
128- openssl, { This implements the procedure InitSSLInterface }
129- opensslsockets;
130-
131-var
132- Client: TFPHttpClient;
133-
134-begin
135-
136- { SSL initialization has to be done by hand here }
137- InitSSLInterface;
138-
139- Client := TFPHttpClient.Create(nil);
140- try
141- { Allow redirections }
142- Client.AllowRedirect := true;
143- writeln(Client.Get('https://google.com/'));
144- finally
145- Client.Free;
146- end;
147-end.
116+
117+ {$mode delphi}{$ifdef windows}{$apptype console}{$endif}
118+
119+ uses
120+ classes,
121+ fphttpclient,
122+ openssl, { This implements the procedure InitSSLInterface }
123+ opensslsockets;
124+
125+ var
126+ Client: TFPHttpClient;
127+
128+ begin
129+
130+ { SSL initialization has to be done by hand here }
131+ InitSSLInterface;
132+
133+ Client := TFPHttpClient.Create(nil);
134+ try
135+ Client.AddHeader('User-Agent', 'Mozilla/5.0 (compatible; fpweb)');
136+ { Allow redirections }
137+ Client.AllowRedirect := true;
138+ Client.ConnectTimeout:= 10000; // msec
139+ Client.IOTimeout := 15000; // msec
140+ writeln(Client.Get('https://google.com/'));
141+ finally
142+ Client.Free;
143+ end;
144+ end.
148145```
149146
150-You see this requires slightly more code, but it is still a very small program. Well, now we go to the last example, which downloads any file and saves it to disk. You can use it as a template for your own code, it demonstrates almost everything you need.
151-
152-``` pascal
147+You see this requires slightly more code, but it is still a very small program. Well, now we go to the last example, which downloads any file and saves it to disk. You can use it as a template for your own code, it demonstrates almost everything you need.
148+```
153149program dl_fphttp_d;
154-
155-{$mode delphi}{$ifdef windows}{$apptype console}{$endif}
156-
157-uses
158- sysutils,
159- classes,
160- fphttpclient,
161- openssl,
162- opensslsockets;
163-
164-const
165- Filename = 'testdownload.txt';
166-
167-var
168- Client: TFPHttpClient;
169- FS: TStream;
170- SL: TStringList;
171-
172-begin
173-
174- { SSL initialization has to be done by hand here }
175- InitSSLInterface;
176-
177- Client := TFPHttpClient.Create(nil);
178- FS := TFileStream.Create(Filename,fmCreate or fmOpenWrite);
179- try
180- try
181- { Allow redirections }
182- Client.AllowRedirect := true;
183- Client.Get('https://google.com/',FS);
184- except
185- on E: EHttpClient do
186- writeln(E.Message)
187- else
188- raise;
189- end;
190- finally
191- FS.Free;
192- Client.Free;
193- end;
194-
195- { Test our file }
196- if FileExists(Filename) then
197- try
198- SL := TStringList.Create;
199- SL.LoadFromFile(Filename);
200- writeln(SL.Text);
201- finally
202- SL.Free;
203- end;
204-end.
150+
151+ {$mode delphi}{$ifdef windows}{$apptype console}{$endif}
152+
153+ uses
154+ sysutils,
155+ classes,
156+ fphttpclient,
157+ openssl,
158+ opensslsockets;
159+
160+ const
161+ Filename = 'testdownload.txt';
162+
163+ var
164+ Client: TFPHttpClient;
165+ FS: TStream;
166+ SL: TStringList;
167+
168+ begin
169+
170+ { SSL initialization has to be done by hand here }
171+ InitSSLInterface;
172+
173+ Client := TFPHttpClient.Create(nil);
174+ FS := TFileStream.Create(Filename,fmCreate or fmOpenWrite);
175+ try
176+ try
177+ Client.AddHeader('User-Agent', 'Mozilla/5.0 (compatible; fpweb)');
178+ { Allow redirections }
179+ Client.AllowRedirect := true;
180+ Client.ConnectTimeout:= 10000; // msec
181+ Client.IOTimeout := 15000; // msec
182+ Client.Get('https://google.com/',FS);
183+ except
184+ on E: EHttpClient do
185+ writeln(E.Message)
186+ else
187+ raise;
188+ end;
189+ finally
190+ FS.Free;
191+ Client.Free;
192+ end;
193+
194+ { Test our file }
195+ if FileExists(Filename) then
196+ try
197+ SL := TStringList.Create;
198+ SL.LoadFromFile(Filename);
199+ writeln(SL.Text);
200+ finally
201+ SL.Free;
202+ end;
203+ end.
205204```
206205
207206### Get file size from URL
208207
209-If you will use HTTPS links, you will need to use unit "opensslsockets". The following function assumes that server supports HEAD requests, only rare servers these days do not support it.
210-
211-``` pascal
208+If you will use HTTPS links, you will need to use unit "opensslsockets". The following function assumes that server supports HEAD requests, only rare servers these days do not support it.
209+```
212210uses
213- opensslsockets, fphttpclient;
214-
215-function GetRemoteFileSize(const URL: string): Int64;
216-var
217- SL: TStringList;
218- S: string;
219-begin
220- SL:= TStringList.Create;
221- try
222- TFPHTTPClient.Head(URL, SL);
223- //SL.NameValueSeparator := ':'; // Already done in TFPCustomHTTPClient.Create()
224- S:= SL.Values['Content-Length'];
225- Result:= StrToInt64Def(S, -1);
226- finally
227- FreeAndNil(SL);
228- end;
229-end;
211+ opensslsockets, fphttpclient;
212+
213+ function GetRemoteFileSize(const URL: string): Int64;
214+ var
215+ SL: TStringList;
216+ S: string;
217+ begin
218+ SL:= TStringList.Create;
219+ try
220+ TFPHTTPClient.Head(URL, SL);
221+ //SL.NameValueSeparator := ':'; // Already done in TFPCustomHTTPClient.Create()
222+ S:= SL.Values['Content-Length'];
223+ Result:= StrToInt64Def(S, -1);
224+ finally
225+ FreeAndNil(SL);
226+ end;
227+ end;
230228```
231229
232230### Upload a file using POST
233231
234-Use TFPHTTPClient.FileFormPost(), which allows the caller to specify the path to a local file to be uploaded and the content of the *name* field (see <https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Disposition#directives> for more information):
235-
236-``` pascal
232+Use TFPHTTPClient.FileFormPost(), which allows the caller to specify the path to a local file to be uploaded and the content of the _name_ field (see <https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Disposition#directives> for more information):
233+```
237234{$mode delphi}
238-
239-uses fphttpclient, classes;
240-
241-const
242- FieldName = 'myfield'; { This is the name of the HTTP field in the form you are filling }
243- FileName = 'test.txt'; { This file must exist on your computer }
244-
245-Var
246- Respo: TStringStream;
247- S : String;
248-
249-begin
250- With TFPHttpClient.Create(Nil) do
251- try
252- Respo := TStringStream.Create('');
253- FileFormPost('http://example.com',
254- FieldName,
255- FileName,
256- Respo);
257- S := Respo.DataString;
258- WriteLn('Response: ');
259- WriteLn(S);
260- Respo.Destroy;
261- finally
262- Free;
263- end;
264-end.
235+
236+ uses fphttpclient, classes;
237+
238+ const
239+ FieldName = 'myfield'; { This is the name of the HTTP field in the form you are filling }
240+ FileName = 'test.txt'; { This file must exist on your computer }
241+
242+ Var
243+ Respo: TStringStream;
244+ S : String;
245+
246+ begin
247+ With TFPHttpClient.Create(Nil) do
248+ try
249+ Respo := TStringStream.Create('');
250+ FileFormPost('http://example.com',
251+ FieldName,
252+ FileName,
253+ Respo);
254+ S := Respo.DataString;
255+ WriteLn('Response: ');
256+ WriteLn(S);
257+ Respo.Destroy;
258+ finally
259+ Free;
260+ end;
261+ end.
265262```
266263
267-There is a method StreamFormPost which will upload a stream instead of directly reading a file.
264+There is a method StreamFormPost which will upload a stream instead of directly reading a file.
268265
269266### Form data and encoding
270-
271-``` pascal
272- FormPost(const URL: string; FormData: TStrings; const Response: TStream);
273267```
274-
275-``` pascal
276- FormPost(const URL, FormData: string; const Response: TStream);
268+FormPost(const URL: string; FormData: TStrings; const Response: TStream);
277269```
270+```
271+FormPost(const URL, FormData: string; const Response: TStream);
272+```
278273
279-If you pass FormData as [[TStrings]] the FormPost procedure performs *EncodeURLElement* but if you pass FormData as simple [[string]] to FormPost, then *EncodeURLElement* is not performed.
274+If you pass FormData as [[TStrings]] the FormPost procedure performs _EncodeURLElement_ but if you pass FormData as simple [[string]] to FormPost, then _EncodeURLElement_ is not performed.
280275
281-There is no difference in the behaviour if the data in FormData does not need to be encoded, but there is different behaviour for strings which include characters which are not allowed (eg '@', '=', etc).
276+There is no difference in the behaviour if the data in FormData does not need to be encoded, but there is different behaviour for strings which include characters which are not allowed (eg '@', '=', etc).
282277
283278### Posting JSON
284279
285-JSON is a popular way for machine to machine talk, and requires that appropriate headers be set. This example sends a short JSON string and gets back, in 'Response' there is some more JSON.
286-
287-``` pascal
280+JSON is a popular way for machine to machine talk, and requires that appropriate headers be set. This example sends a short JSON string and gets back, in 'Response' there is some more JSON.
281+```
288282var
289- Client: TFPHttpClient;
290- Response: TStringStream;
291- Params: string = '{"title": "Some note", "content": "Awesome stuff"}';
292-begin
293- Client := TFPHttpClient.Create(nil);
294- Client.AddHeader('User-Agent', 'Mozilla/5.0 (compatible; fpweb)');
295- Client.AddHeader('Content-Type', 'application/json; charset=UTF-8');
296- Client.AddHeader('Accept', 'application/json');
297- Client.AllowRedirect := true;
298- Client.UserName := USER_STRING;
299- Client.Password := PASSW_STRING;
300- Client.RequestBody := TRawByteStringStream.Create(Params);
301- Response := TStringStream.Create('');
302- try
303- try
304- Client.Post(TheURL, Response);
305- Writeln('Response Code: ' + IntToStr(Client.ResponseStatusCode)); // better be 200
306- except on E: Exception do
307- Writeln('Something bad happened: ' + E.Message);
308- end;
309- finally
310- Client.RequestBody.Free;
311- Client.Free;
312- Response.Free;
313- end;
283+ Client: TFPHttpClient;
284+ Response: TStringStream;
285+ Params: string = '{"title": "Some note", "content": "Awesome stuff"}';
286+ begin
287+ Client := TFPHttpClient.Create(nil);
288+ Client.AddHeader('User-Agent', 'Mozilla/5.0 (compatible; fpweb)');
289+ Client.AddHeader('Content-Type', 'application/json; charset=UTF-8');
290+ Client.AddHeader('Accept', 'application/json');
291+ Client.AllowRedirect := true;
292+ Client.ConnectTimeout := 10000; // msec
293+ Client.IOTimeout := 15000; // msec
294+ Client.UserName := USER_STRING;
295+ Client.Password := PASSW_STRING;
296+ Client.RequestBody := TRawByteStringStream.Create(Params);
297+ Response := TStringStream.Create('');
298+ try
299+ try
300+ Client.Post(TheURL, Response);
301+ Writeln('Response Code: ' + IntToStr(Client.ResponseStatusCode)); // better be 200
302+ except on E: Exception do
303+ Writeln('Something bad happened: ' + E.Message);
304+ end;
305+ finally
306+ Client.RequestBody.Free;
307+ Client.Free;
308+ Response.Free;
309+ end;
314310```
315311
316-Note that using Client.FormPost() will overwrite the content-type header with "application/x-www-form-urlencoded" causing a lot of confusion with a server that is expecting JSON.
312+Note that using Client.FormPost() will overwrite the content-type header with "application/x-www-form-urlencoded" causing a lot of confusion with a server that is expecting JSON.
317313
318314### Get external IP address
319315
320-If your computer is connected to the internet via a LAN (cabled or wireless), the IP address of your network card most probably is not your external IP address.
321-
322-You can retrieve your external IP address from e.g. your router or an external site. The code below tries to get it from an external site (thanks to JoStudio on the forum for the inspiration: [1](http://lazarus.freepascal.org/index.php/topic,17506.msg110917.html#msg110917)):
316+If your computer is connected to the internet via a LAN (cabled or wireless), the IP address of your network card most probably is not your external IP address.
323317
324-``` pascal
318+You can retrieve your external IP address from e.g. your router or an external site. The code below tries to get it from an external site (thanks to JoStudio on the forum for the inspiration: [[1]](<http://lazarus.freepascal.org/index.php/topic,17506.msg110917.html#msg110917>)):
319+```
325320{$mode objfpc}{$H+}
326-
327-uses
328- Classes, SysUtils, fphttpclient, RegExpr;
329-
330-function GetExternalIPAddress: string;
331-var
332- HTTPClient: TFPHTTPClient;
333- IPRegex: TRegExpr;
334- RawData: string;
335-begin
336- try
337- HTTPClient := TFPHTTPClient.Create(nil);
338- IPRegex := TRegExpr.Create;
339- try
340- //returns something like:
341- {
342-<html><head><title>Current IP Check</title></head><body>Current IP Address: 44.151.191.44</body></html>
343- }
344- RawData := HTTPClient.Get('http://checkip.dyndns.org');
345- // adjust for expected output; we just capture the first IP address now:
346- IPRegex.Expression := '\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\b';
347- //or '\b(?:\d{1,3}\.){3}\d{1,3}\b'
348- if IPRegex.Exec(RawData) then
349- Result := IPRegex.Match[0]
350- else
351- Result := 'Got invalid results getting external IP address. Details:'
352- + LineEnding + RawData;
353- except
354- on E: Exception do
355- begin
356- Result := 'Error retrieving external IP address: ' + E.Message;
321+
322+ uses
323+ Classes, SysUtils, fphttpclient, RegExpr;
324+
325+ function GetExternalIPAddress: string;
326+ var
327+ HTTPClient: TFPHTTPClient;
328+ IPRegex: TRegExpr;
329+ RawData: string;
330+ begin
331+ try
332+ HTTPClient := TFPHTTPClient.Create(nil);
333+ IPRegex := TRegExpr.Create;
334+ try
335+ //returns something like:
336+ {
337+ <html><head><title>Current IP Check</title></head><body>Current IP Address: 44.151.191.44</body></html>
338+ }
339+ RawData := HTTPClient.Get('http://checkip.dyndns.org');
340+ // adjust for expected output; we just capture the first IP address now:
341+ IPRegex.Expression := '\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\b';
342+ //or '\b(?:\d{1,3}\.){3}\d{1,3}\b'
343+ if IPRegex.Exec(RawData) then
344+ Result := IPRegex.Match[0]
345+ else
346+ Result := 'Got invalid results getting external IP address. Details:'
347+ + LineEnding + RawData;
348+ except
349+ on E: Exception do
350+ begin
351+ Result := 'Error retrieving external IP address: ' + E.Message;
352+ end;
353+ end;
354+ finally
355+ HTTPClient.Free;
356+ IPRegex.Free;
357357 end;
358358 end;
359- finally
360- HTTPClient.Free;
361- IPRegex.Free;
362- end;
363-end;
364-
365-begin
366- Writeln('External IP address:', GetExternalIPAddress);
367-end.
359+
360+ begin
361+ Writeln('External IP address:', GetExternalIPAddress);
362+ end.
368363```
369364
370365### Translate text using Google Translate
371366
372367See [[Using Google Translate]]
373368
374369## See also
375370
376-- [[macOS NSURLConnection]]
377-- [[macOS NSURLSession]]
378-- [[macOS Programming Tips|macOS OpenSSL, LibreSSL, Secure Transport, Network Framework]]
379-- [[Windows Programming Tips|Windows native WinInet API]]
371+ * [[macOS NSURLConnection]]
372+ * [[macOS NSURLSession]]
373+ * [[macOS Programming Tips|macOS OpenSSL, LibreSSL, Secure Transport, Network Framework]]
374+ * [[Windows Programming Tips|Windows native WinInet API]]
380375
381376## External links
382377
383-- [fpHTTPClient Tutorial](http://lazplanet.blogspot.com/2019/03/how-to-get-contents-of-url-in-2-ways.html).
378+ * [fpHTTPClient Tutorial](<http://lazplanet.blogspot.com/2019/03/how-to-get-contents-of-url-in-2-ways.html>).
384379
385380---
386-*From the Free Pascal wiki, page "fphttpclient", as it stood on 2023-04-06 after a change by Egsuh, out of the wiki's dump of 2024-05-26. Copyright stays with the author who wrote it, according to the old wiki's [[Licensing]] page. If you have concerns about this material, [message the admin](/wiki-contact).*
387-Category: Code Snippets
388-Category: FPC
389-Category: Networking
381+*From the Free Pascal wiki, page "fphttpclient", as the Internet Archive kept it on 2026-08-15, last changed on 2026-05-22. Copyright stays with the author who wrote it, according to the old wiki's [[Licensing]] page. If you have concerns about this material, [message the admin](/wiki-contact).*

Back to history