git-svn-id: trunk@17443 -
This commit is contained in:
michael 2011-05-13 15:08:07 +00:00
parent 9214ef8c96
commit bc25040332
2 changed files with 383 additions and 0 deletions

1
.gitattributes vendored
View File

@ -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

View 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.