Ver Fonte

* More clear and flexible way to process content from stdin

git-svn-id: trunk@26563 -
michael há 11 anos atrás
pai
commit
72d43272ac
1 ficheiros alterados com 33 adições e 15 exclusões
  1. 33 15
      packages/fcl-web/src/base/custcgi.pp

+ 33 - 15
packages/fcl-web/src/base/custcgi.pp

@@ -26,17 +26,25 @@ uses
 Type
   { TCGIRequest }
   TCGIHandler = Class;
+  // Content read handler. PByte points to rad content, len is length. Return False in ContinueReading to abort reading.
+  TCGIContentReadEvent = Procedure (Sender : TRequest; Content : PByte; Len : Integer; Var ContinueReading : Boolean) of object;
 
   TCGIRequest = Class(TRequest)
   Private
     FCGI : TCGIHandler;
+    FOnContentRead: TCGIContentReadEvent;
     function GetCGIVar(Index: integer): String;
   Protected
     Function GetFieldValue(Index : Integer) : String; override;
     Procedure InitFromEnvironment; virtual;
+    // Read content from STDin. Calls DoContentRead to see if reading must be aborted.
     procedure ReadContent; override;
+    // Called whenever input is read from stdin. Calls OnContentRead.
+    // If Return True to continue reading, false to abort reading.
+    Function DoContentRead(B : PByte; Len : Integer) : Boolean; virtual;
   Public
     Constructor CreateCGI(ACGI : TCGIHandler);
+    Property OnContentRead  : TCGIContentReadEvent Read FOnContentRead Write FOnContentRead;
     Property GatewayInterface : String Index 1 Read GetCGIVar;
     Property RemoteIdent : String Index 2 read GetCGIVar;
     Property RemoteUser : String Index 3 read GetCGIVar;
@@ -113,6 +121,8 @@ Var
   CGIRequestClass : TCGIRequestClass = TCGIRequest;
   CGIResponseClass : TCGIResponseClass = TCGIResponse;
   CGIWebHandlerClass : TCgiHandlerClass = TCgiHandler;
+  ContentReadRetryInterval : Word = 100;
+  ContentReadMaxRetryCount : Word = 150;
 
 ResourceString
   SWebMaster = 'webmaster';
@@ -256,7 +266,7 @@ begin
   Terminate;
 end;
 
-constructor TCgiRequest.CreateCGI(ACGI: TCgiHandler);
+constructor TCGIRequest.CreateCGI(ACGI: TCGIHandler);
 begin
   Inherited Create;
   FCGI:=ACGI;
@@ -282,7 +292,7 @@ begin
   Result:=HTTPDecode(R);
 end;
 
-Procedure TCGIRequest.InitFromEnvironment;
+procedure TCGIRequest.InitFromEnvironment;
 
 
 Var
@@ -311,6 +321,7 @@ var
   B : Byte;
   retrycount: integer;
   BytesRead, a: longint;
+  AbortRead : Boolean;
   S : String;
 
 begin
@@ -324,22 +335,22 @@ begin
       // until all data is really read
       SetLength(S,Cl);
       BytesRead:=0;
+      RetryCount:=0;
+      AbortRead:=False;
       repeat
-      a := I.Read(S[BytesRead+1],Cl-BytesRead);
-      BytesRead:=BytesRead+a;
-      if a=0 then // In fact this can not happen, but the content could be delayed...
-        begin
-        sleep(10);
         a := I.Read(S[BytesRead+1],Cl-BytesRead);
-        if a=0 then for retrycount := 0 to 149 do // timeout of about 15 seconds
+        BytesRead:=BytesRead+a;
+        if (A=0) then // In fact this can not happen, but the content could be delayed...
           begin
-          sleep(100);
-          a := I.Read(S[BytesRead+1],Cl-BytesRead);
-          if a<>0 then break;
-          end;
+          Inc(RetryCount);
+          AbortRead:=RetryCount>ContentReadMaxRetryCount;
+          if not AbortRead then
+            Sleep(ContentReadRetryInterval);
+          end
+        else
+          AbortRead:=DoContentRead(PByte(@S[BytesRead+1]),A);
         BytesRead:=BytesRead+a;
-        end;
-      until (BytesRead>=Cl) or (a=0);
+      until (BytesRead>=Cl) or (AbortRead);
       // In fact the request is incomplete, but this is not the place thrown an error for that
       if BytesRead<Cl then
         SetLength(S,BytesRead);
@@ -356,7 +367,14 @@ begin
   end;
 end;
 
-Function TCGIRequest.GetFieldValue(Index : Integer) : String;
+function TCGIRequest.DoContentRead(B: PByte; Len: Integer): Boolean;
+begin
+  Result:=True;
+  if Assigned(FOnContentRead) then
+    FOnContentRead(Self,B,Len,Result);
+end;
+
+function TCGIRequest.GetFieldValue(Index: Integer): String;
 
   Function DecodeVar(I : Integer; DoDecode : Boolean = true) : String;