You are not logged in.
Pages: 1
Hi @moctes
i have made the correction.
You can download the sample project here
https://1drv.ms/u/s!Ajd1--MjHzRWqxG2SeS … N?e=1JwpMd
PS : I don't have XE to validate the compilation.
You can find a sample server here :
https://1drv.ms/u/s!Ajd1--MjHzRWqxG2SeS … N?e=1JwpMd
I'm using an overloaded version of TSQLRestDBServer to add two APIs:
- IsValidToken () to test whether the token is still active and allowed.
- RefreshToken () to regenerate it if it has expired. If the session is no longer existing, this method adds a new session.
RefreshToken expects two parameters (User and password).
These methods must be called with a bearer in the http header.
Compiled with Delphi XE3.
Hi,
For those who are interested here is the latest version of this piece of code.
https://1drv.ms/u/s!Ajd1--MjHzRWqw7-27x … i?e=Oz6DWO
I will try to make a sample project quickly.
AB, if you can watch and tell me if I have not done a lot of bullshit, that would help me a lot.
Thank you.
Sorry Ab. I'll be careful next time.
Hi,
I have made modifications for use TSQLHttpClient with this authentication.
Here the complete Unit :
unit Web.Serveur.U_JWT;
interface
uses
Windows,
SysUtils,
Classes,
SynZip,
SynLZ,
SynCrtSock,
{$ifndef NOHTTPCLIENTWEBSOCKETS}
SynBidirSock, // for WebSockets
{$endif}
SynCrypto, // for hcSynShaAes
SynCommons,
SynLog,
mORMot,
mORMotHttpClient;
type
TSQLRestRoutingREST_JWT = class(TSQLRestRoutingREST)
protected
procedure AuthenticationFailed(Reason: TNotifyAuthenticationFailedReason); override;
end;
TSQLRestServerAuthenticationJWT = class(TSQLRestServerAuthenticationHttpBasic)
protected
function CheckPassword(Ctxt: TSQLRestServerURIContext;
User: TSQLAuthUser; const aPassWord: RawUTF8): boolean; override;
procedure SessionCreate(Ctxt: TSQLRestServerURIContext; var User: TSQLAuthUser); override;
function getAlgo(const Value : RawUTF8) : TSignAlgo;
procedure AuthenticationFailed(Ctxt: TSQLRestServerURIContext; Reason: TNotifyAuthenticationFailedReason);
class function ClientGetSessionKey(Sender: TSQLRestClientURI;
User: TSQLAuthUser; const aNameValueParameters: array of const): RawUTF8; override;
public
function RetrieveSession(Ctxt: TSQLRestServerURIContext): TAuthSession; override;
function Auth(Ctxt: TSQLRestServerURIContext): boolean; override;
class function ClientSetUser(Sender: TSQLRestClientURI; const aUserName, aPassword: RawUTF8;
aPasswordKind: TSQLRestServerAuthenticationClientSetUserPassword=passClear;
const aHashSalt: RawUTF8=''; aHashRound: integer=20000): boolean; override;
end;
TSQLHttpClientJWT = class(TSQLHttpClientRequest)
private
fJWT: RawUTF8;
protected
procedure InternalSetClass; override;
function InternalRequest(const url, method: RawUTF8;
var Header, Data, DataType: RawUTF8): Int64Rec; override;
public
function SetUser(const aUserName, aPassword: RawUTF8;
aHashedPassword: Boolean=false): boolean; reintroduce;
property jwt : RawUTF8 read fJWT write fJWT;
end;
implementation
function HeaderOnce(const Head : RawUTF8; upper: PAnsiChar): RawUTF8;
{$ifdef HASINLINE}inline;{$endif}
begin
if (Head <> '') then
result := FindIniNameValue(pointer(Head),upper)
else result := '';
end;
{ TSQLRestRoutingREST_JWT }
procedure TSQLRestRoutingREST_JWT.AuthenticationFailed(
Reason: TNotifyAuthenticationFailedReason);
begin
inherited AuthenticationFailed(Reason);
end;
{ TSQLRestServerAuthenticationJWT }
function TSQLRestServerAuthenticationJWT.Auth(
Ctxt: TSQLRestServerURIContext): boolean;
var aUserName, aPassWord : RawUTF8;
User: TSQLAuthUser;
begin
result := False;
if AuthSessionRelease(Ctxt) then
exit;
if not Assigned(fServer.JWTForUnauthenticatedRequest) then begin
AuthenticationFailed(Ctxt, afJWTRequired);
Exit;
end;
aUserName := Ctxt.InputUTF8OrVoid['UserName'];
aPassWord := Ctxt.InputUTF8OrVoid['Password'];
if (aUserName<>'') and (length(aPassWord)>0) then begin
User := GetUser(Ctxt,aUserName);
try
result := User<>nil;
if result then begin
if CheckPassword(Ctxt, User, aPassWord) then
SessionCreate(Ctxt, User)
else AuthenticationFailed(Ctxt, afInvalidPassword);
end
else AuthenticationFailed(Ctxt, afUnknownUser);
finally
if result then User.Free;
end;
end
else AuthenticationFailed(Ctxt, afUnknownUser);
end;
procedure TSQLRestServerAuthenticationJWT.AuthenticationFailed(Ctxt: TSQLRestServerURIContext;
Reason: TNotifyAuthenticationFailedReason);
begin
if Ctxt is TSQLRestRoutingREST_JWT then
TSQLRestRoutingREST_JWT(Ctxt).AuthenticationFailed(Reason);
end;
function TSQLRestServerAuthenticationJWT.CheckPassword(
Ctxt: TSQLRestServerURIContext; User: TSQLAuthUser;
const aPassWord: RawUTF8): boolean;
var expectedPass: RawUTF8;
begin
expectedPass := User.PasswordHashHexa;
User.PasswordPlain := aPassWord;
User.PasswordHashHexa := SHA256(aPassWord);
result := IdemPropNameU(User.PasswordHashHexa,expectedPass);
end;
class function TSQLRestServerAuthenticationJWT.ClientGetSessionKey(
Sender: TSQLRestClientURI; User: TSQLAuthUser;
const aNameValueParameters: array of const): RawUTF8;
var resp: RawUTF8;
values: array[0..9] of TValuePUTF8Char;
a: integer;
algo: TSQLRestServerAuthenticationSignedURIAlgo absolute a;
begin
Result := '';
if (Sender.CallBackGet('Auth',aNameValueParameters,resp)=HTTP_SUCCESS) then
result := resp;
end;
class function TSQLRestServerAuthenticationJWT.ClientSetUser(
Sender: TSQLRestClientURI; const aUserName, aPassword: RawUTF8;
aPasswordKind: TSQLRestServerAuthenticationClientSetUserPassword;
const aHashSalt: RawUTF8; aHashRound: integer): boolean;
var res: RawUTF8;
U: TSQLAuthUser;
vTmp : Variant;
begin
result := false;
if (aUserName='') or (Sender=nil) then
exit;
if not Sender.InheritsFrom(TSQLHttpClientJWT) then
exit;
if aPasswordKind<>passClear then
raise ESecurityException.CreateUTF8('%.ClientSetUser(%) expects passClear',
[self,Sender]);
Sender.SessionClose; // ensure Sender.SessionUser=nil
try // inherited ClientSetUser() won't fit with Auth() method below
ClientSetUserHttpOnly(Sender,aUserName,aPassword);
TSQLHttpClientJWT(Sender).jwt := '';
U := TSQLAuthUser(Sender.Model.GetTableInherited(TSQLAuthUser).Create);
try
U.LogonName := trim(aUserName);
res := ClientGetSessionKey(Sender,U,['Username', aUserName, 'password', aPassword]);
if res<>'' then begin
vTmp := _JsonFast(res);
if DocVariantType.IsOfType(vTmp) then begin
result := TSQLHttpClientJWT(Sender).SessionCreate(self,U,TDocvariantData(vTmp).U['result']);
if result then
TSQLHttpClientJWT(Sender).jwt := TDocvariantData(vTmp).U['jwt'];
end;
end;
finally
U.Free;
end;
finally
if not result then begin
// on error, reverse all values
TSQLHttpClientJWT(Sender).jwt := '';
end;
if Assigned(Sender.OnSetUser) then
Sender.OnSetUser(Sender); // always notify of user change, even if failed
end;
end;
function TSQLRestServerAuthenticationJWT.getAlgo(
const Value: RawUTF8): TSignAlgo;
var i : TSignAlgo;
begin
Result := saSha256;
for i := low(JWT_TEXT) to High(JWT_TEXT) do
if SameTextU(Value, JWT_TEXT[i]) then begin
result := i;
break;
end;
end;
function TSQLRestServerAuthenticationJWT.RetrieveSession(
Ctxt: TSQLRestServerURIContext): TAuthSession;
var aUserName : RawUTF8;
User: TSQLAuthUser;
i : Integer;
tmpIdsession : Cardinal;
vSession : variant;
pSession : PDocVariantData;
vSessionPrivateSalt : RawUTF8;
begin
result := inherited RetrieveSession(Ctxt);
if result <> nil then
Exit;
if not Assigned(fServer.JWTForUnauthenticatedRequest) then
Exit;
vSessionPrivateSalt := '';
if Ctxt.AuthenticationBearerToken <> '' then
if Ctxt.AuthenticationCheck(fServer.JWTForUnauthenticatedRequest) then begin
aUserName := Ctxt.JWTContent.reg[jrcIssuer];
User := GetUser(Ctxt,aUserName);
try
if User <> nil then begin
if Ctxt.Server.Sessions <> nil then begin
if Ctxt.JWTContent.data.GetValueIndex('sessionkey') >= 0 then begin
vSession := _Json(Ctxt.JWTContent.data.U['sessionkey']);
if DocVariantType.IsOfType(vSession) then
vSessionPrivateSalt := vSession.Result;
end;
Ctxt.Server.Sessions.Safe.Lock;
try
// Search session for User
if (reOneSessionPerUser in Ctxt.Call^.RestAccessRights^.AllowRemoteExecute) and
(Ctxt.Server.Sessions<>nil) then
for i := 0 to Pred(Ctxt.Server.Sessions.Count) do
if TAuthSession(Ctxt.Server.Sessions[i]).User.ID = User.ID then begin
Result := TAuthSession(Ctxt.Server.Sessions[i]);
Ctxt.Session := Result.IDCardinal;
break;
end;
// Search session by privatesalt
if result = nil then
for i := 0 to Pred(Ctxt.Server.Sessions.Count) do
if SameTextU(vSessionPrivateSalt, TAuthSession(Ctxt.Server.Sessions[i]).ID + '+' + TAuthSession(Ctxt.Server.Sessions[i]).PrivateKey) then begin
Result := TAuthSession(Ctxt.Server.Sessions[i]);
Ctxt.Session := Result.IDCardinal;
break;
end;
finally
Ctxt.Server.Sessions.Safe.unLock;
end;
end;
end;
finally
User.free;
end;
end;
end;
procedure TSQLRestServerAuthenticationJWT.SessionCreate(
Ctxt: TSQLRestServerURIContext; var User: TSQLAuthUser);
var Session: TAuthSession;
i : Integer;
Token : RawUTF8;
jWtClass : TJWTSynSignerAbstractClass;
vPass, vUser, Signat, vSessionKey : RawUTF8;
vTmp : Variant;
begin
vUser := User.LogonName;
vPass := User.PasswordHashHexa;
inherited SessionCreate(Ctxt, User);
if Ctxt.Call^.OutStatus = HTTP_SUCCESS then begin
if fServer.JWTForUnauthenticatedRequest <> nil then begin
jwtClass := JWT_CLASS[getAlgo(fServer.JWTForUnauthenticatedRequest.Algorithm)];
Token := (fServer.JWTForUnauthenticatedRequest as jwtClass).Compute([
'sessionkey', Ctxt.Call^.OutBody],
vUser,
'jwt.access',
'',0,60, @Signat);
vTmp := _JsonFast(Ctxt.Call^.OutBody);
if DocVariantType.IsOfType(vTmp) then
Ctxt.Call^.OutBody := _Obj(['result', TDocvariantData(vTmp).U['result'], 'jwt', Token]);
end;
end;
end;
{ TSQLHttpClientJWT }
function TSQLHttpClientJWT.InternalRequest(const url, method: RawUTF8;
var Header, Data, DataType: RawUTF8): Int64Rec;
var vBasic : RawUTF8;
h : Integer;
begin
if fjwt <> '' then begin // Change Header if jwt exist
vBasic := HeaderOnce(Header, 'AUTHORIZATION: BASIC ');
if vBasic <> '' then begin
h := PosEx(vBasic, Header);
if h = 22 then
header := copy(Header, h + Length(vBasic), Length(header))
else header := copy(Header, 1, h - 21) + copy(Header, h + Length(vBasic), Length(header));
header := Trim(header);
end;
Header := trim(HEADER_BEARER_UPPER + fJWT + #13#10 + Header);
end;
result := inherited InternalRequest(url, method, Header, Data, DataType);
end;
procedure TSQLHttpClientJWT.InternalSetClass;
begin
fRequestClass := TWinHTTP;
inherited;
end;
function TSQLHttpClientJWT.SetUser(const aUserName, aPassword: RawUTF8;
aHashedPassword: Boolean): boolean;
const HASH: array[boolean] of TSQLRestServerAuthenticationClientSetUserPassword =
(passClear, passHashed);
begin
if self=nil then begin
result := false;
exit;
end;
result := TSQLRestServerAuthenticationJWT.
ClientSetUser(self,aUserName,aPassword,HASH[aHashedPassword]);
end;
end.
TSQLRestServerAuthenticationJWT.Auth() method return a RawUTF8 JSON Object containing two fields :
- result : session privatesalt (ID + '+' + privatekey)
- jwt : the Token
The TSQLHttpClientJWT class is to used with Delphi client.
FClient := TSQLHttpClientJWT.Create(SERVER_ADDRESS, DEFAULT_PORT, FDBModel);
if FClient.SetUser('synopse', 'mormot', False) then
....
For Ajax client, you must parse Auth() API response.
$("#submit").click(function(){
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function(event) {
if (this.readyState === XMLHttpRequest.DONE) {
if (this.status === 200) {
tmp = JSON.parse(xhr.responseText);
sessionStorage.setItem("jwt",tmp.jwt);
} else {
tmp = xhr.statusText;
}
}
};
username = $("#login").val();
mpass = $("#mdp").val();
xhr.open('GET', "http://127.0.0.1/MyServer/Auth?username=" + username + "&password=" + mpass, true);
xhr.send(null);
});
And use jwt value in each call :
var GET_Testjwt = function(jwt,callback){
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function(event) {
if (this.readyState === XMLHttpRequest.DONE) {
if (this.status === 200) {
response = xhr.responseText;
} else {
response = xhr.statusText;
}
callback(200, response);
}
};
jwt = sessionStorage.getItem("jwt");
xhr.open('GET', "http://127.0.0.1/MyServer/" + arequest, true);
xhr.setRequestHeader('Authorization', ' bearer ' + jwt);
xhr.send(null);
}
I hope I did not forget anything.
The code runs on the tests and will soon be in production. I'll see if it's okay.
Any comments or suggestions are welcome.
Hi,
did you try to initialize OtherDynarray ?
Like OtherDynarray.Init(TypeInfo(TArray<TFieldData>), Tab)
Hi,
I have done this to keep session :
Implement a TSQLRestServerAuthenticationHttpBasic :
TSQLRestServerAuthenticationJWT = class(TSQLRestServerAuthenticationHttpBasic)
protected
procedure SessionCreate(Ctxt: TSQLRestServerURIContext; var User: TSQLAuthUser); override;
function getAlgo(const Value : RawUTF8) : TSignAlgo;
procedure AuthenticationFailed(Ctxt: TSQLRestServerURIContext; Reason: TNotifyAuthenticationFailedReason);
public
function RetrieveSession(Ctxt: TSQLRestServerURIContext): TAuthSession; override;
function Auth(Ctxt: TSQLRestServerURIContext): boolean; override;
end;
....
procedure TSQLRestServerAuthenticationJWT.SessionCreate(
Ctxt: TSQLRestServerURIContext; var User: TSQLAuthUser);
var Session: TAuthSession;
i : Integer;
Token : RawUTF8;
jWtClass : TJWTSynSignerAbstractClass;
vUser, Signat : RawUTF8;
begin
vUser := User.LogonName;
inherited SessionCreate(Ctxt, User);
if Ctxt.Call^.OutStatus = HTTP_SUCCESS then begin
if fServer.JWTForUnauthenticatedRequest <> nil then begin
jwtClass := JWT_CLASS[getAlgo(fServer.JWTForUnauthenticatedRequest.Algorithm)];
(fServer.JWTForUnauthenticatedRequest as jwtClass).SignPrepared.Init(saSha256, SHA256(Ctxt.UserAgent + 'salt'));
Token := fServer.JWTForUnauthenticatedRequest.Compute(['sessionkey', Ctxt.Call^.OutBody],
vUser,
'MyPortail',
'',0,60, @Signat);
Ctxt.Call^.OutBody := Token; // <- on retourne le token
end;
end;
end;
function TSQLRestServerAuthenticationJWT.getAlgo(
const Value: RawUTF8): TSignAlgo;
var i : TSignAlgo;
begin
Result := saSha256;
for i := low(JWT_TEXT) to High(JWT_TEXT) do
if SameTextU(Value, JWT_TEXT[i]) then begin
result := i;
break;
end;
end;
procedure TSQLRestServerAuthenticationJWT.AuthenticationFailed(Ctxt: TSQLRestServerURIContext;
Reason: TNotifyAuthenticationFailedReason);
begin
if Ctxt is TSQLRestRoutingREST_JWT then
TSQLRestRoutingREST_JWT(Ctxt).AuthenticationFailed(Reason);
end;
function TSQLRestServerAuthenticationJWT.RetrieveSession(
Ctxt: TSQLRestServerURIContext): TAuthSession;
var aUserName : RawUTF8;
User: TSQLAuthUser;
i : Integer;
tmpIdsession : Cardinal;
vSession : variant;
pSession : PDocVariantData;
vSessionPrivateSalt : RawUTF8;
begin
result := inherited RetrieveSession(Ctxt);
if result <> nil then
Exit;
if not Assigned(fServer.JWTForUnauthenticatedRequest) then
Exit;
vSessionPrivateSalt := '';
if Ctxt.AuthenticationBearerToken <> '' then
if Ctxt.AuthenticationCheck(fServer.JWTForUnauthenticatedRequest) then begin
aUserName := Ctxt.JWTContent.reg[jrcIssuer];
User := GetUser(Ctxt,aUserName);
try
if User <> nil then begin
if Ctxt.Server.Sessions <> nil then begin
if Ctxt.JWTContent.data.GetValueIndex('sessionkey') >= 0 then begin
vSession := _Json(Ctxt.JWTContent.data.U['sessionkey']);
if DocVariantType.IsOfType(vSession) then
vSessionPrivateSalt := vSession.Result;
end;
Ctxt.Server.Sessions.Safe.Lock;
try
// Search session by privatesalt
for i := 0 to Pred(Ctxt.Server.Sessions.Count) do
if SameTextU(vSessionPrivateSalt, TAuthSession(Ctxt.Server.Sessions[i]).ID + '+' + TAuthSession(Ctxt.Server.Sessions[i]).PrivateKey) then begin
Result := TAuthSession(Ctxt.Server.Sessions[i]);
Ctxt.Session := Result.IDCardinal;
break;
end;
// Search session for User
if result = nil then
for i := 0 to Pred(Ctxt.Server.Sessions.Count) do
if TAuthSession(Ctxt.Server.Sessions[i]).User.ID = User.ID then begin
Result := TAuthSession(Ctxt.Server.Sessions[i]);
Ctxt.Session := Result.IDCardinal;
break;
end;
finally
Ctxt.Server.Sessions.Safe.unLock;
end;
end;
end;
finally
User.free;
end;
end;
end;
function TSQLRestServerAuthenticationJWT.Auth(
Ctxt: TSQLRestServerURIContext): boolean;
var aUserName, aPassWord : RawUTF8;
User: TSQLAuthUser;
begin
result := False;
if AuthSessionRelease(Ctxt) then
exit;
if not Assigned(fServer.JWTForUnauthenticatedRequest) then begin
AuthenticationFailed(Ctxt, afJWTRequired);
Exit;
end;
aUserName := Ctxt.InputUTF8OrVoid['UserName'];
aPassWord := Ctxt.InputUTF8OrVoid['Password'];
if (aUserName<>'') and (length(aPassWord)>0) then begin
User := GetUser(Ctxt,aUserName);
try
result := User<>nil;
if result then begin
if CheckPassword(Ctxt, User, aPassWord) then
SessionCreate(Ctxt, User)
else AuthenticationFailed(Ctxt, afInvalidPassword);
end
else AuthenticationFailed(Ctxt, afUnknownUser);
finally
if result then User.Free;
end;
end
else AuthenticationFailed(Ctxt, afUnknownUser);
end;
Implement the TSQLRestRoutingREST for access to protected AuthenticationFailed function :
TSQLRestRoutingREST_JWT = class(TSQLRestRoutingREST)
protected
procedure AuthenticationFailed(Reason: TNotifyAuthenticationFailedReason); override;
end;
....
procedure TSQLRestRoutingREST_JWT.AuthenticationFailed(
Reason: TNotifyAuthenticationFailedReason);
begin
inherited AuthenticationFailed(Reason);
end;
For the Rest server creation :
fRestServer.AuthenticationRegister(TSQLRestServerAuthenticationJWT);
fRestServer.ServicesRouting := TSQLRestRoutingREST_JWT;
fRestServer.JWTForUnauthenticatedRequest := fServerSettings.AuthenticationMode.JWTClass.Create('secret', 0, [jrcIssuer, jrcSubject], [], 60);
JWTForUnauthenticatedRequest instance is used in TSQLRestServerAuthenticationJWT.
Work fine.
Thank's
hi,
when I define NOSSPIAUTH directive, I have a compilation error under TSQLHTTPServer.Create().
I make this modification :
const AUTH: array[TSQLHttpServerRestAuthentication] of TSQLRestServerAuthenticationClass = (
// adDefault, adHttpBasic, adWeak, adSSPI
TSQLRestServerAuthenticationDefault, TSQLRestServerAuthenticationHttpBasic,
TSQLRestServerAuthenticationNone,
{$ifdef MSWINDOWS}
/*...Modif....*/
{$ifdef SPPIAUTH}TSQLRestServerAuthenticationSSPI{$else}nil{$endif}
/*...End...*/
{$else}nil{$endif});
best regards
Christophe
That don't works for me too.
The @ab solution works.
--> ftDateTime: PDateTimeRec(Dest)^.DateTime := TimeStampToMSecs(TS);
If TS have not Time part (TS.Time = 0) then PDateTime(Data)^ doesn't have a valid date.
I used DataSetToJSON(MyInterbaseQuery) to store data in RawUTF8 buffer.
I reload data with TSynSQLTableDataSet.CreateFromJSON(nil, MyBuffer, MyTSQLFieldsType)
Hi,
when i compiled a package including Mormot unit under Delphi XE3, i've got this compilator error :
[dcc32 Error] mORMot.pas(2363):E2003 Unknown identifier : "TsynExtended"
Is everybody have an idea ?
PS : USEPACKAGES is activate in Synopse.inc
Next time, I will try to sign my neurons.
Thank's a lot
Hi,
I'm trying to use a TRawByteStringArray Field in a TSQLRecord Object.
Under Delphi XE3 (64 bit platform for compilation) compilater report this exception :
E2100 : Data type too large: exceeds 2 GB
The only way I have found is to change TRawByteStringArray declaration from static array to dynamic array in Syncommons.
// TRawByteStringArray = array[0..MaxInt div SizeOf(RawByteString)-1] of RawByteString;
TRawByteStringArray = array of RawByteString;
What's your opinion about this modification ?
thank's in advance.
Hi
when i use TByteDynArray(Table.GetBytes(...)) the result contains more bytes (7) than the stored array (perhaps Base64Encode ?).
With TByteDynArray(Table.GetBytes(...)) --> (1,0,12,15,18,48,54,1,2,3,4,5,6,7,8,9,10,11,12)
With client.Retrieve(row, MySQLrecord) --> (1,2,3,4,5,6,7,8,9,10,11,12)
But if i use MySQLRecord.FillFrom(Table) all is fine.
It's good for me.
Thanks a lot.
I've done it first with table.GetBytes but I have don't find how to load the TByteDynArray variable with it.
Do you have a sample. I dont find anything in the documentation and in the forum.
Thanks.
Hi,
I didin't find how to read TByteDynArray Field from a TSQLHttpClientWinHTTP.list() result.
TRHhisto = class(TSQLRecord)
private
fHisBuffer : TRawUTF8DynArray;
fHisMois : TByteDynArray;
public
procedure Clear; override;
published
property hisBuffer : TRawUTF8DynArray read fHisBuffer write fHisBuffer;
property hisMois : TByteDynArray read fHisMois write fHisMois;
end;
{...}
var Table : TSQLTableJSON;
bl : TSQLRawBlob;
{...}
Table := Client.List([TRHhisto], 'rowID, HISPERID, HISMOIS', StringToUTF8(sWhere));
if Table <> nil then
begin
{...}
bl := Table.getBlob(idx, Table.fieldIndex('HISMOIS'));
------> How to convert bl to a TByteDynArray variable ?
end;
Thanks in advance.
I will test it.
Thanks ab.
HI,
when i execute MVCServer sample with PUREPASCAL Directive On, i have this error :
Unit Mormot.pas
constructor TSQLRecordProperties.Create(aTable: TSQLRecordClass);
{...}
line 34813 :
if PosEx(' '+LowerCase(F.Name)+' ',SQLITE3_KEYWORDS)>0 then // Result = 226 with F.Name = 'Title'
raise EORMException.CreateUTF8('%.% field name conflicts with a SQL keyword',
If PUREPASCAL is Off, the result of PosEx is 0.
Thanks for your reply and sorry, i have not restart server after installation of MongoDB.
After restart, it's work fine.
Yes I do.
MongoDB version : 2.6.1 (x64-2008 msi)
Windows 8 x64
I've got same results with Windows server 2008 x64, Windows server 2012 x64 and MongoDB 2.6.1 x32 on Windows XP sp 4.
Hello there,
when i use this piece of code for initialized a new MongoDB database
MongoClient := TMongoClient.Create(Host_ip,27017);
DB := MongoClient.Database[DTB_name];
Model := TSQLModel.Create([TMYMODEL]);
Client := TSQLRestClientDB.Create(Model,nil,':memory:',TSQLRestServerDB);
try
if StaticMongoDBRegister(TMYMODEL,
Client.Server,
DB,
DTB_name)=nil then
raise Exception.Create('Error');
i've got this error : Unknown collection "system.indexes"
only on a new installation of MongoDB server and when a field is marked "AS_UNIQUE" in TSQLMODEL declaration.
But when i used a direct mongoDB database access as in your post http://blog.synopse.info/post/2014/05/0 … ase-access , system.indexes collection is correctly initialized.
So,
- did i must initialized database first with direct access ?
- Is there something wrong in my code ?
Thank´s for your time
Sorry,
All is in the header :
sIn := StringToUTF8(vfilename);
sHead := 'Content-Type: ' + HTTP_RESP_STATICFILE + #13 +
'Content-Disposition: attachment; filename="MyInstallprog.exe"';
aParams.Head^ := sHead;
aParams.Resp := sIn;
result := 200;
Hi,
When I try to download a file (HTTP_RESP_STATICFILE) from a CALLBACKGET Method (TSQLRESTServer class), the output filename is the CALLBACKGET Method name.
Is anyone know what must i do for change it ?
sIn := StringToUTF8(vfilename);
sHead := 'Content-Type: ' + HTTP_RESP_STATICFILE;
aParams.Head^ := sHead;
aParams.Resp := sIn;
result := 200;
The aim is to download a client application for a local network server from his location (SERVERIP/client/Index?myInstallclient.exe).
Pages: 1