Browse Source

Merged revisions 7043-7044,7049-7050 via svnmerge from
svn+ssh://[email protected]/FPC/svn/fpc/trunk

........
r7043 | michael | 2007-03-31 23:04:22 +0200 (Sat, 31 Mar 2007) | 1 line

* Fixed some typing error in a type
........
r7044 | michael | 2007-03-31 23:04:58 +0200 (Sat, 31 Mar 2007) | 1 line

* initial version of apache support (not yet in Makefile)
........
r7049 | michael | 2007-04-01 17:06:56 +0200 (Sun, 01 Apr 2007) | 5 lines

* Added some delphi compatibility properties
* Apache module now works.
* Removed debug define.
* Extended webutil.

........
r7050 | michael | 2007-04-01 17:09:35 +0200 (Sun, 01 Apr 2007) | 1 line

* Added fpapache explanation
........

git-svn-id: branches/fixes_2_2@7214 -

joost 18 years ago
parent
commit
f7fc19de6b

+ 1 - 0
.gitattributes

@@ -4195,6 +4195,7 @@ packages/fcl-web/Makefile svneol=native#text/plain
 packages/fcl-web/Makefile.fpc svneol=native#text/plain
 packages/fcl-web/src/README svneol=native#text/plain
 packages/fcl-web/src/custcgi.pp svneol=native#text/plain
+packages/fcl-web/src/fpapache.pp svneol=native#text/plain
 packages/fcl-web/src/fpcgi.pp svneol=native#text/plain
 packages/fcl-web/src/fpdatasetform.pp svneol=native#text/plain
 packages/fcl-web/src/fphtml.pp svneol=native#text/plain

+ 9 - 0
packages/fcl-web/src/README

@@ -143,3 +143,12 @@ TCGIApplication:
   to create a TCustomHTTPModuleClass to handle the request.
 
 It contains an Application instance which handles everything.
+
+fpApache:
+---------
+  Apache Module support.
+
+TCustomApacheApplication:
+  Uses fpweb to create TCustomHTTPModuleClass instances to 
+  handle the request. 
+

+ 583 - 0
packages/fcl-web/src/fpapache.pp

@@ -0,0 +1,583 @@
+{
+    $Id: header,v 1.1 2000/07/13 06:33:45 michael Exp $
+    This file is part of the Free Component Library (FCL)
+    Copyright (c) 1999-2000 by the Free Pascal development team
+
+    See the file COPYING.FPC, included in this distribution,
+    for details about the copyright.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+ **********************************************************************}
+{$mode objfpc}
+{$H+}
+unit fpapache;
+
+interface
+
+uses SysUtils,Classes,CustApp,httpDefs,fpHTTP,httpd, apr;
+
+Type
+
+  TCustomApacheApplication = Class;
+
+  { TApacheRequest }
+
+  TApacheRequest = Class(TRequest)
+  Private
+    FApache : TCustomApacheApplication;
+    FRequest : PRequest_rec;
+    FContent : String;
+    FContentRead : Boolean;
+    procedure ReadContent;
+  Protected
+    Function GetFieldValue(Index : Integer) : String; override;
+    Procedure InitFromRequest;
+  Public
+    Constructor CreateReq(App : TCustomApacheApplication; ARequest : PRequest_rec);
+    Property ApacheRequest : Prequest_rec Read FRequest;
+    Property ApacheApp : TCustomApacheApplication Read FApache;
+  end;
+
+  { TCGIResponse }
+
+  { TApacheResponse }
+
+  TApacheResponse = Class(TResponse)
+  private
+    FApache : TCustomApacheApplication;
+    FRequest : PRequest_rec;
+    procedure SendStream(S: TStream);
+  Protected
+    Procedure DoSendHeaders(Headers : TStrings); override;
+    Procedure DoSendContent; override;
+  Public
+    Constructor CreateApache(Req : TApacheRequest);
+    Property ApacheRequest : Prequest_rec Read FRequest;
+    Property ApacheApp : TCustomApacheApplication Read FApache;
+  end;
+
+
+  { TCustomApacheApplication }
+  THandlerPriority = (hpFirst,hpMiddle,hpLast);
+  TGetModuleEvent = Procedure (Sender : TObject; ARequest : TRequest;
+                               Var ModuleClass : TCustomHTTPModuleClass) of object;
+  TBeforeRequestEvent = Procedure(Sender : TObject; Const AHandler : String;
+                                  Var AllowRequest : Boolean) of object;
+
+  TCustomApacheApplication = Class(TCustomApplication)
+  private
+    FAdministrator: String;
+    FBaseLocation: String;
+    FBeforeRequest: TBeforeRequestEvent;
+    FEmail: String;
+    FHandlerName: String;
+    FModuleName: String;
+    FOnGetModule: TGetModuleEvent;
+    FAllowDefaultModule: Boolean;
+    FModules : Array[0..1] of TStrings;
+    FPriority: THandlerPriority;
+    FModuleRecord : PModule;
+    function GetModules(Index: integer): TStrings;
+    procedure SetModules(Index: integer; const AValue: TStrings);
+    procedure ShowRequestException(R: TResponse; E: Exception);
+  Protected
+    Function ProcessRequest(P : PRequest_Rec) : Integer; virtual;
+    Function GetModuleName(ARequest : TRequest) : string;
+    function FindModule(ModuleClass : TCustomHTTPModuleClass): TCustomHTTPModule;
+    Procedure DoRun; override;
+    Function AllowRequest(P : PRequest_Rec) : Boolean; virtual;
+  Public
+    Constructor Create(AOwner : TComponent); override;
+    Procedure SetModuleRecord(Var ModuleRecord : Module);
+    Procedure Initialize; override;
+    Procedure ShowException(E : Exception); override;
+    Procedure CreateForm(AClass : TComponentClass; Var Reference : TComponent);
+    Procedure handleRequest(ARequest : TRequest; AResponse : TResponse); virtual;
+    Property OnGetModule : TGetModuleEvent Read FOnGetModule Write FOnGetModule;
+    Property AllowDefaultModule : Boolean Read FAllowDefaultModule Write FAllowDefaultModule;
+    Property HandlerPriority : THandlerPriority Read FPriority Write FPriority default hpMiddle;
+    Property BeforeModules : TStrings Index 0 Read GetModules Write SetModules;
+    Property AfterModules : TStrings Index 1 Read GetModules Write SetModules;
+    Property BaseLocation : String Read FBaseLocation Write FBaseLocation;
+    Property ModuleName : String Read FModuleName Write FModuleName;
+    Property HandlerName : String Read FHandlerName Write FHandlerName;
+    Property BeforeRequest : TBeforeRequestEvent Read FBeforeRequest Write FBeforeRequest;
+    Property Email : String Read FEmail Write FEmail;
+    Property Administrator : String Read FAdministrator Write FAdministrator;
+  end;
+
+  TApacheApplication = Class(TCustomApacheApplication)
+  Public
+    Property HandlerPriority;
+    Property BeforeModules;
+    Property AfterModules;
+    Property AllowDefaultModule;
+    Property OnGetModule;
+    Property BaseLocation;
+    Property ModuleName;
+  end;
+  
+
+  EFPApacheError = Class(Exception);
+  
+Var
+  Application : TCustomApacheApplication = Nil;
+  ShowCleanUpErrors : Boolean = False;
+  AlternateHandler : ap_hook_handler_t = Nil;
+
+Implementation
+
+resourcestring
+  SErrNoModuleNameForRequest = 'Could not determine HTTP module name for request';
+  SErrNoModuleForRequest = 'Could not determine HTTP module for request "%s"';
+  SErrNoModuleRecord = 'No module record location set.';
+  SErrNoModuleName = 'No module name set';
+  SModuleError  = 'Module Error';
+  SAppEncounteredError = 'The application encountered the following error:';
+  SError     = 'Error: ';
+  SNotify    = 'Notify: ';
+
+const
+  HPRIO : Array[THandlerPriority] of Integer
+        = (APR_HOOK_FIRST,APR_HOOK_MIDDLE,APR_HOOK_LAST);
+
+
+Procedure InitApache;
+
+begin
+  Application:=TCustomApacheApplication.Create(Nil);
+end;
+
+Procedure DoneApache;
+
+begin
+  Try
+    FreeAndNil(Application);
+  except
+    if ShowCleanUpErrors then
+      Raise;
+  end;
+end;
+
+Function DefaultApacheHandler(P : PRequest_Rec) : integer;cdecl;
+
+begin
+  If (AlternateHandler<>Nil) then
+    Result:=AlterNateHandler(P)
+  else
+    If Application.AllowRequest(P) then
+      Result:=Application.ProcessRequest(P)
+    else
+      Result:=DECLINED;
+end;
+
+Procedure RegisterApacheHooks(P: PApr_pool_t);cdecl;
+
+Var
+  H : ap_hook_handler_t;
+  PP1,PP2 : PPChar;
+
+begin
+  H:=AlternateHandler;
+  If (H=Nil) then
+    H:=@DefaultApacheHandler;
+  PP1:=Nil;
+  PP2:=Nil;
+  ap_hook_handler(H,PP1,PP2,HPRIO[Application.HandlerPriority]);
+end;
+
+{ TCustomApacheApplication }
+
+function TCustomApacheApplication.GetModules(Index: integer): TStrings;
+begin
+  If (FModules[Index]=Nil) then
+    FModules[Index]:=TStringList.Create;
+  Result:=FModules[Index];
+end;
+
+procedure TCustomApacheApplication.SetModules(Index: integer;
+  const AValue: TStrings);
+begin
+  If (FModules[Index]=Nil) then
+    FModules[Index]:=TStringList.Create;
+  FModules[Index].Assign(AValue);
+end;
+
+Function TCustomApacheApplication.ProcessRequest(P: PRequest_Rec) : Integer;
+
+Var
+  Req : TApacheRequest;
+  Resp : TApacheResponse;
+
+begin
+  Req:=TApacheRequest.CreateReq(Self,P);
+  Try
+    Resp:=TApacheResponse.CreateApache(Req);
+    Try
+      HandleRequest(Req,Resp);
+    Finally
+      Result:=OK;
+      Resp.Free;
+    end;
+  Finally
+    Req.Free;
+  end;
+end;
+
+function TCustomApacheApplication.GetModuleName(Arequest: TRequest): string;
+
+
+begin
+  Result:=ARequest.GetNextPathInfo;
+end;
+
+function TCustomApacheApplication.FindModule(ModuleClass : TCustomHTTPModuleClass): TCustomHTTPModule;
+
+Var
+  I : Integer;
+
+begin
+  I:=ComponentCount-1;
+  While (I>=0) and (Not (Components[i] is ModuleClass)) do
+    Dec(i);
+  if (I>=0) then
+    Result:=Components[i] as TCustomHTTPModule
+  else
+    Result:=Nil;
+end;
+
+procedure TCustomApacheApplication.DoRun;
+begin
+  inherited DoRun;
+end;
+
+function TCustomApacheApplication.AllowRequest(P: PRequest_Rec): Boolean;
+
+Var
+  Hn : String;
+
+begin
+  HN:=StrPas(p^.Handler);
+  Result:=CompareText(HN,FHandlerName)=0;
+  If Assigned(FBeforeRequest) then
+    FBeforeRequest(Self,HN,Result);
+end;
+
+constructor TCustomApacheApplication.Create(AOwner: TComponent);
+begin
+  inherited Create(AOwner);
+  FAllowDefaultModule:=True;
+  FPriority:=hpMiddle;
+end;
+
+procedure TCustomApacheApplication.SetModuleRecord(var ModuleRecord: Module);
+begin
+  FModuleRecord:=@ModuleRecord;
+  FillChar(ModuleRecord,SizeOf(ModuleRecord),0);
+end;
+
+procedure TCustomApacheApplication.Initialize;
+
+begin
+  If (FModuleRecord=nil) then
+    Raise EFPApacheError.Create(SErrNoModuleRecord);
+  if (FModuleName='') and (FModuleRecord^.Name=Nil) then
+    Raise EFPApacheError.Create(SErrNoModuleName);
+  STANDARD20_MODULE_STUFF(FModuleRecord^);
+  If (StrPas(FModuleRecord^.name)<>FModuleName) then
+    FModuleRecord^.Name:=PChar(FModuleName);
+  FModuleRecord^.register_hooks:=@RegisterApacheHooks;
+end;
+
+procedure TCustomApacheApplication.ShowRequestException(R : TResponse; E: Exception);
+
+Var
+ TheEmail : String;
+ FrameCount: integer;
+ Frames: PPointer;
+ FrameNumber:Integer;
+ S : TStrings;
+
+begin
+  If not R.HeadersSent then
+    begin
+    R.ContentType:='text/html';
+    R.SendHeaders;
+    end;
+  If (R.ContentType='text/html') then
+    begin
+    S:=TStringList.Create;
+    Try
+      With S do
+        begin
+        Add('<html><head><title>'+Title+': '+SModuleError+'</title></head>'+LineEnding);
+        Add('<body>');
+        Add('<center><hr><h1>'+Title+': ERROR</h1><hr></center><br><br>');
+        Add(SAppEncounteredError+'<br>');
+        Add('<ul>');
+        Add('<li>'+SError+' <b>'+E.Message+'</b>');
+        Add('<li> Stack trace:<br>');
+        Add(BackTraceStrFunc(ExceptAddr)+'<br>');
+        FrameCount:=ExceptFrameCount;
+        Frames:=ExceptFrames;
+        for FrameNumber := 0 to FrameCount-1 do
+          Add(BackTraceStrFunc(Frames[FrameNumber])+'<br>');
+        Add('</ul><hr>');
+        TheEmail:=Email;
+        If (TheEmail<>'') then
+          Add('<h5><p><i>'+SNotify+Administrator+': <a href="mailto:'+TheEmail+'">'+TheEmail+'</a></i></p></h5>');
+        Add('</body></html>');
+        end;
+      R.Content:=S.Text;
+      R.SendContent;
+    Finally
+      FreeAndNil(S);
+    end;
+    end;
+end;
+
+procedure TCustomApacheApplication.ShowException(E: Exception);
+begin
+  ap_log_error(pchar(FModuleName),0,APLOG_ERR,0,Nil,'module: %s',[Pchar(E.Message)]);
+end;
+
+procedure TCustomApacheApplication.CreateForm(AClass: TComponentClass;
+  var Reference: TComponent);
+begin
+  Reference:=AClass.Create(Self);
+end;
+
+procedure TCustomApacheApplication.HandleRequest(ARequest: TRequest; AResponse: TResponse);
+
+Var
+  MC : TCustomHTTPModuleClass;
+  M  : TCustomHTTPModule;
+  MN : String;
+  MI : TModuleItem;
+  
+begin
+  try
+    MC:=Nil;
+    If (OnGetModule<>Nil) then
+      OnGetModule(Self,ARequest,MC);
+    If (MC=Nil) then
+      begin
+      MN:=GetModuleName(ARequest);
+      If (MN='') and Not AllowDefaultModule then
+        Raise EFPApacheError.Create(SErrNoModuleNameForRequest);
+      MI:=ModuleFactory.FindModule(MN);
+      If (MI=Nil) and (ModuleFactory.Count=1) then
+        MI:=ModuleFactory[0];
+      if (MI=Nil) then
+        begin
+        Raise EFPApacheError.CreateFmt(SErrNoModuleForRequest,[MN]);
+        end;
+      MC:=MI.ModuleClass;
+      M:=FindModule(MC); // Check if a module exists already
+      end;
+    If (M=Nil) then
+      begin
+      M:=MC.Create(Self);
+      end;
+    M.HandleRequest(ARequest,AResponse);
+  except
+    On E : Exception do
+      ShowRequestException(AResponse,E);
+  end;
+end;
+
+{ TApacheRequest }
+
+function TApacheRequest.GetFieldValue(Index: Integer): String;
+
+var
+  P : Pchar;
+  FN : String;
+  I : Integer;
+  
+begin
+
+  Result:='';
+  If (Index in [1..NoHTTPFields]) then
+    begin
+    FN:=HTTPFieldNames[Index];
+    P:=apr_table_get(FRequest^.headers_in,pchar(FN));
+    If (P<>Nil) then
+      Result:=StrPas(P);
+    end;
+  if (Result='') then
+    case Index of
+      0  : Result:=strpas(FRequest^.protocol); // ProtocolVersion
+      7  : Result:=Strpas(FRequest^.content_encoding); //ContentEncoding
+      25 : Result:=StrPas(FRequest^.path_info); // PathInfo
+      26 : Result:=StrPas(FRequest^.filename); // PathTranslated
+      27 : // RemoteAddr
+           If (FRequest^.Connection<>Nil) then
+             Result:=StrPas(FRequest^.Connection^.remote_ip);
+      28 : // RemoteHost
+           ap_get_remote_host(FRequest^.Connection,
+                              FRequest^.Per_Dir_Config,
+                              REMOTE_HOST,Nil);
+      29 : begin // ScriptName
+           Result:=StrPas(FRequest^.unparsed_uri);
+           I:=Pos('?',Result)-1;
+           If (I=-1) then
+             I:=Length(Result);
+           Result:=Copy(Result,1,I-Length(PathInfo));
+           end;
+      30 : Result:=IntToStr(ap_get_server_port(FRequest)); // ServerPort
+      31 : Result:=StrPas(FRequest^.method); // Method
+      32 : Result:=StrPas(FRequest^.unparsed_uri); // URL
+      33 : Result:=StrPas(FRequest^.args); // Query
+      34 : Result:=StrPas(FRequest^.HostName); // Host
+      35 : begin // Content
+           If Not FContentRead then
+             ReadContent;
+           Result:=FContent;
+           end;
+    else
+      Result:=inherited GetFieldValue(Index);
+    end;
+end;
+
+procedure TApacheRequest.ReadContent;
+
+  Function MinS(A,B : Integer) : Integer;
+  
+  begin
+    If A<B then
+      Result:=A
+    else
+      Result:=B;
+  end;
+
+Var
+  Left,Len,Count,Bytes : Integer;
+  P : Pchar;
+  
+begin
+  ap_setup_client_block(Frequest,REQUEST_CHUNKED_DECHUNK);
+  If (ap_should_client_block(Frequest)=1) then
+    begin
+    Len:=ContentLength;
+    If (Len>0) then
+      begin
+      SetLength(FContent,Len);
+      P:=PChar(FContent);
+      Left:=Len;
+      Count:=0;
+      Repeat
+        Bytes:=ap_get_client_block(FRequest,P,MinS(10*1024,Left));
+        Dec(Left,Bytes);
+        Inc(P,Bytes);
+        Inc(Count,Bytes);
+      Until (Count>=Len) or (Bytes=0);
+      SetLength(FContent,Count);
+      end;
+    end;
+  FContentRead:=True;
+end;
+
+procedure TApacheRequest.InitFromRequest;
+
+Var
+  I : Integer;
+  S : String;
+  
+begin
+  // This fills the internal table. We should try
+  // to get rid of it.
+  For I:=0 to NoHTTPFields do
+    begin
+    S:=GetFieldValue(i);
+    If (S<>'') then
+      SetFieldValue(I,S);
+    end;
+end;
+
+Constructor TApacheRequest.CreateReq(App : TCustomApacheApplication; ARequest : PRequest_rec);
+
+begin
+  FApache:=App;
+  FRequest:=Arequest;
+  ReturnedPathInfo:=App.BaseLocation;
+  InitFromRequest;
+  Inherited Create;
+end;
+
+{ TApacheResponse }
+
+procedure TApacheResponse.DoSendHeaders(Headers: TStrings);
+
+Var
+  I,P : Integer;
+  N,V : String;
+
+begin
+  For I:=0 to Headers.Count-1 do
+    begin
+    V:=Headers[i];
+    P:=Pos(':',V);
+    If (P<>0) and (P<Length(V)) then
+      begin
+      N:=Copy(V,1,P-1);
+      System.Delete(V,1,P);
+      apr_table_set(FRequest^.headers_out,Pchar(N),Pchar(V));
+      end;
+    end;
+end;
+
+procedure TApacheResponse.DoSendContent;
+
+Var
+  S : String;
+  I : Integer;
+
+begin
+  S:=ContentType;
+  If (S<>'') then
+    FRequest^.content_type:=apr_pstrdup(FRequest^.pool,Pchar(S));
+  If (ContentStream<>Nil) then
+    SendStream(Contentstream)
+  else
+    for I:=0 to Contents.Count-1 do
+      begin
+      S:=Contents[i]+LineEnding;
+      // If there is a null, it's written also with ap_rwrite
+      ap_rwrite(PChar(S),Length(S),FRequest);
+      end;
+end;
+
+Procedure TApacheResponse.SendStream(S : TStream);
+
+Var
+  Buf : Array[0..(10*1024)-1] of Byte;
+  Count : Integer;
+
+begin
+  Repeat
+    Count:=S.Read(Buf,SizeOf(Buf));
+    If Count>0 then
+      ap_rwrite(@Buf,Count,FRequest);
+  Until (Count=0);
+end;
+
+
+Constructor TApacheResponse.CreateApache(Req : TApacheRequest);
+begin
+  FApache:=Req.ApacheApp;
+  Frequest:=Req.ApacheRequest;
+  Inherited Create(Req);
+end;
+
+
+Initialization
+  InitApache;
+  
+Finalization
+  DoneApache;
+  
+end.

+ 0 - 1
packages/fcl-web/src/fphtml.pp

@@ -38,7 +38,6 @@ type
     Function ProduceContent : String; override; // Here to test the output. Replace to protected after tests
     property ParentElement : THTMLCustomElement read FElement write FElement;
     property Writer : THTMLWriter read FWriter write SetWriter;
-  published
     Property HTMLDocument : THTMLDocument read FDocument write SetDocument;
   end;
 

+ 15 - 7
packages/fcl-web/src/httpdefs.pp

@@ -24,7 +24,7 @@
 }
 {$mode objfpc}
 {$H+}
-{$DEFINE CGIDEBUG}
+{ $DEFINE CGIDEBUG}
 unit HTTPDefs;
 
 interface
@@ -75,10 +75,10 @@ const
 
 
 Type
-  TTHttpFields = Array[1..NoHTTPFields] of string; 
+  THttpFields = Array[1..NoHTTPFields] of string;
 
 Const
-  HTTPFieldNames : TTHttpFields
+  HTTPFieldNames : THttpFields
              = (fieldAccept, fieldAcceptCharset, fieldAcceptEncoding, 
                 fieldAcceptLanguage, fieldAuthorization, fieldConnection,
                 fieldContentEncoding, fieldContentLanguage, fieldContentLength,
@@ -172,7 +172,7 @@ type
     FContentFields: TStrings;
     FCookieFields: TStrings;
     FHTTPVersion : String;
-    FFields : TTHttpFields;
+    FFields : THttpFields;
     FQueryFields: TStrings;
     function GetSetField(AIndex: Integer): String;
     function GetSetFieldName(AIndex: Integer): String;
@@ -197,6 +197,8 @@ type
     Function LoadFromStream(Stream : TStream; IncludeCommand : Boolean) : integer;
     Function LoadFromStrings(Strings: TStrings; IncludeCommand : Boolean) : integer; virtual;
     // Common access
+    // This is an internal table. We should try to get rid of it,
+    // It requires a lot of duplication.
     property FieldCount: Integer read GetFieldCount;
     property Fields[AIndex: Integer]: String read GetSetField;
     property FieldNames[AIndex: Integer]: String read GetSetFieldName;
@@ -212,7 +214,7 @@ type
     property Connection: String Index 6 Read GetFieldValue Write SetFieldValue;
     property ContentEncoding: String Index 7 Read GetFieldValue Write SetFieldValue;
     property ContentLanguage: String Index 8 Read GetFieldValue Write SetFieldValue;
-    property ContentLength: Integer Read GetContentLength Write SetContentLength;
+    property ContentLength: Integer Read GetContentLength Write SetContentLength; // Index 9
     property ContentType: String Index 10 Read GetFieldValue Write SetFieldValue;
     property Cookie: String Index 11 Read GetFieldValue Write SetFieldValue;
     property Date: String Index 12 Read GetFieldValue Write SetFieldValue;
@@ -241,6 +243,11 @@ type
     Property HTTPIfModifiedSince : String Index 15 read GetFieldValue Write SetFieldValue; // Maybe change to TDateTime ??
     Property HTTPReferer : String Index 19 read GetFieldValue Write SetFieldValue;
     Property HTTPUserAgent : String Index 23 read GetFieldValue Write SetFieldValue;
+    Property Method : String Index 31 read GetFieldValue Write SetFieldValue;
+    Property URL : String Index 32 read GetFieldValue Write SetFieldValue;
+    Property Query : String Index 33 read GetFieldValue Write SetFieldValue;
+    Property Host : String Index 34 Read GetFieldValue Write SetFieldValue;
+    Property Content : String Index 35 Read GetFieldValue Write SetFieldValue;
     // Lists
     Property CookieFields : TStrings Read FCookieFields Write SetCookieFields;
     Property ContentFields: TStrings read FContentFields;
@@ -259,12 +266,13 @@ type
     FFiles : TUploadedFiles;
     FReturnedPathInfo : String;
     procedure ParseFirstHeaderLine(const line: String);override;
-    function  GetFirstHeaderLine: String;
+    function GetFirstHeaderLine: String;
   Protected
     Procedure ProcessMultiPart(Stream : TStream; Const Boundary : String); virtual;
     Procedure ProcessQueryString(Const FQueryString : String); virtual;
     procedure ProcessURLEncoded(Stream : TStream); virtual;
     Function  GetTempUploadFileName : String; virtual;
+    Property ReturnedPathInfo : String Read FReturnedPathInfo Write FReturnedPathInfo;
   public
     constructor Create; override;
     destructor destroy; override;
@@ -667,7 +675,7 @@ var
 begin
   I:=GetFieldNameIndex(AName);
   If (I<>0) then
-    Result:=FFields[i];
+    Result:=self.GetFieldValue(i);
 end;
 
 Function THTTPHeader.LoadFromStream(Stream: TStream; IncludeCommand : Boolean) : Integer;

+ 5 - 0
packages/fcl-web/src/webutil.pp

@@ -70,6 +70,11 @@ begin
     AddNV('RemoteHost',RemoteHost);
     AddNV('ScriptName',ScriptName);
     AddNV('ServerPort',IntToStr(ServerPort));
+    AddNV('Method',Method);
+    AddNV('URL',URL);
+    AddNV('Query',Query);
+    AddNV('Host',Host);
+    AddNV('Content',Content);
     Add('</TABLE><P>');
     // Additional headers
     If (QueryFields.Count>0) then