123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418 |
- {
- $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 websession;
- {$mode objfpc}{$H+}
- { $define cgidebug}
- interface
- uses
- Classes, SysUtils, fphttp, inifiles, httpdefs;
-
- Type
- { TSessionHTTPModule }
- TSessionHTTPModule = Class(TCustomHTTPModule)
- Private
- FCreateSession : Boolean;
- FOnNewSession: TNotifyEvent;
- FOnSessionExpired: TNotifyEvent;
- FSession: TCustomSession;
- function GetSession: TCustomSession;
- procedure SetSession(const AValue: TCustomSession);
- Protected
- Procedure CheckSession(ARequest : TRequest);
- Procedure InitSession(AResponse : TResponse);
- Procedure UpdateSession(AResponse : TResponse);
- Procedure DoneSession; virtual;
- Public
- destructor destroy; override;
- Procedure Notification(AComponent : TComponent;Operation : TOperation); override;
- Procedure Loaded; Override;
- Property CreateSession : Boolean Read FCreateSession Write FCreateSession;
- Property Session : TCustomSession Read GetSession Write SetSession;
- Property OnNewSession : TNotifyEvent Read FOnNewSession Write FOnNewSession;
- Property OnSessionExpired : TNotifyEvent Read FOnSessionExpired Write FOnSessionExpired;
- end;
-
- { TIniWebSession }
- TIniWebSession = Class(TCustomSession)
- Private
- FSessionStarted : Boolean;
- FCached: Boolean;
- FIniFile : TMemInifile;
- FSessionCookie: String;
- FSessionCookiePath: String;
- FSessionDir: String;
- FTerminated :Boolean;
- SID : String;
- private
- procedure FreeIniFile;
- function GetSessionDir: String;
- 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 GetSessionDir 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;
- TFPWebSession = Class(TIniWebSession)
- Public
- Property Cached;
- property SessionCookie;
- Property SessionCookiePath;
- Property SessionDir;
- end;
- EWebSessionError = Class(HTTPError);
- TGetSessionEvent = Procedure(Var ASession : TCustomSession) of object;
- Var
- GlobalSessionDir : String;
- OnGetDefaultSession : TGetSessionEvent;
- Function GetDefaultSession : TCustomSession;
- 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';
- Function GetDefaultSession : TCustomSession;
- begin
- {$ifdef cgidebug}SendMethodEnter('GetDefaultSession');{$endif}
- Result:=Nil;
- If (GlobalSessionDir='') then
- GlobalSessionDir:=IncludeTrailingPathDelimiter(GetTempDir(True))
- else
- GlobalSessionDir:=IncludeTrailingPathDelimiter(GlobalSessionDir);
- {$ifdef cgidebug}SendDebug('GetDefaultSession, session dir: '+GlobalSessionDir);{$endif}
- If Assigned(OnGetDefaultSession) then
- OnGetDefaultSession(Result);
- if (Result=Nil) then
- begin
- {$ifdef cgidebug}Senddebug('Creating iniwebsession');{$endif}
- Result:=TFPWebSession.Create(Nil);
- end;
- {$ifdef cgidebug}SendMethodExit('GetDefaultSession');{$endif}
- 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;
- function TIniWebSession.GetSessionDir: String;
- begin
- Result:=FSessionDir;
- If (Result='') then
- Result:=GlobalSessionDir;
- 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);
- L:=Finifile.ReadDateTime(SSession,KeyLast,0);
- {$ifdef cgidebug}
- If (L=0) then
- SendDebug('No datetime in inifile (or not valid datetime : '+Finifile.ReadString(SSession,KeyLast,''));
- {$endif}
- T:=FIniFile.ReadInteger(SSession,KeyTimeOut,Self.TimeOutMinutes);
- {$ifdef cgidebug}SendDebug('Timeout :'+IntToStr(t));{$endif}
- {$ifdef cgidebug}SendDebug('Last :'+FormatDateTime('yyyy/mm/dd hh:nn:ss.zzz',L));{$endif}
- If ((Now-L)>(T/(24*60))) then
- begin
- {$ifdef cgidebug}SendDebug('Timeout :'+FloatToStr(T/(24*60)));{$endif}
- {$ifdef cgidebug}SendDebug('Timeout :'+FormatDateTime('hh:nn:ss.zzz',(T/(24*60))));{$endif}
- {$ifdef cgidebug}SendDebug('Diff :'+FormatDateTime('hh:nn:ss.zzz',Now-L));{$endif}
- {$ifdef cgidebug}SendDebug('Ini file session expired: '+S);{$endif}
- // Expire session.
- If Assigned(OnExpired) then
- OnExpired(Self);
- DeleteFile(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;
- function TSessionHTTPModule.GetSession: TCustomSession;
- begin
- {$ifdef cgidebug}SendMethodEnter('SessionHTTPModule.GetSession');{$endif}
- If (csDesigning in ComponentState) then
- begin
- {$ifdef cgidebug}SendDebug('Sending session');{$endif}
- Result:=FSession
- end
- else
- begin
- If (FSession=Nil) then
- begin
- {$ifdef cgidebug}SendDebug('Getting default session');{$endif}
- FSession:=GetDefaultSession;
- FSession.FreeNotification(Self);
- end;
- Result:=FSession
- end;
- {$ifdef cgidebug}SendMethodExit('SessionHTTPModule.GetSession');{$endif}
- end;
- procedure TSessionHTTPModule.SetSession(const AValue: TCustomSession);
- begin
- if FSession<>AValue then
- begin
- If Assigned(FSession) then
- FSession.RemoveFreeNotification(Self);
- FSession:=AValue;
- If Assigned(FSession) then
- FSession.FreeNotification(Self);
- end;
- end;
- procedure TSessionHTTPModule.CheckSession(ARequest : TRequest);
- begin
- {$ifdef cgidebug}SendMethodEnter('SessionHTTPModule('+Name+').CheckSession');{$endif}
- If CreateSession then
- begin
- If (FSession=Nil) then
- FSession:=GetDefaultSession;
- if Assigned(FSession) then
- FSession.InitSession(ARequest,FOnNewSession,FOnSessionExpired);
- end;
- {$ifdef cgidebug}SendMethodExit('SessionHTTPModule('+Name+').CheckSession');{$endif}
- end;
- procedure TSessionHTTPModule.InitSession(AResponse: TResponse);
- begin
- {$ifdef cgidebug}SendMethodEnter('SessionHTTPModule('+Name+').InitSession');{$endif}
- If CreateSession and Assigned(FSession) then
- FSession.InitResponse(AResponse);
- {$ifdef cgidebug}SendMethodExit('SessionHTTPModule('+Name+').InitSession');{$endif}
- end;
- procedure TSessionHTTPModule.UpdateSession(AResponse: TResponse);
- begin
- If CreateSession And Assigned(FSession) then
- FSession.UpdateResponse(AResponse);
- end;
- procedure TSessionHTTPModule.DoneSession;
- begin
- FreeAndNil(FSession);
- end;
- destructor TSessionHTTPModule.destroy;
- begin
- // Prevent memory leaks.
- If Assigned(FSession) then
- DoneSession;
- inherited destroy;
- end;
- procedure TSessionHTTPModule.Notification(AComponent: TComponent;
- Operation: TOperation);
- begin
- {$ifdef cgidebug}SendMethodEnter('SessionHTTPModule('+Name+').Notification');{$endif}
- inherited Notification(AComponent, Operation);
- If (Operation=opRemove) then
- if (AComponent=FSession) Then
- FSession:=Nil;
- {$ifdef cgidebug}SendMethodExit('SessionHTTPModule('+Name+').Notification');{$endif}
- end;
- procedure TSessionHTTPModule.Loaded;
- begin
- {$ifdef cgidebug}SendMethodEnter('SessionHTTPModule.Loaded');{$endif}
- inherited Loaded;
- If CreateSession And (FSession=Nil) then
- FSession:=GetDefaultSession;
- {$ifdef cgidebug}SendMethodExit('SessionHTTPModule.Loaded');{$endif}
- end;
- end.
|