Atozed Forums

Full Version: IdHTTPServer and session management Tutorial
You're currently viewing a stripped down version of our content. View the full version with proper formatting.
Hi every body,

After working with IdTCPServer, I'm now using IdHTTPServer and for client management I need to use sessions. My web researchs send me to a Remy's tutorial here 

https://forums.embarcadero.com/thread.js...eID=845373  but I always get the following answer 

type : exception error
description : the server encounter an internal error that prevented it from fulfilling this request

I believe the forums.embarcadero site is no longer available. 

I hope somebody can help me to find this tuto.

Regards
(05-26-2020, 10:43 AM)Alan.F Wrote: [ -> ]I believe the forums.embarcadero site is no longer available. 

Correct, it is no longer available, and has not been for some time.

(05-26-2020, 10:43 AM)Alan.F Wrote: [ -> ]I hope somebody can help me to find this tuto.

There is no tutorial, really. Is there something in particular you are having trouble with? To use sessions, simply set the server's SessionState property to true, tweak its SessionIDCookieName property if desired, and optionally use its OnCreateSession and OnInvalidSession events if needed (if you don't create you own session objects in the OnCreateSession event, default objects are created automatically). Then you can use the ARequestInfo.Session.Content and AResponseInfo.Session.Content properties in the OnCommand... events to read/write per-session values as needed.
Hi Remy, thank you for your reply.  Perhaps it was not a tuto but the link was mentionned to be a "complete example for authentication and users management".

Based on my experience with TidTCPServer I would like to do the following comparisons : 

  1. with TCPServer we can use the "AContext: TIdContext" to manage authentication and specific client management. 
  2. we can use the onconnect and ondisconnect events at the beginning and at the end.
  3. we can create a "TMyClient = class(TidServerContext)" to keep memory of the session between each automatic run of the TCPServer OnExecute
  4. we can use TCPserver.Contexts.Locklist to perform safe operations across active connections (count, send message, .....).
  1. with HTTPServer this has to be done with ARequestInfo: TIdHTTPRequestInfo; AResponseInfo: TIdHTTPResponseInfo
  2. we can use OnCreateSession and OnSessionEnd
  3. we can create a "TMySession = class(TIdHTTPSession) to keep memory with the Content
  4. there is also HTTPserver.Contexts.Locklist but I don't see any access to the sessions list and there is also the HTTPServer.SessionList but I have not seen if it's possible to use it to get access to each Session data and how to do it safely.
Could you please confirm the comparisons 1, 2 and 3 and provide me with some help on point 4

Regards
(05-28-2020, 10:24 AM)Alan.F Wrote: [ -> ]Based on my experience with TidTCPServer I would like to do the following comparisons : 

  1. with TCPServer we can use the "AContext: TIdContext" to manage authentication and specific client management. 
  2. we can use the onconnect and ondisconnect events at the beginning and at the end.
  3. we can create a "TMyClient = class(TidServerContext)" to keep memory of the session between each automatic run of the TCPServer OnExecute
  4. we can use TCPserver.Contexts.Locklist to perform safe operations across active connections (count, send message, .....).

All of those items exist in TIdHTTPServer as well, since it is a TIdTCPServer descendant after all (well, TIdCustomTCPServer, anyway).

However, TIdContext is per-connection, not per-session.  HTTP requests are not restricted to just 1 connection per session.

(05-28-2020, 10:24 AM)Alan.F Wrote: [ -> ]
  1. there is also HTTPserver.Contexts.Locklist but I don't see any access to the sessions list and there is also the HTTPServer.SessionList but I have not seen if it's possible to use it to get access to each Session data and how to do it safely.

No, HTTP session data is not directly accessible via TIdContext, because that is not where the session data belongs.  TIdHTTPRequestInfo and TIdHTTPResponseInfo have a Session property instead, since those objects are handled on a per-request basis, regardless of which connection is making each request.

Though, you can type-cast a server-side TIdContext to TIdServerContext to access its Server property, which you can then type-cast to TIdHTTPServer to access its SessionList property.

And yes, the TIdHTTPServer.SessionList is where you can access all of the server's stored session data.  TIdHTTPCustomSessionList has a GetSession() method, if you know the exact SessionID and RemoteIP of a given session.  By default, the TIdHTTPServer.SessionList property points to a TIdHTTPDefaultSessionList object (if you don't assign your own object), which has its own SessionList property that is a TThreadList of TIdHTTPSession objects (similar to how the TIdTCPServer.Contexts is a TThreadList of TIdContext objects).  Or, you can derive your own class from TIdHTTPCustomSessionList and store session data however you want.
Thanks Remy

I've done the following with success :
Code:
procedure TForm1.IdHTTPServer1SessionStart(Sender: TIdHTTPSession);
begin
  Sender.Content.Create;
  Sender.Content.AddPair('phase','1');
end;

procedure TForm1.IdHTTPServer1CommandGet(AContext: TIdContext; ARequestInfo: TIdHTTPRequestInfo; AResponseInfo: TIdHTTPResponseInfo);
var
  phase : string;
begin
  if ARequestInfo.Session <> nil then phase := ARequestInfo.Session.Content.Values['phase'];
  ....
end;

Concerning the threadlist, with IdHTTPServer1.SessionList I don't see how I can lock the list. Please can you help me ?
(06-03-2020, 02:04 PM)Alan.F Wrote: [ -> ]
Code:
procedure TForm1.IdHTTPServer1SessionStart(Sender: TIdHTTPSession);
begin
  Sender.Content.Create;
  Sender.Content.AddPair('phase','1');
end;

First, that is not the correct syntax to use to create an object.

Second, you don't need to create the Content object manually anyway, as it is already created for you when the TIdHTTPSession object is created. So just get rid of that line completely:

Code:
procedure TForm1.IdHTTPServer1SessionStart(Sender: TIdHTTPSession);
begin
  Sender.Content.AddPair('phase','1');
end;

(06-03-2020, 02:04 PM)Alan.F Wrote: [ -> ]
Code:
procedure TForm1.IdHTTPServer1CommandGet(AContext: TIdContext; ARequestInfo: TIdHTTPRequestInfo; AResponseInfo: TIdHTTPResponseInfo);
var
  phase : string;
begin
  if ARequestInfo.Session <> nil then phase := ARequestInfo.Session.Content.Values['phase'];
  ....
end;

That code is fine. You can freely access and set the ARequestInfo.Session.Content and AResponseInfo.Session.Content as needed.

(06-03-2020, 02:04 PM)Alan.F Wrote: [ -> ]Concerning the threadlist, with IdHTTPServer1.SessionList I don't see how I can lock the list. Please can you help me ?

As I told you earlier, the TIdHTTPServer.SessionList property is a TIdHTTPCustomSessionList, which points to a TIdHTTPDefaultSessionList by default, and TIdHTTPDefaultSessionList is where the TThreadList resides, not in TIdHTTPCustomSessionList. So, you will have to type-cast the TIdHTTPServer.SessionList in order to access the TThreadList, eg:

Code:
var
  List: TIdHTTPSessionList;

with (IdHTTPServer1.SessionList as TIdHTTPDefaultSessionList).SessionList do
begin
  List := LockList;
  try
    // use List as needed...
  finally
    UnlockList;
  end;
end;