websession.pp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372
  1. {
  2. $Id: header,v 1.1 2000/07/13 06:33:45 michael Exp $
  3. This file is part of the Free Component Library (FCL)
  4. Copyright (c) 1999-2000 by the Free Pascal development team
  5. See the file COPYING.FPC, included in this distribution,
  6. for details about the copyright.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  10. **********************************************************************}
  11. unit websession;
  12. {$mode objfpc}{$H+}
  13. {$define cgidebug}
  14. interface
  15. uses
  16. Classes, SysUtils, fphttp, inifiles, httpdefs;
  17. Type
  18. { TSessionHTTPModule }
  19. TSessionHTTPModule = Class(TCustomHTTPModule)
  20. Private
  21. FCreateSession : Boolean;
  22. FOnNewSession: TNotifyEvent;
  23. FOnSessionExpired: TNotifyEvent;
  24. FSession: TCustomSession;
  25. function GetSession: TCustomSession;
  26. procedure SetSession(const AValue: TCustomSession);
  27. Protected
  28. Procedure CheckSession(ARequest : TRequest);
  29. Procedure InitSession(AResponse : TResponse);
  30. Procedure UpdateSession(AResponse : TResponse);
  31. Public
  32. Procedure Notification(AComponent : TComponent;Operation : TOperation); override;
  33. Procedure Loaded; Override;
  34. Property CreateSession : Boolean Read FCreateSession Write FCreateSession;
  35. Property Session : TCustomSession Read GetSession Write SetSession;
  36. Property OnNewSession : TNotifyEvent Read FOnNewSession Write FOnNewSession;
  37. Property OnSessionExpired : TNotifyEvent Read FOnSessionExpired Write FOnSessionExpired;
  38. end;
  39. { TIniWebSession }
  40. TIniWebSession = Class(TCustomSession)
  41. Private
  42. FSessionStarted : Boolean;
  43. FCached: Boolean;
  44. FIniFile : TMemInifile;
  45. FSessionCookie: String;
  46. FSessionDir: String;
  47. FTerminated :Boolean;
  48. SID : String;
  49. Protected
  50. Procedure CheckSession;
  51. Function GetSessionID : String; override;
  52. Function GetSessionVariable(VarName : String) : String; override;
  53. procedure SetSessionVariable(VarName : String; const AValue: String); override;
  54. Property Cached : Boolean Read FCached Write FCached;
  55. property SessionCookie : String Read FSessionCookie Write FSessionCookie;
  56. Property SessionDir : String Read FSessionDir Write FSessionDir;
  57. Public
  58. Destructor Destroy; override;
  59. Procedure Terminate; override;
  60. Procedure UpdateResponse(AResponse : TResponse); override;
  61. Procedure InitSession(ARequest : TRequest; OnNewSession, OnExpired: TNotifyEvent); override;
  62. Procedure InitResponse(AResponse : TResponse); override;
  63. Procedure RemoveVariable(VariableName : String); override;
  64. end;
  65. TFPWebSession = Class(TIniWebSession)
  66. Public
  67. Property Cached;
  68. property SessionCookie;
  69. Property SessionDir;
  70. end;
  71. EWebSessionError = Class(HTTPError);
  72. TGetSessionEvent = Procedure(Var ASession : TCustomSession) of object;
  73. Var
  74. GlobalSessionDir : String;
  75. OnGetDefaultSession : TGetSessionEvent;
  76. Function GetDefaultSession : TCustomSession;
  77. implementation
  78. {$ifdef cgidebug}
  79. uses dbugintf;
  80. {$endif}
  81. Const
  82. // Sections in ini file
  83. SSession = 'Session';
  84. SData = 'Data';
  85. KeyStart = 'Start'; // Start time of session
  86. KeyLast = 'Start'; // Last seen time of session
  87. KeyTimeOut = 'Timeout'; // Timeout in seconds;
  88. SFPWebSession = 'FPWebSession'; // Cookie name for session.
  89. resourcestring
  90. SErrSessionTerminated = 'No web session active: Session was terminated';
  91. SErrNoSession = 'No web session active: Session was not started';
  92. Function GetDefaultSession : TCustomSession;
  93. Var
  94. W : TFPWebSession;
  95. begin
  96. {$ifdef cgidebug}SendMethodEnter('GetDefaultSession');{$endif}
  97. Result:=Nil;
  98. If (GlobalSessionDir='') then
  99. GlobalSessionDir:=IncludeTrailingPathDelimiter(GetTempDir(True));
  100. If Assigned(OnGetDefaultSession) then
  101. OnGetDefaultSession(Result);
  102. if (Result=Nil) then
  103. begin
  104. {$ifdef cgidebug}Senddebug('Creating iniwebsession');{$endif}
  105. W:=TFPWebSession.Create(Nil);
  106. W.SessionDir:=GlobalSessionDir;
  107. Result:=W;
  108. end;
  109. {$ifdef cgidebug}SendMethodExit('GetDefaultSession');{$endif}
  110. end;
  111. { TIniWebSession }
  112. function TIniWebSession.GetSessionID: String;
  113. begin
  114. If (SID='') then
  115. SID:=inherited GetSessionID;
  116. Result:=SID;
  117. end;
  118. Procedure TIniWebSession.CheckSession;
  119. begin
  120. If Not Assigned(FInifile) then
  121. if FTerminated then
  122. Raise EWebSessionError.Create(SErrSessionTerminated)
  123. else
  124. Raise EWebSessionError.Create(SErrNoSession)
  125. end;
  126. function TIniWebSession.GetSessionVariable(VarName: String): String;
  127. begin
  128. CheckSession;
  129. Result:=FIniFile.ReadString(SData,VarName,'');
  130. end;
  131. procedure TIniWebSession.SetSessionVariable(VarName: String;
  132. const AValue: String);
  133. begin
  134. CheckSession;
  135. FIniFile.WriteString(SData,VarName,AValue);
  136. If Not Cached then
  137. TMemIniFile(FIniFile).UpdateFile;
  138. end;
  139. destructor TIniWebSession.Destroy;
  140. begin
  141. If Cached and Assigned(FIniFile) then
  142. TMemIniFile(FIniFile).UpdateFile;
  143. FreeAndNil(FIniFile);
  144. inherited Destroy;
  145. end;
  146. procedure TIniWebSession.Terminate;
  147. begin
  148. FTerminated:=True;
  149. If Assigned(FIniFile) Then
  150. begin
  151. DeleteFile(Finifile.FileName);
  152. FreeAndNil(FIniFile);
  153. end;
  154. end;
  155. procedure TIniWebSession.UpdateResponse(AResponse: TResponse);
  156. begin
  157. // Do nothing. Init has done the job.
  158. If Cached and Assigned(FIniFile) then
  159. TMemIniFile(FIniFile).UpdateFile;
  160. end;
  161. procedure TIniWebSession.InitSession(ARequest: TRequest; OnNewSession,OnExpired: TNotifyEvent);
  162. Var
  163. L,D : TDateTime;
  164. T : Integer;
  165. S : String;
  166. begin
  167. {$ifdef cgidebug}SendMethodEnter('TIniWebSession.InitSession');{$endif}
  168. If (SessionCookie='') then
  169. SessionCookie:=SFPWebSession;
  170. S:=ARequest.CookieFields.Values[SessionCookie];
  171. // have session cookie ?
  172. If (S<>'') then
  173. begin
  174. {$ifdef cgidebug}SendDebug('Reading ini file:'+S);{$endif}
  175. FiniFile:=TMemIniFile.Create(IncludeTrailingPathDelimiter(SessionDir)+S);
  176. L:=Finifile.ReadDateTime(SSession,KeyLast,0);
  177. {$ifdef cgidebug}
  178. If (L=0) then
  179. SendDebug('No datetime in inifile');
  180. {$endif}
  181. T:=FIniFile.ReadInteger(SSession,KeyTimeOut,Self.TimeOutMinutes);
  182. {$ifdef cgidebug}SendDebug('Timeout :'+IntToStr(t));{$endif}
  183. {$ifdef cgidebug}SendDebug('Last :'+FormatDateTime('yyyy/mm/dd hh:nn:ss.zzz',L));{$endif}
  184. If ((Now-L)>(T/(24*60))) then
  185. begin
  186. {$ifdef cgidebug}SendDebug('Timeout :'+FloatToStr(T/(24*60)));{$endif}
  187. {$ifdef cgidebug}SendDebug('Timeout :'+FormatDateTime('hh:nn:ss.zzz',(T/(24*60))));{$endif}
  188. {$ifdef cgidebug}SendDebug('Diff :'+FormatDateTime('hh:nn:ss.zzz',Now-L));{$endif}
  189. {$ifdef cgidebug}SendDebug('Ini file session expired: '+S);{$endif}
  190. // Expire session.
  191. If Assigned(OnExpired) then
  192. OnExpired(Self);
  193. DeleteFile(FIniFIle.FileName);
  194. FreeAndNil(FInifile);
  195. S:='';
  196. end
  197. else
  198. SID:=S;
  199. end;
  200. If (S='') then
  201. begin
  202. If Assigned(OnNewSession) then
  203. OnNewSession(Self);
  204. GetSessionID;
  205. {$ifdef cgidebug}SendDebug('Creating new Ini file : '+SessionID);{$endif}
  206. FIniFile:=TMemIniFile.Create(IncludeTrailingPathDelimiter(SessionDir)+SessionID);
  207. FIniFile.WriteDateTime(SSession,KeyStart,Now);
  208. FIniFile.WriteInteger(SSession,KeyTimeOut,Self.TimeOutMinutes);
  209. end;
  210. FIniFile.WriteDateTime(SSession,KeyLast,Now);
  211. If not FCached then
  212. FIniFile.UpdateFile;
  213. FSessionStarted:=True;
  214. {$ifdef cgidebug}SendMethodExit('TIniWebSession.InitSession');{$endif}
  215. end;
  216. procedure TIniWebSession.InitResponse(AResponse: TResponse);
  217. Var
  218. C : TCookie;
  219. begin
  220. {$ifdef cgidebug}SendMethodEnter('TIniWebSession.InitResponse');{$endif}
  221. If FSessionStarted then
  222. begin
  223. {$ifdef cgidebug}SendDebug('Session started');{$endif}
  224. C:=AResponse.Cookies.Add;
  225. C.Name:=SessionCookie;
  226. C.Value:=SID;
  227. end
  228. else If FTerminated then
  229. begin
  230. {$ifdef cgidebug}SendDebug('Session terminated');{$endif}
  231. C:=AResponse.Cookies.Add;
  232. C.Name:=SessionCookie;
  233. C.Value:='';
  234. end;
  235. {$ifdef cgidebug}SendMethodExit('TIniWebSession.InitResponse');{$endif}
  236. end;
  237. procedure TIniWebSession.RemoveVariable(VariableName: String);
  238. begin
  239. {$ifdef cgidebug}SendMethodEnter('TIniWebSession.RemoveVariable');{$endif}
  240. CheckSession;
  241. FIniFile.DeleteKey(SData,VariableName);
  242. If Not Cached then
  243. TMemIniFile(FIniFile).UpdateFile;
  244. {$ifdef cgidebug}SendMethodExit('TIniWebSession.RemoveVariable');{$endif}
  245. end;
  246. function TSessionHTTPModule.GetSession: TCustomSession;
  247. begin
  248. {$ifdef cgidebug}SendMethodEnter('SessionHTTPModule.GetSession');{$endif}
  249. If (csDesigning in ComponentState) then
  250. begin
  251. {$ifdef cgidebug}SendDebug('Sending session');{$endif}
  252. Result:=FSession
  253. end
  254. else
  255. begin
  256. If (FSession=Nil) then
  257. begin
  258. {$ifdef cgidebug}SendDebug('Getting default session');{$endif}
  259. FSession:=GetDefaultSession;
  260. end;
  261. Result:=FSession
  262. end;
  263. {$ifdef cgidebug}SendMethodExit('SessionHTTPModule.GetSession');{$endif}
  264. end;
  265. procedure TSessionHTTPModule.SetSession(const AValue: TCustomSession);
  266. begin
  267. if FSession<>AValue then
  268. begin
  269. If Assigned(FSession) then
  270. FSession.RemoveFreeNotification(Self);
  271. FSession:=AValue;
  272. If Assigned(FSession) then
  273. FSession.FreeNotification(Self);
  274. end;
  275. end;
  276. procedure TSessionHTTPModule.CheckSession(ARequest : TRequest);
  277. Var
  278. S : TCustomSession;
  279. begin
  280. {$ifdef cgidebug}SendMethodEnter('SessionHTTPModule('+Name+').CheckSession');{$endif}
  281. If CreateSession and Assigned(FSession) then
  282. begin
  283. S:=FSession;
  284. FSession.InitSession(ARequest,FOnNewSession,FOnSessionExpired);
  285. end;
  286. {$ifdef cgidebug}SendMethodExit('SessionHTTPModule('+Name+').CheckSession');{$endif}
  287. end;
  288. procedure TSessionHTTPModule.InitSession(AResponse: TResponse);
  289. begin
  290. {$ifdef cgidebug}SendMethodEnter('SessionHTTPModule('+Name+').InitSession');{$endif}
  291. If CreateSession and Assigned(FSession) then
  292. FSession.InitResponse(AResponse);
  293. {$ifdef cgidebug}SendMethodExit('SessionHTTPModule('+Name+').InitSession');{$endif}
  294. end;
  295. procedure TSessionHTTPModule.UpdateSession(AResponse: TResponse);
  296. begin
  297. If CreateSession And Assigned(FSession) then
  298. FSession.UpdateResponse(AResponse);
  299. end;
  300. procedure TSessionHTTPModule.Notification(AComponent: TComponent;
  301. Operation: TOperation);
  302. begin
  303. {$ifdef cgidebug}SendMethodEnter('SessionHTTPModule('+Name+').Notification');{$endif}
  304. inherited Notification(AComponent, Operation);
  305. If (Operation=opRemove) then
  306. if (AComponent=FSession) Then
  307. FSession:=Nil;
  308. {$ifdef cgidebug}SendMethodExit('SessionHTTPModule('+Name+').Notification');{$endif}
  309. end;
  310. procedure TSessionHTTPModule.Loaded;
  311. begin
  312. {$ifdef cgidebug}SendMethodEnter('SessionHTTPModule.Loaded');{$endif}
  313. inherited Loaded;
  314. If CreateSession And (FSession=Nil) then
  315. FSession:=GetDefaultSession;
  316. {$ifdef cgidebug}SendMethodExit('SessionHTTPModule.Loaded');{$endif}
  317. end;
  318. end.