Repository URL to install this package:
Version:
3.0.0 ▾
|
{$mode objfpc}
{$h+}
unit fpwebfile;
interface
uses SysUtils, Classes, httpdefs, fphttp;
Type
TFPCustomFileModule = Class(TCustomHTTPModule)
Protected
// Determine filename frome request.
Function GetRequestFileName(Const ARequest : TRequest) : String; virtual;
// Map request filename to physical filename.
Function MapFileName(Const AFileName : String) : String; virtual;
// Override to implement security. Returns true by default.
Function AllowFile(Const AFileName : String) : Boolean; virtual;
// Actually Send file to client.
Procedure SendFile(Const AFileName : String; AResponse : TResponse); virtual;
// Overrides TCustomHTTPModule to implement file serving.
Procedure HandleRequest(ARequest : TRequest; AResponse : TResponse); override;
end;
TFPCustomFileModuleClass = Class of TFPCustomFileModule;
Var
// Set this if you want a descendent class to serve the files.
// You can use this to customize the behaviour in the descendent, for instance if you have multiple virtual hosts.
DefaultFileModuleClass : TFPCustomFileModuleClass = TFPCustomFileModule;
// Setting this will load mime types from that file.
MimeTypesFile : string;
// use this to map locations (relative to BaseURL of the application) to physical directories.
// More than one location can be registered. Directory must exist, location must not have / or \
Procedure RegisterFileLocation(Const ALocation,ADirectory : String);
implementation
uses fpmimetypes;
Resourcestring
SErrNoLocation = 'Cannot register an empty location.';
SErrInvalidLocation = 'Location contains invalid characters.';
SErrInvalidDirectory = 'Directory "%s" does not exist';
Var
Locations : TStrings;
MimeLoaded : Boolean;
Procedure CheckMimeLoaded;
begin
If (Not MimeLoaded) and (MimeTypesFile<>'') then
begin
MimeTypes.LoadFromFile(MimeTypesFile);
MimeLoaded:=true;
end;
end;
Procedure RegisterFileLocation(Const ALocation,ADirectory : String);
begin
if (ALocation='') then
Raise HTTPError.Create(SErrNoLocation);
if Pos('/',ALocation)<>0 then
Raise HTTPError.Create(SErrInvalidLocation);
if not DirectoryExists(ADirectory) then
Raise HTTPError.Create(SErrInvalidDirectory);
if (Locations=Nil) then
Locations:=TStringList.Create;
if DefaultFileModuleClass=Nil then
DefaultFileModuleClass:=TFPCustomFileModule;
if (ADirectory='') then
Locations.Values[IncludeHTTPPathDelimiter(ALocation)]:=ExtractFilePath(ParamStr(0))
else
Locations.Values[IncludeHTTPPathDelimiter(ALocation)]:=IncludeTrailingPathDelimiter(ADirectory);
RegisterHTTPModule(ALocation,DefaultFileModuleClass,true);
end;
Function TFPCustomFileModule.GetRequestFileName(Const ARequest : TRequest) : String;
procedure sb;
begin
If (Result<>'') and (Result[1]='/') then
Delete(Result,1,1);
end;
begin
Result:=ARequest.PathInfo;
If (Result='') then
Result:=ARequest.URI;
sb;
If (BaseURL<>'') and (Pos(BaseURL,Result)=1) then
Delete(Result,1,Length(BaseURL));
sb;
end;
Function TFPCustomFileModule.MapFileName(Const AFileName : String) : String;
Var
D : String;
begin
if (BaseURL='') then
Result:=AFileName
else
begin
D:=Locations.Values[BaseURL];
If (D='') then
Result:=''
else
begin
Result:=D+AFileName;
DoDirSeparators(Result);
end;
end;
end;
Function TFPCustomFileModule.AllowFile(Const AFileName : String) : Boolean;
begin
Result:=True;
end;
procedure TFPCustomFileModule.SendFile(Const AFileName : String; AResponse : TResponse);
Var
F : TFileStream;
begin
CheckMimeLoaded;
AResponse.ContentType:=MimeTypes.GetMimeType(ExtractFileExt(AFileName));
If (AResponse.ContentType='') then
AResponse.ContentType:='Application/octet-stream';
F:=TFileStream.Create(AFileName,fmOpenRead or fmShareDenyWrite);
try
AResponse.ContentLength:=F.Size;
AResponse.ContentStream:=F;
AResponse.SendContent;
AResponse.ContentStream:=Nil;
finally
F.Free;
end;
end;
Procedure TFPCustomFileModule.HandleRequest(ARequest : TRequest; AResponse : TResponse);
Var
RFN,FN : String;
begin
If CompareText(ARequest.Method,'GET')<>0 then
begin
AResponse.Code:=405;
AResponse.CodeText:='Method not allowed';
AResponse.SendContent;
Exit;
end;
RFN:=GetRequestFileName(ARequest);
if (RFN='') then
begin
AResponse.Code:=400;
AResponse.CodeText:='Bad request';
AResponse.SendContent;
exit;
end;
FN:=MapFileName(RFN);
if (FN='') or not FileExists(FN) then
begin
AResponse.Code:=404;
AResponse.CodeText:='Not found';
AResponse.SendContent;
exit;
end;
if not AllowFile(FN) then
begin
AResponse.Code:=403;
AResponse.CodeText:='Forbidden';
AResponse.SendContent;
exit;
end;
SendFile(FN,AResponse);
end;
initialization
finalization
FreeAndNil(Locations);
end.