* Changes as suggested in bug ID #24810, so a threaded web application can be stopped correctly, even from a request

git-svn-id: trunk@25571 -
This commit is contained in:
michael 2013-09-25 19:06:16 +00:00
parent 83cad92b11
commit 973c0687fc
3 changed files with 69 additions and 14 deletions

View File

@ -33,8 +33,8 @@ Type
Private Private
FWebHandler: TFPHTTPServerHandler; FWebHandler: TFPHTTPServerHandler;
protected protected
Procedure InitRequest(ARequest : TFPHTTPConnectionRequest); virtual; Procedure InitRequest(ARequest : TFPHTTPConnectionRequest); override;
Procedure InitResponse(AResponse : TFPHTTPConnectionResponse); virtual; Procedure InitResponse(AResponse : TFPHTTPConnectionResponse); override;
Property WebHandler : TFPHTTPServerHandler Read FWebHandler; Property WebHandler : TFPHTTPServerHandler Read FWebHandler;
Property Active; Property Active;
end; end;
@ -44,9 +44,6 @@ Type
{ TFPHTTPServerHandler } { TFPHTTPServerHandler }
TFPHTTPServerHandler = class(TWebHandler) TFPHTTPServerHandler = class(TWebHandler)
procedure HTTPHandleRequest(Sender: TObject;
var ARequest: TFPHTTPConnectionRequest;
var AResponse: TFPHTTPConnectionResponse);
Private Private
FOnRequestError: TRequestErrorHandler; FOnRequestError: TRequestErrorHandler;
FServer: TEmbeddedHTTPServer; FServer: TEmbeddedHTTPServer;
@ -61,6 +58,7 @@ Type
function GetLookupHostNames : Boolean; function GetLookupHostNames : Boolean;
Procedure SetLookupHostnames(Avalue : Boolean); Procedure SetLookupHostnames(Avalue : Boolean);
protected protected
procedure HTTPHandleRequest(Sender: TObject; var ARequest: TFPHTTPConnectionRequest; var AResponse: TFPHTTPConnectionResponse); virtual;
procedure HandleRequestError(Sender: TObject; E: Exception); virtual; procedure HandleRequestError(Sender: TObject; E: Exception); virtual;
Procedure InitRequest(ARequest : TRequest); override; Procedure InitRequest(ARequest : TRequest); override;
Procedure InitResponse(AResponse : TResponse); override; Procedure InitResponse(AResponse : TResponse); override;
@ -69,6 +67,7 @@ Type
Property HTTPServer : TEmbeddedHttpServer Read FServer; Property HTTPServer : TEmbeddedHttpServer Read FServer;
Public Public
Procedure Run; override; Procedure Run; override;
Procedure Terminate; override;
constructor Create(AOwner: TComponent); override; constructor Create(AOwner: TComponent); override;
destructor Destroy; override; destructor Destroy; override;
// Port to listen on. // Port to listen on.
@ -225,8 +224,6 @@ begin
ARequest:=Nil; ARequest:=Nil;
AResponse:=Nil; AResponse:=Nil;
end; end;
If Terminated And Assigned(FServer) then
FServer.Active:=False;
if Assigned(OnIdle) then if Assigned(OnIdle) then
OnIdle(Self); OnIdle(Self);
end; end;
@ -311,6 +308,13 @@ begin
Fserver.Active:=True; Fserver.Active:=True;
end; end;
procedure TFPHTTPServerHandler.Terminate;
begin
Inherited;
if Assigned(FServer) then
Fserver.Active:=False;
end;
constructor TFPHTTPServerHandler.Create(AOwner: TComponent); constructor TFPHTTPServerHandler.Create(AOwner: TComponent);
begin begin
inherited Create(AOwner); inherited Create(AOwner);
@ -322,8 +326,11 @@ end;
destructor TFPHTTPServerHandler.Destroy; destructor TFPHTTPServerHandler.Destroy;
begin begin
FServer.Active:=False; if Assigned(FServer) then
FreeAndNil(FServer); begin
FServer.Active:=False;
FreeAndNil(FServer);
end;
inherited Destroy; inherited Destroy;
end; end;

View File

@ -106,7 +106,7 @@ Type
FOnLog : TLogEvent; FOnLog : TLogEvent;
FPreferModuleName : Boolean; FPreferModuleName : Boolean;
protected protected
procedure Terminate; procedure Terminate; virtual;
Function GetModuleName(Arequest : TRequest) : string; Function GetModuleName(Arequest : TRequest) : string;
function WaitForRequest(out ARequest : TRequest; out AResponse : TResponse) : boolean; virtual; abstract; function WaitForRequest(out ARequest : TRequest; out AResponse : TResponse) : boolean; virtual; abstract;
procedure EndRequest(ARequest : TRequest;AResponse : TResponse); virtual; procedure EndRequest(ARequest : TRequest;AResponse : TResponse); virtual;

View File

@ -119,6 +119,7 @@ Type
FServerBanner: string; FServerBanner: string;
FLookupHostNames, FLookupHostNames,
FThreaded: Boolean; FThreaded: Boolean;
FConnectionCount : Integer;
function GetActive: Boolean; function GetActive: Boolean;
procedure SetActive(const AValue: Boolean); procedure SetActive(const AValue: Boolean);
procedure SetOnAllowConnect(const AValue: TConnectQuery); procedure SetOnAllowConnect(const AValue: TConnectQuery);
@ -126,13 +127,15 @@ Type
procedure SetQueueSize(const AValue: Word); procedure SetQueueSize(const AValue: Word);
procedure SetThreaded(const AValue: Boolean); procedure SetThreaded(const AValue: Boolean);
procedure SetupSocket; procedure SetupSocket;
procedure StartServerSocket; procedure WaitForRequests;
Protected Protected
// Override these to create descendents of the request/response instead. // Override these to create descendents of the request/response instead.
Function CreateRequest : TFPHTTPConnectionRequest; virtual; Function CreateRequest : TFPHTTPConnectionRequest; virtual;
Function CreateResponse(ARequest : TFPHTTPConnectionRequest) : TFPHTTPConnectionResponse; virtual; Function CreateResponse(ARequest : TFPHTTPConnectionRequest) : TFPHTTPConnectionResponse; virtual;
Procedure InitRequest(ARequest : TFPHTTPConnectionRequest); virtual; Procedure InitRequest(ARequest : TFPHTTPConnectionRequest); virtual;
Procedure InitResponse(AResponse : TFPHTTPConnectionResponse); virtual; Procedure InitResponse(AResponse : TFPHTTPConnectionResponse); virtual;
// Called on accept errors
procedure DoAcceptError(Sender: TObject; ASocket: Longint; E: Exception; var ErrorAction: TAcceptErrorAction);
// Create a connection handling object. // Create a connection handling object.
function CreateConnection(Data : TSocketStream) : TFPHTTPConnection; virtual; function CreateConnection(Data : TSocketStream) : TFPHTTPConnection; virtual;
// Create a connection handling thread. // Create a connection handling thread.
@ -143,13 +146,19 @@ Type
Procedure DoConnect(Sender : TObject; Data : TSocketStream); virtual; Procedure DoConnect(Sender : TObject; Data : TSocketStream); virtual;
// Create and configure TInetServer // Create and configure TInetServer
Procedure CreateServerSocket; virtual; Procedure CreateServerSocket; virtual;
// Stop and free TInetServer // Start server socket
procedure StartServerSocket; virtual;
// Stop server stocket
procedure StopServerSocket; virtual;
// free server socket instance
Procedure FreeServerSocket; virtual; Procedure FreeServerSocket; virtual;
// Handle request. This calls OnRequest. It can be overridden by descendants to provide standard handling. // Handle request. This calls OnRequest. It can be overridden by descendants to provide standard handling.
procedure HandleRequest(Var ARequest: TFPHTTPConnectionRequest; procedure HandleRequest(Var ARequest: TFPHTTPConnectionRequest;
Var AResponse : TFPHTTPConnectionResponse); virtual; Var AResponse : TFPHTTPConnectionResponse); virtual;
// Called when a connection encounters an unexpected error. Will call OnRequestError when set. // Called when a connection encounters an unexpected error. Will call OnRequestError when set.
procedure HandleRequestError(Sender: TObject; E: Exception); virtual; procedure HandleRequestError(Sender: TObject; E: Exception); virtual;
// Connection count
Property ConnectionCount : Integer Read FConnectionCount;
public public
Constructor Create(AOwner : TComponent); override; Constructor Create(AOwner : TComponent); override;
Destructor Destroy; override; Destructor Destroy; override;
@ -542,10 +551,14 @@ constructor TFPHTTPConnection.Create(AServer: TFPCustomHttpServer; ASocket: TSoc
begin begin
FSocket:=ASocket; FSocket:=ASocket;
FServer:=AServer; FServer:=AServer;
If Assigned(FServer) then
InterLockedIncrement(FServer.FConnectionCount)
end; end;
destructor TFPHTTPConnection.Destroy; destructor TFPHTTPConnection.Destroy;
begin begin
If Assigned(FServer) then
InterLockedDecrement(FServer.FConnectionCount);
FreeAndNil(FSocket); FreeAndNil(FSocket);
Inherited; Inherited;
end; end;
@ -634,6 +647,15 @@ begin
end end
end; end;
procedure TFPCustomHttpServer.DoAcceptError(Sender: TObject; ASocket: Longint;
E: Exception; var ErrorAction: TAcceptErrorAction);
begin
If Not Active then
ErrorAction:=AEAStop
else
ErrorAction:=AEARaise
end;
function TFPCustomHttpServer.GetActive: Boolean; function TFPCustomHttpServer.GetActive: Boolean;
begin begin
if (csDesigning in ComponentState) then if (csDesigning in ComponentState) then
@ -642,6 +664,11 @@ begin
Result:=Assigned(FServer); Result:=Assigned(FServer);
end; end;
procedure TFPCustomHttpServer.StopServerSocket;
begin
FServer.StopAccepting(True);
end;
procedure TFPCustomHttpServer.SetActive(const AValue: Boolean); procedure TFPCustomHttpServer.SetActive(const AValue: Boolean);
begin begin
If AValue=GetActive then exit; If AValue=GetActive then exit;
@ -652,9 +679,10 @@ begin
CreateServerSocket; CreateServerSocket;
SetupSocket; SetupSocket;
StartServerSocket; StartServerSocket;
FreeServerSocket;
end end
else else
FreeServerSocket; StopServerSocket;
end; end;
procedure TFPCustomHttpServer.SetOnAllowConnect(const AValue: TConnectQuery); procedure TFPCustomHttpServer.SetOnAllowConnect(const AValue: TConnectQuery);
@ -758,6 +786,7 @@ begin
FServer.MaxConnections:=-1; FServer.MaxConnections:=-1;
FServer.OnConnectQuery:=OnAllowConnect; FServer.OnConnectQuery:=OnAllowConnect;
FServer.OnConnect:=@DOConnect; FServer.OnConnect:=@DOConnect;
FServer.OnAcceptError:=@DoAcceptError;
end; end;
procedure TFPCustomHttpServer.StartServerSocket; procedure TFPCustomHttpServer.StartServerSocket;
@ -769,7 +798,6 @@ end;
procedure TFPCustomHttpServer.FreeServerSocket; procedure TFPCustomHttpServer.FreeServerSocket;
begin begin
FServer.StopAccepting;
FreeAndNil(FServer); FreeAndNil(FServer);
end; end;
@ -788,9 +816,29 @@ begin
FServerBanner := 'Freepascal'; FServerBanner := 'Freepascal';
end; end;
Procedure TFPCustomHttpServer.WaitForRequests;
Var
FLastCount,ACount : Integer;
begin
ACount:=0;
FLastCount:=FConnectionCount;
While (FConnectionCount>0) and (ACount<10) do
begin
Sleep(100);
if (FConnectionCount=FLastCount) then
Dec(ACount)
else
FLastCount:=FConnectionCount;
end;
end;
destructor TFPCustomHttpServer.Destroy; destructor TFPCustomHttpServer.Destroy;
begin begin
Active:=False; Active:=False;
if Threaded and (FConnectionCount>0) then
WaitForRequests;
inherited Destroy; inherited Destroy;
end; end;