* Merging revisions 42743,42766,42767,42768,42782 from trunk:

------------------------------------------------------------------------
    r42743 | michael | 2019-08-20 09:03:24 +0200 (Tue, 20 Aug 2019) | 1 line
    
    * Fix bug #0035985
    ------------------------------------------------------------------------
    r42766 | michael | 2019-08-23 08:45:11 +0200 (Fri, 23 Aug 2019) | 1 line
    
    * Fix bug ID #0035596: better detection of vcs device
    ------------------------------------------------------------------------
    r42767 | michael | 2019-08-23 09:21:03 +0200 (Fri, 23 Aug 2019) | 1 line
    
    * Make TResponse.Content a RawByteString
    ------------------------------------------------------------------------
    r42768 | michael | 2019-08-23 09:21:44 +0200 (Fri, 23 Aug 2019) | 1 line
    
    * Set content-type on response (bug ID 35990)
    ------------------------------------------------------------------------
    r42782 | michael | 2019-08-24 10:54:24 +0200 (Sat, 24 Aug 2019) | 1 line
    
    * Add WideString support in json string constructor
    ------------------------------------------------------------------------

git-svn-id: branches/fixes_3_2@42844 -
This commit is contained in:
michael 2019-08-27 06:57:58 +00:00
parent b8b5501fb9
commit 909b54579d
5 changed files with 120 additions and 65 deletions

View File

@ -2497,6 +2497,8 @@ begin
vtExtended : Result:=CreateJSON(VExtended^); vtExtended : Result:=CreateJSON(VExtended^);
vtString : Result:=CreateJSON(vString^); vtString : Result:=CreateJSON(vString^);
vtAnsiString : Result:=CreateJSON(UTF8Decode(StrPas(VPChar))); vtAnsiString : Result:=CreateJSON(UTF8Decode(StrPas(VPChar)));
vtUnicodeString: Result:=CreateJSON(UnicodeString(VUnicodeString));
vtWideString: Result:=CreateJSON(WideString(VWideString));
vtPChar : Result:=CreateJSON(StrPas(VPChar)); vtPChar : Result:=CreateJSON(StrPas(VPChar));
vtPointer : If (VPointer<>Nil) then vtPointer : If (VPointer<>Nil) then
TJSONData.DoError(SErrPointerNotNil,[SourceType]) TJSONData.DoError(SErrPointerNotNil,[SourceType])

View File

@ -53,7 +53,7 @@ type
Procedure SetUp; override; Procedure SetUp; override;
Procedure TestItemCount(J : TJSONData;Expected : Integer); Procedure TestItemCount(J : TJSONData;Expected : Integer);
Procedure TestJSONType(J : TJSONData;Expected : TJSONType); Procedure TestJSONType(J : TJSONData;Expected : TJSONType);
Procedure TestJSON(J : TJSONData;Expected : String); Procedure TestJSON(J : TJSONData;Expected : TJSONStringType);
Procedure TestIsNull(J : TJSONData;Expected : Boolean); Procedure TestIsNull(J : TJSONData;Expected : Boolean);
Procedure TestAsBoolean(J : TJSONData;Expected : Boolean; ExpectError : boolean = False); Procedure TestAsBoolean(J : TJSONData;Expected : Boolean; ExpectError : boolean = False);
Procedure TestAsInteger(J : TJSONData; Expected : Integer; ExpectError : boolean = False); Procedure TestAsInteger(J : TJSONData; Expected : Integer; ExpectError : boolean = False);
@ -238,6 +238,8 @@ type
procedure TestCreateBoolean; procedure TestCreateBoolean;
procedure TestCreateBooleanUnquoted; procedure TestCreateBooleanUnquoted;
procedure TestCreateObject; procedure TestCreateObject;
procedure TestCreateJSONUnicodeString;
procedure TestCreateJSONWideString;
procedure TestCreateJSONString; procedure TestCreateJSONString;
procedure TestCreateJSONStringUnquoted; procedure TestCreateJSONStringUnquoted;
procedure TestCreateJSONObject; procedure TestCreateJSONObject;
@ -1078,7 +1080,7 @@ begin
AssertEquals(J.ClassName+'.JSONType',Ord(Expected),Ord(J.JSONType)); AssertEquals(J.ClassName+'.JSONType',Ord(Expected),Ord(J.JSONType));
end; end;
Procedure TTestJSON.TestJSON(J: TJSONData; Expected: String); Procedure TTestJSON.TestJSON(J: TJSONData; Expected: TJSONStringType);
begin begin
AssertEquals(J.ClassName+'.AsJSON',Expected,J.AsJSON); AssertEquals(J.ClassName+'.AsJSON',Expected,J.AsJSON);
end; end;
@ -3926,6 +3928,44 @@ begin
end; end;
end; end;
procedure TTestObject.TestCreateJSONUnicodeString;
Const
A = 'A';
S : Unicodestring = 'A string';
Var
O : TJSONObject;
begin
O:=TJSONObject.Create([A,S]);
try
TestItemCount(O,1);
TestJSONType(O[A],jtString);
TestJSON(O,'{ "A" : "'+UTF8Encode(S)+'" }');
finally
FreeAndNil(O);
end;
end;
procedure TTestObject.TestCreateJSONWideString;
Const
A = 'A';
W : WideString = 'A string';
Var
O : TJSONObject;
begin
O:=TJSONObject.Create([A,W]);
try
TestItemCount(O,1);
TestJSONType(O[A],jtString);
TestJSON(O,'{ "A" : "'+UTF8Encode(W)+'" }');
finally
FreeAndNil(O);
end;
end;
procedure TTestObject.TestCreateNilPointer; procedure TTestObject.TestCreateNilPointer;
Const Const

View File

@ -475,8 +475,8 @@ type
FContentSent: Boolean; FContentSent: Boolean;
FRequest : TRequest; FRequest : TRequest;
FCookies : TCookies; FCookies : TCookies;
function GetContent: String; function GetContent: RawByteString;
procedure SetContent(const AValue: String); procedure SetContent(const AValue: RawByteString);
procedure SetContents(AValue: TStrings); procedure SetContents(AValue: TStrings);
procedure SetContentStream(const AValue: TStream); procedure SetContentStream(const AValue: TStream);
procedure SetFirstHeaderLine(const line: String); procedure SetFirstHeaderLine(const line: String);
@ -507,7 +507,7 @@ type
Property RetryAfter : String Index Ord(hhRetryAfter) Read GetHeaderValue Write SetHeaderValue; Property RetryAfter : String Index Ord(hhRetryAfter) Read GetHeaderValue Write SetHeaderValue;
Property FirstHeaderLine : String Read GetFirstHeaderLine Write SetFirstHeaderLine; Property FirstHeaderLine : String Read GetFirstHeaderLine Write SetFirstHeaderLine;
Property ContentStream : TStream Read FContentStream Write SetContentStream; Property ContentStream : TStream Read FContentStream Write SetContentStream;
Property Content : String Read GetContent Write SetContent; Property Content : RawByteString Read GetContent Write SetContent;
property Contents : TStrings read FContents Write SetContents; property Contents : TStrings read FContents Write SetContents;
Property HeadersSent : Boolean Read FHeadersSent; Property HeadersSent : Boolean Read FHeadersSent;
Property ContentSent : Boolean Read FContentSent; Property ContentSent : Boolean Read FContentSent;
@ -1985,7 +1985,7 @@ begin
FContents:=TStringList.Create; FContents:=TStringList.Create;
TStringList(FContents).OnChange:=@ContentsChanged; TStringList(FContents).OnChange:=@ContentsChanged;
FCookies:=TCookies.Create(TCookie); FCookies:=TCookies.Create(TCookie);
FCustomHeaders:=TStringList.Create; FCustomHeaders:=TStringList.Create; // Destroyed in parent
end; end;
destructor TResponse.destroy; destructor TResponse.destroy;
@ -2074,14 +2074,18 @@ begin
FContents.Assign(AValue); FContents.Assign(AValue);
end; end;
function TResponse.GetContent: String; function TResponse.GetContent: RawByteString;
begin begin
Result:=Contents.Text; Result:=Contents.Text;
end; end;
procedure TResponse.SetContent(const AValue: String); procedure TResponse.SetContent(const AValue: RawByteString);
begin begin
FContentStream:=Nil; if Assigned(FContentStream) then
if FreeContentStream then
FreeAndNil(FContentStream)
else
FContentStream:=Nil;
FContents.Text:=AValue; FContents.Text:=AValue;
end; end;

View File

@ -89,8 +89,10 @@ Type
FOptions: TJSONRPCDispatchOptions; FOptions: TJSONRPCDispatchOptions;
FRequest: TRequest; FRequest: TRequest;
FResponse: TResponse; FResponse: TResponse;
FResponseContentType: String;
procedure SetDispatcher(const AValue: TCustomJSONRPCDispatcher); procedure SetDispatcher(const AValue: TCustomJSONRPCDispatcher);
Protected Protected
Function GetResponseContentType : String;
Function CreateDispatcher : TCustomJSONRPCDispatcher; virtual; Function CreateDispatcher : TCustomJSONRPCDispatcher; virtual;
procedure Notification(AComponent: TComponent; Operation: TOperation);override; procedure Notification(AComponent: TComponent; Operation: TOperation);override;
Property Dispatcher : TCustomJSONRPCDispatcher Read FDispatcher Write SetDispatcher; Property Dispatcher : TCustomJSONRPCDispatcher Read FDispatcher Write SetDispatcher;
@ -102,14 +104,19 @@ Type
Property Request: TRequest Read FRequest; Property Request: TRequest Read FRequest;
// Access to response // Access to response
Property Response: TResponse Read FResponse; Property Response: TResponse Read FResponse;
// Response Content-Type. If left empty, application/json is used.
Property ResponseContentType : String Read FResponseContentType Write FResponseContentType;
end; end;
{ TJSONRPCDataModule } { TJSONRPCDataModule }
{ TJSONRPCModule }
TJSONRPCModule = Class(TCustomJSONRPCModule) TJSONRPCModule = Class(TCustomJSONRPCModule)
Published Published
Property Dispatcher; Property Dispatcher;
Property DispatchOptions; Property DispatchOptions;
Property ResponseContentType;
end; end;
implementation implementation
@ -118,6 +125,9 @@ implementation
uses dbugintf; uses dbugintf;
{$endif} {$endif}
Const
SApplicationJSON = 'application/json';
{ TCustomJSONRPCContentProducer } { TCustomJSONRPCContentProducer }
function TCustomJSONRPCContentProducer.GetIDProperty: String; function TCustomJSONRPCContentProducer.GetIDProperty: String;
@ -133,7 +143,7 @@ Var
Disp : TCustomJSONRPCDispatcher; Disp : TCustomJSONRPCDispatcher;
P : TJSONParser; P : TJSONParser;
Req,res : TJSONData; Req,res : TJSONData;
R : String; R : TJSONStringType;
begin begin
Disp:=Self.GetDispatcher; Disp:=Self.GetDispatcher;
@ -211,6 +221,13 @@ begin
FDispatcher.FreeNotification(Self); FDispatcher.FreeNotification(Self);
end; end;
function TCustomJSONRPCModule.GetResponseContentType: String;
begin
Result:=FResponseContentType;
if Result='' then
Result:=SApplicationJSON;
end;
function TCustomJSONRPCModule.CreateDispatcher: TCustomJSONRPCDispatcher; function TCustomJSONRPCModule.CreateDispatcher: TCustomJSONRPCDispatcher;
Var Var
@ -245,6 +262,7 @@ procedure TCustomJSONRPCModule.HandleRequest(ARequest: TRequest;
Var Var
Disp : TCustomJSONRPCDispatcher; Disp : TCustomJSONRPCDispatcher;
res : TJSONData; res : TJSONData;
R : TJSONStringType;
begin begin
If (Dispatcher=Nil) then If (Dispatcher=Nil) then
@ -254,10 +272,15 @@ begin
try try
If Assigned(Res) then If Assigned(Res) then
begin begin
AResponse.Content:=Res.AsJSON; AResponse.FreeContentStream:=True;
AResponse.ContentLength:=Length(AResponse.Content); AResponse.ContentStream:=TMemoryStream.Create;
R:=Res.AsJSON;
AResponse.ContentStream.WriteBuffer(R[1],Length(R));
AResponse.ContentLength:=AResponse.ContentStream.Size;
R:=''; // Free up mem
AResponse.ContentType:=GetResponseContentType;
end; end;
AResponse.SendResponse; AResponse.SendResponse;
finally finally
Res.Free; Res.Free;
end; end;

View File

@ -82,73 +82,59 @@ end;
procedure detect_linuxvcs; procedure detect_linuxvcs;
var f:text; var f:text;
f_open : boolean; fields:array [0..60] of int64;
c,pc:char; fieldct,i:integer;
pid,cpid,dummy:longint; pid,ppid:longint;
device:dword; magnitude:int64;
s:string[15]; s:string[15];
statln:ansistring;
begin begin
{Extremely aggressive VCSA detection. Works even through Midnight {Extremely aggressive VCSA detection. Works even through Midnight
Commander. Idea from the C++ Turbo Vision project, credits go Commander. Idea from the C++ Turbo Vision project, credits go
to Martynas Kunigelis <algikun@santaka.sc-uni.ktu.lt>.} to Martynas Kunigelis <algikun@santaka.sc-uni.ktu.lt>.}
pid:=fpgetpid; pid:=fpgetpid;
f_open:=false;
{$push}
{$I-}
{$R-}
repeat repeat
cpid:=pid;
str(pid,s); str(pid,s);
assign(f,'/proc/'+s+'/stat'); assign(f, '/proc/'+s+'/stat');
{$I-}
reset(f); reset(f);
{$I+}
if ioresult<>0 then if ioresult<>0 then
exit; break;
f_open:=true; readln(f, statln);
{ from here we can discard I/O errors, as long as we avoid
infinite loops }
{ first number is pid }
dummy:=0;
read(f,dummy);
if dummy<>pid then
exit;
{ after comes the name of the binary within (), look for closing brace followed by space }
c:=#0;
repeat
pc:=c;
read(f,c);
if ioresult<>0 then
break;
until (pc=')') and (c=' ');
{ now comes the state letter }
repeat
read(f,c);
if ioresult<>0 then
break;
until c=' ';
{ parent pid }
pid:=-1;
read(f,pid);
{ process group }
read(f,dummy);
{ session }
read(f,dummy);
{ device number }
device:=0;
read(f,device);
close(f); close(f);
f_open:=false; magnitude := 1;
if (device and $ffffffc0)=$00000400 then {/dev/tty*} fieldct := 0;
fields[fieldct] := 0;
for i := high(statln) downto low(statln) do
begin begin
vcs_device:=device and $3f; case statln[i] of
'-': magnitude := -1;
'0'..'9': begin
fields[fieldct] := fields[fieldct]
+ (magnitude * (ord(statln[i]) - ord('0')));
magnitude := magnitude * 10;
end;
' ': begin
magnitude := 1;
fieldct := fieldct + 1;
fields[fieldct] := 0;
end;
else
break;
end;
end;
ppid := pid;
pid := fields[fieldct - 1];
if (fields[fieldct - 4] and $ffffffc0) = $00000400 then {/dev/tty*}
begin
vcs_device:=fields[fieldct - 4] and $3f;
break; break;
end; end;
until (device=0) {Not attached to a terminal, i.e. an xterm.} until (fields[fieldct - 4]=0) {Not attached to a terminal, i.e. an xterm.}
or (pid=-1) or (pid=-1)
or (cpid=pid); or (ppid=pid);
if f_open then
close(f);
{$pop}
end; end;
begin begin