Sign in Join
Wiki copytemporary

fpwebfile: what changed

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

Title: fpwebfile

OldNewLine
1+## Intro
2+
3+fpwebfile is a unit with a simple HTTP module (*TFPCustomFileModule* and *TSimpleFileModule*) to serve files in fcl-web.
4+
5+You don't need to do anything except register a location from which to serve files. The module does the rest.
6+
7+The unit also has a *TFPWebFileLocationAPIModule* module which allows to remotely manage the file locations which are served by the *TSimpleFileModule* class in a JSON & REST fashion.
8+
9+## Usage
10+
11+### Various locations
12+
13+To serve files from a location, all you need to do is call **RegisterFileLocation**:
14+
15+``` pascal
16+Procedure RegisterFileLocation(Const ALocation,ADirectory : String);
17+```
18+
19+like so:
20+
21+``` pascal
22+ RegisterFileLocation('home','/home/myuser/public_html');
23+```
24+
25+after this call, an url
26+
27+ http://localhost:8080/home/index.html
28+
29+will attempt to serve the file
30+
31+ /home/myuser/public_html/index.html
32+
33+You can stop serving files with **UnRegisterFileLocation**
34+
35+``` pascal
36+Procedure UnRegisterFileLocation(Const ALocation: String);
37+```
38+
39+like this:
40+
41+``` pascal
42+ UnRegisterFileLocation('home');
43+```
44+
45+### Default location
46+
47+Note that all paths registered with *RegisterFileLocation* must have a prefix: the name of the location. This means that the following URL cannot be served:
48+
49+ http://localhost:8080/index.html
50+
51+However, to serve this kind of file anyway, the **TSimpleFileModule** can be registered as the default route:
52+
53+``` pascal
54+Class Procedure TSimpleFileModule.RegisterDefaultRoute(OverAllDefault : Boolean = True);
55+```
56+
57+when invoked like this:
58+
59+``` pascal
60+TSimpleFileModule.BaseDir:='/home/myuser/public_html/';
61+TSimpleFileModule.RegisterDefaultRoute;
62+```
63+
64+The URL
65+
66+ http://localhost:8080/index.html
67+
68+will be correctly served.
69+
70+If the URL does not contain a document, but only a directory:
71+
72+ http://localhost:8080/
73+
74+You can tell the **TSimpleFileModule** to serve file *index.html* by setting
75+
76+``` pascal
77+TSimpleFileModule.IndexPageName:='index.html';
78+```
79+
80+You can mix *RegisterFileLocation* and *TSimpleFileModule.RegisterDefaultRoute*. When an URL is checked, the various locations registered with *RegisterFileLocation* will be tried first. If no location matches, the default location will be tried.
81+
82+### Registration order
83+
84+Note that the order in which you register locations is important: the first match on the initial element of the URL path will be used.
85+
86+When you use both *RegisterFileLocation* and *TSimpleFileModule.RegisterDefaultRoute*, then the locations created with *RegisterFileLocation* will always be checked before the default route.
87+
88+## API
89+
90+The *TFPWebFileLocationAPIModule* module is a ready-to-run module which allows to remotely manage the file locations. It is basically a REST interface to the *RegisterFileLocation* and *UnRegisterFileLocation* routines.
91+
92+The class can be registered with the followin class method:
93+
94+``` pascal
95+Class procedure RegisterFileLocationAPI(Const aPath,aPassword : String);
96+```
97+
98+For example, the following call:
99+
100+``` pascal
101+TFPWebFileLocationAPIModule.RegisterFileLocationAPI('_locations','mysecret');
102+```
103+
104+Will enable the following REST URL:
105+
106+ http://localhost:8080/_locations/
107+
108+If a password was supplied in the *RegisterFileLocationAPI* call, you must authenticate requests to the locations endpoint.
109+
110+This can be done in one of 2 ways:
111+
112+1. Provide the key with the APIKey query variable.
113+2. Or provide the key as an Authorization bearer token.
114+
115+The first way results in an URL like this:
116+
117+ http://localhost:3003/_locations/?APIKey=mysecret
118+
119+For the second way, the following header must be added to the request
120+
121+ Authorization: Bearer mysecret
122+
123+The 4 CRUD operations are supported in the REST API.
124+
125+### GET
126+
127+use the GET command to get a list of locations:
128+
129+ wget -q 'http://localhost:3003/_locations/?APIKey=mysecret&fmt=1' -O -
130+
131+This will result in something like
132+
133+ {
134+ "data" : [
135+ {
136+ "location" : "tmp",
137+ "path" : "/tmp/"
138+ },
139+ {
140+ "location" : "*",
141+ "path" : "/home/michael/public_html/"
142+ }
143+ ]
144+ }
145+
146+if you omit the *fmt=1* query parameter then the returned JSON will not be formatted.
147+
148+### POST
149+
150+a *POST* command will register a new location. The content-type must be **application/json**, and the payload a JSON object with 2 keys:
151+
152+location
153+the name of the location
154+
155+path
156+the directory for the location
157+
158+Several checks are done:
159+
160+1. The path must exist and be a directory.
161+2. The location name may not be empty.
162+3. The location name may not contain **/** characters.
163+4. The location name may not yet be registered.
164+
165+So, for example, the above 'tmp' location may be registered as:
166+
167+ wget -q --post-data='{ "location" : "tmp", "path": "/tmp" }' \
168+ --header="Content-Type: application/json" \
169+ 'http://localhost:3003/_locations/?APIKey=mysecret&fmt=1' -O -
170+
171+if all went well, the output is the new location:
172+
173+ { "location" : "tmp", "path" : "/tmp" }
174+
175+Using fphttpclient:
176+
177+``` pascal
178+Uses classes, fphttpclient, fpjson;
179+...
180+ JSON:=TStringStream.Create('{'
181+ +'"location" : "'+StringToJSONString(Location)+'",'
182+ +'"path": "'+StringToJSONString(Path)+'"'
183+ +'}');
184+ Client:=TFPHTTPClient.Create(Nil);
185+ Response:=TMemoryStream.Create;
186+ try
187+ Client.RequestBody:=JSON;
188+ Client.AddHeader('Content-Type','application/json');
189+ Client.HTTPMethod('POST',URL,Response,[201,200]);
190+ Response.Position:=0;
191+ // maybe: check response
192+ finally
193+ Response.Free;
194+ JSON.Free;
195+ Client.Free;
196+ end;
197+```
198+
199+### PUT
200+
201+a *PUT* command will update an existing location. The content-type must be **application/json**, and the payload a JSON object with 1 or 2 keys as for the POST call. The name of the location can be part of the url:
202+
203+ wget -q --post-data='{ "path": "/tmp2" }' \
204+ --header="Content-Type: application/json" \
205+ --method=PUT 'http://localhost:3003/_locations/tmp?APIKey=mysecret&fmt=1' -O -
206+
207+If the *location* element is present in the payload, it will be used to rename the location.
208+
209+### DELETE
210+
211+a *DELETE* command will delete an existing location. No payload must be present.
212+
213+ wget -q --method=DELETE 'http://localhost:3003/_locations/tmp?APIKey=mysecret&fmt=1' -O -
214+
215+If the *location* element is present in the payload, it will be used to rename the location.
216+
217+Using fphttpclient:
218+
219+``` pascal
220+uses classes, fphttpclient;
221+...
222+ URL:='http://127.0.0.1:'+IntToStr(Port)+'/'+APIPath+'/'+Location+'?APIKey='+APIKey+'&fmt=1';
223+ Response:=TMemoryStream.Create;
224+ Client:=TFPHTTPClient.Create(Nil);
225+ try
226+ Client.HTTPMethod('DELETE',URL,Response,[204,200]);
227+ Response.Position:=0;
228+ // maybe: check response
229+ finally
230+ Response.Free;
231+ Client.Free;
232+ end;
233+```
234+
235+## Customization
236+
237+### File serving
238+
239+If you want to customize the request treatment, you can always create a descendant of the *TSimpleFileModule* class and register that:
240+
241+``` pascal
242+TSimpleFileModule.DefaultSimpleFileModuleClass:=TMySimpleFileModule;
243+```
244+
245+requests will be handled by creating an instance of `TMySimpleFileModule` for each file served.
246+
247+You can use this for example to implement authentication or file filtering.
248+
249+### API
250+
251+Similarly if you want to customize the API request treatment, you can always create a descendant of the *TFPWebFileLocationAPIModule* class and register that:
252+
253+``` pascal
254+TFPWebFileLocationAPIModule.LocationAPIModuleClass:=TMyFileAPIModule;
255+```
256+
257+requests will be handled by creating an instance of `TMyFileAPIModule` for each API request.
258+
259+### CORS Considerations
260+
261+The API allows CORS requests by default. You can disable this by creating a descendent and setting *Cors.Enabled* to *False* in the constructor. The file serving mechanism is not CORS enabled.
262+
263+---
264+*From the Free Pascal wiki, page "fpwebfile", as it stood on 2021-09-15 after a change by Mattias2, 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).*

Back to history