Watch, Follow, &
Connect with Us

For forums, blogs and more please visit our
Developer Tools Community.


Welcome, Guest
Guest Settings
Help

Thread: Trying to understand IdHTTP Server


This question is answered. Helpful answers available: 2. Correct answers available: 1.


Permlink Replies: 6 - Last Post: Aug 2, 2016 10:16 AM Last Post By: Jay Dee
Jay Dee

Posts: 44
Registered: 11/22/10
Trying to understand IdHTTP Server  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Jul 26, 2016 10:01 AM
Hi there everyone,

Forgive my ignorance but I'm trying to better understand how IdHTTP server and client works. I have an IdHTTP server application & I would like to know at any time who is connected to the server. I'm using some old code I got from Remy which worked very well with IdTCP server/client. I'm using Lazarus & I apologize for that in advance.

What I want is for every new client to login to the HTTPServer and if the login is successful, I want to see the logged-in clients in a listview on the server. The code I'm using for this is below

procedure TfrmServeur.HTTPServerCommandGet(AContext: TIdContext;
  ARequestInfo: TIdHTTPRequestInfo; AResponseInfo: TIdHTTPResponseInfo);
var
  ServerMethod: TServerMethods;
  strJSON, strJSONRequest: string;
  jsResult: TJSONData;
begin
  //
  case Trim(ARequestInfo.URI) of 
    '/login', '/login/'
    :
      begin
        case ARequestInfo.Command of
          'GET':
            begin
            
            end;      // GET
          'POST':
            begin
              // Retrieve the JSON content sent by the client
              ARequestInfo.PostStream.Position := 0;
              SetLength(strJSONRequest, ARequestInfo.PostStream.Size);
              ARequestInfo.PostStream.Read(Pointer(strJSONRequest)^, Length(strJSONRequest));
 
              // ServerMethod
              ServerMethod := TServerMethods.Create;
              //
              try
                // Post the JSON string
                if AnsiContainsText(ARequestInfo.URI, '/login') then
                begin
                  // login the client by verfying username & password 
                  strJSON := ServerMethod.LoginResource(strJSONRequest);
                  //
                  AResponseInfo.ResponseNo := 200;
                  AResponseInfo.ContentType := 'application/json';
                  AResponseInfo.CharSet := 'utf-8';
                  //
                  AResponseInfo.ContentStream := TMemoryStream.Create;
                  try
                    AResponseInfo.ContentStream.Write(Pointer(strJSON)^, LengtIdh(strJSON));
                    AResponseInfo.ContentStream.Position := 0;
                    AResponseInfo.WriteContent;
                  finally
                    AResponseInfo.ContentStream := nil;
                  end;
 
                  // Update the server listview if the Login was OK!
                  if AnsiContainsText(strJSON, 'OK') then
                  begin
                    try
                      jsResult := GetJSON(strJSON);
 
                      // Fill TMyData
                      TMyData(AContext.Data).UserID          := jsResult.FindPath('id').AsInteger;
                      TMyData(AContext.Data).IP              := AContext.Binding.PeerIP;
                      TMyData(AContext.Data).Computer        := GStack.HostByAddress(AContext.Binding.PeerIP);
                      TMyData(AContext.Data).Pseudo          := jsResult.FindPath('pseudo').AsString;
                      TMyData(AContext.Data).FName           := jsResult.FindPath('first_name').AsString;
                      TMyData(AContext.Data).LName           := jsResult.FindPath('last_name').AsString;
                      TMyData(AContext.Data).Access          := jsResult.FindPath('acces').AsInteger;
                      TMyData(AContext.Data).ConnectionTime  := StrToDateTime(jsResult.FindPath('last_connection').AsString);
                      TMyData(AContext.Data).LastRecvTime    := StrToDateTime(jsResult.FindPath('last_connection').AsString);
                      TMyData(AContext.Data).LastPingTime    := 0.0;
                      
                      // Add client to list of clients connected to the server
                      // THIS IS NOT WORKING & I DON'T KNOW WHY!!!!
                      with TAddClientToUI.Create do
                      begin
                        IP              := TMyData(AContext.Data).IP;
                        Ordinateur      := TMyData(AContext.Data).Ordinateur;
                        Pseudo          := TMyData(AContext.Data).Pseudo;
                        Prenom          := TMyData(AContext.Data).Prenom;
                        Nom             := TMyData(AContext.Data).Nom;
                        NiveauAccess    := TMyData(AContext.Data).NiveauAccess;
                        ConnectionTime  := TMyData(AContext.Data).ConnectionTime;
                        LastRecvTime    := TMyData(AContext.Data).LastRecvTime;
                        Notify;
                      end;       // with TAddClientToUI.Create do
                    finally
                      jsResult.Free;
                    end;
                  end   // if AnsiContainsText(strJSON, 'OK') then
                end     // if AnsiContainsText(ARequestInfo.URI, '/login') then
                else
                  strJSON := ServerMethod.PostPutResource(ARequestInfo.URI, strJSONRequest);
                //
                if strJSON <> EmptyStr then
                begin
                  //ShowMessage(strJSON);
                  AResponseInfo.ResponseNo := 200;
                  AResponseInfo.ContentType := 'application/json';
                  AResponseInfo.CharSet := 'utf-8';
                  //
                  AResponseInfo.ContentStream := TMemoryStream.Create;
                  try
                    AResponseInfo.ContentStream.Write(Pointer(strJSON)^, Length(strJSON));
                    AResponseInfo.ContentStream.Position := 0;
                    AResponseInfo.WriteContent;
                  finally
                    AResponseInfo.ContentStream := nil;
                  end;
                end
                else
                begin
                  AResponseInfo.ResponseNo := 404;
                  AResponseInfo.ContentType := 'text/html';
                  AResponseInfo.CharSet := 'utf-8';
                  AResponseInfo.ContentText := 'Resource not found';
                end;
              finally
                ServerMethod.Free;
              end;
            end;          // POST
        end;
      end;
    else
      begin
        // ServerMethod
        ServerMethod := TServerMethods.Create;
        //
        try
          //
          AResponseInfo.ResponseNo := 404;         // 404 is a show stopper; Test for it on client side & catch it
          AResponseInfo.ContentType := 'text/html';
          AResponseInfo.CharSet := 'utf-8';
          AResponseInfo.ContentText := strNotFound;       // Not Found
        finally
          ServerMethod.Free;
        end;
      end;
  end;      // case Trim(ARequestInfo.URI) of
end;
 


My problem is that I cannot see the client in the listview at all BUT I know the data is there because I use the JSON result client-side.

I addition, I've noticed that every client request passes through HTTPServer Connect! Is there any way to restrict it to just once when the client logs in and for all other requests, CommandGet or CommandOther is called directly.

Thanks a lot for your time

JayDee

Edited by: Jay Dee on Jul 26, 2016 7:01 PM

Edited by: Jay Dee on Jul 26, 2016 7:04 PM
Remy Lebeau (Te...


Posts: 9,447
Registered: 12/23/01
Re: Trying to understand IdHTTP Server [Edit]  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Jul 26, 2016 12:02 PM   in response to: Jay Dee in response to: Jay Dee
Jay wrote:

I have an IdHTTP server application & I would like to know at any
time who is connected to the server. I'm using some old code I got
from Remy which worked very well with IdTCP server/client.

TIdHTTPServer is a TCustomTCPServer descendant, so you should be able to
apply your existing logic with TIdHTTPServer.

The code I'm using for this is below

I see some logic issues with that code.

My problem is that I cannot see the client in the listview at all BUT
I know the data is there because I use the JSON result client-side.

Just because the client can see the JSON response does not mean your server's
main thread has the same data. If it is not showing up in your ListView
then either:

1. you are not adding it to your ListView correctly

2. your TAddClientToUI.DoNotify() implementation is not being called, if
your main thread is not handling Notify requests correctly.

3. the client is disconnecting and being removed from the ListView (assuming
you are handling that in the TIdHTTPServer.OnDisconnect event) before you
can see it appear. I supect this is the likely culprit.

I addition, I've noticed that every client request passes through
HTTPServer Connect! Is there any way to restrict it to just once
when the client logs in and for all other requests, CommandGet or
CommandOther is called directly.

HTTP is stateless, there is no requirement for a client to remain connected
in between multiple requests to the same server. The client may choose to
ask for an HTTP keep-alive as an optimization (keep-alives are disabled in
TIdHTTPServer by default, you need to enable the TIdHTTPServer.KeepAlive
property), but that is still no guarantee. The client, or a proxy/router
in between the client and server, may still close the connection at any time.

What you really need to do is store your tracking data in an HTTP session
instead of in the TIdContext. That way, a client can disconnect and reconnect
as many times as it wants and still be logged in to the same session. You
can then remove the client from your ListView when it explicitly logs out
or when the HTTP session expires.

Try something more like this instead:

type
  TMySession = class(TIdHTTPSession)
  public
    LoggedIn: Boolean;
    UserID: string;
    IP: string;
    Computer: string;
    Pseudo: string;
    FName: string;
    LName: string;
    Access: Integer;
    ConnectionTime: TDateTime;
    LastRecvTime: TDateTime;
    LastPingTime: TDateTime;
  end;
 
  TMySessionList = class(TIdHTTPDefaultSessionList)
  public
    function CreateSession(const RemoteIP, SessionID: String): TIdHTTPSession; 
override;
  end;
 
function TMySessionList.CreateSession(const RemoteIP, SessionID: String): 
TIdHTTPSession;
begin
  Result := TMySession.CreateInitialized(Self, SessionID, RemoteIP);
  SessionList.Add(Result);
end;
 
procedure TfrmServeur.FormCreate(Sender: TObject);
begin
  HTTPServer.SessionList := TMySessionList.Create(HTTPServer);
  HTTPServer.SessionState := True;
  HTTPServer.SessionTimeOut := ...;
  HTTPServer.AutoStartSession := True;
  ...
end;
 
procedure TfrmServeur.HTTPServerCommandSessionEnd(Sender: TIdHTTPSession);
begin
  if TMySession(Sender).LoggedIn then
  begin
    // Remove client from list of clients connected to the server
    with TRemoveClientFromUI.Create do
    begin
      ...
      Notify;
    end;
  end;
end;
 
procedure TfrmServeur.HTTPServerCommandGet(AContext: TIdContext; ARequestInfo: 
TIdHTTPRequestInfo; AResponseInfo: TIdHTTPResponseInfo);
var
  ServerMethod: TServerMethods;
  strJSON, strJSONRequest: string;
  jsResult: TJSONData;
begin
  case Trim(ARequestInfo.URI) of
    '/login', '/login/':
    begin
      if ARequestInfo.CommandType <> hcPOST then
      begin
        AResponseInfo.ResponseNo := 405;
        AResponseInfo.CustomHeaders.Values['Allow'] := 'POST';
        Exit;
      end;
 
      if TMySession(ARequestInfo.Session).LoggedIn then
      begin
        // send a response that lets the client know it is already logged 
in...
        Exit;
      end;
 
      // Retrieve the JSON content sent by the client
      ARequestInfo.PostStream.Position := 0;
      strJSONRequest := ReadStringFromStream(ARequestInfo.PostStream, -1, 
IndyTextEncoding_8Bit, IndyTextEncoding_8Bit);
 
      ServerMethod := TServerMethods.Create;
      try
        // login the client by verfying username & password
        strJSON := ServerMethod.LoginResource(strJSONRequest);
      finally
        ServerMethod.Free;
      end;
 
      // Update the server listview if the Login was OK!
      if AnsiContainsText(strJSON, 'OK') then
      begin
        jsResult := GetJSON(strJSON);
        try
          // Fill TMySession
          TMySession(ARequestInfo.Session).LoggedIn := True;
          TMySession(ARequestInfo.Session).UserID := jsResult.FindPath('id').AsInteger;
          TMySession(ARequestInfo.Session).IP := ARequestInfo.RemoteIP;
          TMySession(ARequestInfo.Session).Computer := GStack.HostByAddress(ARequestInfo.RemoteIP);
          TMySession(ARequestInfo.Session).Pseudo := jsResult.FindPath('pseudo').AsString;
          TMySession(ARequestInfo.Session).FName := jsResult.FindPath('first_name').AsString;
          TMySession(ARequestInfo.Session).LName := jsResult.FindPath('last_name').AsString;
          TMySession(ARequestInfo.Session).Access := jsResult.FindPath('acces').AsInteger;
          TMySession(ARequestInfo.Session).ConnectionTime := StrToDateTime(jsResult.FindPath('last_connection').AsString);
          TMySession(ARequestInfo.Session).LastRecvTime := StrToDateTime(jsResult.FindPath('last_connection').AsString);
          TMySession(ARequestInfo.Session).LastPingTime := 0.0;
        finally
          jsResult.Free;
        end;
 
        // Add client to list of clients connected to the server
        with TAddClientToUI.Create do
        begin
          IP := TMySession(ARequestInfo.Session).IP;
          Ordinateur := TMySession(ARequestInfo.Session).Ordinateur;
          Pseudo := TMySession(ARequestInfo.Session).Pseudo;
          Prenom := TMySession(ARequestInfo.Session).Prenom;
          Nom := TMySession(ARequestInfo.Session).Nom;
          NiveauAccess := TMySession(ARequestInfo.Session).NiveauAccess;
          ConnectionTime := TMySession(ARequestInfo.Session).ConnectionTime;
          LastRecvTime := TMySession(ARequestInfo.Session).LastRecvTime;
          Notify;
        end;
      end;
    end;
 
    '/logout', '/logout/':
    begin
      if not TMySession(ARequestInfo.Session).LoggedIn then
      begin
        // send a response that lets the client know it is already logged 
out...
        Exit;
      end;
 
      ServerMethod := TServerMethods.Create;
      try
        // logout the client
        strJSON := ServerMethod.LogoutResource(...);
      finally
        ServerMethod.Free;
      end;
 
      // Update the server listview if the Login was OK!
      if AnsiContainsText(strJSON, 'OK') then
      begin
        // Remove client from list of clients connected to the server
        with TRemoveClientFromUI.Create do
        begin
          ...
          Notify;
        end;
      end;
    end;
  else
    begin
      if not (ARequestInfo.CommandType in [hcPOST, hcPUT]) then
      begin
        AResponseInfo.ResponseNo := 405;
        AResponseInfo.CustomHeaders.Values['Allow'] := 'POST, 'PUT';
        Exit;
      end;
 
      if not TMySession(ARequestInfo.Session).LoggedIn then
      begin
        // send a response that lets the client know it needs to login first...
        Exit;
      end;
 
      // Retrieve the JSON content sent by the client
      if ARequestInfo.PostStream <> nil then
      begin
        ARequestInfo.PostStream.Position := 0;
        strJSONRequest := ReadStringFromStream(ARequestInfo.PostStream, -1, 
IndyTextEncoding_8Bit, IndyTextEncoding_8Bit);
      end;
 
      ServerMethod := TServerMethods.Create;
      try
        strJSON := ServerMethod.PostPutResource(ARequestInfo.URI, strJSONRequest);
      finally
        ServerMethod.Free;
      end;
    end;
  end;      // case Trim(ARequestInfo.URI) of
 
  if strJSON <> EmptyStr then
  begin
    //ShowMessage(strJSON);
    AResponseInfo.ResponseNo := 200;
    AResponseInfo.ContentType := 'application/json';
    AResponseInfo.CharSet := 'utf-8';
    AResponseInfo.ContentStream := TIdMemoryBufferStream.Create(Pointer(strJSON), 
Length(strJSON));
    AResponseInfo.WriteContent;
  end
  else
  begin
    AResponseInfo.ResponseNo := 404;         // 404 is a show stopper; Test 
for it on client side & catch it
    AResponseInfo.ContentType := 'text/html';
    AResponseInfo.CharSet := 'utf-8';
    AResponseInfo.ContentText := strNotFound;
  end;
end;


--
Remy Lebeau (TeamB)
Jay Dee

Posts: 44
Registered: 11/22/10
Re: Trying to understand IdHTTP Server [Edit]  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Jul 26, 2016 6:25 PM   in response to: Remy Lebeau (Te... in response to: Remy Lebeau (Te...
Remy Lebeau (TeamB) wrote:
3. the client is disconnecting and being removed from the ListView (assuming
you are handling that in the TIdHTTPServer.OnDisconnect event) before you
can see it appear. I supect this is the likely culprit.

I believe that this is the problem because the client is disconnected immediately after the request is served. If I step through the code, I see the client in the listview. In my Server's FormCreate, I set KeepAlive to true. By the way, is HTTPServer.SessionTimeOut := 120 okay or do you recommend a higher value?

  //
  HTTPServer := TIdHTTPServer.Create(nil);
  HTTPServer.SessionList := TMySessionList.Create(HTTPServer);
  HTTPServer.SessionState := True;
  HTTPServer.SessionTimeOut := 120;
  HTTPServer.AutoStartSession := True;
  //HTTPIOHandler := TIdServerIOHandlerSSLOpenSSL.Create(nil);
  //HTTPIOHandler.SSLOptions.SSLVersions := [sslvTLSv1, sslvTLSv1_1, sslvTLSv1_2];
 
  //
  with HTTPServer do
  begin
    //IOHandler         := HTTPIOHandler;
    OnCommandGet      := @HTTPServerCommandGet;
    OnCommandOther    := @HTTPServerCommandOther;
    OnConnect         := @HTTPServerConnect;
    OnDisconnect      := @HTTPServerDisconnect;
    OnSessionEnd      := @HTTPServerCommandSessionEnd;
    //OnCreateSession   := @HTTPServerCreateSession;
    //OnSessionStart    := @HTTPServerSessionStart;
    KeepAlive         := True;
  end;



HTTP is stateless, there is no requirement for a client to remain connected
in between multiple requests to the same server. The client may choose to
ask for an HTTP keep-alive as an optimization (keep-alives are disabled in
TIdHTTPServer by default, you need to enable the TIdHTTPServer.KeepAlive
property), but that is still no guarantee. The client, or a proxy/router
in between the client and server, may still close the connection at any time.

What you really need to do is store your tracking data in an HTTP session
instead of in the TIdContext. That way, a client can disconnect and reconnect
as many times as it wants and still be logged in to the same session. You
can then remove the client from your ListView when it explicitly logs out
or when the HTTP session expires.

Try something more like this instead:

Thanks a million for the code. I don't know how HTTP sessions work so it was a learning experience for me. What can I do to keep the client session in the listview, allow the client to connect/disconnect as often as possible until the user decides to quit the session by closing the client application OR until the session expires?


...
case Trim(ARequestInfo.URI) of
'/login', '/login/':
begin
if ARequestInfo.CommandType <> hcPOST then
begin
AResponseInfo.ResponseNo := 405;
AResponseInfo.CustomHeaders.Values['Allow'] := 'POST';
Exit;
end;

I don't understand the code snippet above. What does it do & why do I need to "allow" POST?

begin
if not (ARequestInfo.CommandType in [hcPOST, hcPUT]) then
begin
AResponseInfo.ResponseNo := 405;
AResponseInfo.CustomHeaders.Values['Allow'] := 'POST, 'PUT';
Exit;
end;

Same as above. I do not understand that section.

Thanks,

JayDee
Remy Lebeau (Te...


Posts: 9,447
Registered: 12/23/01
Re: Trying to understand IdHTTP Server [Edit]  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Jul 26, 2016 8:42 PM   in response to: Jay Dee in response to: Jay Dee
Jay wrote:

I believe that this is the problem because the client is disconnected
immediately after the request is served.

That is the default behavior when the TIdHTTPServer.KeepAlive property is
false.

If I step through the code, I see the client in the listview. In my Server's
FormCreate,
I set KeepAlive to true.

Even if KeepAlive is true, that does not guarantee that keep-alives are
actually used. It just means that if a client requests the server to leave
the connection open after sending a response, the server will agree to it,
unless your OnCommand... handler sets AResponseInfo.CloseConnection to false
(or an error occurs, which usually close the connection).

By the way, is HTTPServer.SessionTimeOut := 120 okay or do you recommend
a higher value?

The value is entirely up to you, but note that it is expressed in milliseconds,
so 120ms is pretty low.

I don't know how HTTP sessions work

The server creates an object in memory to store state information for the
client, and then sends the client a cookie identifying that object. On subsequent
requests, if the client sends the cookie back, the ARequestInfo.Session and
AResponseInfo.Session properties will point at that object, thus allowing
stateful data to persist across multiple requests.

What can I do to keep the client session in the listview, allow the client
to connect/disconnect as often as possible until the user decides to quit
the session by closing the client application OR until the session expires?

I already gave you code to do exactly that.

I don't understand the code snippet above. What does it do & why do I
need to "allow" POST?

The code snippet forces clients to only send POST requests to your login
URL. Your original code was allowing GET requests as well, but not actually
doing anything with GET requests. This way, if a client tries to send anything
other than a POST for login, the client will get a 405 error response. The
"Allow" response header simply tells the client what type of request(s) are
allowed.

Same as above. I do not understand that section.

Save as above, but allowing both POST and PUT. Given that your procedure
name is PostPutResource(), I assume it only works when receiving data via
a POST or PUT request. If you don't actually support PUT requests, then
your procedure name is misleading, and you can remove the check for hcPUT.

--
Remy Lebeau (TeamB)
Jay Dee

Posts: 44
Registered: 11/22/10
Re: Trying to understand IdHTTP Server [Edit]  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Jul 27, 2016 1:47 AM   in response to: Remy Lebeau (Te... in response to: Remy Lebeau (Te...
Remy Lebeau (TeamB) wrote:

Even if KeepAlive is true, that does not guarantee that keep-alives are
actually used. It just means that if a client requests the server to leave
the connection open after sending a response, the server will agree to it,
unless your OnCommand... handler sets AResponseInfo.CloseConnection to false
(or an error occurs, which usually close the connection).

By the way, is HTTPServer.SessionTimeOut := 120 okay or do you recommend
a higher value?

The value is entirely up to you, but note that it is expressed in milliseconds,
so 120ms is pretty low.

Noted. I'll increase it. The thing is that the HTTP Server is an application server for a database. I want the server to handle no more than 20 connections at a time (I already have a connection pool in place). I want to be sure that


I don't know how HTTP sessions work

The server creates an object in memory to store state information for the
client, and then sends the client a cookie identifying that object. On subsequent
requests, if the client sends the cookie back, the ARequestInfo.Session and
AResponseInfo.Session properties will point at that object, thus allowing
stateful data to persist across multiple requests.

That is exactly what I want. So it is cookies I need to introduce & manage. I'm afraid I have to ask you to show me again how I can implement what you are describing using cookies. For some strange reason I was thinking in terms of unique session id for each client. How is the expiration of a cookie tied to the termination of a session?

I guess persisting stateful data means my server will no longer be a RESTful server?


I don't understand the code snippet above. What does it do & why do I
need to "allow" POST?

The code snippet forces clients to only send POST requests to your login
URL. Your original code was allowing GET requests as well, but not actually
doing anything with GET requests. This way, if a client tries to send anything
other than a POST for login, the client will get a 405 error response. The
"Allow" response header simply tells the client what type of request(s) are
allowed.

OK. Thanks for correcting my errors

JayDee
Remy Lebeau (Te...


Posts: 9,447
Registered: 12/23/01
Re: Trying to understand IdHTTP Server [Edit]  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Jul 27, 2016 3:18 PM   in response to: Jay Dee in response to: Jay Dee
Jay wrote:

The thing is that the HTTP Server is an application server for a database.
I want the server to handle no more than 20 connections at a time

See the server's MaxConnections property.

That is exactly what I want. So it is cookies I need to introduce &
manage.

TIdHTTPServer manages the session cookies for you when SessionState is true,
you do not need to do anything extra for that functionality.

The default cookie name is 'IDHTTPSESSIONID', but you can change it with
the server's SessionIDCookieName property.

I'm afraid I have to ask you to show me again how I can implement what
you are describing using cookies.

You don't need to implement it manually. I already gave you all of the code
you need for this. Have you tried the code I have already given you? Are
you having a problem with it?

For some strange reason I was thinking in terms of unique session id
for each client.

Yes, and TIdHTTPServer already manages that for you. By default, sessions
it creates for you have unique IDs, and those IDs are passed around using
cookies that TIdHTTPServer manages for you.

How is the expiration of a cookie tied to the termination of a
session?

TIdHTTPServer does not assign an expiration for its session cookies. They
expire when a web browser is closed, or if the client is an app then when
it frees its cookie store from memory.

TIdHTTPServer's session objects, on the other hand, expire when the server's
SessionTimeout elapses after the last time the session is requested. If
the client sends a cookie for a session that has already expired, the server
fires its OnInvalidSession event.

You can call AResponseInfo.CloseSession() to close an active session (set
AResponseInfo.Session to nil) and send an expired cookie back to the client.

I guess persisting stateful data means my server will no longer be a
RESTful server?

If you persist the data on the server-side, then yes. A REST server is not
allowed to store cllient-specific state data on the server-side. If you
want to persist data between requests, it has to be stored on the client-side
instead. Which means storing the data in cookies or other exchangable payload
that is sent to the client and then sent back to the server in subsequent
requests.

--
Remy Lebeau (TeamB)
Jay Dee

Posts: 44
Registered: 11/22/10
Re: Trying to understand IdHTTP Server [Edit]  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Aug 2, 2016 10:16 AM   in response to: Remy Lebeau (Te... in response to: Remy Lebeau (Te...
Thanks a lot Remy. It is much clearer now. By the way, the code you gave me works very well.
Legend
Helpful Answer (5 pts)
Correct Answer (10 pts)

Server Response from: ETNAJIVE02