Difference between revisions of "fpwebfile"

From Lazarus wiki
Jump to navigationJump to search
(Created page with "== Intro == fpwebfile is a unit with a simple HTTP module (''TFPCustomFileModule'' and ''TSimpleFileModule'') to serve files in fcl-web. You don't need to do anything excep...")
 
Line 12: Line 12:
 
=== Various locations ===
 
=== Various locations ===
 
To serve files from a location, all you need to do is call '''RegisterFileLocation''':
 
To serve files from a location, all you need to do is call '''RegisterFileLocation''':
<pre>
+
<syntaxhighlight lang="pascal">
 
Procedure RegisterFileLocation(Const ALocation,ADirectory : String);
 
Procedure RegisterFileLocation(Const ALocation,ADirectory : String);
</pre>
+
</syntaxhighlight>
  
 
like so:
 
like so:
<pre>
+
<syntaxhighlight lang="pascal">
 
   RegisterFileLocation('home','/home/myuser/public_html');
 
   RegisterFileLocation('home','/home/myuser/public_html');
</pre>
+
</syntaxhighlight>
 
after this call, an url
 
after this call, an url
 
<pre>
 
<pre>
Line 30: Line 30:
  
 
You can stop serving files with '''UnRegisterFileLocation'''
 
You can stop serving files with '''UnRegisterFileLocation'''
<pre>
+
<syntaxhighlight lang="pascal">
 
Procedure UnRegisterFileLocation(Const ALocation: String);
 
Procedure UnRegisterFileLocation(Const ALocation: String);
</pre>
+
</syntaxhighlight>
 
like this:
 
like this:
<pre>
+
<syntaxhighlight lang="pascal">
 
   UnRegisterFileLocation('home');
 
   UnRegisterFileLocation('home');
</pre>
+
</syntaxhighlight>
  
 
=== Default location ===
 
=== Default location ===
Line 45: Line 45:
  
 
However, to serve this kind of file anyway, the '''TSimpleFileModule''' can be registered as the default route:
 
However, to serve this kind of file anyway, the '''TSimpleFileModule''' can be registered as the default route:
<pre>
+
<syntaxhighlight lang="pascal">
 
Class Procedure TSimpleFileModule.RegisterDefaultRoute(OverAllDefault : Boolean = True);
 
Class Procedure TSimpleFileModule.RegisterDefaultRoute(OverAllDefault : Boolean = True);
</pre>
+
</syntaxhighlight>
 
when invoked like this:
 
when invoked like this:
<pre>
+
<syntaxhighlight lang="pascal">
 
TSimpleFileModule.BaseDir:='/home/myuser/public_html/';
 
TSimpleFileModule.BaseDir:='/home/myuser/public_html/';
 
TSimpleFileModule.RegisterDefaultRoute;
 
TSimpleFileModule.RegisterDefaultRoute;
</pre>
+
</syntaxhighlight>
 
The URL
 
The URL
 
<pre>
 
<pre>
Line 64: Line 64:
 
</pre>
 
</pre>
 
You can tell the '''TSimpleFileModule''' to serve file ''index.html'' by setting  
 
You can tell the '''TSimpleFileModule''' to serve file ''index.html'' by setting  
<pre>
+
<syntaxhighlight lang="pascal">
 
TSimpleFileModule.IndexPageName:='index.html';
 
TSimpleFileModule.IndexPageName:='index.html';
</pre>
+
</syntaxhighlight>
  
 
You can mix ''RegisterFileLocation'' and ''TSimpleFileModule.RegisterDefaultRoute''.  
 
You can mix ''RegisterFileLocation'' and ''TSimpleFileModule.RegisterDefaultRoute''.  
Line 84: Line 84:
  
 
The class can be registered with the followin class method:
 
The class can be registered with the followin class method:
<pre>
+
<syntaxhighlight lang="pascal">
 
Class procedure RegisterFileLocationAPI(Const aPath,aPassword : String);
 
Class procedure RegisterFileLocationAPI(Const aPath,aPassword : String);
</pre>
+
</syntaxhighlight>
  
 
For example, the following call:
 
For example, the following call:
<pre>
+
<syntaxhighlight lang="pascal">
 
TFPWebFileLocationAPIModule.RegisterFileLocationAPI('_locations','mysecret');
 
TFPWebFileLocationAPIModule.RegisterFileLocationAPI('_locations','mysecret');
</pre>
+
</syntaxhighlight>
 
Will enable the following REST URL:
 
Will enable the following REST URL:
 
<pre>
 
<pre>
Line 178: Line 178:
 
=== File serving ===  
 
=== File serving ===  
 
If you want to customize the request treatment, you can always create a descendant of the ''TSimpleFileModule'' class and register that:
 
If you want to customize the request treatment, you can always create a descendant of the ''TSimpleFileModule'' class and register that:
<pre>
+
<syntaxhighlight lang="pascal">
 
TSimpleFileModule.DefaultSimpleFileModuleClass:=TMySimpleFileModule;
 
TSimpleFileModule.DefaultSimpleFileModuleClass:=TMySimpleFileModule;
</pre>
+
</syntaxhighlight>
 
requests will be handled by creating an instance of <var>TMySimpleFileModule</var> for each file served.
 
requests will be handled by creating an instance of <var>TMySimpleFileModule</var> for each file served.
  
Line 186: Line 186:
 
=== API ===  
 
=== API ===  
 
Similarly if you want to customize the API request treatment, you can always create a descendant of the ''TFPWebFileLocationAPIModule'' class and register that:
 
Similarly if you want to customize the API request treatment, you can always create a descendant of the ''TFPWebFileLocationAPIModule'' class and register that:
<pre>
+
<syntaxhighlight lang="pascal">
 
TFPWebFileLocationAPIModule.LocationAPIModuleClass:=TMyFileAPIModule;
 
TFPWebFileLocationAPIModule.LocationAPIModuleClass:=TMyFileAPIModule;
</pre>
+
</syntaxhighlight>
 
requests will be handled by creating an instance of <var>TMyFileAPIModule</var> for each API request.
 
requests will be handled by creating an instance of <var>TMyFileAPIModule</var> for each API request.
  

Revision as of 15:59, 4 September 2021

Intro

fpwebfile is a unit with a simple HTTP module (TFPCustomFileModule and TSimpleFileModule) to serve files in fcl-web.

You don't need to do anything except register a location from which to serve files. The module does the rest.

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.

Usage

Various locations

To serve files from a location, all you need to do is call RegisterFileLocation:

Procedure RegisterFileLocation(Const ALocation,ADirectory : String);

like so:

  RegisterFileLocation('home','/home/myuser/public_html');

after this call, an url

http://localhost:8080/home/index.html

will attempt to serve the file

/home/myuser/public_html/index.html

You can stop serving files with UnRegisterFileLocation

Procedure UnRegisterFileLocation(Const ALocation: String);

like this:

  UnRegisterFileLocation('home');

Default location

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:

http://localhost:8080/index.html

However, to serve this kind of file anyway, the TSimpleFileModule can be registered as the default route:

Class Procedure TSimpleFileModule.RegisterDefaultRoute(OverAllDefault : Boolean = True);

when invoked like this:

TSimpleFileModule.BaseDir:='/home/myuser/public_html/';
TSimpleFileModule.RegisterDefaultRoute;

The URL

http://localhost:8080/index.html

will be correctly served.

If the URL does not contain a document, but only a directory:

http://localhost:8080/

You can tell the TSimpleFileModule to serve file index.html by setting

TSimpleFileModule.IndexPageName:='index.html';

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.

Registration order

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.

When you use both RegisterFileLocation and TSimpleFileModule.RegisterDefaultRoute, then the locations created with RegisterFileLocation will always be checked before the default route.

API

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.

The class can be registered with the followin class method:

Class procedure RegisterFileLocationAPI(Const aPath,aPassword : String);

For example, the following call:

TFPWebFileLocationAPIModule.RegisterFileLocationAPI('_locations','mysecret');

Will enable the following REST URL:

http://localhost:8080/_locations/

If a password was supplied in the RegisterFileLocationAPI call, you must authenticate requests to the locations endpoint.

This can be done in one of 2 ways:

  1. Provide the key with the APIKey query variable.
  2. Or provide the key as an Authorization bearer token.

The first way results in an URL like this:

http://localhost:3003/_locations/?APIKey=mysecret

For the second way, the following header must be added to the request

Authorization: Bearer mysecret

The 4 CRUD operations are supported in the REST API.

GET

use the GET command to get a list of locations:

wget -q 'http://localhost:3003/_locations/?APIKey=mysecret&fmt=1' -O -

This will result in something like

{
  "data" : [
    {
      "location" : "tmp",
      "path" : "/tmp/"
    },
    {
      "location" : "*",
      "path" : "/home/michael/public_html/"
    }
  ]
}

if you omit the fmt=1 query parameter then the returned JSON will not be formatted.

POST

a POST command will register a new location. The content-type must be application/json, and the payload a JSON object with 2 keys:

location
the name of the location
path
the directory for the location

Several checks are done:

  1. The path must exist and be a directory.
  2. The location name may not be empty.
  3. The location name may not contain / characters.
  4. The location name may not yet be registered.

So, for example, the above 'tmp' location may be registered as:

wget -q --post-data='{ "location" : "tmp", "path": "/tmp" }' \
  --header="Content-Type: application/json" \
  'http://localhost:3003/_locations/?APIKey=mysecret&fmt=1' -O -

if all went well, the output is the new location:

{ "location" : "tmp", "path" : "/tmp" }

PUT

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:

wget -q --post-data='{ "path": "/tmp2" }' \
  --header="Content-Type: application/json" \
  --method=PUT 'http://localhost:3003/_locations/tmp?APIKey=mysecret&fmt=1' -O -

If the location element is present in the payload, it will be used to rename the location.

DELETE

a DELETE command will delete an existing location. No payload must be present.

wget -q --method=DELETE 'http://localhost:3003/_locations/tmp?APIKey=mysecret&fmt=1' -O -

If the location element is present in the payload, it will be used to rename the location.

Customization

File serving

If you want to customize the request treatment, you can always create a descendant of the TSimpleFileModule class and register that:

TSimpleFileModule.DefaultSimpleFileModuleClass:=TMySimpleFileModule;

requests will be handled by creating an instance of TMySimpleFileModule for each file served.

You can use this for example to implement authentication or file filtering.

API

Similarly if you want to customize the API request treatment, you can always create a descendant of the TFPWebFileLocationAPIModule class and register that:

TFPWebFileLocationAPIModule.LocationAPIModuleClass:=TMyFileAPIModule;

requests will be handled by creating an instance of TMyFileAPIModule for each API request.

CORS Considerations

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.