2
0
Эх сурвалжийг харах

--- Merging r15576 into '.':
U packages/fcl-web/src/webdata/Makefile.fpc
C packages/fcl-web/src/webdata/Makefile
--- Merging r15853 into '.':
U packages/fcl-web/src/base/fpweb.pp
--- Merging r15859 into '.':
U packages/fcl-web/src/webdata/extjsjson.pp
U packages/fcl-web/src/webdata/extjsxml.pp
--- Merging r15861 into '.':
G packages/fcl-web/src/webdata/extjsjson.pp
G packages/fcl-web/src/webdata/extjsxml.pp
--- Merging r15863 into '.':
U packages/fcl-web/src/base/custfcgi.pp
--- Merging r15881 into '.':
G packages/fcl-web/src/base/custfcgi.pp
--- Merging r15893 into '.':
G packages/fcl-web/src/webdata/extjsjson.pp
U packages/fcl-web/src/webdata/fpwebdata.pp
G packages/fcl-web/src/webdata/extjsxml.pp
--- Merging r15920 into '.':
G packages/fcl-web/src/webdata/extjsjson.pp
--- Merging r15940 into '.':
G packages/fcl-web/src/base/custfcgi.pp
--- Merging r16068 into '.':
U packages/fcl-web/src/webdata/sqldbwebdata.pp
--- Merging r16069 into '.':
G packages/fcl-web/src/base/fpweb.pp
U packages/fcl-web/src/base/websession.pp
Summary of conflicts:
Text conflicts: 1

# revisions: 15576,15853,15859,15861,15863,15881,15893,15920,15940,16068,16069
------------------------------------------------------------------------
r15576 | jonas | 2010-07-15 10:02:23 +0200 (Thu, 15 Jul 2010) | 2 lines
Changed paths:
M /trunk/packages/fcl-web/src/webdata/Makefile
M /trunk/packages/fcl-web/src/webdata/Makefile.fpc

* added fcl-web to the unit search path

------------------------------------------------------------------------
------------------------------------------------------------------------
r15853 | michael | 2010-08-19 18:57:32 +0200 (Thu, 19 Aug 2010) | 1 line
Changed paths:
M /trunk/packages/fcl-web/src/base/fpweb.pp

* Applied patch from Luiz Americo
------------------------------------------------------------------------
------------------------------------------------------------------------
r15859 | michael | 2010-08-20 09:18:40 +0200 (Fri, 20 Aug 2010) | 1 line
Changed paths:
M /trunk/packages/fcl-web/src/webdata/extjsjson.pp
M /trunk/packages/fcl-web/src/webdata/extjsxml.pp

* Added events to influence streaming process
------------------------------------------------------------------------
------------------------------------------------------------------------
r15861 | michael | 2010-08-20 10:58:13 +0200 (Fri, 20 Aug 2010) | 1 line
Changed paths:
M /trunk/packages/fcl-web/src/webdata/extjsjson.pp
M /trunk/packages/fcl-web/src/webdata/extjsxml.pp

* Error event implemented
------------------------------------------------------------------------
------------------------------------------------------------------------
r15863 | michael | 2010-08-20 16:38:45 +0200 (Fri, 20 Aug 2010) | 1 line
Changed paths:
M /trunk/packages/fcl-web/src/base/custfcgi.pp

* Fixed memory leak when reading fastcgi records
------------------------------------------------------------------------
------------------------------------------------------------------------
r15881 | michael | 2010-08-23 14:55:26 +0200 (Mon, 23 Aug 2010) | 1 line
Changed paths:
M /trunk/packages/fcl-web/src/base/custfcgi.pp

* Fixed reading of name=length pairs with lenfth>128
------------------------------------------------------------------------
------------------------------------------------------------------------
r15893 | michael | 2010-08-24 16:40:22 +0200 (Tue, 24 Aug 2010) | 1 line
Changed paths:
M /trunk/packages/fcl-web/src/webdata/extjsjson.pp
M /trunk/packages/fcl-web/src/webdata/extjsxml.pp
M /trunk/packages/fcl-web/src/webdata/fpwebdata.pp

* Fixed (BLOB) display, added support for transcoding
------------------------------------------------------------------------
------------------------------------------------------------------------
r15920 | michael | 2010-08-30 09:39:39 +0200 (Mon, 30 Aug 2010) | 1 line
Changed paths:
M /trunk/packages/fcl-web/src/webdata/extjsjson.pp

* After insert/update/delete events
------------------------------------------------------------------------
------------------------------------------------------------------------
r15940 | michael | 2010-09-03 10:18:41 +0200 (Fri, 03 Sep 2010) | 2 lines
Changed paths:
M /trunk/packages/fcl-web/src/base/custfcgi.pp

* Better error handling when reading from socket.
* Handle case where (windows) tcp/ip stack returns only partial number of bytes
------------------------------------------------------------------------
------------------------------------------------------------------------
r16068 | michael | 2010-09-30 10:50:14 +0200 (Thu, 30 Sep 2010) | 1 line
Changed paths:
M /trunk/packages/fcl-web/src/webdata/sqldbwebdata.pp

* RegenerateParams was not called in all cases
------------------------------------------------------------------------
------------------------------------------------------------------------
r16069 | michael | 2010-09-30 10:54:19 +0200 (Thu, 30 Sep 2010) | 4 lines
Changed paths:
M /trunk/packages/fcl-web/src/base/fpweb.pp
M /trunk/packages/fcl-web/src/base/websession.pp

* improved session management:
- GlobalSessionDir is now always used, even when creating descendents of TWebIniSession.
- Explicitly Free session. (Prepares for persistent session info for fastcgi apps)

------------------------------------------------------------------------

git-svn-id: branches/fixes_2_4@16406 -

marco 14 жил өмнө
parent
commit
0ccf3830cd

+ 83 - 53
packages/fcl-web/src/base/custfcgi.pp

@@ -120,10 +120,12 @@ Type
   end;
 
 ResourceString
-  SNoInputHandle = 'Failed to open input-handle passed from server. Socket Error: %d';
-  SNoSocket      = 'Failed to open socket. Socket Error: %d';
-  SBindFailed    = 'Failed to bind to port %d. Socket Error: %d';
-  SListenFailed  = 'Failed to listen to port %d. Socket Error: %d';
+  SNoInputHandle    = 'Failed to open input-handle passed from server. Socket Error: %d';
+  SNoSocket         = 'Failed to open socket. Socket Error: %d';
+  SBindFailed       = 'Failed to bind to port %d. Socket Error: %d';
+  SListenFailed     = 'Failed to listen to port %d. Socket Error: %d';
+  SErrReadingSocket = 'Failed to read data from socket. Error: %d';
+  SErrReadingHeader = 'Failed to read FastCGI header. Read only %d bytes';
 
 Implementation
 
@@ -207,9 +209,9 @@ var
       Result:=ARecord^.ContentData[i]
     else
       begin
-      Result:=BEtoN(PWord(@(ARecord^.ContentData[i]))^);
-      // ((ARecord^.ContentData[i] and $7f) shl 24) + (ARecord^.ContentData[i+1] shl 16)
-      //             + (ARecord^.ContentData[i+2] shl 8) + (ARecord^.ContentData[i+3]);
+//      Result:=BEtoN(PLongint(@(ARecord^.ContentData[i]))^);
+      Result:=((ARecord^.ContentData[i] and $7f) shl 24) + (ARecord^.ContentData[i+1] shl 16)
+                   + (ARecord^.ContentData[i+2] shl 8) + (ARecord^.ContentData[i+3]);
       inc(i,3);
       end;
     inc(i);
@@ -433,44 +435,69 @@ end;
 
 function TFCgiHandler.Read_FCGIRecord : PFCGI_Header;
 
+  function ReadBytes(ReadBuf: Pointer; ByteAmount : Word) : Integer;
+
+  Var
+    P : PByte;
+    Count : Integer;
+
+  begin
+    Result := 0;
+    P:=ReadBuf;
+    if (ByteAmount=0) then exit;
+    Repeat
+      Count:=sockets.fpRecv(FHandle, P, ByteAmount, NoSignalAttr);
+      If (Count>0) then
+        begin
+        Dec(ByteAmount,Count);
+        P:=P+Count;
+        Inc(Result,Count);
+        end
+      else if (Count<0) then
+        Raise HTTPError.CreateFmt(SErrReadingSocket,[Count]);
+    until (ByteAmount=0) or (Count=0);
+  end;
+
 var Header : FCGI_Header;
-    BytesRead : integer;
+    {I,}BytesRead : integer;
     ContentLength : word;
     PaddingLength : byte;
     ResRecord : pointer;
     ReadBuf : pointer;
+    s : string;
 
-  function ReadBytes(ByteAmount : Word) : boolean;
-  begin
-   result := False;
-    if ByteAmount>0 then
-      begin
-      BytesRead := sockets.fpRecv(FHandle, ReadBuf, ByteAmount, NoSignalAttr);
-      if BytesRead<>ByteAmount then
-        begin
-//        SendDebug('FCGIRecord incomplete');
-//        SendDebug('BytesRead: '+inttostr(BytesRead)+', expected: '+inttostr(ByteAmount));
-        exit;
-        end
-      else
-        Result := True;
-      end;
-  end;
 
 begin
   Result := Nil;
   ResRecord:=Nil;
   ReadBuf:=@Header;
-  if not ReadBytes(Sizeof(Header)) then exit;
+  BytesRead:=ReadBytes(ReadBuf,Sizeof(Header));
+  If (BytesRead<>Sizeof(Header)) then
+    Raise HTTPError.CreateFmt(SErrReadingHeader,[BytesRead]);
   ContentLength:=BetoN(Header.contentLength);
   PaddingLength:=Header.paddingLength;
   Getmem(ResRecord,BytesRead+ContentLength+PaddingLength);
   PFCGI_Header(ResRecord)^:=Header;
   ReadBuf:=ResRecord+BytesRead;
-  ReadBytes(ContentLength);
+  BytesRead:=ReadBytes(ReadBuf,ContentLength);
   ReadBuf:=ReadBuf+BytesRead;
-  ReadBytes(PaddingLength);
+  BytesRead:=ReadBytes(ReadBuf,PaddingLength);
   Result := ResRecord;
+{
+  Writeln('Dumping record ', Sizeof(Header),',',Contentlength,',',PaddingLength);
+  For I:=0 to Sizeof(Header)+ContentLength+PaddingLength-1 do
+    begin
+    Write(Format('%:3d ',[PByte(ResRecord)[i]]));
+    If PByte(ResRecord)[i]>30 then
+      S:=S+char(PByte(ResRecord)[i]);
+    if (I mod 16) = 0 then
+       begin
+       writeln('  ',S);
+       S:='';
+       end;
+    end;
+  Writeln('  ',S)
+}
 end;
 
 function TFCgiHandler.WaitForRequest(out ARequest: TRequest; out AResponse: TResponse): boolean;
@@ -525,34 +552,37 @@ begin
   repeat
   AFCGI_Record:=Read_FCGIRecord;
   if assigned(AFCGI_Record) then
-    begin
-    ARequestID:=BEtoN(AFCGI_Record^.requestID);
-    if AFCGI_Record^.reqtype = FCGI_BEGIN_REQUEST then
-      begin
-      if ARequestID>FRequestsAvail then
+    try
+      ARequestID:=BEtoN(AFCGI_Record^.requestID);
+      if AFCGI_Record^.reqtype = FCGI_BEGIN_REQUEST then
         begin
-        inc(FRequestsAvail,10);
-        SetLength(FRequestsArray,FRequestsAvail);
+        if ARequestID>FRequestsAvail then
+          begin
+          inc(FRequestsAvail,10);
+          SetLength(FRequestsArray,FRequestsAvail);
+          end;
+        assert(not assigned(FRequestsArray[ARequestID].Request));
+        assert(not assigned(FRequestsArray[ARequestID].Response));
+
+        ATempRequest:=TFCGIRequest.Create;
+        ATempRequest.RequestID:=ARequestID;
+        ATempRequest.Handle:=FHandle;
+        ATempRequest.ProtocolOptions:=Self.Protocoloptions;
+        ATempRequest.OnUnknownRecord:=Self.OnUnknownRecord;
+        FRequestsArray[ARequestID].Request := ATempRequest;
         end;
-      assert(not assigned(FRequestsArray[ARequestID].Request));
-      assert(not assigned(FRequestsArray[ARequestID].Response));
-
-      ATempRequest:=TFCGIRequest.Create;
-      ATempRequest.RequestID:=ARequestID;
-      ATempRequest.Handle:=FHandle;
-      ATempRequest.ProtocolOptions:=Self.Protocoloptions;
-      ATempRequest.OnUnknownRecord:=Self.OnUnknownRecord;
-      FRequestsArray[ARequestID].Request := ATempRequest;
-      end;
-    if FRequestsArray[ARequestID].Request.ProcessFCGIRecord(AFCGI_Record) then
-      begin
-      ARequest:=FRequestsArray[ARequestID].Request;
-      FRequestsArray[ARequestID].Response := TFCGIResponse.Create(ARequest);
-      FRequestsArray[ARequestID].Response.ProtocolOptions:=Self.ProtocolOptions;
-      AResponse:=FRequestsArray[ARequestID].Response;
-      Result := True;
-      Break;
-      end;
+      if FRequestsArray[ARequestID].Request.ProcessFCGIRecord(AFCGI_Record) then
+        begin
+        ARequest:=FRequestsArray[ARequestID].Request;
+        FRequestsArray[ARequestID].Response := TFCGIResponse.Create(ARequest);
+        FRequestsArray[ARequestID].Response.ProtocolOptions:=Self.ProtocolOptions;
+        AResponse:=FRequestsArray[ARequestID].Response;
+        Result := True;
+        Break;
+        end;
+    Finally
+      FreeMem(AFCGI_Record);
+      AFCGI_Record:=Nil;
     end;
   until (1<>1);
 end;

+ 25 - 30
packages/fcl-web/src/base/fpweb.pp

@@ -29,9 +29,7 @@ Type
     FOnrequest: TWebActionEvent;
     FContents : TStrings;
     FTemplate : TFPTemplate;
-    function  GetStringContent: String;
     function  GetContents: TStrings;
-    procedure SetContent(const AValue: String);
     procedure SetContents(const AValue: TStrings);
     Procedure SetTemplate(const AValue : TFPTemplate);
   Protected  
@@ -43,7 +41,6 @@ Type
     Destructor destroy; override;
     Procedure Assign(Source : TPersistent); override;
   published
-    Property Content : String Read GetStringContent Write SetContent;
     Property Contents : TStrings Read GetContents Write SetContents;
     Property OnRequest: TWebActionEvent Read FOnrequest Write FOnrequest;
     Property Template : TFPTemplate Read FTemplate Write SetTemplate;
@@ -174,7 +171,7 @@ uses dbugintf;
 procedure TFPWebAction.GetContent(ARequest: TRequest; Content: TStream; Var Handled : Boolean);
 
 begin
-
+  DoGetContent(ARequest, Content, Handled);
 end;
 
 procedure TFPWebAction.Assign(Source: TPersistent);
@@ -185,12 +182,12 @@ Var
 begin
   If (Source is TFPWebAction) then
     begin
-    A:=Source as TFPWebAction;
+    A:=TFPWebAction(Source);
     Name:=A.Name;
-    Content:=A.Content;
     AfterResponse:=A.AfterResponse;
     BeforeRequest:=A.BeforeRequest;
     Default:=A.default;
+    Contents:=A.FContents;
     ContentProducer:=A.ContentProducer;
     OnRequest:=A.OnRequest;
     FTemplate.Assign(A.Template);
@@ -211,11 +208,6 @@ begin
   inherited destroy;
 end;
 
-function TFPWebAction.GetStringContent: String;
-begin
-  Result:=Contents.Text;
-end;
-
 function TFPWebAction.GetContents: TStrings;
 begin
   If Not Assigned(FContents) then
@@ -223,23 +215,17 @@ begin
   Result:=FContents;
 end;
 
-procedure TFPWebAction.SetContent(const AValue: String);
+procedure TFPWebAction.SetContents(const AValue: TStrings);
 begin
-  If (AValue='') then
+  if AValue = nil then
     FreeAndNil(FContents)
   else
-    Contents.Text:=AValue;
-end;
-
-procedure TFPWebAction.SetContents(const AValue: TStrings);
-begin
-  Contents.Assign(AValue);
+    Contents.Assign(AValue);
 end;
 
 procedure TFPWebAction.SetTemplate(const AValue: TFPTemplate);
 begin
-  If Assigned(AValue) then
-    FTemplate.Assign(AValue);
+  FTemplate.Assign(AValue);
 end;
 
 
@@ -268,8 +254,9 @@ begin
     Inherited DoHandleRequest(ARequest,AResponse,Handled);
     If not Handled then
       begin
-      AResponse.Contents.AddStrings(Self.Contents);
-      Handled:=(AResponse.Content<>'');
+      Handled := (FContents <> nil) and (FContents.Count > 0);
+      if Handled then
+        AResponse.Contents.AddStrings(FContents);
       end;
     end;
 {$ifdef cgidebug}
@@ -279,12 +266,24 @@ end;
 
 procedure TFPWebAction.DoGetContent(ARequest: TRequest; Content: TStream; Var Handled : Boolean);
 
+  //isolate string references in a subprocedure to avoid implicit exceptions in main procedure
+  procedure CopyContent;
+  var
+    ContentStr: String;
+  begin
+    if FContents <> nil then
+    begin
+      ContentStr := FContents.Text;
+      If ContentStr<>'' then
+        Content.Write(ContentStr[1],Length(ContentStr));
+    end;
+  end;
+
 begin
   If Assigned(ContentProducer) then
     ContentProducer.GetContent(ARequest,Content,Handled)
   else
-    If (Self.Content<>'') then
-      Content.Write(Self.Content[1],Length(Self.Content));
+    CopyContent;
 end;
 
 
@@ -466,11 +465,7 @@ begin
   FRequest := Nil;
   FResponse := Nil;
   // Clean up session for the case the webmodule is used again
-  if assigned(Session) then
-    begin
-    Session.Free;
-    Session := nil;
-    end;
+  DoneSession;
 {$ifdef cgidebug}
   SendMethodExit('WebModule('+Name+').handlerequest');
 {$endif cgidebug}

+ 27 - 9
packages/fcl-web/src/base/websession.pp

@@ -36,7 +36,9 @@ Type
     Procedure CheckSession(ARequest : TRequest);
     Procedure InitSession(AResponse : TResponse);
     Procedure UpdateSession(AResponse : TResponse);
+    Procedure DoneSession; virtual;
   Public
+    destructor destroy; override;
     Procedure Notification(AComponent : TComponent;Operation : TOperation); override;
     Procedure Loaded; Override;
     Property CreateSession : Boolean Read FCreateSession Write FCreateSession;
@@ -59,6 +61,7 @@ Type
     SID : String;
   private
     procedure FreeIniFile;
+    function GetSessionDir: String;
   Protected
     Procedure CheckSession;
     Function GetSessionID : String; override;
@@ -66,7 +69,7 @@ Type
     procedure SetSessionVariable(VarName : String; const AValue: String); override;
     Property Cached : Boolean Read FCached Write FCached;
     property SessionCookie : String Read FSessionCookie Write FSessionCookie;
-    Property SessionDir : String Read FSessionDir Write FSessionDir;
+    Property SessionDir : String Read GetSessionDir Write FSessionDir;
     Property SessionCookiePath : String Read FSessionCookiePath write FSessionCookiePath;
   Public
     Destructor Destroy; override;
@@ -107,7 +110,7 @@ Const
   SData      = 'Data';
 
   KeyStart   = 'Start';         // Start time of session
-  KeyLast    = 'Start';         // Last seen time of session
+  KeyLast    = 'Last';          // Last seen time of session
   KeyTimeOut = 'Timeout';       // Timeout in seconds;
 
   SFPWebSession = 'FPWebSession'; // Cookie name for session.
@@ -118,9 +121,6 @@ resourcestring
 
 Function GetDefaultSession : TCustomSession;
 
-Var
-  W : TFPWebSession;
-
 begin
 {$ifdef cgidebug}SendMethodEnter('GetDefaultSession');{$endif}
   Result:=Nil;
@@ -134,9 +134,7 @@ begin
   if (Result=Nil) then
     begin
     {$ifdef cgidebug}Senddebug('Creating iniwebsession');{$endif}
-    W:=TFPWebSession.Create(Nil);
-    W.SessionDir:=GlobalSessionDir;
-    Result:=W;
+    Result:=TFPWebSession.Create(Nil);
     end;
 {$ifdef cgidebug}SendMethodExit('GetDefaultSession');{$endif}
 end;
@@ -157,6 +155,13 @@ begin
   FreeAndNil(FIniFile);
 end;
 
+function TIniWebSession.GetSessionDir: String;
+begin
+  Result:=FSessionDir;
+  If (Result='') then
+    Result:=GlobalSessionDir;
+end;
+
 Procedure TIniWebSession.CheckSession;
 
 begin
@@ -234,7 +239,7 @@ begin
     L:=Finifile.ReadDateTime(SSession,KeyLast,0);
 {$ifdef cgidebug}
     If (L=0) then
-    SendDebug('No datetime in inifile');
+    SendDebug('No datetime in inifile (or not valid datetime : '+Finifile.ReadString(SSession,KeyLast,''));
 {$endif}
     T:=FIniFile.ReadInteger(SSession,KeyTimeOut,Self.TimeOutMinutes);
 {$ifdef cgidebug}SendDebug('Timeout :'+IntToStr(t));{$endif}
@@ -374,6 +379,19 @@ begin
     FSession.UpdateResponse(AResponse);
 end;
 
+procedure TSessionHTTPModule.DoneSession;
+begin
+  FreeAndNil(FSession);
+end;
+
+destructor TSessionHTTPModule.destroy;
+begin
+  // Prevent memory leaks.
+  If Assigned(FSession) then
+    DoneSession;
+  inherited destroy;
+end;
+
 procedure TSessionHTTPModule.Notification(AComponent: TComponent;
   Operation: TOperation);
 begin

+ 88 - 2
packages/fcl-web/src/webdata/Makefile

@@ -1,5 +1,5 @@
 #
-# Don't edit, this file is generated by FPCMake Version 2.0.0 [2010/11/22]
+# Don't edit, this file is generated by FPCMake Version 2.0.0 [2010/11/23]
 #
 default: all
 MAKEFILETARGETS=i386-linux i386-go32v2 i386-win32 i386-os2 i386-freebsd i386-beos i386-haiku i386-netbsd i386-solaris i386-qnx i386-netware i386-openbsd i386-wdosx i386-darwin i386-emx i386-watcom i386-netwlibc i386-wince i386-embedded i386-symbian m68k-linux m68k-freebsd m68k-netbsd m68k-amiga m68k-atari m68k-openbsd m68k-palmos m68k-embedded powerpc-linux powerpc-netbsd powerpc-amiga powerpc-macos powerpc-darwin powerpc-morphos powerpc-embedded sparc-linux sparc-netbsd sparc-solaris sparc-embedded x86_64-linux x86_64-freebsd x86_64-solaris x86_64-darwin x86_64-win64 x86_64-embedded arm-linux arm-palmos arm-darwin arm-wince arm-gba arm-nds arm-embedded arm-symbian powerpc64-linux powerpc64-darwin powerpc64-embedded avr-embedded armeb-linux armeb-embedded mipsel-linux
@@ -1425,7 +1425,7 @@ else
 TAROPT=vz
 TAREXT=.tar.gz
 endif
-override REQUIRE_PACKAGES=rtl fcl-base fcl-xml fcl-db fcl-json
+override REQUIRE_PACKAGES=rtl fcl-base fcl-xml fcl-db fcl-json fcl-process
 ifeq ($(FULL_TARGET),i386-linux)
 REQUIRE_PACKAGES_RTL=1
 REQUIRE_PACKAGES_FCL-BASE=1
@@ -1433,6 +1433,7 @@ REQUIRE_PACKAGES_ICONVENC=1
 REQUIRE_PACKAGES_FCL-XML=1
 REQUIRE_PACKAGES_FCL-DB=1
 REQUIRE_PACKAGES_FCL-JSON=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
 REQUIRE_PACKAGES_IBASE=1
 REQUIRE_PACKAGES_POSTGRES=1
 REQUIRE_PACKAGES_MYSQL=1
@@ -1447,6 +1448,7 @@ REQUIRE_PACKAGES_FCL-BASE=1
 REQUIRE_PACKAGES_FCL-XML=1
 REQUIRE_PACKAGES_FCL-DB=1
 REQUIRE_PACKAGES_FCL-JSON=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
 endif
 ifeq ($(FULL_TARGET),i386-win32)
 REQUIRE_PACKAGES_RTL=1
@@ -1454,6 +1456,7 @@ REQUIRE_PACKAGES_FCL-BASE=1
 REQUIRE_PACKAGES_FCL-XML=1
 REQUIRE_PACKAGES_FCL-DB=1
 REQUIRE_PACKAGES_FCL-JSON=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
 REQUIRE_PACKAGES_IBASE=1
 REQUIRE_PACKAGES_POSTGRES=1
 REQUIRE_PACKAGES_MYSQL=1
@@ -1468,6 +1471,7 @@ REQUIRE_PACKAGES_FCL-BASE=1
 REQUIRE_PACKAGES_FCL-XML=1
 REQUIRE_PACKAGES_FCL-DB=1
 REQUIRE_PACKAGES_FCL-JSON=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
 endif
 ifeq ($(FULL_TARGET),i386-freebsd)
 REQUIRE_PACKAGES_RTL=1
@@ -1476,6 +1480,7 @@ REQUIRE_PACKAGES_ICONVENC=1
 REQUIRE_PACKAGES_FCL-XML=1
 REQUIRE_PACKAGES_FCL-DB=1
 REQUIRE_PACKAGES_FCL-JSON=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
 REQUIRE_PACKAGES_IBASE=1
 REQUIRE_PACKAGES_POSTGRES=1
 REQUIRE_PACKAGES_MYSQL=1
@@ -1491,6 +1496,7 @@ REQUIRE_PACKAGES_ICONVENC=1
 REQUIRE_PACKAGES_FCL-XML=1
 REQUIRE_PACKAGES_FCL-DB=1
 REQUIRE_PACKAGES_FCL-JSON=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
 REQUIRE_PACKAGES_IBASE=1
 REQUIRE_PACKAGES_POSTGRES=1
 REQUIRE_PACKAGES_MYSQL=1
@@ -1506,6 +1512,7 @@ REQUIRE_PACKAGES_ICONVENC=1
 REQUIRE_PACKAGES_FCL-XML=1
 REQUIRE_PACKAGES_FCL-DB=1
 REQUIRE_PACKAGES_FCL-JSON=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
 REQUIRE_PACKAGES_SQLITE=1
 REQUIRE_PACKAGES_PXLIB=1
 endif
@@ -1515,6 +1522,7 @@ REQUIRE_PACKAGES_FCL-BASE=1
 REQUIRE_PACKAGES_FCL-XML=1
 REQUIRE_PACKAGES_FCL-DB=1
 REQUIRE_PACKAGES_FCL-JSON=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
 REQUIRE_PACKAGES_IBASE=1
 REQUIRE_PACKAGES_POSTGRES=1
 REQUIRE_PACKAGES_MYSQL=1
@@ -1529,6 +1537,7 @@ REQUIRE_PACKAGES_FCL-BASE=1
 REQUIRE_PACKAGES_FCL-XML=1
 REQUIRE_PACKAGES_FCL-DB=1
 REQUIRE_PACKAGES_FCL-JSON=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
 REQUIRE_PACKAGES_SQLITE=1
 endif
 ifeq ($(FULL_TARGET),i386-qnx)
@@ -1537,6 +1546,7 @@ REQUIRE_PACKAGES_FCL-BASE=1
 REQUIRE_PACKAGES_FCL-XML=1
 REQUIRE_PACKAGES_FCL-DB=1
 REQUIRE_PACKAGES_FCL-JSON=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
 endif
 ifeq ($(FULL_TARGET),i386-netware)
 REQUIRE_PACKAGES_RTL=1
@@ -1544,6 +1554,7 @@ REQUIRE_PACKAGES_FCL-BASE=1
 REQUIRE_PACKAGES_FCL-XML=1
 REQUIRE_PACKAGES_FCL-DB=1
 REQUIRE_PACKAGES_FCL-JSON=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
 endif
 ifeq ($(FULL_TARGET),i386-openbsd)
 REQUIRE_PACKAGES_RTL=1
@@ -1551,6 +1562,7 @@ REQUIRE_PACKAGES_FCL-BASE=1
 REQUIRE_PACKAGES_FCL-XML=1
 REQUIRE_PACKAGES_FCL-DB=1
 REQUIRE_PACKAGES_FCL-JSON=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
 REQUIRE_PACKAGES_IBASE=1
 REQUIRE_PACKAGES_POSTGRES=1
 REQUIRE_PACKAGES_MYSQL=1
@@ -1565,6 +1577,7 @@ REQUIRE_PACKAGES_FCL-BASE=1
 REQUIRE_PACKAGES_FCL-XML=1
 REQUIRE_PACKAGES_FCL-DB=1
 REQUIRE_PACKAGES_FCL-JSON=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
 endif
 ifeq ($(FULL_TARGET),i386-darwin)
 REQUIRE_PACKAGES_RTL=1
@@ -1574,6 +1587,7 @@ REQUIRE_PACKAGES_ICONVENC=1
 REQUIRE_PACKAGES_FCL-XML=1
 REQUIRE_PACKAGES_FCL-DB=1
 REQUIRE_PACKAGES_FCL-JSON=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
 REQUIRE_PACKAGES_IBASE=1
 REQUIRE_PACKAGES_POSTGRES=1
 REQUIRE_PACKAGES_MYSQL=1
@@ -1587,6 +1601,7 @@ REQUIRE_PACKAGES_FCL-BASE=1
 REQUIRE_PACKAGES_FCL-XML=1
 REQUIRE_PACKAGES_FCL-DB=1
 REQUIRE_PACKAGES_FCL-JSON=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
 endif
 ifeq ($(FULL_TARGET),i386-watcom)
 REQUIRE_PACKAGES_RTL=1
@@ -1594,6 +1609,7 @@ REQUIRE_PACKAGES_FCL-BASE=1
 REQUIRE_PACKAGES_FCL-XML=1
 REQUIRE_PACKAGES_FCL-DB=1
 REQUIRE_PACKAGES_FCL-JSON=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
 endif
 ifeq ($(FULL_TARGET),i386-netwlibc)
 REQUIRE_PACKAGES_RTL=1
@@ -1601,6 +1617,7 @@ REQUIRE_PACKAGES_FCL-BASE=1
 REQUIRE_PACKAGES_FCL-XML=1
 REQUIRE_PACKAGES_FCL-DB=1
 REQUIRE_PACKAGES_FCL-JSON=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
 endif
 ifeq ($(FULL_TARGET),i386-wince)
 REQUIRE_PACKAGES_RTL=1
@@ -1608,6 +1625,7 @@ REQUIRE_PACKAGES_FCL-BASE=1
 REQUIRE_PACKAGES_FCL-XML=1
 REQUIRE_PACKAGES_FCL-DB=1
 REQUIRE_PACKAGES_FCL-JSON=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
 REQUIRE_PACKAGES_IBASE=1
 REQUIRE_PACKAGES_POSTGRES=1
 REQUIRE_PACKAGES_MYSQL=1
@@ -1621,6 +1639,7 @@ REQUIRE_PACKAGES_FCL-BASE=1
 REQUIRE_PACKAGES_FCL-XML=1
 REQUIRE_PACKAGES_FCL-DB=1
 REQUIRE_PACKAGES_FCL-JSON=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
 endif
 ifeq ($(FULL_TARGET),i386-symbian)
 REQUIRE_PACKAGES_RTL=1
@@ -1628,6 +1647,7 @@ REQUIRE_PACKAGES_FCL-BASE=1
 REQUIRE_PACKAGES_FCL-XML=1
 REQUIRE_PACKAGES_FCL-DB=1
 REQUIRE_PACKAGES_FCL-JSON=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
 endif
 ifeq ($(FULL_TARGET),m68k-linux)
 REQUIRE_PACKAGES_RTL=1
@@ -1636,6 +1656,7 @@ REQUIRE_PACKAGES_ICONVENC=1
 REQUIRE_PACKAGES_FCL-XML=1
 REQUIRE_PACKAGES_FCL-DB=1
 REQUIRE_PACKAGES_FCL-JSON=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
 REQUIRE_PACKAGES_IBASE=1
 REQUIRE_PACKAGES_POSTGRES=1
 REQUIRE_PACKAGES_MYSQL=1
@@ -1651,6 +1672,7 @@ REQUIRE_PACKAGES_ICONVENC=1
 REQUIRE_PACKAGES_FCL-XML=1
 REQUIRE_PACKAGES_FCL-DB=1
 REQUIRE_PACKAGES_FCL-JSON=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
 REQUIRE_PACKAGES_IBASE=1
 REQUIRE_PACKAGES_POSTGRES=1
 REQUIRE_PACKAGES_MYSQL=1
@@ -1665,6 +1687,7 @@ REQUIRE_PACKAGES_FCL-BASE=1
 REQUIRE_PACKAGES_FCL-XML=1
 REQUIRE_PACKAGES_FCL-DB=1
 REQUIRE_PACKAGES_FCL-JSON=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
 REQUIRE_PACKAGES_IBASE=1
 REQUIRE_PACKAGES_POSTGRES=1
 REQUIRE_PACKAGES_MYSQL=1
@@ -1679,6 +1702,7 @@ REQUIRE_PACKAGES_FCL-BASE=1
 REQUIRE_PACKAGES_FCL-XML=1
 REQUIRE_PACKAGES_FCL-DB=1
 REQUIRE_PACKAGES_FCL-JSON=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
 endif
 ifeq ($(FULL_TARGET),m68k-atari)
 REQUIRE_PACKAGES_RTL=1
@@ -1686,6 +1710,7 @@ REQUIRE_PACKAGES_FCL-BASE=1
 REQUIRE_PACKAGES_FCL-XML=1
 REQUIRE_PACKAGES_FCL-DB=1
 REQUIRE_PACKAGES_FCL-JSON=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
 endif
 ifeq ($(FULL_TARGET),m68k-openbsd)
 REQUIRE_PACKAGES_RTL=1
@@ -1693,6 +1718,7 @@ REQUIRE_PACKAGES_FCL-BASE=1
 REQUIRE_PACKAGES_FCL-XML=1
 REQUIRE_PACKAGES_FCL-DB=1
 REQUIRE_PACKAGES_FCL-JSON=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
 REQUIRE_PACKAGES_IBASE=1
 REQUIRE_PACKAGES_POSTGRES=1
 REQUIRE_PACKAGES_MYSQL=1
@@ -1707,6 +1733,7 @@ REQUIRE_PACKAGES_FCL-BASE=1
 REQUIRE_PACKAGES_FCL-XML=1
 REQUIRE_PACKAGES_FCL-DB=1
 REQUIRE_PACKAGES_FCL-JSON=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
 endif
 ifeq ($(FULL_TARGET),m68k-embedded)
 REQUIRE_PACKAGES_RTL=1
@@ -1714,6 +1741,7 @@ REQUIRE_PACKAGES_FCL-BASE=1
 REQUIRE_PACKAGES_FCL-XML=1
 REQUIRE_PACKAGES_FCL-DB=1
 REQUIRE_PACKAGES_FCL-JSON=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
 endif
 ifeq ($(FULL_TARGET),powerpc-linux)
 REQUIRE_PACKAGES_RTL=1
@@ -1722,6 +1750,7 @@ REQUIRE_PACKAGES_ICONVENC=1
 REQUIRE_PACKAGES_FCL-XML=1
 REQUIRE_PACKAGES_FCL-DB=1
 REQUIRE_PACKAGES_FCL-JSON=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
 REQUIRE_PACKAGES_IBASE=1
 REQUIRE_PACKAGES_POSTGRES=1
 REQUIRE_PACKAGES_MYSQL=1
@@ -1736,6 +1765,7 @@ REQUIRE_PACKAGES_FCL-BASE=1
 REQUIRE_PACKAGES_FCL-XML=1
 REQUIRE_PACKAGES_FCL-DB=1
 REQUIRE_PACKAGES_FCL-JSON=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
 REQUIRE_PACKAGES_IBASE=1
 REQUIRE_PACKAGES_POSTGRES=1
 REQUIRE_PACKAGES_MYSQL=1
@@ -1750,6 +1780,7 @@ REQUIRE_PACKAGES_FCL-BASE=1
 REQUIRE_PACKAGES_FCL-XML=1
 REQUIRE_PACKAGES_FCL-DB=1
 REQUIRE_PACKAGES_FCL-JSON=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
 endif
 ifeq ($(FULL_TARGET),powerpc-macos)
 REQUIRE_PACKAGES_RTL=1
@@ -1757,6 +1788,7 @@ REQUIRE_PACKAGES_FCL-BASE=1
 REQUIRE_PACKAGES_FCL-XML=1
 REQUIRE_PACKAGES_FCL-DB=1
 REQUIRE_PACKAGES_FCL-JSON=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
 endif
 ifeq ($(FULL_TARGET),powerpc-darwin)
 REQUIRE_PACKAGES_RTL=1
@@ -1766,6 +1798,7 @@ REQUIRE_PACKAGES_ICONVENC=1
 REQUIRE_PACKAGES_FCL-XML=1
 REQUIRE_PACKAGES_FCL-DB=1
 REQUIRE_PACKAGES_FCL-JSON=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
 REQUIRE_PACKAGES_IBASE=1
 REQUIRE_PACKAGES_POSTGRES=1
 REQUIRE_PACKAGES_MYSQL=1
@@ -1779,6 +1812,7 @@ REQUIRE_PACKAGES_FCL-BASE=1
 REQUIRE_PACKAGES_FCL-XML=1
 REQUIRE_PACKAGES_FCL-DB=1
 REQUIRE_PACKAGES_FCL-JSON=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
 endif
 ifeq ($(FULL_TARGET),powerpc-embedded)
 REQUIRE_PACKAGES_RTL=1
@@ -1786,6 +1820,7 @@ REQUIRE_PACKAGES_FCL-BASE=1
 REQUIRE_PACKAGES_FCL-XML=1
 REQUIRE_PACKAGES_FCL-DB=1
 REQUIRE_PACKAGES_FCL-JSON=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
 endif
 ifeq ($(FULL_TARGET),sparc-linux)
 REQUIRE_PACKAGES_RTL=1
@@ -1794,6 +1829,7 @@ REQUIRE_PACKAGES_ICONVENC=1
 REQUIRE_PACKAGES_FCL-XML=1
 REQUIRE_PACKAGES_FCL-DB=1
 REQUIRE_PACKAGES_FCL-JSON=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
 REQUIRE_PACKAGES_IBASE=1
 REQUIRE_PACKAGES_POSTGRES=1
 REQUIRE_PACKAGES_MYSQL=1
@@ -1808,6 +1844,7 @@ REQUIRE_PACKAGES_FCL-BASE=1
 REQUIRE_PACKAGES_FCL-XML=1
 REQUIRE_PACKAGES_FCL-DB=1
 REQUIRE_PACKAGES_FCL-JSON=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
 REQUIRE_PACKAGES_IBASE=1
 REQUIRE_PACKAGES_POSTGRES=1
 REQUIRE_PACKAGES_MYSQL=1
@@ -1822,6 +1859,7 @@ REQUIRE_PACKAGES_FCL-BASE=1
 REQUIRE_PACKAGES_FCL-XML=1
 REQUIRE_PACKAGES_FCL-DB=1
 REQUIRE_PACKAGES_FCL-JSON=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
 REQUIRE_PACKAGES_SQLITE=1
 endif
 ifeq ($(FULL_TARGET),sparc-embedded)
@@ -1830,6 +1868,7 @@ REQUIRE_PACKAGES_FCL-BASE=1
 REQUIRE_PACKAGES_FCL-XML=1
 REQUIRE_PACKAGES_FCL-DB=1
 REQUIRE_PACKAGES_FCL-JSON=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
 endif
 ifeq ($(FULL_TARGET),x86_64-linux)
 REQUIRE_PACKAGES_RTL=1
@@ -1838,6 +1877,7 @@ REQUIRE_PACKAGES_ICONVENC=1
 REQUIRE_PACKAGES_FCL-XML=1
 REQUIRE_PACKAGES_FCL-DB=1
 REQUIRE_PACKAGES_FCL-JSON=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
 REQUIRE_PACKAGES_IBASE=1
 REQUIRE_PACKAGES_POSTGRES=1
 REQUIRE_PACKAGES_MYSQL=1
@@ -1853,6 +1893,7 @@ REQUIRE_PACKAGES_ICONVENC=1
 REQUIRE_PACKAGES_FCL-XML=1
 REQUIRE_PACKAGES_FCL-DB=1
 REQUIRE_PACKAGES_FCL-JSON=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
 REQUIRE_PACKAGES_IBASE=1
 REQUIRE_PACKAGES_POSTGRES=1
 REQUIRE_PACKAGES_MYSQL=1
@@ -1867,6 +1908,7 @@ REQUIRE_PACKAGES_FCL-BASE=1
 REQUIRE_PACKAGES_FCL-XML=1
 REQUIRE_PACKAGES_FCL-DB=1
 REQUIRE_PACKAGES_FCL-JSON=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
 REQUIRE_PACKAGES_SQLITE=1
 endif
 ifeq ($(FULL_TARGET),x86_64-darwin)
@@ -1877,6 +1919,7 @@ REQUIRE_PACKAGES_ICONVENC=1
 REQUIRE_PACKAGES_FCL-XML=1
 REQUIRE_PACKAGES_FCL-DB=1
 REQUIRE_PACKAGES_FCL-JSON=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
 REQUIRE_PACKAGES_IBASE=1
 REQUIRE_PACKAGES_POSTGRES=1
 REQUIRE_PACKAGES_MYSQL=1
@@ -1890,6 +1933,7 @@ REQUIRE_PACKAGES_FCL-BASE=1
 REQUIRE_PACKAGES_FCL-XML=1
 REQUIRE_PACKAGES_FCL-DB=1
 REQUIRE_PACKAGES_FCL-JSON=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
 REQUIRE_PACKAGES_IBASE=1
 REQUIRE_PACKAGES_ODBC=1
 REQUIRE_PACKAGES_MYSQL=1
@@ -1901,6 +1945,7 @@ REQUIRE_PACKAGES_FCL-BASE=1
 REQUIRE_PACKAGES_FCL-XML=1
 REQUIRE_PACKAGES_FCL-DB=1
 REQUIRE_PACKAGES_FCL-JSON=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
 endif
 ifeq ($(FULL_TARGET),arm-linux)
 REQUIRE_PACKAGES_RTL=1
@@ -1909,6 +1954,7 @@ REQUIRE_PACKAGES_ICONVENC=1
 REQUIRE_PACKAGES_FCL-XML=1
 REQUIRE_PACKAGES_FCL-DB=1
 REQUIRE_PACKAGES_FCL-JSON=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
 REQUIRE_PACKAGES_IBASE=1
 REQUIRE_PACKAGES_POSTGRES=1
 REQUIRE_PACKAGES_MYSQL=1
@@ -1923,6 +1969,7 @@ REQUIRE_PACKAGES_FCL-BASE=1
 REQUIRE_PACKAGES_FCL-XML=1
 REQUIRE_PACKAGES_FCL-DB=1
 REQUIRE_PACKAGES_FCL-JSON=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
 endif
 ifeq ($(FULL_TARGET),arm-darwin)
 REQUIRE_PACKAGES_RTL=1
@@ -1932,6 +1979,7 @@ REQUIRE_PACKAGES_ICONVENC=1
 REQUIRE_PACKAGES_FCL-XML=1
 REQUIRE_PACKAGES_FCL-DB=1
 REQUIRE_PACKAGES_FCL-JSON=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
 REQUIRE_PACKAGES_IBASE=1
 REQUIRE_PACKAGES_POSTGRES=1
 REQUIRE_PACKAGES_MYSQL=1
@@ -1945,6 +1993,7 @@ REQUIRE_PACKAGES_FCL-BASE=1
 REQUIRE_PACKAGES_FCL-XML=1
 REQUIRE_PACKAGES_FCL-DB=1
 REQUIRE_PACKAGES_FCL-JSON=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
 REQUIRE_PACKAGES_IBASE=1
 REQUIRE_PACKAGES_POSTGRES=1
 REQUIRE_PACKAGES_MYSQL=1
@@ -1958,6 +2007,7 @@ REQUIRE_PACKAGES_FCL-BASE=1
 REQUIRE_PACKAGES_FCL-XML=1
 REQUIRE_PACKAGES_FCL-DB=1
 REQUIRE_PACKAGES_FCL-JSON=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
 endif
 ifeq ($(FULL_TARGET),arm-nds)
 REQUIRE_PACKAGES_RTL=1
@@ -1965,6 +2015,7 @@ REQUIRE_PACKAGES_FCL-BASE=1
 REQUIRE_PACKAGES_FCL-XML=1
 REQUIRE_PACKAGES_FCL-DB=1
 REQUIRE_PACKAGES_FCL-JSON=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
 endif
 ifeq ($(FULL_TARGET),arm-embedded)
 REQUIRE_PACKAGES_RTL=1
@@ -1972,6 +2023,7 @@ REQUIRE_PACKAGES_FCL-BASE=1
 REQUIRE_PACKAGES_FCL-XML=1
 REQUIRE_PACKAGES_FCL-DB=1
 REQUIRE_PACKAGES_FCL-JSON=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
 endif
 ifeq ($(FULL_TARGET),arm-symbian)
 REQUIRE_PACKAGES_RTL=1
@@ -1979,6 +2031,7 @@ REQUIRE_PACKAGES_FCL-BASE=1
 REQUIRE_PACKAGES_FCL-XML=1
 REQUIRE_PACKAGES_FCL-DB=1
 REQUIRE_PACKAGES_FCL-JSON=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
 endif
 ifeq ($(FULL_TARGET),powerpc64-linux)
 REQUIRE_PACKAGES_RTL=1
@@ -1987,6 +2040,7 @@ REQUIRE_PACKAGES_ICONVENC=1
 REQUIRE_PACKAGES_FCL-XML=1
 REQUIRE_PACKAGES_FCL-DB=1
 REQUIRE_PACKAGES_FCL-JSON=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
 REQUIRE_PACKAGES_IBASE=1
 REQUIRE_PACKAGES_POSTGRES=1
 REQUIRE_PACKAGES_MYSQL=1
@@ -2003,6 +2057,7 @@ REQUIRE_PACKAGES_ICONVENC=1
 REQUIRE_PACKAGES_FCL-XML=1
 REQUIRE_PACKAGES_FCL-DB=1
 REQUIRE_PACKAGES_FCL-JSON=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
 REQUIRE_PACKAGES_IBASE=1
 REQUIRE_PACKAGES_POSTGRES=1
 REQUIRE_PACKAGES_MYSQL=1
@@ -2016,6 +2071,7 @@ REQUIRE_PACKAGES_FCL-BASE=1
 REQUIRE_PACKAGES_FCL-XML=1
 REQUIRE_PACKAGES_FCL-DB=1
 REQUIRE_PACKAGES_FCL-JSON=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
 endif
 ifeq ($(FULL_TARGET),avr-embedded)
 REQUIRE_PACKAGES_RTL=1
@@ -2023,6 +2079,7 @@ REQUIRE_PACKAGES_FCL-BASE=1
 REQUIRE_PACKAGES_FCL-XML=1
 REQUIRE_PACKAGES_FCL-DB=1
 REQUIRE_PACKAGES_FCL-JSON=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
 endif
 ifeq ($(FULL_TARGET),armeb-linux)
 REQUIRE_PACKAGES_RTL=1
@@ -2031,6 +2088,7 @@ REQUIRE_PACKAGES_ICONVENC=1
 REQUIRE_PACKAGES_FCL-XML=1
 REQUIRE_PACKAGES_FCL-DB=1
 REQUIRE_PACKAGES_FCL-JSON=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
 REQUIRE_PACKAGES_IBASE=1
 REQUIRE_PACKAGES_POSTGRES=1
 REQUIRE_PACKAGES_MYSQL=1
@@ -2045,6 +2103,7 @@ REQUIRE_PACKAGES_FCL-BASE=1
 REQUIRE_PACKAGES_FCL-XML=1
 REQUIRE_PACKAGES_FCL-DB=1
 REQUIRE_PACKAGES_FCL-JSON=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
 endif
 ifeq ($(FULL_TARGET),mipsel-linux)
 REQUIRE_PACKAGES_RTL=1
@@ -2053,6 +2112,7 @@ REQUIRE_PACKAGES_ICONVENC=1
 REQUIRE_PACKAGES_FCL-XML=1
 REQUIRE_PACKAGES_FCL-DB=1
 REQUIRE_PACKAGES_FCL-JSON=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
 REQUIRE_PACKAGES_IBASE=1
 REQUIRE_PACKAGES_POSTGRES=1
 REQUIRE_PACKAGES_MYSQL=1
@@ -2217,6 +2277,32 @@ ifdef UNITDIR_FCL-JSON
 override COMPILER_UNITDIR+=$(UNITDIR_FCL-JSON)
 endif
 endif
+ifdef REQUIRE_PACKAGES_FCL-PROCESS
+PACKAGEDIR_FCL-PROCESS:=$(firstword $(subst /Makefile.fpc,,$(strip $(wildcard $(addsuffix /fcl-process/Makefile.fpc,$(PACKAGESDIR))))))
+ifneq ($(PACKAGEDIR_FCL-PROCESS),)
+ifneq ($(wildcard $(PACKAGEDIR_FCL-PROCESS)/units/$(TARGETSUFFIX)),)
+UNITDIR_FCL-PROCESS=$(PACKAGEDIR_FCL-PROCESS)/units/$(TARGETSUFFIX)
+else
+UNITDIR_FCL-PROCESS=$(PACKAGEDIR_FCL-PROCESS)
+endif
+ifdef CHECKDEPEND
+$(PACKAGEDIR_FCL-PROCESS)/$(FPCMADE):
+	$(MAKE) -C $(PACKAGEDIR_FCL-PROCESS) $(FPCMADE)
+override ALLDEPENDENCIES+=$(PACKAGEDIR_FCL-PROCESS)/$(FPCMADE)
+endif
+else
+PACKAGEDIR_FCL-PROCESS=
+UNITDIR_FCL-PROCESS:=$(subst /Package.fpc,,$(strip $(wildcard $(addsuffix /fcl-process/Package.fpc,$(UNITSDIR)))))
+ifneq ($(UNITDIR_FCL-PROCESS),)
+UNITDIR_FCL-PROCESS:=$(firstword $(UNITDIR_FCL-PROCESS))
+else
+UNITDIR_FCL-PROCESS=
+endif
+endif
+ifdef UNITDIR_FCL-PROCESS
+override COMPILER_UNITDIR+=$(UNITDIR_FCL-PROCESS)
+endif
+endif
 ifdef REQUIRE_PACKAGES_IBASE
 PACKAGEDIR_IBASE:=$(firstword $(subst /Makefile.fpc,,$(strip $(wildcard $(addsuffix /ibase/Makefile.fpc,$(PACKAGESDIR))))))
 ifneq ($(PACKAGEDIR_IBASE),)

+ 1 - 1
packages/fcl-web/src/webdata/Makefile.fpc

@@ -10,7 +10,7 @@ version=2.5.1
 units=fpwebdata sqldbwebdata fpextjs extjsjson extjsxml
 
 [require]
-packages=fcl-base fcl-xml fcl-db fcl-json
+packages=fcl-base fcl-xml fcl-db fcl-json fcl-process
 
 [compiler]
 options=-S2h

+ 109 - 15
packages/fcl-web/src/webdata/extjsjson.pp

@@ -5,7 +5,7 @@ unit extjsjson;
 interface
 
 uses
-  Classes, SysUtils, httpdefs, fphttp,fpwebdata, fpextjs, fpjson, db, jsonparser;
+  Classes, SysUtils, httpdefs, fphttp, fpwebdata, fpextjs, fpjson, db, jsonparser;
 
 type
 
@@ -23,22 +23,58 @@ type
     Function TryFieldValue(Const AFieldName : String; out AValue : String) : Boolean; override;
     Destructor destroy; override;
   end;
+
   { TExtJSJSONDataFormatter }
+  TJSONObjectEvent = Procedure(Sender : TObject; AObject : TJSONObject) of Object;
+  TJSONExceptionObjectEvent = Procedure(Sender : TObject; E : Exception; AResponse : TJSONObject) of Object;
 
   TExtJSJSONDataFormatter = Class(TExtJSDataFormatter)
   private
-    procedure SendSuccess(ResponseContent: TStream; AddIDValue : Boolean = False);
+    FAfterDataToJSON: TJSONObjectEvent;
+    FAfterDelete: TJSONObjectEvent;
+    FAfterInsert: TJSONObjectEvent;
+    FAfterRowToJSON: TJSONObjectEvent;
+    FAfterUpdate: TJSONObjectEvent;
+    FBeforeDataToJSON: TJSONObjectEvent;
+    FBeforeRowToJSON: TJSONObjectEvent;
+    FOnErrorResponse: TJSONExceptionObjectEvent;
+    FOnMetaDataToJSON: TJSONObjectEvent;
+    procedure SendSuccess(ResponseContent: TStream; AddIDValue : Boolean = False; CallBack : TJSONObjectEvent = Nil);
   protected
     Function CreateAdaptor(ARequest : TRequest) : TCustomWebdataInputAdaptor; override;
     Function AddFieldToJSON(O: TJSONObject; AFieldName: String; F: TField): TJSONData;
     function GetDataContentType: String; override;
     Function GetJSONMetaData: TJSONObject;
     function RowToJSON: TJSONObject;
+    Procedure DoBeforeRow(ARow : TJSONObject); virtual;
+    Procedure DoAfterRow(ARow : TJSONObject); virtual;
+    Procedure DoBeforeData(AResponse : TJSONObject); virtual;
+    Procedure DoAfterData(AResponse : TJSONObject); virtual;
+    Procedure DoOnMetaData(AMetadata : TJSONObject); virtual;
     procedure DatasetToStream(Stream: TStream); override;
     Procedure DoExceptionToStream(E : Exception; ResponseContent : TStream); override;
     Procedure DoInsertRecord(ResponseContent : TStream); override;
     Procedure DoUpdateRecord(ResponseContent : TStream); override;
     Procedure DoDeleteRecord(ResponseContent : TStream); override;
+  Published
+    // Called before any fields are added to row object (passed to handler).
+    Property AfterRowToJSON : TJSONObjectEvent Read FAfterRowToJSON Write FAfterRowToJSON;
+    // Called After all fields are added to row object (passed to handler).
+    Property BeforeRowToJSON : TJSONObjectEvent Read FBeforeRowToJSON Write FBeforeRowToJSON;
+    // Called when metadata object has been created (passed to handler).
+    Property OnMetaDataToJSON : TJSONObjectEvent Read FOnMetaDataToJSON Write FOnMetaDataToJSON;
+    // Called when response object has been created, and has Rows property (response passed to handler).
+    Property AfterDataToJSON : TJSONObjectEvent Read FAfterDataToJSON Write FAfterDataToJSON;
+    // Called just before response object will be streamed (response passed to handler).
+    Property BeforeDataToJSON : TJSONObjectEvent Read FBeforeDataToJSON Write FBeforeDataToJSON;
+    // Called when an exception is caught and formatted.
+    Property OnErrorResponse : TJSONExceptionObjectEvent Read FOnErrorResponse Write FOnErrorResponse;
+    // After a record was succesfully updated
+    Property AfterUpdate : TJSONObjectEvent Read FAfterUpdate Write FAfterUpdate;
+    // After a record was succesfully inserted.
+    Property AfterInsert : TJSONObjectEvent Read FAfterInsert Write FAfterInsert;
+    // After a record was succesfully inserted.
+    Property AfterDelete : TJSONObjectEvent Read FAfterDelete Write FAfterDelete;
   end;
 
 implementation
@@ -79,6 +115,10 @@ end;
 
 function TExtJSJSONDataFormatter.AddFieldToJSON(O : TJSONObject; AFieldName : String; F : TField): TJSONData;
 
+Var
+  S : String;
+
+
 begin
  if F.IsNull then
    Result:=O.Items[O.Add(AFieldName)]
@@ -102,9 +142,18 @@ begin
     ftMemo,
     ftFmtMemo,
     ftWideMemo,
-    ftBlob :O.Items[O.Add(AFieldName,F.AsString)];
+    ftBlob :
+      begin
+      S:=F.AsString;
+      If (OnTranscode<>Nil) then
+        OnTranscode(Self,F,S,True);
+      Result:=O.Items[O.Add(AFieldName,S)];
+      end;
   else
-    Result:=O.Items[O.Add(AFieldName,F.DisplayText)];
+    S:=F.DisplayText;
+    If (OnTranscode<>Nil) then
+      OnTranscode(Self,F,S,True);
+    Result:=O.Items[O.Add(AFieldName,S)];
   end;
 end;
 
@@ -117,11 +166,48 @@ Var
 
 begin
   Result:=TJSONObject.Create();
-  For I:=0 to Dataset.Fields.Count-1 do
-    begin
-    F:=Dataset.Fields[I];
-    AddFieldToJSON(Result,F.FieldName,F);
-    end;
+  try
+    DobeforeRow(Result);
+    For I:=0 to Dataset.Fields.Count-1 do
+      begin
+      F:=Dataset.Fields[I];
+      AddFieldToJSON(Result,F.FieldName,F);
+      end;
+    DoAfterRow(Result);
+  except
+    Result.Free;
+    Raise;
+  end;
+end;
+
+procedure TExtJSJSONDataFormatter.DoBeforeRow(ARow: TJSONObject);
+begin
+  If Assigned(FBeforeRowToJSON) then
+    FBeforeRowToJSON(Self,ARow);
+end;
+
+procedure TExtJSJSONDataFormatter.DoAfterRow(ARow: TJSONObject);
+begin
+  If Assigned(FAfterRowToJSON) then
+    FAfterRowToJSON(Self,ARow);
+end;
+
+procedure TExtJSJSONDataFormatter.DoBeforeData(AResponse: TJSONObject);
+begin
+  If Assigned(FBeforeDataToJSON) then
+    FBeforeDataToJSON(Self,AResponse);
+end;
+
+procedure TExtJSJSONDataFormatter.DoAfterData(AResponse: TJSONObject);
+begin
+  If Assigned(FAfterDataToJSON) then
+    FAfterDataToJSON(Self,AResponse);
+end;
+
+procedure TExtJSJSONDataFormatter.DoOnMetaData(AMetadata: TJSONObject);
+begin
+  If Assigned(FOnMetaDataToJSON) then
+    FOnMetaDataToJSON(Self,AMetaData);
 end;
 
 Function TExtJSJSONDataFormatter.GetJSONMetaData: TJSONObject;
@@ -200,7 +286,8 @@ begin
     Result.Add(SIdProperty,Provider.IDFieldName);
     Result.Add(SSuccessProperty, SuccessProperty);
     Result.Add(SRootProperty, RowsProperty);
-    Result.Add(STotalProperty, totalProperty)
+    Result.Add(STotalProperty, totalProperty);
+    DoOnMetaData(Result);
   except
     Result.free;
     Raise;
@@ -221,6 +308,8 @@ begin
   Resp:=TJSONObject.Create;
   try
     Rows:=TJSONArray.Create();
+    Resp.Add(RowsProperty,Rows);
+    DoBeforeData(Resp);
     DS:=Dataset;
     DS.First;
     RCount:=0;
@@ -251,10 +340,10 @@ begin
         Inc(RCount);
         DS.Next;
         end;
-    Resp.Add(RowsProperty,Rows);
     Resp.Add(SuccessProperty,True);
     If (PageSize>0) then
        Resp.Add(TotalProperty,RCount);
+    DoAfterData(Resp);
     L:=Resp.AsJSON;
     Stream.WriteBuffer(L[1],Length(L));
   finally
@@ -280,12 +369,15 @@ begin
     L:=Resp.AsJSON;
     If Length(L)>0 then
       ResponseContent.WriteBuffer(L[1],Length(L));
+    Resp.Add(RowsProperty,TJSONArray.Create());
+    If Assigned(FOnErrorResponse) then
+      FOnErrorResponse(Self,E,Resp);
   finally
     Resp.Free;
   end;
 end;
 
-procedure TExtJSJSONDataFormatter.SendSuccess(ResponseContent: TStream; AddIDValue : Boolean = False);
+procedure TExtJSJSONDataFormatter.SendSuccess(ResponseContent: TStream; AddIDValue : Boolean = False; CallBack : TJSONObjectEvent = Nil);
 
 Var
    Resp : TJSonObject;
@@ -296,6 +388,8 @@ begin
     Resp:=TJsonObject.Create;
     Resp.Add(SuccessProperty,True);
     Resp.Add(Provider.IDFieldName,Provider.IDFieldValue);
+    If Assigned(CallBack) then
+      CallBack(Self,Resp);
     L:=Resp.AsJSON;
     ResponseContent.WriteBuffer(L[1],Length(L));
   finally
@@ -307,19 +401,19 @@ procedure TExtJSJSONDataFormatter.DoInsertRecord(ResponseContent: TStream);
 
 begin
   Inherited;
-  SendSuccess(ResponseContent,True);
+  SendSuccess(ResponseContent,True,FAfterInsert);
 end;
 
 procedure TExtJSJSONDataFormatter.DoUpdateRecord(ResponseContent: TStream);
 begin
   inherited DoUpdateRecord(ResponseContent);
-  SendSuccess(ResponseContent,False);
+  SendSuccess(ResponseContent,False,FAfterUpdate);
 end;
 
 procedure TExtJSJSONDataFormatter.DoDeleteRecord(ResponseContent: TStream);
 begin
   inherited DoDeleteRecord(ResponseContent);
-  SendSuccess(ResponseContent,False);
+  SendSuccess(ResponseContent,False,FAfterDelete);
 end;
 
 { TExtJSJSonWebdataInputAdaptor }

+ 70 - 8
packages/fcl-web/src/webdata/extjsxml.pp

@@ -37,10 +37,17 @@ Type
   { TExtJSJSONDataFormatter }
 
   { TExtJSXMLDataFormatter }
+  TXMLElementEvent = Procedure (Sender : TObject; AElement : TDOMElement) of object;
+  TXMLExceptionObjectEvent = Procedure(Sender : TObject; E : Exception; AResponse : TDOMElement) of Object;
 
   TExtJSXMLDataFormatter = Class(TExtJSDataFormatter)
   private
+    FAfterDataToXML: TXMLElementEvent;
+    FAfterRowToXML: TXMLElementEvent;
+    FBeforeDataToXML: TXMLElementEvent;
+    FBeforeRowToXML: TXMLElementEvent;
     FDP: String;
+    FOnErrorResponse: TXmlExceptionObjectEvent;
     FReP: String;
     FRP: String;
     function IsDocumentStored: boolean;
@@ -51,6 +58,10 @@ Type
     Procedure DoExceptionToStream(E : Exception; ResponseContent : TStream); override;
     Function GetDataContentType : String; override;
     function RowToXML(Doc: TXMLDocument): TDOMelement;
+    Procedure DoBeforeRow(ARow : TDOMElement); virtual;
+    Procedure DoAfterRow(ARow : TDOMElement); virtual;
+    Procedure DoBeforeData(Data : TDOMElement); virtual;
+    Procedure DoAfterData(Data: TDOMElement); virtual;
     procedure DatasetToStream(Stream: TStream); override;
   public
     Constructor Create(AOwner : TComponent); override;
@@ -58,6 +69,16 @@ Type
     Property RootProperty : String Read FRP Write FRP Stored IsRootStored;
     Property RecordProperty : String Read FReP Write FReP Stored IsRecordStored;
     Property DocumentProperty : String Read FDP Write FDP Stored IsDocumentStored;
+    // Called before row element (passed to handler) is filled with fields.
+    Property BeforeRowToXML : TXMLElementEvent Read FBeforeRowToXML Write FBeforeRowToXML;
+    // Called after row element (passed to handler) was filled with fields.
+    Property AfterRowToXML : TXMLElementEvent Read FAfterRowToXML Write FAfterRowToXML;
+    // Called before any rows are added to root element (passed to handler).
+    Property BeforeDataToXML : TXMLElementEvent Read FBeforeDataToXML Write FBeforeDataToXML;
+    // Called after all rows are appended to root element (passed to handler).
+    Property AfterDataToXML : TXMLElementEvent Read FAfterDataToXML Write FAfterDataToXML;
+    // Called when an exception is caught and formatted.
+    Property OnErrorResponse : TXmlExceptionObjectEvent Read FOnErrorResponse Write FOnErrorResponse;
   end;
 
 implementation
@@ -132,6 +153,8 @@ begin
       C.AppendChild(XML.CreateTextNode(E.Message))
     else
       C.AppendChild(XML.CreateTextNode(SerrNoExceptionMessage));
+    If Assigned(FOnErrorResponse) then
+      FOnErrorResponse(Self,E,El);
     WriteXMLFile(XML,ResponseContent);
   Finally
     XML.Free;
@@ -149,15 +172,53 @@ Var
   E : TDOMElement;
   F : TField;
   I : Integer;
+  S : String;
 begin
   Result:=Doc.CreateElement(RecordProperty);
-  For I:=0 to Dataset.Fields.Count-1 do
-    begin
-    F:=Dataset.Fields[i];
-    E:=Doc.CreateElement(F.FieldName);
-    E.AppendChild(Doc.CreateTextNode(F.DisplayText));
-    Result.AppendChild(E);
-    end;
+  try
+    DoBeforeRow(Result);
+    For I:=0 to Dataset.Fields.Count-1 do
+      begin
+      F:=Dataset.Fields[i];
+      E:=Doc.CreateElement(F.FieldName);
+      If F.DataType in [ftMemo, ftFmtMemo, ftWideMemo, ftBlob ] then
+        S:=F.AsString
+      else
+        S:=F.DisplayText;
+      If (OnTranscode<>Nil) then
+        OnTranscode(Self,F,S,True);
+      E.AppendChild(Doc.CreateTextNode(S));
+      Result.AppendChild(E);
+      end;
+    DoAfterRow(Result);
+  except
+    Result.Free;
+    Raise;
+  end;
+end;
+
+procedure TExtJSXMLDataFormatter.DoBeforeRow(ARow: TDOMElement);
+begin
+  If Assigned(FBEforeRowToXml) then
+    FBEforeRowToXml(Self,ARow);
+end;
+
+procedure TExtJSXMLDataFormatter.DoAfterRow(ARow: TDOMElement);
+begin
+  If Assigned(FAfterRowToXml) then
+    FAfterRowToXml(Self,ARow);
+end;
+
+procedure TExtJSXMLDataFormatter.DoBeforeData(Data: TDOMElement);
+begin
+  If Assigned(FBeforeDataToXML) then
+    FBeforeDataToXML(Self,Data);
+end;
+
+procedure TExtJSXMLDataFormatter.DoAfterDAta(Data: TDOMElement);
+begin
+  If Assigned(FAfterDataToXML) then
+    FAfterDataToXML(Self,Data);
 end;
 
 procedure TExtJSXMLDataFormatter.DatasetToStream(Stream: TStream);
@@ -176,6 +237,7 @@ begin
    try
      E:=XML.CreateElement(RootProperty);
      XML.AppendChild(E);
+     DoBeforeData(E);
      // Go to start
      ACount:=PageStart;
      While (Not DS.EOF) and (ACount>0) do
@@ -204,8 +266,8 @@ begin
      C:=XML.CreateElement(SuccessProperty);
      C.AppendChild(XML.CreateTextNode('true'));
      E.AppendChild(C);
+     DoAfterData(E);
      WriteXMLFile(XML,Stream);
-
    finally
      XML.Free;
    end;

+ 4 - 0
packages/fcl-web/src/webdata/fpwebdata.pp

@@ -122,12 +122,15 @@ type
   // Handle request for read/create/update/delete and return a result.
 
   { TCustomHTTPDataContentProducer }
+  // Support for transcoding from/to UTF-8. If outbound is true, the value is going from server to browser.
+  TOnTranscodeEvent = Procedure (Sender : TObject; F : TField; Var S : String; Outbound : Boolean) of object;
 
   TCustomHTTPDataContentProducer = Class(THTTPContentProducer)
   Private
     FAllowPageSize: Boolean;
     FDataProvider: TFPCustomWebDataProvider;
     FMetadata: Boolean;
+    FOnTranscode: TOnTranscodeEvent;
     FPageSize: Integer;
     FPageStart: Integer;
     FSD: Boolean;
@@ -161,6 +164,7 @@ type
     Property SortField : String Read FSortField Write FSortField;
     Property SortDescending : Boolean Read FSD Write FSD default False;
     Property AllowPageSize : Boolean Read FAllowPageSize Write FAllowPageSize default True;
+    Property OnTransCode : TOnTranscodeEvent Read FOnTranscode Write FOnTranscode;
   end;
   TCustomHTTPDataContentProducerClass = Class of TCustomHTTPDataContentProducer;
 

+ 6 - 3
packages/fcl-web/src/webdata/sqldbwebdata.pp

@@ -126,10 +126,13 @@ end;
 
 procedure TCustomSQLDBWebDataProvider.SQLChanged(Sender: TObject);
 begin
-  If (Sender=SelectSQL) and Assigned(FQuery) then
+  If (Sender=SelectSQL)  then
     begin
-    FQuery.Close;
-    FQuery.SQL.Assign(SelectSQL);
+    if Assigned(FQuery) then
+      begin
+      FQuery.Close;
+      FQuery.SQL.Assign(SelectSQL);
+      end;
     If Not (csLoading in ComponentState) then
       RegenerateParams;
     end;