Browse Source

* 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 -

michael 6 years ago
parent
commit
909b54579d

+ 2 - 0
packages/fcl-json/src/fpjson.pp

@@ -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])

+ 42 - 2
packages/fcl-json/tests/testjsondata.pp

@@ -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

+ 11 - 7
packages/fcl-web/src/base/httpdefs.pp

@@ -475,8 +475,8 @@ type
     FContentSent: Boolean;
     FContentSent: Boolean;
     FRequest : TRequest;
     FRequest : TRequest;
     FCookies : TCookies;
     FCookies : TCookies;
-    function GetContent: String;
-    procedure SetContent(const AValue: String);
+    function GetContent: RawByteString;
+    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;
 
 

+ 27 - 4
packages/fcl-web/src/jsonrpc/webjsonrpc.pp

@@ -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.ContentLength:=Length(AResponse.Content);
+      AResponse.FreeContentStream:=True;
+      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;

+ 38 - 52
rtl/linux/linuxvcs.pp

@@ -82,73 +82,59 @@ end;
 procedure detect_linuxvcs;
 procedure detect_linuxvcs;
 
 
 var f:text;
 var f:text;
-    f_open : boolean;
-    c,pc:char;
-    pid,cpid,dummy:longint;
-    device:dword;
+    fields:array [0..60] of int64;
+    fieldct,i:integer;
+    pid,ppid:longint;
+    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 <[email protected]>.}
    to Martynas Kunigelis <[email protected]>.}
   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;
-    f_open:=true;
-    { 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);
+      break;
+    readln(f, statln);
     close(f);
     close(f);
-    f_open:=false;
-    if (device and $ffffffc0)=$00000400 then {/dev/tty*}
+    magnitude := 1;
+    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.}
-      or (pid=-1)
-      or (cpid=pid);
-  if f_open then
-    close(f);
-  {$pop}
+  until (fields[fieldct - 4]=0) {Not attached to a terminal, i.e. an xterm.}
+        or (pid=-1)
+        or (ppid=pid);
 end;
 end;
 
 
 begin
 begin