-
-
Notifications
You must be signed in to change notification settings - Fork 367
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
6d22cf6
commit 8ac772f
Showing
9 changed files
with
1,356 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,138 @@ | ||
unit ControllerU; | ||
|
||
interface | ||
|
||
uses | ||
MVCFramework, MVCFramework.Commons, MVCFramework.Serializer.Commons, System.Generics.Collections, | ||
System.Classes; | ||
|
||
type | ||
[MVCPath('/api')] | ||
TMyController = class(TMVCController) | ||
public | ||
[MVCPath('/files/($FileName)')] | ||
[MVCHTTPMethod([httpGET])] | ||
function GetFileByName(const FileName: String): TStream; | ||
|
||
[MVCPath('/files2/($FileName)')] | ||
[MVCHTTPMethod([httpGET])] | ||
procedure GetStreamByFileName(const FileName: String); | ||
end; | ||
|
||
implementation | ||
|
||
uses | ||
System.SysUtils, | ||
System.IOUtils, | ||
MVCFramework.Logger, | ||
System.StrUtils; | ||
|
||
{ TMyController } | ||
|
||
{ | ||
This action show how to return binary contents using a functional action (the action is a function) | ||
} | ||
function TMyController.GetFileByName(const FileName: String): TStream; | ||
var | ||
lPath: String; | ||
lExt: String; | ||
begin | ||
lPath := TPath.Combine(TPath.Combine(TDirectory.GetParent(AppPath), 'files_repository'), FileName); | ||
lPath := TPath.GetFullPath(lPath); | ||
if not lPath.StartsWith(AppPath) then // directory traversal check | ||
begin | ||
raise EMVCException.Create(HTTP_STATUS.BadRequest, 'Invalid path'); | ||
end; | ||
|
||
LogD(Context.QualifiedClassName + ': ' + lPath); | ||
|
||
if not TFile.Exists(lPath) then | ||
begin | ||
raise EMVCException.Create(HTTP_STATUS.NotFound, 'File not found'); | ||
end; | ||
|
||
lExt := TPath.GetExtension(lPath).ToLower; | ||
|
||
if lExt = '.jpg' then | ||
begin | ||
Context.Response.ContentType := TMVCMediaType.IMAGE_JPEG; | ||
end | ||
else if lExt = '.txt' then | ||
begin | ||
Context.Response.ContentType := TMVCMediaType.TEXT_PLAIN; | ||
end | ||
else if lExt = '.pdf' then | ||
begin | ||
Context.Response.ContentType := TMVCMediaType.APPLICATION_PDF; | ||
end | ||
else if lExt = '.png' then | ||
begin | ||
Context.Response.ContentType := TMVCMediaType.IMAGE_PNG; | ||
end | ||
else if lExt = '.html' then | ||
begin | ||
Context.Response.ContentType := TMVCMediaType.TEXT_HTML; | ||
end | ||
else | ||
begin | ||
Context.Response.ContentType := TMVCMediaType.APPLICATION_OCTET_STREAM; | ||
end; | ||
StatusCode := HTTP_STATUS.OK; | ||
Result := TFileStream.Create(lPath, fmOpenRead, fmShareDenyNone) | ||
end; | ||
|
||
|
||
{ | ||
This action show how to return binary contents using a classic action (the action is a procedure) | ||
} | ||
procedure TMyController.GetStreamByFileName(const FileName: String); | ||
var | ||
lPath: String; | ||
lExt: String; | ||
begin | ||
lPath := TPath.Combine(TPath.Combine(TDirectory.GetParent(AppPath), 'files_repository'), FileName); | ||
lPath := TPath.GetFullPath(lPath); | ||
if not lPath.StartsWith(AppPath) then // directory traversal check | ||
begin | ||
raise EMVCException.Create(HTTP_STATUS.BadRequest, 'Invalid path'); | ||
end; | ||
|
||
LogD(Context.QualifiedClassName + ': ' + lPath); | ||
|
||
if not TFile.Exists(lPath) then | ||
begin | ||
raise EMVCException.Create(HTTP_STATUS.NotFound, 'File not found'); | ||
end; | ||
|
||
lExt := TPath.GetExtension(lPath).ToLower; | ||
|
||
if lExt = '.jpg' then | ||
begin | ||
Context.Response.ContentType := TMVCMediaType.IMAGE_JPEG; | ||
end | ||
else if lExt = '.txt' then | ||
begin | ||
Context.Response.ContentType := TMVCMediaType.TEXT_PLAIN; | ||
end | ||
else if lExt = '.pdf' then | ||
begin | ||
Context.Response.ContentType := TMVCMediaType.APPLICATION_PDF; | ||
end | ||
else if lExt = '.png' then | ||
begin | ||
Context.Response.ContentType := TMVCMediaType.IMAGE_PNG; | ||
end | ||
else if lExt = '.html' then | ||
begin | ||
Context.Response.ContentType := TMVCMediaType.TEXT_HTML; | ||
end | ||
else | ||
begin | ||
Context.Response.ContentType := TMVCMediaType.APPLICATION_OCTET_STREAM; | ||
end; | ||
StatusCode := HTTP_STATUS.OK; | ||
SendFile(lPath); | ||
end; | ||
|
||
end. | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
object MyWebModule: TMyWebModule | ||
OnCreate = WebModuleCreate | ||
OnDestroy = WebModuleDestroy | ||
Actions = <> | ||
Height = 230 | ||
Width = 415 | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,82 @@ | ||
unit WebModuleU; | ||
|
||
interface | ||
|
||
uses | ||
System.SysUtils, | ||
System.Classes, | ||
Web.HTTPApp, | ||
MVCFramework; | ||
|
||
type | ||
TMyWebModule = class(TWebModule) | ||
procedure WebModuleCreate(Sender: TObject); | ||
procedure WebModuleDestroy(Sender: TObject); | ||
private | ||
fMVC: TMVCEngine; | ||
end; | ||
|
||
var | ||
WebModuleClass: TComponentClass = TMyWebModule; | ||
|
||
implementation | ||
|
||
{$R *.dfm} | ||
|
||
uses | ||
System.IOUtils, | ||
MVCFramework.Commons, | ||
MVCFramework.Middleware.ActiveRecord, | ||
MVCFramework.Middleware.StaticFiles, | ||
MVCFramework.Middleware.Analytics, | ||
MVCFramework.Middleware.Trace, | ||
MVCFramework.Middleware.CORS, | ||
MVCFramework.Middleware.ETag, | ||
MVCFramework.Middleware.Compression, ControllerU; | ||
|
||
procedure TMyWebModule.WebModuleCreate(Sender: TObject); | ||
begin | ||
FMVC := TMVCEngine.Create(Self, | ||
procedure(Config: TMVCConfig) | ||
begin | ||
// session timeout (0 means session cookie) | ||
Config[TMVCConfigKey.SessionTimeout] := dotEnv.Env('dmvc.session_timeout', '0'); | ||
//default content-type | ||
Config[TMVCConfigKey.DefaultContentType] := dotEnv.Env('dmvc.default.content_type', TMVCConstants.DEFAULT_CONTENT_TYPE); | ||
//default content charset | ||
Config[TMVCConfigKey.DefaultContentCharset] := dotEnv.Env('dmvc.default.content_charset', TMVCConstants.DEFAULT_CONTENT_CHARSET); | ||
//unhandled actions are permitted? | ||
Config[TMVCConfigKey.AllowUnhandledAction] := dotEnv.Env('dmvc.allow_unhandled_actions', 'false'); | ||
//enables or not system controllers loading (available only from localhost requests) | ||
Config[TMVCConfigKey.LoadSystemControllers] := dotEnv.Env('dmvc.load_system_controllers', 'true'); | ||
//default view file extension | ||
Config[TMVCConfigKey.DefaultViewFileExtension] := dotEnv.Env('dmvc.default.view_file_extension', 'html'); | ||
//view path | ||
Config[TMVCConfigKey.ViewPath] := dotEnv.Env('dmvc.view_path', 'templates'); | ||
//use cache for server side views (use "false" in debug and "true" in production for faster performances | ||
Config[TMVCConfigKey.ViewCache] := dotEnv.Env('dmvc.view_cache', 'false'); | ||
//Max Record Count for automatic Entities CRUD | ||
Config[TMVCConfigKey.MaxEntitiesRecordCount] := dotEnv.Env('dmvc.max_entities_record_count', IntToStr(TMVCConstants.MAX_RECORD_COUNT)); | ||
//Enable Server Signature in response | ||
Config[TMVCConfigKey.ExposeServerSignature] := dotEnv.Env('dmvc.expose_server_signature', 'false'); | ||
//Enable X-Powered-By Header in response | ||
Config[TMVCConfigKey.ExposeXPoweredBy] := dotEnv.Env('dmvc.expose_x_powered_by', 'true'); | ||
// Max request size in bytes | ||
Config[TMVCConfigKey.MaxRequestSize] := dotEnv.Env('dmvc.max_request_size', IntToStr(TMVCConstants.DEFAULT_MAX_REQUEST_SIZE)); | ||
end); | ||
|
||
// Controllers | ||
FMVC.AddController(TMyController); | ||
// Controllers - END | ||
|
||
// Middleware | ||
// Middleware - END | ||
|
||
end; | ||
|
||
procedure TMyWebModule.WebModuleDestroy(Sender: TObject); | ||
begin | ||
FMVC.Free; | ||
end; | ||
|
||
end. |
File renamed without changes
File renamed without changes
File renamed without changes
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,83 @@ | ||
program render_binary_contents; | ||
|
||
{$APPTYPE CONSOLE} | ||
|
||
uses | ||
System.SysUtils, | ||
Web.ReqMulti, | ||
Web.WebReq, | ||
Web.WebBroker, | ||
IdContext, | ||
IdHTTPWebBrokerBridge, | ||
MVCFramework, | ||
MVCFramework.Logger, | ||
MVCFramework.DotEnv, | ||
MVCFramework.Commons, | ||
MVCFramework.Serializer.Commons, | ||
MVCFramework.Signal, | ||
ControllerU in 'ControllerU.pas', | ||
WebModuleU in 'WebModuleU.pas' {MyWebModule: TWebModule}; | ||
|
||
{$R *.res} | ||
|
||
procedure RunServer(APort: Integer); | ||
var | ||
LServer: TIdHTTPWebBrokerBridge; | ||
begin | ||
LServer := TIdHTTPWebBrokerBridge.Create(nil); | ||
try | ||
LServer.OnParseAuthentication := TMVCParseAuthentication.OnParseAuthentication; | ||
LServer.DefaultPort := APort; | ||
LServer.KeepAlive := dotEnv.Env('dmvc.indy.keep_alive', True); | ||
LServer.MaxConnections := dotEnv.Env('dmvc.webbroker.max_connections', 0); | ||
LServer.ListenQueue := dotEnv.Env('dmvc.indy.listen_queue', 500); | ||
LServer.Active := True; | ||
LogI('Listening on port ' + APort.ToString); | ||
LogI('Application started. Press Ctrl+C to shut down.'); | ||
WaitForTerminationSignal; | ||
EnterInShutdownState; | ||
LServer.Active := False; | ||
finally | ||
LServer.Free; | ||
end; | ||
end; | ||
|
||
begin | ||
{ Enable ReportMemoryLeaksOnShutdown during debug } | ||
// ReportMemoryLeaksOnShutdown := True; | ||
IsMultiThread := True; | ||
|
||
// DMVCFramework Specific Configurations | ||
// When MVCSerializeNulls = True empty nullables and nil are serialized as json null. | ||
// When MVCSerializeNulls = False empty nullables and nil are not serialized at all. | ||
MVCSerializeNulls := True; | ||
|
||
// MVCNameCaseDefault defines the name case of property names generated by the serializers. | ||
// Possibile values are: ncAsIs, ncUpperCase, ncLowerCase (default), ncCamelCase, ncPascalCase, ncSnakeCase | ||
MVCNameCaseDefault := TMVCNameCase.ncLowerCase; | ||
|
||
// UseConsoleLogger defines if logs must be emitted to also the console (if available). | ||
UseConsoleLogger := True; | ||
|
||
LogI('** DMVCFramework Server ** build ' + DMVCFRAMEWORK_VERSION); | ||
|
||
try | ||
if WebRequestHandler <> nil then | ||
WebRequestHandler.WebModuleClass := WebModuleClass; | ||
|
||
WebRequestHandlerProc.MaxConnections := dotEnv.Env('dmvc.handler.max_connections', 1024); | ||
|
||
{$IF CompilerVersion >= 34} //SYDNEY+ | ||
if dotEnv.Env('dmvc.profiler.enabled', false) then | ||
begin | ||
Profiler.ProfileLogger := Log; | ||
Profiler.WarningThreshold := dotEnv.Env('dmvc.profiler.warning_threshold', 2000); | ||
end; | ||
{$ENDIF} | ||
|
||
RunServer(dotEnv.Env('dmvc.server.port', 8080)); | ||
except | ||
on E: Exception do | ||
LogF(E.ClassName + ': ' + E.Message); | ||
end; | ||
end. |
Oops, something went wrong.