-
Notifications
You must be signed in to change notification settings - Fork 37
Static file request support #20
Comments
Other day I tried to use static files. I had seen fpmimetypes and even tried to improve the brookhttpapp broker, but, unfortunately, fpmimetypes is coupled in fpweb. :( His solution seems the best to use fpmimetypes. Can you to create a small example and provide it on the demos folder? Thanks. |
This is as general as I can make: unit Static;
{$mode objfpc}{$H+}
interface
uses
Classes, SysUtils;
// This is the only thing that user may know from this unit
procedure RegisterDirectory(ARequestPath,ADirectory: String);
implementation
uses
StrUtils, ghashmap, fpmimetypes, HTTPDefs, BrookAction;
resourcestring
EmptyRequestPathErrMsg = 'Request path may not be empty';
DirectoryNotExistErrMsg = 'Directory not exists: %s';
type
{ TStringHash }
TStringHash = class
class function hash(s: String; n: Integer): Integer;
end;
TRequestDirectoryMap = specialize THashmap<String,String,TStringHash>;
{ TStaticFileAction }
TStaticFileAction = class(TBrookAction)
public
procedure Get; override;
end;
var
RequestDirectoryMap: TRequestDirectoryMap;
{ TStringHash }
class function TStringHash.hash(s: String; n: Integer): Integer;
var
c: Char;
begin
Result := 0;
for c in LowerCase(s) do
Inc(Result,Ord(c));
Result := Result mod n;
end;
{ TStaticFileAction }
procedure TStaticFileAction.Get;
var
LastSlashPos: Integer;
PathInfo,FilePath,Buffer: String;
ContentType: String;
begin
PathInfo := GetRequest.PathInfo;
LastSlashPos := RPos('/',PathInfo);
System.Delete(PathInfo,LastSlashPos + 1,Length(PathInfo) - LastSlashPos);
FilePath := RequestDirectoryMap[PathInfo] + Values['file'].AsString;
if FileExists(FilePath) then begin
ContentType := MimeTypes.GetMimeType(ExtractFileExt(FilePath));
if ContentType = '' then
ContentType := 'application/octet-stream';
GetResponse.ContentType := ContentType;
with TFileStream.Create(FilePath,fmOpenRead) do
try
SetLength(Buffer,Size);
Read(Buffer[1],Size);
Self.Write(Buffer);
finally
Free;
end;
end;
end;
procedure RegisterDirectory(ARequestPath,ADirectory: String);
begin
if Length(ARequestPath) = 0 then raise Exception.Create(EmptyRequestPathErrMsg);
if not DirectoryExists(ADirectory) then raise Exception.CreateFmt(DirectoryNotExistErrMsg,[ADirectory]);
// add required slashes
if ARequestPath[1] <> '/' then ARequestPath := '/' + ARequestPath;
if ARequestPath[Length(ARequestPath)] <> '/' then ARequestPath := ARequestPath + '/';
RequestDirectoryMap[ARequestPath] := IncludeTrailingPathDelimiter(ADirectory);
TStaticFileAction.Register(ARequestPath + ':file');
end;
initialization
RequestDirectoryMap := TRequestDirectoryMap.Create;
finalization
RequestDirectoryMap.Free;
end. The responsibility is now leveraged to the user of this unit to call: MimeTypes.LoadFromFile('mime.types'); // for correct content-type
RegisterDirectory('css','/full/path/to/css');
RegisterDirectory('js','relative/path/may/work/js');
RegisterDirectory('img','/top/level/images');
RegisterDirectory('img/messages','/top/level/images/messages');
I'll make a simple demo, but I need to know where to put this unit and what better name it should have. Note that as the example |
Friend, I'll make a demo with this nice code and provides it on the demos folder. :) It would be interesting implement a broker for use this together with BrookFCLHTTPAppBroker/BrookFCLHTTPDaemonBroker broker. |
Do you mean to have 2 brokers active at the same time? Is that possible? |
Yep. Eg:
Or (pseudo code):
Can you implement this idea? Feel free if yes! :) |
Hmm... I'll have to dig in the code first, I'm not sure how 2 brokers can be active at the same time... |
you can use as much brokers as you want at the same time providing you dont implement the same service more than once, otherwise it'd lead to ambiguity or something like "service already registered" error. |
Yes, that's what I'm afraid of. For mimetypes broker, it should be easy as it doesn't deal with request handling. But static file request broker will do request handling in the same way as CGI/FCGI/HTTPApp/DaemonApp broker (actually, it's the sub of them as it depends on either of them). So could I simply use Static unit implementation above renamed as BrookStaticFileBroker? |
BrookStaticFileBroker (so, StaticFile or StaticFiles? :/ ) is a good name for this new broker.
Interesting? |
Too much user code IMO, better just register directory and corresponding request path. |
Hi trying to get the static unit to work, but where do I find the mime.types file? Nevermind, copied it from a linux box. |
In case anybody need one: https://dl.dropboxusercontent.com/u/22124591/mime.types |
Done. (1251c7c) @leledumbo , can you upload to working branch a very small sample showing how to use the "brookstaticfilebroker.pas" unit please? |
Will do tonight if I'm not exhausted EDIT: Done, but I think I did something wrong, please check |
I saw and it worked fine on my Win8 64. It is a nice demo. :) I refactored some code and also updated the brokers unit for can compile the project. Please check if the current implementation in brookstaticfilebroker unit is the last implementation that you was implemented. I renamed the register method too. |
Yep, that seems so. |
Thank you very much! :) |
fpweb has fpwebfile that defines default request for static files. I currently define my own action for this:
Is there any better way?
The text was updated successfully, but these errors were encountered: