|
@@ -19,14 +19,34 @@ unit sqldbrestbridge;
|
|
interface
|
|
interface
|
|
|
|
|
|
uses
|
|
uses
|
|
- Classes, SysUtils, DB, SQLDB, httpdefs, httproute, fpjson, sqldbrestschema, sqldbrestio, sqldbrestdata, sqldbrestauth;
|
|
|
|
|
|
+ Classes, SysUtils, DB, SqlTypes, SQLDB, httpdefs, httproute, fpjson, sqldbrestschema, sqldbrestio, sqldbrestdata, sqldbrestauth;
|
|
|
|
|
|
Type
|
|
Type
|
|
- TRestDispatcherOption = (rdoConnectionInURL,rdoExposeMetadata,rdoCustomView,rdoHandleCORS,rdoAccessCheckNeedsDB);
|
|
|
|
|
|
+ TRestDispatcherOption = (rdoConnectionInURL, // Route includes connection :Connection/:Resource[/:ID]
|
|
|
|
+ rdoExposeMetadata, // expose metadata resource /metadata[/:Resource]
|
|
|
|
+ rdoCustomView, // Expose custom view /customview
|
|
|
|
+ rdoHandleCORS, // Handle CORS requests
|
|
|
|
+ rdoAccessCheckNeedsDB, // Authenticate after connection to database was made.
|
|
|
|
+ rdoConnectionResource // Enable connection managament through /_connection[/:Conn] resource
|
|
|
|
+ // rdoServerInfo // Enable querying server info through /_serverinfo resource
|
|
|
|
+ );
|
|
|
|
+
|
|
TRestDispatcherOptions = set of TRestDispatcherOption;
|
|
TRestDispatcherOptions = set of TRestDispatcherOption;
|
|
|
|
+ TRestDispatcherLogOption = (rloUser, // Include username in log messages, when available
|
|
|
|
+ rtloHTTP, // Log HTTP request (remote, URL)
|
|
|
|
+ rloResource, // Log resource requests (operation, resource)
|
|
|
|
+ rloConnection, // Log database connections (connect to database)
|
|
|
|
+ rloAuthentication, // Log authentication attempt
|
|
|
|
+ rloSQL, // Log SQL statements. (not on user-supplied connection)
|
|
|
|
+ rloResultStatus // Log result status.
|
|
|
|
+ );
|
|
|
|
+ TRestDispatcherLogOptions = Set of TRestDispatcherLogOption;
|
|
|
|
|
|
Const
|
|
Const
|
|
DefaultDispatcherOptions = [rdoExposeMetadata];
|
|
DefaultDispatcherOptions = [rdoExposeMetadata];
|
|
|
|
+ AllDispatcherLogOptions = [Low(TRestDispatcherLogOption)..High(TRestDispatcherLogOption)];
|
|
|
|
+ DefaultDispatcherLogOptions = AllDispatcherLogOptions-[rloSQL];
|
|
|
|
+ DefaultLogSQLOptions = LogAllEvents;
|
|
|
|
|
|
Type
|
|
Type
|
|
|
|
|
|
@@ -45,6 +65,7 @@ Type
|
|
FPassword: UTF8String;
|
|
FPassword: UTF8String;
|
|
FPort: Word;
|
|
FPort: Word;
|
|
FRole: UTF8String;
|
|
FRole: UTF8String;
|
|
|
|
+ FSchemaName: UTF8String;
|
|
FUserName: UTF8String;
|
|
FUserName: UTF8String;
|
|
FNotifier : TComponent;
|
|
FNotifier : TComponent;
|
|
function GetName: UTF8String;
|
|
function GetName: UTF8String;
|
|
@@ -52,6 +73,8 @@ Type
|
|
procedure SetParams(AValue: TStrings);
|
|
procedure SetParams(AValue: TStrings);
|
|
Protected
|
|
Protected
|
|
Function GetDisplayName: string; override;
|
|
Function GetDisplayName: string; override;
|
|
|
|
+ // For use in the REST Connection resource
|
|
|
|
+ Property SchemaName : UTF8String Read FSchemaName Write FSchemaName;
|
|
Public
|
|
Public
|
|
constructor Create(ACollection: TCollection); override;
|
|
constructor Create(ACollection: TCollection); override;
|
|
Destructor Destroy; override;
|
|
Destructor Destroy; override;
|
|
@@ -92,9 +115,9 @@ Type
|
|
procedure SetConn(aIndex : integer; AValue: TSQLDBRestConnection);
|
|
procedure SetConn(aIndex : integer; AValue: TSQLDBRestConnection);
|
|
Public
|
|
Public
|
|
// Index of connection by name (case insensitive)
|
|
// Index of connection by name (case insensitive)
|
|
- Function IndexOfConnection(const aName : string) : Integer;
|
|
|
|
|
|
+ Function IndexOfConnection(const aName : UTF8string) : Integer;
|
|
// Find connection by name (case insensitive), nil if none found
|
|
// Find connection by name (case insensitive), nil if none found
|
|
- Function FindConnection(const aName : string) : TSQLDBRestConnection;
|
|
|
|
|
|
+ Function FindConnection(const aName : UTF8string) : TSQLDBRestConnection;
|
|
// Add new instance, setting basic properties. Return new instance
|
|
// Add new instance, setting basic properties. Return new instance
|
|
Function AddConnection(Const AType,aHostName,aDatabaseName,aUserName,aPassword : UTF8String) : TSQLDBRestConnection;
|
|
Function AddConnection(Const AType,aHostName,aDatabaseName,aUserName,aPassword : UTF8String) : TSQLDBRestConnection;
|
|
// Save connection definitions to JSON file.
|
|
// Save connection definitions to JSON file.
|
|
@@ -142,6 +165,7 @@ Type
|
|
procedure SetSchema(aIndex : Integer; AValue: TSQLDBRestSchemaRef);
|
|
procedure SetSchema(aIndex : Integer; AValue: TSQLDBRestSchemaRef);
|
|
Public
|
|
Public
|
|
Function AddSchema (aSchema : TSQLDBRestSchema) : TSQLDBRestSchemaRef;
|
|
Function AddSchema (aSchema : TSQLDBRestSchema) : TSQLDBRestSchemaRef;
|
|
|
|
+ Function IndexOfSchema(aSchemaName : String) : Integer;
|
|
Property Schemas[aIndex :Integer] : TSQLDBRestSchemaRef Read GetSchema Write SetSchema;default;
|
|
Property Schemas[aIndex :Integer] : TSQLDBRestSchemaRef Read GetSchema Write SetSchema;default;
|
|
end;
|
|
end;
|
|
|
|
|
|
@@ -155,20 +179,25 @@ Type
|
|
TRestExceptionEvent = Procedure(Sender : TObject; aRequest : TRequest; Const AResource : string; E : Exception) of object;
|
|
TRestExceptionEvent = Procedure(Sender : TObject; aRequest : TRequest; Const AResource : string; E : Exception) of object;
|
|
TRestOperationEvent = Procedure(Sender : TObject; aConn: TSQLConnection; aResource : TSQLDBRestResource) of object;
|
|
TRestOperationEvent = Procedure(Sender : TObject; aConn: TSQLConnection; aResource : TSQLDBRestResource) of object;
|
|
TRestGetFormatEvent = Procedure(Sender : TObject; aRest : TRequest; var aFormat : String) of object;
|
|
TRestGetFormatEvent = Procedure(Sender : TObject; aRest : TRequest; var aFormat : String) of object;
|
|
|
|
+ TRestLogEvent = Procedure(Sender : TObject; aType : TRestDispatcherLogOption; Const aMessage : UTF8String) of object;
|
|
|
|
|
|
TSQLDBRestDispatcher = Class(TComponent)
|
|
TSQLDBRestDispatcher = Class(TComponent)
|
|
Private
|
|
Private
|
|
Class Var FIOClass : TRestIOClass;
|
|
Class Var FIOClass : TRestIOClass;
|
|
Class Var FDBHandlerClass : TSQLDBRestDBHandlerClass;
|
|
Class Var FDBHandlerClass : TSQLDBRestDBHandlerClass;
|
|
private
|
|
private
|
|
|
|
+ FAdminUserIDs: TStrings;
|
|
FCORSAllowCredentials: Boolean;
|
|
FCORSAllowCredentials: Boolean;
|
|
FCORSAllowedOrigins: String;
|
|
FCORSAllowedOrigins: String;
|
|
FCORSMaxAge: Integer;
|
|
FCORSMaxAge: Integer;
|
|
|
|
+ FDBLogOptions: TDBEventTypes;
|
|
FDispatchOptions: TRestDispatcherOptions;
|
|
FDispatchOptions: TRestDispatcherOptions;
|
|
FInputFormat: String;
|
|
FInputFormat: String;
|
|
FCustomViewResource : TSQLDBRestResource;
|
|
FCustomViewResource : TSQLDBRestResource;
|
|
|
|
+ FLogOptions: TRestDispatcherLogOptions;
|
|
FMetadataResource : TSQLDBRestResource;
|
|
FMetadataResource : TSQLDBRestResource;
|
|
FMetadataDetailResource : TSQLDBRestResource;
|
|
FMetadataDetailResource : TSQLDBRestResource;
|
|
|
|
+ FConnectionResource : TSQLDBRestResource;
|
|
FActive: Boolean;
|
|
FActive: Boolean;
|
|
FAfterDelete: TRestOperationEvent;
|
|
FAfterDelete: TRestOperationEvent;
|
|
FAfterGet: TRestOperationEvent;
|
|
FAfterGet: TRestOperationEvent;
|
|
@@ -190,21 +219,35 @@ Type
|
|
FOnGetConnectionName: TGetConnectionNameEvent;
|
|
FOnGetConnectionName: TGetConnectionNameEvent;
|
|
FOnGetInputFormat: TRestGetFormatEvent;
|
|
FOnGetInputFormat: TRestGetFormatEvent;
|
|
FOnGetOutputFormat: TRestGetFormatEvent;
|
|
FOnGetOutputFormat: TRestGetFormatEvent;
|
|
|
|
+ FOnLog: TRestLogEvent;
|
|
FOutputFormat: String;
|
|
FOutputFormat: String;
|
|
FOutputOptions: TRestOutputoptions;
|
|
FOutputOptions: TRestOutputoptions;
|
|
FSchemas: TSQLDBRestSchemaList;
|
|
FSchemas: TSQLDBRestSchemaList;
|
|
FListRoute: THTTPRoute;
|
|
FListRoute: THTTPRoute;
|
|
FItemRoute: THTTPRoute;
|
|
FItemRoute: THTTPRoute;
|
|
|
|
+ FConnectionsRoute: THTTPRoute;
|
|
|
|
+ FConnectionItemRoute: THTTPRoute;
|
|
|
|
+ FMetadataRoute: THTTPRoute;
|
|
|
|
+ FMetadataItemRoute: THTTPRoute;
|
|
FStatus: TRestStatusConfig;
|
|
FStatus: TRestStatusConfig;
|
|
FStrings: TRestStringsConfig;
|
|
FStrings: TRestStringsConfig;
|
|
procedure SetActive(AValue: Boolean);
|
|
procedure SetActive(AValue: Boolean);
|
|
|
|
+ procedure SetAdminUserIDS(AValue: TStrings);
|
|
procedure SetAuthenticator(AValue: TRestAuthenticator);
|
|
procedure SetAuthenticator(AValue: TRestAuthenticator);
|
|
procedure SetConnections(AValue: TSQLDBRestConnectionList);
|
|
procedure SetConnections(AValue: TSQLDBRestConnectionList);
|
|
|
|
+ procedure SetDispatchOptions(AValue: TRestDispatcherOptions);
|
|
procedure SetSchemas(AValue: TSQLDBRestSchemaList);
|
|
procedure SetSchemas(AValue: TSQLDBRestSchemaList);
|
|
procedure SetStatus(AValue: TRestStatusConfig);
|
|
procedure SetStatus(AValue: TRestStatusConfig);
|
|
procedure SetStrings(AValue: TRestStringsConfig);
|
|
procedure SetStrings(AValue: TRestStringsConfig);
|
|
Protected
|
|
Protected
|
|
|
|
+ // Logging
|
|
|
|
+ Function MustLog(aLog : TRestDispatcherLogOption) : Boolean; inline;
|
|
|
|
+ procedure DoSQLLog(Sender: TObject; EventType: TDBEventType; const Msg: String); virtual;
|
|
|
|
+ procedure DoLog(aLog: TRestDispatcherLogOption; IO : TRestIO; const aMessage: UTF8String); virtual;
|
|
|
|
+ procedure DoLog(aLog: TRestDispatcherLogOption; IO : TRestIO; const Fmt: UTF8String;
|
|
|
|
+ Args: array of const);
|
|
// Auxiliary methods.
|
|
// Auxiliary methods.
|
|
|
|
+ Procedure Loaded; override;
|
|
Procedure Notification(AComponent: TComponent; Operation: TOperation); override;
|
|
Procedure Notification(AComponent: TComponent; Operation: TOperation); override;
|
|
function FindConnection(IO: TRestIO): TSQLDBRestConnection;
|
|
function FindConnection(IO: TRestIO): TSQLDBRestConnection;
|
|
// Factory methods. Override these to customize various helper classes.
|
|
// Factory methods. Override these to customize various helper classes.
|
|
@@ -222,6 +265,13 @@ Type
|
|
function GetConnectionName(IO: TRestIO): UTF8String;
|
|
function GetConnectionName(IO: TRestIO): UTF8String;
|
|
function GetSQLConnection(aConnection: TSQLDBRestConnection; Out aTransaction : TSQLTransaction): TSQLConnection; virtual;
|
|
function GetSQLConnection(aConnection: TSQLDBRestConnection; Out aTransaction : TSQLTransaction): TSQLConnection; virtual;
|
|
procedure DoneSQLConnection(aConnection: TSQLDBRestConnection; AConn: TSQLConnection; aTransaction : TSQLTransaction); virtual;
|
|
procedure DoneSQLConnection(aConnection: TSQLDBRestConnection; AConn: TSQLConnection; aTransaction : TSQLTransaction); virtual;
|
|
|
|
+ // Connections dataset API
|
|
|
|
+ procedure ConnectionsToDataset(D: TDataset); virtual;
|
|
|
|
+ procedure DoConnectionDelete(DataSet: TDataSet); virtual;
|
|
|
|
+ procedure DoConnectionPost(DataSet: TDataSet);virtual;
|
|
|
|
+ procedure DatasetToConnection(D: TDataset; C: TSQLDBRestConnection); virtual;
|
|
|
|
+ procedure ConnectionToDataset(C: TSQLDBRestConnection; D: TDataset); virtual;
|
|
|
|
+ procedure DoConnectionResourceAllowed(aSender: TObject; aContext: TBaseRestContext; var allowResource: Boolean);
|
|
// Error handling
|
|
// Error handling
|
|
procedure CreateErrorContent(IO: TRestIO; aCode: Integer; AExtraMessage: UTF8String); virtual;
|
|
procedure CreateErrorContent(IO: TRestIO; aCode: Integer; AExtraMessage: UTF8String); virtual;
|
|
procedure HandleException(E: Exception; IO: TRestIO); virtual;
|
|
procedure HandleException(E: Exception; IO: TRestIO); virtual;
|
|
@@ -245,8 +295,10 @@ Type
|
|
// Special resources for Metadata handling
|
|
// Special resources for Metadata handling
|
|
function CreateMetadataDataset(IO: TRestIO; AOwner: TComponent): TDataset; virtual;
|
|
function CreateMetadataDataset(IO: TRestIO; AOwner: TComponent): TDataset; virtual;
|
|
function CreateMetadataDetailDataset(IO: TRestIO; Const aResourceName : String; AOwner: TComponent): TDataset; virtual;
|
|
function CreateMetadataDetailDataset(IO: TRestIO; Const aResourceName : String; AOwner: TComponent): TDataset; virtual;
|
|
|
|
+ function CreateConnectionDataset(IO: TRestIO; AOwner: TComponent): TDataset; virtual;
|
|
function CreateMetadataDetailResource: TSQLDBRestResource; virtual;
|
|
function CreateMetadataDetailResource: TSQLDBRestResource; virtual;
|
|
function CreateMetadataResource: TSQLDBRestResource; virtual;
|
|
function CreateMetadataResource: TSQLDBRestResource; virtual;
|
|
|
|
+ Function CreateConnectionResource : TSQLDBRestResource; virtual;
|
|
// Custom view handling
|
|
// Custom view handling
|
|
function CreateCustomViewResource: TSQLDBRestResource; virtual;
|
|
function CreateCustomViewResource: TSQLDBRestResource; virtual;
|
|
function CreateCustomViewDataset(IO: TRestIO; const aSQL: String; AOwner: TComponent): TDataset;
|
|
function CreateCustomViewDataset(IO: TRestIO; const aSQL: String; AOwner: TComponent): TDataset;
|
|
@@ -266,6 +318,8 @@ Type
|
|
Destructor Destroy; override;
|
|
Destructor Destroy; override;
|
|
procedure RegisterRoutes;
|
|
procedure RegisterRoutes;
|
|
procedure UnRegisterRoutes;
|
|
procedure UnRegisterRoutes;
|
|
|
|
+ procedure HandleMetadataRequest(aRequest : TRequest; aResponse : TResponse);
|
|
|
|
+ procedure HandleConnRequest(aRequest : TRequest; aResponse : TResponse);
|
|
procedure HandleRequest(aRequest : TRequest; aResponse : TResponse);
|
|
procedure HandleRequest(aRequest : TRequest; aResponse : TResponse);
|
|
Function ExposeDatabase(Const aType,aHostName,aDatabaseName,aUserName,aPassword : String; aTables : Array of String; aMinFieldOpts : TRestFieldOptions = []) : TSQLDBRestConnection;
|
|
Function ExposeDatabase(Const aType,aHostName,aDatabaseName,aUserName,aPassword : String; aTables : Array of String; aMinFieldOpts : TRestFieldOptions = []) : TSQLDBRestConnection;
|
|
Function ExposeDatabase(Const aType,aHostName,aDatabaseName,aUserName,aPassword : String; aTables : TStrings = nil; aMinFieldOpts : TRestFieldOptions = []) : TSQLDBRestConnection;
|
|
Function ExposeDatabase(Const aType,aHostName,aDatabaseName,aUserName,aPassword : String; aTables : TStrings = nil; aMinFieldOpts : TRestFieldOptions = []) : TSQLDBRestConnection;
|
|
@@ -281,6 +335,8 @@ Type
|
|
// Base URL
|
|
// Base URL
|
|
property BasePath : UTF8String Read FBaseURL Write FBaseURL;
|
|
property BasePath : UTF8String Read FBaseURL Write FBaseURL;
|
|
// Default connection to use if none is detected from request/schema
|
|
// Default connection to use if none is detected from request/schema
|
|
|
|
+ // This connection will also be used to authenticate the user for connection API,
|
|
|
|
+ // so it must be set if you use SQL to authenticate the user.
|
|
Property DefaultConnection : UTF8String Read FDefaultConnection Write FDefaultConnection;
|
|
Property DefaultConnection : UTF8String Read FDefaultConnection Write FDefaultConnection;
|
|
// Input/Output strings configuration
|
|
// Input/Output strings configuration
|
|
Property Strings : TRestStringsConfig Read FStrings Write SetStrings;
|
|
Property Strings : TRestStringsConfig Read FStrings Write SetStrings;
|
|
@@ -293,7 +349,7 @@ Type
|
|
// Set this to allow only this output format.
|
|
// Set this to allow only this output format.
|
|
Property OutputFormat : String Read FOutputFormat Write FOutputFormat;
|
|
Property OutputFormat : String Read FOutputFormat Write FOutputFormat;
|
|
// Dispatcher options
|
|
// Dispatcher options
|
|
- Property DispatchOptions : TRestDispatcherOptions Read FDispatchOptions Write FDispatchOptions default DefaultDispatcherOptions;
|
|
|
|
|
|
+ Property DispatchOptions : TRestDispatcherOptions Read FDispatchOptions Write SetDispatchOptions default DefaultDispatcherOptions;
|
|
// Authenticator for requests
|
|
// Authenticator for requests
|
|
Property Authenticator : TRestAuthenticator Read FAuthenticator Write SetAuthenticator;
|
|
Property Authenticator : TRestAuthenticator Read FAuthenticator Write SetAuthenticator;
|
|
// If >0, Enforce a limit on output results.
|
|
// If >0, Enforce a limit on output results.
|
|
@@ -304,6 +360,12 @@ Type
|
|
Property CORSMaxAge : Integer Read FCORSMaxAge Write FCORSMaxAge;
|
|
Property CORSMaxAge : Integer Read FCORSMaxAge Write FCORSMaxAge;
|
|
// Access-Control-Allow-Credentials header value. Set to zero not to send the header
|
|
// Access-Control-Allow-Credentials header value. Set to zero not to send the header
|
|
Property CORSAllowCredentials : Boolean Read FCORSAllowCredentials Write FCORSAllowCredentials;
|
|
Property CORSAllowCredentials : Boolean Read FCORSAllowCredentials Write FCORSAllowCredentials;
|
|
|
|
+ // UserIDs of the user(s) that are allowed to see and modify the connection resource.
|
|
|
|
+ Property AdminUserIDs : TStrings Read FAdminUserIDs Write SetAdminUserIDS;
|
|
|
|
+ // Logging options
|
|
|
|
+ Property LogOptions : TRestDispatcherLogOptions Read FLogOptions write FLogOptions default DefaultDispatcherLogOptions;
|
|
|
|
+ // SQL Log options. Only for connections managed by RestDispatcher
|
|
|
|
+ Property LogSQLOptions : TDBEventTypes Read FDBLogOptions write FDBLogOptions default DefaultLogSQLOptions;
|
|
// Called when Basic authentication is sufficient.
|
|
// Called when Basic authentication is sufficient.
|
|
Property OnBasicAuthentication : TBasicAuthenticationEvent Read FOnBasicAuthentication Write FOnBasicAuthentication;
|
|
Property OnBasicAuthentication : TBasicAuthenticationEvent Read FOnBasicAuthentication Write FOnBasicAuthentication;
|
|
// Allow a particular resource or not.
|
|
// Allow a particular resource or not.
|
|
@@ -334,9 +396,14 @@ Type
|
|
Property BeforeDelete : TRestOperationEvent Read FBeforeDelete Write FBeforeDelete;
|
|
Property BeforeDelete : TRestOperationEvent Read FBeforeDelete Write FBeforeDelete;
|
|
// Called After a DELETE request.
|
|
// Called After a DELETE request.
|
|
Property AfterDelete : TRestOperationEvent Read FAfterDelete Write FAfterDelete;
|
|
Property AfterDelete : TRestOperationEvent Read FAfterDelete Write FAfterDelete;
|
|
|
|
+ // Called when logging
|
|
|
|
+ Property OnLog : TRestLogEvent Read FOnLog Write FOnLog;
|
|
end;
|
|
end;
|
|
|
|
|
|
-
|
|
|
|
|
|
+Const
|
|
|
|
+ LogNames : Array[TRestDispatcherLogOption] of string = (
|
|
|
|
+ 'User','HTTP','Resource','Connection','Authentication','SQL','Result'
|
|
|
|
+ );
|
|
|
|
|
|
implementation
|
|
implementation
|
|
|
|
|
|
@@ -406,6 +473,13 @@ begin
|
|
Result.Enabled:=True;
|
|
Result.Enabled:=True;
|
|
end;
|
|
end;
|
|
|
|
|
|
|
|
+function TSQLDBRestSchemaList.IndexOfSchema(aSchemaName: String): Integer;
|
|
|
|
+begin
|
|
|
|
+ Result:=Count-1;
|
|
|
|
+ While (Result>=0) and Not (Assigned(GetSchema(Result).Schema) and SameText(GetSchema(Result).Schema.Name,aSchemaName)) do
|
|
|
|
+ Dec(Result);
|
|
|
|
+end;
|
|
|
|
+
|
|
{ TSQLDBRestDispatcher }
|
|
{ TSQLDBRestDispatcher }
|
|
|
|
|
|
procedure TSQLDBRestDispatcher.SetConnections(AValue: TSQLDBRestConnectionList);
|
|
procedure TSQLDBRestDispatcher.SetConnections(AValue: TSQLDBRestConnectionList);
|
|
@@ -414,15 +488,40 @@ begin
|
|
FConnections.Assign(AValue);
|
|
FConnections.Assign(AValue);
|
|
end;
|
|
end;
|
|
|
|
|
|
|
|
+procedure TSQLDBRestDispatcher.SetDispatchOptions(AValue: TRestDispatcherOptions);
|
|
|
|
+
|
|
|
|
+begin
|
|
|
|
+ if (rdoConnectionResource in aValue) then
|
|
|
|
+ Include(aValue,rdoConnectionInURL);
|
|
|
|
+ if FDispatchOptions=AValue then Exit;
|
|
|
|
+ FDispatchOptions:=AValue;
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+procedure TSQLDBRestDispatcher.DoConnectionResourceAllowed(aSender: TObject;
|
|
|
|
+ aContext: TBaseRestContext; var allowResource: Boolean);
|
|
|
|
+begin
|
|
|
|
+ AllowResource:=(AdminUserIDs.Count=0) or (AdminUserIDs.IndexOf(aContext.UserID)<>-1);
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+
|
|
procedure TSQLDBRestDispatcher.SetActive(AValue: Boolean);
|
|
procedure TSQLDBRestDispatcher.SetActive(AValue: Boolean);
|
|
begin
|
|
begin
|
|
- if FActive=AValue then Exit;
|
|
|
|
- if AValue then
|
|
|
|
- DoRegisterRoutes
|
|
|
|
- else
|
|
|
|
- UnRegisterRoutes;
|
|
|
|
|
|
+ if FActive=AValue then
|
|
|
|
+ Exit;
|
|
|
|
+ if Not (csLoading in ComponentState) then
|
|
|
|
+ begin
|
|
|
|
+ if AValue then
|
|
|
|
+ DoRegisterRoutes
|
|
|
|
+ else
|
|
|
|
+ UnRegisterRoutes;
|
|
|
|
+ end;
|
|
FActive:=AValue;
|
|
FActive:=AValue;
|
|
|
|
+end;
|
|
|
|
|
|
|
|
+procedure TSQLDBRestDispatcher.SetAdminUserIDS(AValue: TStrings);
|
|
|
|
+begin
|
|
|
|
+ if FAdminUserIDs=AValue then Exit;
|
|
|
|
+ FAdminUserIDs.Assign(AValue);
|
|
end;
|
|
end;
|
|
|
|
|
|
procedure TSQLDBRestDispatcher.SetAuthenticator(AValue: TRestAuthenticator);
|
|
procedure TSQLDBRestDispatcher.SetAuthenticator(AValue: TRestAuthenticator);
|
|
@@ -453,18 +552,133 @@ begin
|
|
FStrings.Assign(AValue);
|
|
FStrings.Assign(AValue);
|
|
end;
|
|
end;
|
|
|
|
|
|
|
|
+function TSQLDBRestDispatcher.MustLog(aLog: TRestDispatcherLogOption): Boolean;
|
|
|
|
+begin
|
|
|
|
+ Result:=aLog in FLogOptions;
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+procedure TSQLDBRestDispatcher.DoSQLLog(Sender: TObject; EventType: TDBEventType; const Msg: String);
|
|
|
|
+
|
|
|
|
+Const
|
|
|
|
+ EventNames : Array [TDBEventType] of string =
|
|
|
|
+ ('Custom','Prepare', 'Execute', 'Fetch', 'Commit', 'RollBack', 'ParamValue', 'ActualSQL');
|
|
|
|
+
|
|
|
|
+Var
|
|
|
|
+ aMsg : UTF8String;
|
|
|
|
+
|
|
|
|
+begin
|
|
|
|
+ if not MustLog(rloSQl) then // avoid string ops
|
|
|
|
+ exit;
|
|
|
|
+ aMsg:=EventNames[EventType]+': '+Msg;
|
|
|
|
+ if Sender is TRestIO then
|
|
|
|
+ DoLog(rloSQL,TRestIO(Sender),aMsg)
|
|
|
|
+ else
|
|
|
|
+ DoLog(rloSQL,Nil,aMsg)
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+procedure TSQLDBRestDispatcher.DoLog(aLog: TRestDispatcherLogOption; IO: TRestIO; const aMessage: UTF8String);
|
|
|
|
+
|
|
|
|
+Var
|
|
|
|
+ aMsg : UTF8String;
|
|
|
|
+
|
|
|
|
+begin
|
|
|
|
+ aMsg:='';
|
|
|
|
+ if MustLog(aLog) and Assigned(FOnLog) then
|
|
|
|
+ begin
|
|
|
|
+ if MustLog(rloUser) and Assigned(IO) then
|
|
|
|
+ begin
|
|
|
|
+ if IO.UserID='' then
|
|
|
|
+ aMsg:='(User: ?) '
|
|
|
|
+ else
|
|
|
|
+ aMsg:=Format('(User: %s) ',[IO.UserID]);
|
|
|
|
+ end;
|
|
|
|
+ aMsg:=aMsg+aMessage;
|
|
|
|
+ FOnLog(Self,aLog,aMsg);
|
|
|
|
+ end;
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+procedure TSQLDBRestDispatcher.DoLog(aLog: TRestDispatcherLogOption;IO: TRestIO;
|
|
|
|
+ const Fmt: UTF8String; Args: array of const);
|
|
|
|
+
|
|
|
|
+Var
|
|
|
|
+ S : UTF8string;
|
|
|
|
+
|
|
|
|
+begin
|
|
|
|
+ if not MustLog(aLog) then exit; // avoid expensive format
|
|
|
|
+ try
|
|
|
|
+ S:=Format(fmt,Args); // Encode ?
|
|
|
|
+ except
|
|
|
|
+ on E : exception do
|
|
|
|
+ S:=Format('Error "%s" formatting "%s" with %d arguments: %s',[E.ClassName,Fmt,Length(Args),E.Message])
|
|
|
|
+ end;
|
|
|
|
+ DoLog(aLog,IO,S);
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+procedure TSQLDBRestDispatcher.Loaded;
|
|
|
|
+begin
|
|
|
|
+ inherited Loaded;
|
|
|
|
+ if FActive then
|
|
|
|
+ RegisterRoutes;
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+procedure TSQLDBRestDispatcher.HandleConnRequest(aRequest : TRequest; aResponse : TResponse);
|
|
|
|
+
|
|
|
|
+begin
|
|
|
|
+ aRequest.RouteParams['resource']:=Strings.ConnectionResourceName;
|
|
|
|
+ HandleRequest(aRequest,aResponse);
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+procedure TSQLDBRestDispatcher.HandleMetadataRequest(aRequest: TRequest;aResponse: TResponse);
|
|
|
|
+
|
|
|
|
+Var
|
|
|
|
+ LogMsg,UN : UTF8String;
|
|
|
|
+
|
|
|
|
+begin
|
|
|
|
+ if MustLog(rtloHTTP) then
|
|
|
|
+ begin
|
|
|
|
+ LogMsg:='';
|
|
|
|
+ With aRequest do
|
|
|
|
+ begin
|
|
|
|
+ UN:=RemoteHost;
|
|
|
|
+ if (UN='') then
|
|
|
|
+ UN:=RemoteAddr;
|
|
|
|
+ if (UN<>'') then
|
|
|
|
+ LogMsg:='From: '+UN+'; ';
|
|
|
|
+ LogMsg:=LogMsg+'URL: '+URL;
|
|
|
|
+ end;
|
|
|
|
+ UN:=TRestBasicAuthenticator.ExtractUserName(aRequest);
|
|
|
|
+ if (UN<>'?') then
|
|
|
|
+ LogMsg:='User: '+UN+LogMsg;
|
|
|
|
+ DoLog(rtloHTTP,Nil,LogMsg);
|
|
|
|
+ end;
|
|
|
|
+ aRequest.RouteParams['resource']:=Strings.MetadataResourceName;
|
|
|
|
+ HandleRequest(aRequest,aResponse);
|
|
|
|
+end;
|
|
|
|
+
|
|
procedure TSQLDBRestDispatcher.DoRegisterRoutes;
|
|
procedure TSQLDBRestDispatcher.DoRegisterRoutes;
|
|
|
|
|
|
Var
|
|
Var
|
|
- Res : String;
|
|
|
|
|
|
+ Res,C : UTF8String;
|
|
|
|
|
|
begin
|
|
begin
|
|
Res:=IncludeHTTPPathDelimiter(BasePath);
|
|
Res:=IncludeHTTPPathDelimiter(BasePath);
|
|
- if rdoConnectionInURL in DispatchOptions then
|
|
|
|
|
|
+ if (rdoConnectionResource in DispatchOptions) then
|
|
|
|
+ begin
|
|
|
|
+ C:=Strings.GetRestString(rpConnectionResourceName);
|
|
|
|
+ FConnectionsRoute:=HTTPRouter.RegisterRoute(res+C,@HandleConnRequest);
|
|
|
|
+ FConnectionItemRoute:=HTTPRouter.RegisterRoute(res+C+'/:id',@HandleConnRequest);
|
|
|
|
+ end;
|
|
|
|
+ if (rdoConnectionInURL in DispatchOptions) then
|
|
|
|
+ begin
|
|
|
|
+ C:=Strings.GetRestString(rpMetadataResourceName);
|
|
|
|
+ FMetadataRoute:=HTTPRouter.RegisterRoute(res+C,@HandleMetaDataRequest);
|
|
|
|
+ FMetadataItemRoute:=HTTPRouter.RegisterRoute(res+C+'/:id',@HandleMetaDataRequest);
|
|
Res:=Res+':connection/';
|
|
Res:=Res+':connection/';
|
|
|
|
+ end;
|
|
Res:=Res+':resource';
|
|
Res:=Res+':resource';
|
|
FListRoute:=HTTPRouter.RegisterRoute(res,@HandleRequest);
|
|
FListRoute:=HTTPRouter.RegisterRoute(res,@HandleRequest);
|
|
FItemRoute:=HTTPRouter.RegisterRoute(Res+'/:id',@HandleRequest);
|
|
FItemRoute:=HTTPRouter.RegisterRoute(Res+'/:id',@HandleRequest);
|
|
|
|
+
|
|
end;
|
|
end;
|
|
|
|
|
|
function TSQLDBRestDispatcher.GetInputFormat(IO : TRestIO) : String;
|
|
function TSQLDBRestDispatcher.GetInputFormat(IO : TRestIO) : String;
|
|
@@ -630,17 +844,22 @@ begin
|
|
FSchemas:=CreateSchemaList;
|
|
FSchemas:=CreateSchemaList;
|
|
FOutputOptions:=allOutputOptions;
|
|
FOutputOptions:=allOutputOptions;
|
|
FDispatchOptions:=DefaultDispatcherOptions;
|
|
FDispatchOptions:=DefaultDispatcherOptions;
|
|
|
|
+ FLogOptions:=DefaultDispatcherLogOptions;
|
|
|
|
+ FDBLogOptions:=DefaultLogSQLOptions;
|
|
FStatus:=CreateRestStatusConfig;
|
|
FStatus:=CreateRestStatusConfig;
|
|
FCORSMaxAge:=SecsPerDay;
|
|
FCORSMaxAge:=SecsPerDay;
|
|
FCORSAllowCredentials:=True;
|
|
FCORSAllowCredentials:=True;
|
|
|
|
+ FAdminUserIDs:=TStringList.Create;
|
|
end;
|
|
end;
|
|
|
|
|
|
destructor TSQLDBRestDispatcher.Destroy;
|
|
destructor TSQLDBRestDispatcher.Destroy;
|
|
begin
|
|
begin
|
|
Authenticator:=Nil;
|
|
Authenticator:=Nil;
|
|
|
|
+ FreeAndNil(FAdminUserIDs);
|
|
FreeAndNil(FCustomViewResource);
|
|
FreeAndNil(FCustomViewResource);
|
|
FreeAndNil(FMetadataResource);
|
|
FreeAndNil(FMetadataResource);
|
|
FreeAndNil(FMetadataDetailResource);
|
|
FreeAndNil(FMetadataDetailResource);
|
|
|
|
+ FreeAndNil(FConnectionResource);
|
|
FreeAndNil(FSchemas);
|
|
FreeAndNil(FSchemas);
|
|
FreeAndNil(FConnections);
|
|
FreeAndNil(FConnections);
|
|
FreeAndNil(FStrings);
|
|
FreeAndNil(FStrings);
|
|
@@ -681,7 +900,10 @@ function TSQLDBRestDispatcher.CreateCustomViewResource: TSQLDBRestResource;
|
|
begin
|
|
begin
|
|
Result:=TCustomViewResource.Create(Nil);
|
|
Result:=TCustomViewResource.Create(Nil);
|
|
Result.ResourceName:=FStrings.GetRestString(rpCustomViewResourceName);
|
|
Result.ResourceName:=FStrings.GetRestString(rpCustomViewResourceName);
|
|
- Result.AllowedOperations:=[roGet];
|
|
|
|
|
|
+ if rdoHandleCORS in DispatchOptions then
|
|
|
|
+ Result.AllowedOperations:=[roGet,roOptions,roHead]
|
|
|
|
+ else
|
|
|
|
+ Result.AllowedOperations:=[roGet,roHead];
|
|
end;
|
|
end;
|
|
|
|
|
|
function TSQLDBRestDispatcher.CreateMetadataResource: TSQLDBRestResource;
|
|
function TSQLDBRestDispatcher.CreateMetadataResource: TSQLDBRestResource;
|
|
@@ -692,13 +914,13 @@ Var
|
|
|
|
|
|
begin
|
|
begin
|
|
Result:=TSQLDBRestResource.Create(Nil);
|
|
Result:=TSQLDBRestResource.Create(Nil);
|
|
- Result.ResourceName:='metaData';
|
|
|
|
|
|
+ Result.ResourceName:=Strings.GetRestString(rpMetadataResourceName);
|
|
if rdoHandleCORS in DispatchOptions then
|
|
if rdoHandleCORS in DispatchOptions then
|
|
Result.AllowedOperations:=[roGet,roOptions,roHead]
|
|
Result.AllowedOperations:=[roGet,roOptions,roHead]
|
|
else
|
|
else
|
|
Result.AllowedOperations:=[roGet,roHead];
|
|
Result.AllowedOperations:=[roGet,roHead];
|
|
- Result.Fields.AddField('name',rftString,[foRequired]);
|
|
|
|
- Result.Fields.AddField('schemaName',rftString,[foRequired]);
|
|
|
|
|
|
+ Result.Fields.AddField('name',rftString,[foRequired]).MaxLen:=255;
|
|
|
|
+ Result.Fields.AddField('schemaName',rftString,[foRequired]).MaxLen:=255;
|
|
for O in TRestOperation do
|
|
for O in TRestOperation do
|
|
if O<>roUnknown then
|
|
if O<>roUnknown then
|
|
begin
|
|
begin
|
|
@@ -708,6 +930,32 @@ begin
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
|
|
|
|
+function TSQLDBRestDispatcher.CreateConnectionResource: TSQLDBRestResource;
|
|
|
|
+Var
|
|
|
|
+ Def : TRestFieldOptions;
|
|
|
|
+
|
|
|
|
+begin
|
|
|
|
+ Def:=[foInInsert,foInUpdate,foFilter];
|
|
|
|
+ Result:=TSQLDBRestResource.Create(Nil);
|
|
|
|
+ Result.ResourceName:=Strings.GetRestString(rpConnectionResourceName);
|
|
|
|
+ Result.AllowedOperations:=[roGet,roPut,roPost,roDelete];
|
|
|
|
+ if rdoHandleCORS in DispatchOptions then
|
|
|
|
+ Result.AllowedOperations:=Result.AllowedOperations+[roOptions,roHead];
|
|
|
|
+ Result.Fields.AddField('name',rftString,Def+[foInKey,foRequired]);
|
|
|
|
+ Result.Fields.AddField('dbType',rftString,Def+[foRequired]);
|
|
|
|
+ Result.Fields.AddField('dbName',rftString,Def+[foRequired]);
|
|
|
|
+ Result.Fields.AddField('dbHostName',rftString,Def);
|
|
|
|
+ Result.Fields.AddField('dbUserName',rftString,Def);
|
|
|
|
+ Result.Fields.AddField('dbPassword',rftString,Def);
|
|
|
|
+ Result.Fields.AddField('dbCharSet',rftString,Def);
|
|
|
|
+ Result.Fields.AddField('dbRole',rftString,Def);
|
|
|
|
+ Result.Fields.AddField('dbPort',rftInteger,Def);
|
|
|
|
+ Result.Fields.AddField('enabled',rftBoolean,Def);
|
|
|
|
+ Result.Fields.AddField('expose',rftBoolean,Def);
|
|
|
|
+ Result.Fields.AddField('exposeSchemaName',rftString,Def);
|
|
|
|
+ Result.OnResourceAllowed:=@DoConnectionResourceAllowed;
|
|
|
|
+end;
|
|
|
|
+
|
|
function TSQLDBRestDispatcher.CreateMetadataDetailResource: TSQLDBRestResource;
|
|
function TSQLDBRestDispatcher.CreateMetadataDetailResource: TSQLDBRestResource;
|
|
|
|
|
|
Var
|
|
Var
|
|
@@ -721,10 +969,10 @@ begin
|
|
Result.AllowedOperations:=[roGet,roOptions,roHead]
|
|
Result.AllowedOperations:=[roGet,roOptions,roHead]
|
|
else
|
|
else
|
|
Result.AllowedOperations:=[roGet,roHead];
|
|
Result.AllowedOperations:=[roGet,roHead];
|
|
- Result.Fields.AddField('name',rftString,[]);
|
|
|
|
- Result.Fields.AddField('type',rftString,[]);
|
|
|
|
|
|
+ Result.Fields.AddField('name',rftString,[]).MaxLen:=255;
|
|
|
|
+ Result.Fields.AddField('type',rftString,[]).MaxLen:=20;
|
|
Result.Fields.AddField('maxlen',rftInteger,[]);
|
|
Result.Fields.AddField('maxlen',rftInteger,[]);
|
|
- Result.Fields.AddField('format',rftString,[]);
|
|
|
|
|
|
+ Result.Fields.AddField('format',rftString,[]).MaxLen:=50;
|
|
for O in TRestFieldOption do
|
|
for O in TRestFieldOption do
|
|
begin
|
|
begin
|
|
Str(O,S);
|
|
Str(O,S);
|
|
@@ -741,6 +989,7 @@ function TSQLDBRestDispatcher.FindSpecialResource(IO : TRestIO; aResource: UTF8S
|
|
Result:=(rdoCustomView in DispatchOptions)
|
|
Result:=(rdoCustomView in DispatchOptions)
|
|
and SameText(aResource,Strings.GetRestString(rpCustomViewResourceName));
|
|
and SameText(aResource,Strings.GetRestString(rpCustomViewResourceName));
|
|
end;
|
|
end;
|
|
|
|
+
|
|
Function IsMetadata : Boolean;inline;
|
|
Function IsMetadata : Boolean;inline;
|
|
|
|
|
|
begin
|
|
begin
|
|
@@ -748,6 +997,13 @@ function TSQLDBRestDispatcher.FindSpecialResource(IO : TRestIO; aResource: UTF8S
|
|
and SameText(aResource,Strings.GetRestString(rpMetaDataResourceName));
|
|
and SameText(aResource,Strings.GetRestString(rpMetaDataResourceName));
|
|
end;
|
|
end;
|
|
|
|
|
|
|
|
+ Function IsConnection : Boolean;inline;
|
|
|
|
+
|
|
|
|
+ begin
|
|
|
|
+ Result:=(rdoConnectionResource in DispatchOptions)
|
|
|
|
+ and SameText(aResource,Strings.GetRestString(rpConnectionResourceName));
|
|
|
|
+ end;
|
|
|
|
+
|
|
Var
|
|
Var
|
|
N : UTF8String;
|
|
N : UTF8String;
|
|
|
|
|
|
@@ -759,6 +1015,12 @@ begin
|
|
FCustomViewResource:=CreateCustomViewResource;
|
|
FCustomViewResource:=CreateCustomViewResource;
|
|
Result:=FCustomViewResource;
|
|
Result:=FCustomViewResource;
|
|
end
|
|
end
|
|
|
|
+ else if IsConnection then
|
|
|
|
+ begin
|
|
|
|
+ if FConnectionResource=Nil then
|
|
|
|
+ FConnectionResource:=CreateConnectionResource;
|
|
|
|
+ Result:=FConnectionResource;
|
|
|
|
+ end
|
|
else If isMetadata then
|
|
else If isMetadata then
|
|
if (IO.GetVariable('ID',N,[vsRoute,vsQuery])=vsNone) then
|
|
if (IO.GetVariable('ID',N,[vsRoute,vsQuery])=vsNone) then
|
|
begin
|
|
begin
|
|
@@ -775,7 +1037,6 @@ begin
|
|
Result:=FMetadataDetailResource;
|
|
Result:=FMetadataDetailResource;
|
|
end;
|
|
end;
|
|
end
|
|
end
|
|
-
|
|
|
|
end;
|
|
end;
|
|
|
|
|
|
function TSQLDBRestDispatcher.FindRestResource(aResource: UTF8String): TSQLDBRestResource;
|
|
function TSQLDBRestDispatcher.FindRestResource(aResource: UTF8String): TSQLDBRestResource;
|
|
@@ -872,6 +1133,10 @@ function TSQLDBRestDispatcher.GetSQLConnection(
|
|
): TSQLConnection;
|
|
): TSQLConnection;
|
|
|
|
|
|
begin
|
|
begin
|
|
|
|
+ Result:=Nil;
|
|
|
|
+ aTransaction:=Nil;
|
|
|
|
+ if aConnection=Nil then
|
|
|
|
+ exit;
|
|
Result:=aConnection.SingleConnection;
|
|
Result:=aConnection.SingleConnection;
|
|
if (Result=Nil) then
|
|
if (Result=Nil) then
|
|
begin
|
|
begin
|
|
@@ -973,6 +1238,7 @@ begin
|
|
if not Result then exit;
|
|
if not Result then exit;
|
|
Result:=(aResource=FMetadataResource) or
|
|
Result:=(aResource=FMetadataResource) or
|
|
(aResource=FMetadataDetailResource) or
|
|
(aResource=FMetadataDetailResource) or
|
|
|
|
+ (aResource=FConnectionResource) or
|
|
(aResource=FCustomViewResource);
|
|
(aResource=FCustomViewResource);
|
|
end;
|
|
end;
|
|
|
|
|
|
@@ -1124,6 +1390,165 @@ begin
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
|
|
|
|
+procedure TSQLDBRestDispatcher.DatasetToConnection(D: TDataset; C : TSQLDBRestConnection);
|
|
|
|
+
|
|
|
|
+begin
|
|
|
|
+ C.Name:=UTF8Encode(D.FieldByName('name').AsWideString);
|
|
|
|
+ C.ConnectionType:=D.FieldByName('dbType').AsString;
|
|
|
|
+ C.DatabaseName:=UTF8Encode(D.FieldByName('dbName').AsWideString);
|
|
|
|
+ C.HostName:=D.FieldByName('dbHostName').AsString;
|
|
|
|
+ C.UserName:=UTF8Encode(D.FieldByName('dbUserName').AsWideString);
|
|
|
|
+ C.Password:=UTF8Encode(D.FieldByName('dbPassword').AsWideString);
|
|
|
|
+ C.CharSet:=D.FieldByName('dbCharSet').AsString;
|
|
|
|
+ C.Role:=D.FieldByName('dbRole').AsString;
|
|
|
|
+ C.Port:=D.FieldByName('dbPort').AsInteger;
|
|
|
|
+ C.Enabled:=D.FieldByName('enabled').AsBoolean;
|
|
|
|
+ if D.FieldByName('expose').AsBoolean then
|
|
|
|
+ C.SchemaName:=D.FieldByName('exposeSchemaName').AsString;
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+procedure TSQLDBRestDispatcher.ConnectionToDataset(C : TSQLDBRestConnection;D: TDataset);
|
|
|
|
+
|
|
|
|
+begin
|
|
|
|
+ D.FieldByName('key').AsWideString:=UTF8Decode(C.Name);
|
|
|
|
+ D.FieldByName('name').AsWideString:=UTF8Decode(C.Name);
|
|
|
|
+ D.FieldByName('dbType').AsString:=C.ConnectionType;
|
|
|
|
+ D.FieldByName('dbName').AsWideString:=UTF8Decode(C.DatabaseName);
|
|
|
|
+ D.FieldByName('dbHostName').AsString:=C.HostName;
|
|
|
|
+ D.FieldByName('dbUserName').AsWideString:=UTF8Decode(C.UserName);
|
|
|
|
+ D.FieldByName('dbPassword').AsWideString:=UTF8Decode(C.Password);
|
|
|
|
+ D.FieldByName('dbCharSet').AsString:=C.CharSet;
|
|
|
|
+ D.FieldByName('dbRole').AsString:=C.Role;
|
|
|
|
+ D.FieldByName('dbPort').AsInteger:=C.Port;
|
|
|
|
+ D.FieldByName('enabled').AsBoolean:=C.Enabled;
|
|
|
|
+ D.FieldByName('expose').AsBoolean:=(C.SchemaName<>'');
|
|
|
|
+ D.FieldByName('exposeSchemaName').AsString:=C.SchemaName;
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+procedure TSQLDBRestDispatcher.ConnectionsToDataset(D: TDataset);
|
|
|
|
+
|
|
|
|
+Var
|
|
|
|
+ C : TSQLDBRestConnection;
|
|
|
|
+ I : Integer;
|
|
|
|
+
|
|
|
|
+begin
|
|
|
|
+ For I:=0 to Connections.Count-1 do
|
|
|
|
+ begin
|
|
|
|
+ C:=Connections[i];
|
|
|
|
+ D.Append;
|
|
|
|
+ ConnectionToDataset(C,D);
|
|
|
|
+ D.Post;
|
|
|
|
+ end;
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+procedure TSQLDBRestDispatcher.DoConnectionDelete(DataSet: TDataSet);
|
|
|
|
+
|
|
|
|
+Var
|
|
|
|
+ I,J : Integer;
|
|
|
|
+ C : TSQLDBRestConnection;
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+begin
|
|
|
|
+ I:=Connections.IndexOfConnection(UTF8Encode(Dataset.FieldByName('name').AsWideString));
|
|
|
|
+ if I<>-1 then
|
|
|
|
+ begin
|
|
|
|
+ C:=Connections[i];
|
|
|
|
+ if C.SingleConnection<>Nil then
|
|
|
|
+ DoneSQLConnection(C,C.SingleConnection,Nil);
|
|
|
|
+ if C.SchemaName<>'' then
|
|
|
|
+ begin
|
|
|
|
+ J:=Schemas.IndexOfSchema(C.SchemaName);
|
|
|
|
+ if J<>-1 then
|
|
|
|
+ begin
|
|
|
|
+ Schemas[J].Schema.Free;
|
|
|
|
+ Schemas[J].Schema:=Nil;
|
|
|
|
+ end;
|
|
|
|
+ Schemas.Delete(J);
|
|
|
|
+ end;
|
|
|
|
+ Connections.Delete(I);
|
|
|
|
+ end
|
|
|
|
+ else
|
|
|
|
+ Raise ESQLDBRest.Create(404,'NOT FOUND');
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+procedure TSQLDBRestDispatcher.DoConnectionPost(DataSet: TDataSet);
|
|
|
|
+
|
|
|
|
+Var
|
|
|
|
+ isNew : Boolean;
|
|
|
|
+ C : TSQLDBRestConnection;
|
|
|
|
+ N : UTF8String;
|
|
|
|
+ UN : UnicodeString;
|
|
|
|
+ S : TSQLDBRestSchema;
|
|
|
|
+
|
|
|
|
+begin
|
|
|
|
+ IsNew:=Dataset.State=dsInsert;
|
|
|
|
+ if IsNew then
|
|
|
|
+ C:=Connections.Add as TSQLDBRestConnection
|
|
|
|
+ else
|
|
|
|
+ begin
|
|
|
|
+ UN:=UTF8Decode(Dataset.FieldByName('key').AsString);
|
|
|
|
+// C:=Connections[Dataset.RecNo-1];
|
|
|
|
+ C:=Connections.FindConnection(Utf8Encode(UN));
|
|
|
|
+ if (C=Nil) then
|
|
|
|
+ Raise ESQLDBRest.Create(404,'NOT FOUND');
|
|
|
|
+ end;
|
|
|
|
+ if Assigned(C.SingleConnection) then
|
|
|
|
+ DoneSQLConnection(C,C.SingleConnection,Nil);
|
|
|
|
+ DatasetToConnection(Dataset,C);
|
|
|
|
+ if (Dataset.FieldByName('expose').AsBoolean) and isNew then
|
|
|
|
+ begin
|
|
|
|
+ N:=C.SchemaName;
|
|
|
|
+ if N='' then
|
|
|
|
+ N:=C.Name+'schema';
|
|
|
|
+ if (Schemas.IndexOfSchema(N)<>-1) then
|
|
|
|
+ Raise ESQLDBRest.Create(400,'DUPLICATE SCHEMA');
|
|
|
|
+ try
|
|
|
|
+ S:=ExposeConnection(C,Nil);
|
|
|
|
+ except
|
|
|
|
+ if IsNew then
|
|
|
|
+ C.Free;
|
|
|
|
+ Raise;
|
|
|
|
+ end;
|
|
|
|
+ S.Name:=N;
|
|
|
|
+ end;
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+function TSQLDBRestDispatcher.CreateConnectionDataset(IO: TRestIO; AOwner: TComponent): TDataset;
|
|
|
|
+Var
|
|
|
|
+ BD : TRestBufDataset;
|
|
|
|
+
|
|
|
|
+begin
|
|
|
|
+ if IO=Nil then exit;
|
|
|
|
+ BD:=TRestBufDataset.Create(aOwner);
|
|
|
|
+ try
|
|
|
|
+ Result:=BD;
|
|
|
|
+ // Key field is not exposed
|
|
|
|
+ Result.FieldDefs.add('key',ftWidestring,255);
|
|
|
|
+ Result.FieldDefs.add('name',ftWidestring,255);
|
|
|
|
+ Result.FieldDefs.add('dbType',ftString,20);
|
|
|
|
+ Result.FieldDefs.add('dbName',ftWideString,255);
|
|
|
|
+ Result.FieldDefs.add('dbHostName',ftString,255);
|
|
|
|
+ Result.FieldDefs.add('dbUserName',ftWideString,255);
|
|
|
|
+ Result.FieldDefs.add('dbPassword',ftWideString,255);
|
|
|
|
+ Result.FieldDefs.add('dbCharSet',ftString,50);
|
|
|
|
+ Result.FieldDefs.add('dbRole',ftString,255);
|
|
|
|
+ Result.FieldDefs.add('dbPort',ftInteger,0);
|
|
|
|
+ Result.FieldDefs.add('enabled',ftBoolean,0);
|
|
|
|
+ Result.FieldDefs.add('expose',ftBoolean,0);
|
|
|
|
+ Result.FieldDefs.add('exposeSchemaName',ftWideString,255);
|
|
|
|
+ BD.CreateDataset;
|
|
|
|
+ ConnectionsToDataset(BD);
|
|
|
|
+ BD.IndexDefs.Add('uName','name',[ixUnique]);
|
|
|
|
+ BD.IndexName:='uName';
|
|
|
|
+ BD.First;
|
|
|
|
+ BD.BeforePost:=@DoConnectionPost;
|
|
|
|
+ BD.BeforeDelete:=@DoConnectionDelete;
|
|
|
|
+ except
|
|
|
|
+ BD.Free;
|
|
|
|
+ Raise;
|
|
|
|
+ end;
|
|
|
|
+end;
|
|
|
|
+
|
|
function TSQLDBRestDispatcher.CreateCustomViewDataset(IO: TRestIO;
|
|
function TSQLDBRestDispatcher.CreateCustomViewDataset(IO: TRestIO;
|
|
const aSQL: String; AOwner: TComponent): TDataset;
|
|
const aSQL: String; AOwner: TComponent): TDataset;
|
|
|
|
|
|
@@ -1159,6 +1584,8 @@ begin
|
|
Result:=Nil;
|
|
Result:=Nil;
|
|
if (IO.Resource=FMetadataResource) then
|
|
if (IO.Resource=FMetadataResource) then
|
|
Result:=CreateMetadataDataset(IO,AOwner)
|
|
Result:=CreateMetadataDataset(IO,AOwner)
|
|
|
|
+ else if (IO.Resource=FConnectionResource) then
|
|
|
|
+ Result:=CreateConnectionDataset(IO,AOwner)
|
|
else if (IO.Resource=FMetadataDetailResource) then
|
|
else if (IO.Resource=FMetadataDetailResource) then
|
|
begin
|
|
begin
|
|
if IO.GetVariable('ID',RN,[vsRoute,vsQuery])=vsNone then
|
|
if IO.GetVariable('ID',RN,[vsRoute,vsQuery])=vsNone then
|
|
@@ -1220,12 +1647,25 @@ Var
|
|
H : TSQLDBRestDBHandler;
|
|
H : TSQLDBRestDBHandler;
|
|
l,o : Int64;
|
|
l,o : Int64;
|
|
|
|
|
|
|
|
+
|
|
begin
|
|
begin
|
|
|
|
+ if MustLog(rloResource) then
|
|
|
|
+ DoLog(rloResource,IO,'Resource: %s; Operation: %s',[IO.ResourceName,RestMethods[IO.Operation]]);
|
|
H:=Nil;
|
|
H:=Nil;
|
|
Conn:=GetSQLConnection(aConnection,Tr);
|
|
Conn:=GetSQLConnection(aConnection,Tr);
|
|
try
|
|
try
|
|
IO.SetConn(Conn,TR);
|
|
IO.SetConn(Conn,TR);
|
|
Try
|
|
Try
|
|
|
|
+ if MustLog(rloConnection) then
|
|
|
|
+ if Assigned(Conn) then
|
|
|
|
+ DoLog(rloConnection,IO,'Using connection to Host: %s; Database: %s',[Conn.HostName,Conn.DatabaseName])
|
|
|
|
+ else
|
|
|
|
+ DoLog(rloConnection,IO,'Resource %s does not require connection',[IO.ResourceName]);
|
|
|
|
+ if assigned(Conn) and MustLog(rloSQL) then
|
|
|
|
+ begin
|
|
|
|
+ Conn.LogEvents:=LogSQLOptions;
|
|
|
|
+ Conn.OnLog:[email protected];
|
|
|
|
+ end;
|
|
if (rdoHandleCORS in DispatchOptions) then
|
|
if (rdoHandleCORS in DispatchOptions) then
|
|
IO.Response.SetCustomHeader('Access-Control-Allow-Origin',ResolvedCORSAllowedOrigins);
|
|
IO.Response.SetCustomHeader('Access-Control-Allow-Origin',ResolvedCORSAllowedOrigins);
|
|
if not AuthenticateRequest(IO,True) then
|
|
if not AuthenticateRequest(IO,True) then
|
|
@@ -1243,7 +1683,8 @@ begin
|
|
end;
|
|
end;
|
|
H.ExecuteOperation;
|
|
H.ExecuteOperation;
|
|
DoHandleEvent(False,IO);
|
|
DoHandleEvent(False,IO);
|
|
- tr.Commit;
|
|
|
|
|
|
+ if Assigned(TR) then
|
|
|
|
+ TR.Commit;
|
|
SetDefaultResponseCode(IO);
|
|
SetDefaultResponseCode(IO);
|
|
except
|
|
except
|
|
TR.RollBack;
|
|
TR.RollBack;
|
|
@@ -1365,7 +1806,7 @@ begin
|
|
begin
|
|
begin
|
|
IO.SetResource(Resource);
|
|
IO.SetResource(Resource);
|
|
Connection:=FindConnection(IO);
|
|
Connection:=FindConnection(IO);
|
|
- if Connection=Nil then
|
|
|
|
|
|
+ if (Connection=Nil) and not IsSpecialResource(Resource) then
|
|
begin
|
|
begin
|
|
if (rdoConnectionInURL in DispatchOptions) then
|
|
if (rdoConnectionInURL in DispatchOptions) then
|
|
CreateErrorContent(IO,FStatus.GetStatusCode(rsNoConnectionSpecified),Format(SErrNoconnection,[GetConnectionName(IO)]))
|
|
CreateErrorContent(IO,FStatus.GetStatusCode(rsNoConnectionSpecified),Format(SErrNoconnection,[GetConnectionName(IO)]))
|
|
@@ -1396,8 +1837,13 @@ procedure TSQLDBRestDispatcher.UnRegisterRoutes;
|
|
begin
|
|
begin
|
|
Un(FListRoute);
|
|
Un(FListRoute);
|
|
Un(FItemRoute);
|
|
Un(FItemRoute);
|
|
|
|
+ Un(FConnectionItemRoute);
|
|
|
|
+ Un(FConnectionsRoute);
|
|
|
|
+ Un(FMetadataItemRoute);
|
|
|
|
+ Un(FMetadataRoute);
|
|
end;
|
|
end;
|
|
|
|
|
|
|
|
+
|
|
procedure TSQLDBRestDispatcher.RegisterRoutes;
|
|
procedure TSQLDBRestDispatcher.RegisterRoutes;
|
|
begin
|
|
begin
|
|
if (FListRoute<>Nil) then
|
|
if (FListRoute<>Nil) then
|
|
@@ -1456,6 +1902,7 @@ Var
|
|
B : TRestBasicAuthenticator;
|
|
B : TRestBasicAuthenticator;
|
|
A : TRestAuthenticator;
|
|
A : TRestAuthenticator;
|
|
|
|
|
|
|
|
+
|
|
begin
|
|
begin
|
|
A:=Nil;
|
|
A:=Nil;
|
|
B:=Nil;
|
|
B:=Nil;
|
|
@@ -1473,7 +1920,14 @@ begin
|
|
begin
|
|
begin
|
|
Result:=(A.NeedConnection<>Delayed);
|
|
Result:=(A.NeedConnection<>Delayed);
|
|
If Not Result then
|
|
If Not Result then
|
|
- Result:=A.AuthenticateRequest(IO)
|
|
|
|
|
|
+ begin
|
|
|
|
+ Result:=A.AuthenticateRequest(IO);
|
|
|
|
+ if MustLog(rloAuthentication) then
|
|
|
|
+ if Result then
|
|
|
|
+ DoLog(rloAuthentication,IO,'Authenticated user: %s',[IO.UserID])
|
|
|
|
+ else
|
|
|
|
+ DoLog(rloAuthentication,IO,'Authentication failed for user: %s',[TRestBasicAuthenticator.ExtractUserName(IO.Request)]);
|
|
|
|
+ end;
|
|
end;
|
|
end;
|
|
finally
|
|
finally
|
|
if Assigned(B) then
|
|
if Assigned(B) then
|
|
@@ -1506,6 +1960,7 @@ begin
|
|
// First output, then input
|
|
// First output, then input
|
|
IO.RestOutput.InitStreaming;
|
|
IO.RestOutput.InitStreaming;
|
|
IO.RestInput.InitStreaming;
|
|
IO.RestInput.InitStreaming;
|
|
|
|
+ IO.OnSQLLog:[email protected];
|
|
if AuthenticateRequest(IO,False) then
|
|
if AuthenticateRequest(IO,False) then
|
|
DoHandleRequest(IO)
|
|
DoHandleRequest(IO)
|
|
except
|
|
except
|
|
@@ -1513,12 +1968,19 @@ begin
|
|
HandleException(E,IO);
|
|
HandleException(E,IO);
|
|
end;
|
|
end;
|
|
Finally
|
|
Finally
|
|
|
|
+ // Make sure there is a document in case of error
|
|
|
|
+ if (aResponse.ContentStream.Size=0) and Not ((aResponse.Code div 100)=2) then
|
|
|
|
+ IO.RESTOutput.CreateErrorContent(aResponse.Code,aResponse.CodeText);
|
|
if Not (IO.Operation in [roOptions,roHEAD]) then
|
|
if Not (IO.Operation in [roOptions,roHEAD]) then
|
|
IO.RestOutput.FinalizeOutput;
|
|
IO.RestOutput.FinalizeOutput;
|
|
aResponse.ContentStream.Position:=0;
|
|
aResponse.ContentStream.Position:=0;
|
|
aResponse.ContentLength:=aResponse.ContentStream.Size;
|
|
aResponse.ContentLength:=aResponse.ContentStream.Size;
|
|
|
|
+
|
|
if not aResponse.ContentSent then
|
|
if not aResponse.ContentSent then
|
|
aResponse.SendContent;
|
|
aResponse.SendContent;
|
|
|
|
+ if MustLog(rloResultStatus) then
|
|
|
|
+ DoLog(rloResultStatus,IO,'Resource: %s; Operation: %s; Status: %d; Text: %s',[IO.ResourceName,RestMethods[IO.Operation],aResponse.Code,aResponse.CodeText]);
|
|
|
|
+
|
|
IO.Free;
|
|
IO.Free;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
@@ -1651,7 +2113,7 @@ begin
|
|
Items[aIndex]:=aValue;
|
|
Items[aIndex]:=aValue;
|
|
end;
|
|
end;
|
|
|
|
|
|
-function TSQLDBRestConnectionList.IndexOfConnection(const aName: string
|
|
|
|
|
|
+function TSQLDBRestConnectionList.IndexOfConnection(const aName: UTF8string
|
|
): Integer;
|
|
): Integer;
|
|
begin
|
|
begin
|
|
Result:=Count-1;
|
|
Result:=Count-1;
|
|
@@ -1659,7 +2121,7 @@ begin
|
|
Dec(Result);
|
|
Dec(Result);
|
|
end;
|
|
end;
|
|
|
|
|
|
-function TSQLDBRestConnectionList.FindConnection(const aName: string): TSQLDBRestConnection;
|
|
|
|
|
|
+function TSQLDBRestConnectionList.FindConnection(const aName: UTF8string): TSQLDBRestConnection;
|
|
Var
|
|
Var
|
|
Idx : Integer;
|
|
Idx : Integer;
|
|
|
|
|
|
@@ -1849,6 +2311,8 @@ begin
|
|
Role:=C.Role;
|
|
Role:=C.Role;
|
|
DatabaseName:=C.DatabaseName;
|
|
DatabaseName:=C.DatabaseName;
|
|
ConnectionType:=C.ConnectionType;
|
|
ConnectionType:=C.ConnectionType;
|
|
|
|
+ Port:=C.Port;
|
|
|
|
+ SchemaName:=C.SchemaName;
|
|
Params.Assign(C.Params);
|
|
Params.Assign(C.Params);
|
|
end
|
|
end
|
|
else
|
|
else
|