mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-04-19 12:19:25 +02:00
* Fixed
git-svn-id: trunk@17443 -
This commit is contained in:
parent
9214ef8c96
commit
bc25040332
1
.gitattributes
vendored
1
.gitattributes
vendored
@ -2472,6 +2472,7 @@ packages/fcl-web/src/base/fphtml.pp svneol=native#text/plain
|
||||
packages/fcl-web/src/base/fphttp.pp svneol=native#text/plain
|
||||
packages/fcl-web/src/base/fpweb.pp svneol=native#text/plain
|
||||
packages/fcl-web/src/base/httpdefs.pp svneol=native#text/plain
|
||||
packages/fcl-web/src/base/iniwebsession.pp svneol=native#text/plain
|
||||
packages/fcl-web/src/base/webpage.pp svneol=native#text/plain
|
||||
packages/fcl-web/src/base/websession.pp svneol=native#text/plain
|
||||
packages/fcl-web/src/base/webutil.pp svneol=native#text/plain
|
||||
|
382
packages/fcl-web/src/base/iniwebsession.pp
Normal file
382
packages/fcl-web/src/base/iniwebsession.pp
Normal file
@ -0,0 +1,382 @@
|
||||
{
|
||||
$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.
|
||||
|
||||
**********************************************************************}
|
||||
unit iniwebsession;
|
||||
|
||||
{$mode objfpc}{$H+}
|
||||
{ $define cgidebug}
|
||||
interface
|
||||
|
||||
uses
|
||||
Classes, SysUtils, fphttp, inifiles, httpdefs;
|
||||
|
||||
Type
|
||||
|
||||
{ TIniWebSession }
|
||||
|
||||
TIniWebSession = Class(TCustomSession)
|
||||
Private
|
||||
FSessionStarted : Boolean;
|
||||
FCached: Boolean;
|
||||
FIniFile : TMemInifile;
|
||||
FSessionCookie: String;
|
||||
FSessionCookiePath: String;
|
||||
FSessionDir: String;
|
||||
FTerminated :Boolean;
|
||||
SID : String;
|
||||
private
|
||||
procedure FreeIniFile;
|
||||
Protected
|
||||
Procedure CheckSession;
|
||||
Function GetSessionID : String; override;
|
||||
Function GetSessionVariable(VarName : String) : String; override;
|
||||
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 SessionCookiePath : String Read FSessionCookiePath write FSessionCookiePath;
|
||||
Public
|
||||
Destructor Destroy; override;
|
||||
Procedure Terminate; override;
|
||||
Procedure UpdateResponse(AResponse : TResponse); override;
|
||||
Procedure InitSession(ARequest : TRequest; OnNewSession, OnExpired: TNotifyEvent); override;
|
||||
Procedure InitResponse(AResponse : TResponse); override;
|
||||
Procedure RemoveVariable(VariableName : String); override;
|
||||
end;
|
||||
TIniWebSessionClass = Class of TIniWebSession;
|
||||
|
||||
{ TIniSessionFactory }
|
||||
|
||||
TIniSessionFactory = Class(TSessionFactory)
|
||||
private
|
||||
FCached: Boolean;
|
||||
FOldFileNameScheme: Boolean;
|
||||
FSessionDir: String;
|
||||
procedure SetCached(const AValue: Boolean);
|
||||
procedure SetSessionDir(const AValue: String);
|
||||
protected
|
||||
Procedure DeleteSessionFile(const AFileName : String);virtual;
|
||||
Function SessionExpired(Ini : TMemIniFile) : boolean;
|
||||
procedure CheckSessionDir; virtual;
|
||||
Function DoCreateSession(ARequest : TRequest) : TCustomSession; override;
|
||||
// Sweep session direcory and delete expired files.
|
||||
procedure DoCleanupSessions; override;
|
||||
Procedure DoDoneSession(Var ASession : TCustomSession); override;
|
||||
Public
|
||||
// Directory where sessions are kept.
|
||||
Property SessionDir : String Read FSessionDir Write SetSessionDir;
|
||||
// Are ini files cached (written in 1 go before destroying)
|
||||
Property Cached : Boolean Read FCached Write SetCached;
|
||||
// If True, the '{' and '}' will not be stripped from the session filename.
|
||||
Property OldFileNameScheme : Boolean Read FOldFileNameScheme Write FOldFileNameScheme;
|
||||
end;
|
||||
|
||||
Var
|
||||
IniWebSessionClass : TIniWebSessionClass = Nil;
|
||||
|
||||
implementation
|
||||
|
||||
{$ifdef cgidebug}
|
||||
uses dbugintf;
|
||||
{$endif}
|
||||
|
||||
Const
|
||||
// Sections in ini file
|
||||
SSession = 'Session';
|
||||
SData = 'Data';
|
||||
|
||||
KeyStart = 'Start'; // Start time of session
|
||||
KeyLast = 'Last'; // Last seen time of session
|
||||
KeyTimeOut = 'Timeout'; // Timeout in seconds;
|
||||
|
||||
SFPWebSession = 'FPWebSession'; // Cookie name for session.
|
||||
|
||||
resourcestring
|
||||
SErrSessionTerminated = 'No web session active: Session was terminated';
|
||||
SErrNoSession = 'No web session active: Session was not started';
|
||||
|
||||
{ TIniSessionFactory }
|
||||
|
||||
procedure TIniSessionFactory.SetCached(const AValue: Boolean);
|
||||
begin
|
||||
if FCached=AValue then exit;
|
||||
FCached:=AValue;
|
||||
end;
|
||||
|
||||
procedure TIniSessionFactory.SetSessionDir(const AValue: String);
|
||||
begin
|
||||
if FSessionDir=AValue then exit;
|
||||
FSessionDir:=AValue;
|
||||
end;
|
||||
|
||||
procedure TIniSessionFactory.DeleteSessionFile(const AFileName: String);
|
||||
begin
|
||||
DeleteFile(AFileName); // TODO : silently ignoring errors ?
|
||||
end;
|
||||
|
||||
function TIniSessionFactory.SessionExpired(Ini: TMemIniFile): boolean;
|
||||
|
||||
Var
|
||||
L : TDateTime;
|
||||
T : Integer;
|
||||
begin
|
||||
L:=Ini.ReadDateTime(SSession,KeyLast,0);
|
||||
T:=Ini.ReadInteger(SSession,KeyTimeOut,DefaultTimeOutMinutes);
|
||||
{$ifdef cgidebug}
|
||||
If (L=0) then
|
||||
SendDebug('No datetime in inifile (or not valid datetime : '+Ini.ReadString(SSession,KeyLast,''))
|
||||
else
|
||||
SendDebug('Last :'+FormatDateTime('yyyy/mm/dd hh:nn:ss.zzz',L));
|
||||
SendDebug('Timeout :'+IntToStr(t));
|
||||
{$endif}
|
||||
Result:=((Now-L)>(T/(24*60)))
|
||||
{$ifdef cgidebug}
|
||||
if Result then
|
||||
begin
|
||||
SendDebug('Timeout :'+FloatToStr(T/(24*60)));
|
||||
SendDebug('Timeout :'+FormatDateTime('hh:nn:ss.zzz',(T/(24*60))));
|
||||
SendDebug('Diff :'+FormatDateTime('hh:nn:ss.zzz',Now-L));
|
||||
SendDebug('Ini file session expired: '+ExtractFileName(Ini.FileName));
|
||||
end;
|
||||
{$endif}
|
||||
end;
|
||||
|
||||
procedure TIniSessionFactory.CheckSessionDir;
|
||||
|
||||
Var
|
||||
TD : String;
|
||||
|
||||
begin
|
||||
If (FSessionDir='') then
|
||||
begin
|
||||
TD:=IncludeTrailingPathDelimiter(GetTempDir(True));
|
||||
FSessionDir:=TD+'fpwebsessions'+PathDelim;
|
||||
if Not ForceDirectories(FSessionDir) then
|
||||
FSessionDir:=TD; // Assuming temp dir is writeable as fallback
|
||||
end;
|
||||
end;
|
||||
|
||||
|
||||
function TIniSessionFactory.DoCreateSession(ARequest: TRequest): TCustomSession;
|
||||
|
||||
Var
|
||||
S : TIniWebSession;
|
||||
begin
|
||||
CheckSessionDir;
|
||||
if IniWebSessionClass=Nil then
|
||||
S:=TIniWebSession.Create(Nil)
|
||||
else
|
||||
S:=IniWebSessionClass.Create(Nil);
|
||||
S.SessionDir:=SessionDir;
|
||||
S.Cached:=Cached;
|
||||
Result:=S;
|
||||
end;
|
||||
|
||||
procedure TIniSessionFactory.DoCleanupSessions;
|
||||
|
||||
Var
|
||||
Info : TSearchRec;
|
||||
Ini : TMemIniFile;
|
||||
FN : string;
|
||||
|
||||
begin
|
||||
CheckSessionDir;
|
||||
If FindFirst(SessionDir+AllFilesMask,0,info)=0 then
|
||||
try
|
||||
Repeat
|
||||
if (Info.Attr and faDirectory=0) then
|
||||
begin
|
||||
Ini:=TMeminiFile.Create(SessionDir+Info.Name);
|
||||
try
|
||||
If SessionExpired(Ini) then
|
||||
DeleteSessionFile(SessionDir+Info.Name);
|
||||
finally
|
||||
Ini.Free;
|
||||
end;
|
||||
end;
|
||||
Until FindNext(Info)<>0;
|
||||
finally
|
||||
FindClose(Info);
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TIniSessionFactory.DoDoneSession(var ASession: TCustomSession);
|
||||
begin
|
||||
FreeAndNil(ASession);
|
||||
end;
|
||||
|
||||
{ TIniWebSession }
|
||||
|
||||
function TIniWebSession.GetSessionID: String;
|
||||
begin
|
||||
If (SID='') then
|
||||
SID:=inherited GetSessionID;
|
||||
Result:=SID;
|
||||
end;
|
||||
|
||||
procedure TIniWebSession.FreeIniFile;
|
||||
begin
|
||||
If Cached and Assigned(FIniFile) then
|
||||
TMemIniFile(FIniFile).UpdateFile;
|
||||
FreeAndNil(FIniFile);
|
||||
end;
|
||||
|
||||
|
||||
Procedure TIniWebSession.CheckSession;
|
||||
|
||||
begin
|
||||
If Not Assigned(FInifile) then
|
||||
if FTerminated then
|
||||
Raise EWebSessionError.Create(SErrSessionTerminated)
|
||||
else
|
||||
Raise EWebSessionError.Create(SErrNoSession)
|
||||
end;
|
||||
|
||||
function TIniWebSession.GetSessionVariable(VarName: String): String;
|
||||
begin
|
||||
CheckSession;
|
||||
Result:=FIniFile.ReadString(SData,VarName,'');
|
||||
end;
|
||||
|
||||
procedure TIniWebSession.SetSessionVariable(VarName: String;
|
||||
const AValue: String);
|
||||
begin
|
||||
CheckSession;
|
||||
FIniFile.WriteString(SData,VarName,AValue);
|
||||
If Not Cached then
|
||||
TMemIniFile(FIniFile).UpdateFile;
|
||||
end;
|
||||
|
||||
destructor TIniWebSession.Destroy;
|
||||
begin
|
||||
// In case an exception occured and UpdateResponse is not called,
|
||||
// write the updates to disk and free FIniFile
|
||||
FreeIniFile;
|
||||
inherited Destroy;
|
||||
end;
|
||||
|
||||
procedure TIniWebSession.Terminate;
|
||||
begin
|
||||
FTerminated:=True;
|
||||
If Assigned(FIniFile) Then
|
||||
begin
|
||||
DeleteFile(Finifile.FileName);
|
||||
FreeAndNil(FIniFile);
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TIniWebSession.UpdateResponse(AResponse: TResponse);
|
||||
begin
|
||||
// Do nothing. Init has done the job.
|
||||
FreeIniFile;
|
||||
end;
|
||||
|
||||
procedure TIniWebSession.InitSession(ARequest: TRequest; OnNewSession,OnExpired: TNotifyEvent);
|
||||
|
||||
Var
|
||||
L,D : TDateTime;
|
||||
T : Integer;
|
||||
S : String;
|
||||
|
||||
begin
|
||||
{$ifdef cgidebug}SendMethodEnter('TIniWebSession.InitSession');{$endif}
|
||||
// First initialize all session-dependent properties to their default, because
|
||||
// in Apache-modules or fcgi programs the session-instance is re-used
|
||||
SID := '';
|
||||
FSessionStarted := False;
|
||||
FTerminated := False;
|
||||
// If a exception occured during a prior request FIniFile is still not freed
|
||||
if assigned(FIniFile) then FreeIniFile;
|
||||
|
||||
If (SessionCookie='') then
|
||||
SessionCookie:=SFPWebSession;
|
||||
S:=ARequest.CookieFields.Values[SessionCookie];
|
||||
// have session cookie ?
|
||||
If (S<>'') then
|
||||
begin
|
||||
{$ifdef cgidebug}SendDebug('Reading ini file:'+S);{$endif}
|
||||
FIniFile:=TMemIniFile.Create(IncludeTrailingPathDelimiter(SessionDir)+S);
|
||||
if (SessionFactory as TIniSessionFactory).SessionExpired(FIniFile) then
|
||||
begin
|
||||
// Expire session.
|
||||
If Assigned(OnExpired) then
|
||||
OnExpired(Self);
|
||||
(SessionFactory as TIniSessionFactory).DeleteSessionFile(FIniFIle.FileName);
|
||||
FreeAndNil(FInifile);
|
||||
S:='';
|
||||
end
|
||||
else
|
||||
SID:=S;
|
||||
end;
|
||||
If (S='') then
|
||||
begin
|
||||
If Assigned(OnNewSession) then
|
||||
OnNewSession(Self);
|
||||
GetSessionID;
|
||||
S:=IncludeTrailingPathDelimiter(SessionDir)+SessionID;
|
||||
{$ifdef cgidebug}SendDebug('Creating new Ini file : '+S);{$endif}
|
||||
FIniFile:=TMemIniFile.Create(S);
|
||||
FIniFile.WriteDateTime(SSession,KeyStart,Now);
|
||||
FIniFile.WriteInteger(SSession,KeyTimeOut,Self.TimeOutMinutes);
|
||||
FSessionStarted:=True;
|
||||
end;
|
||||
FIniFile.WriteDateTime(SSession,KeyLast,Now);
|
||||
If not FCached then
|
||||
FIniFile.UpdateFile;
|
||||
{$ifdef cgidebug}SendMethodExit('TIniWebSession.InitSession');{$endif}
|
||||
end;
|
||||
|
||||
procedure TIniWebSession.InitResponse(AResponse: TResponse);
|
||||
|
||||
Var
|
||||
C : TCookie;
|
||||
|
||||
begin
|
||||
{$ifdef cgidebug}SendMethodEnter('TIniWebSession.InitResponse');{$endif}
|
||||
If FSessionStarted then
|
||||
begin
|
||||
{$ifdef cgidebug}SendDebug('Session started');{$endif}
|
||||
C:=AResponse.Cookies.FindCookie(SessionCookie);
|
||||
If (C=Nil) then
|
||||
begin
|
||||
C:=AResponse.Cookies.Add;
|
||||
C.Name:=SessionCookie;
|
||||
end;
|
||||
C.Value:=SID;
|
||||
C.Path:=FSessionCookiePath;
|
||||
end
|
||||
else If FTerminated then
|
||||
begin
|
||||
{$ifdef cgidebug}SendDebug('Session terminated');{$endif}
|
||||
C:=AResponse.Cookies.Add;
|
||||
C.Name:=SessionCookie;
|
||||
C.Value:='';
|
||||
end;
|
||||
{$ifdef cgidebug}SendMethodExit('TIniWebSession.InitResponse');{$endif}
|
||||
end;
|
||||
|
||||
procedure TIniWebSession.RemoveVariable(VariableName: String);
|
||||
begin
|
||||
{$ifdef cgidebug}SendMethodEnter('TIniWebSession.RemoveVariable');{$endif}
|
||||
CheckSession;
|
||||
FIniFile.DeleteKey(SData,VariableName);
|
||||
If Not Cached then
|
||||
TMemIniFile(FIniFile).UpdateFile;
|
||||
{$ifdef cgidebug}SendMethodExit('TIniWebSession.RemoveVariable');{$endif}
|
||||
end;
|
||||
|
||||
|
||||
initialization
|
||||
SessionFactoryClass:=TIniSessionFactory;
|
||||
end.
|
||||
|
Loading…
Reference in New Issue
Block a user