* * *

Author Topic: Indy HTTPserver TIdHTTPServer Session problem  (Read 1195 times)

epneeh

  • New member
  • *
  • Posts: 5
Indy HTTPserver TIdHTTPServer Session problem
« on: August 27, 2018, 06:57:11 am »
Hi,

I'm creating Http Server using TidHTTPServer which properties :
Code: Pascal  [Select]
  1. http.AutoStartSession:=True;
  2. http.SessionState:=True;
  3. http.KeepAlive:=true;
  4.  

i'm using webpage as a frontend to the client and fully using AJAX for transaction.. and authentication using IndyHttp server built in session management.

my question is, why if client request to server using diferent Internet Provider or my internet provider request using different IP than the first log-in, indy attempt to change Session Cookie ID? and how to prevent that?

sorry for my bad english.

Remy Lebeau

  • Sr. Member
  • ****
  • Posts: 448
    • Lebeau Software
Re: Indy HTTPserver TIdHTTPServer Session problem
« Reply #1 on: August 30, 2018, 09:29:30 pm »
why if client request to server using diferent Internet Provider or my internet provider request using different IP than the first log-in, indy attempt to change Session Cookie ID?

By default, TIdHTTPServer tracks sessions by a combination of cookie value and IP address.  So, even if the client has an existing cookie from an earlier request, if the client's IP changes afterwards, a subsequent request from the new IP will create a new session, and the old session will eventually timeout.

how to prevent that?

If you don't want to track sessions by IP, you can derive a class from TIdHTTPCustomSessionList and implement its abstract methods to track cookies however you want, and then you can assign an instance of that class to the TIdHTTPServer.SessionList property before activating the server.
« Last Edit: August 30, 2018, 09:31:20 pm by Remy Lebeau »
Remy Lebeau
Lebeau Software - Owner, Developer
Internet Direct (Indy) - Admin, Developer (Support forum)

epneeh

  • New member
  • *
  • Posts: 5
Re: Indy HTTPserver TIdHTTPServer Session problem
« Reply #2 on: September 05, 2018, 03:48:37 pm »
By default, TIdHTTPServer tracks sessions by a combination of cookie value and IP address.  So, even if the client has an existing cookie from an earlier request, if the client's IP changes afterwards, a subsequent request from the new IP will create a new session, and the old session will eventually timeout.

If you don't want to track sessions by IP, you can derive a class from TIdHTTPCustomSessionList and implement its abstract methods to track cookies however you want, and then you can assign an instance of that class to the TIdHTTPServer.SessionList property before activating the server.

Hi remy, i was expecting your answer...

so i managed to disabled track session by IP by editing idCustomHTTPServer :
Code: Pascal  [Select]
  1. function TIdHTTPDefaultSessionList.GetSession(const SessionID, RemoteIP: string): TIdHTTPSession;
  2. var
  3.   LSessionList: TIdHTTPSessionList;
  4.   LSession: TIdHTTPSession;
  5.   i: Integer;
  6. begin
  7.   Result := nil;
  8.   LSessionList := SessionList.LockList;
  9.   try
  10.     // get current time stamp
  11.     for i := 0 to LSessionList.Count - 1 do
  12.     begin
  13.       LSession := TIdHTTPSession(LSessionList[i]);
  14.       // the stale sessions check has been removed... the cleanup thread should suffice plenty
  15.       if Assigned(LSession) and TextIsSame(LSession.FSessionID, SessionID) then {edited from here} //and ((Length(RemoteIP) = 0) or TextIsSame(LSession.RemoteHost, RemoteIP)) then
  16.       begin
  17.         // Session found
  18.         // TODO: use a timer to signal when the session becomes stale, instead of
  19.         // pooling for stale sessions every second...
  20.         LSession.FLastTimeStamp := Now;
  21.         Result := LSession;
  22.         Break;
  23.       end;
  24.     end;
  25.   finally
  26.     SessionList.UnlockList;
  27.   end;
  28. end;
  29.  

i know its not the best practice, but i need fast solution back there.. maybe going to try your solution by derive TIdHTTPCustomSessionList class later...

but there's another problem, when a GET request attempt from client the httpCommandGet method firing repeatedly like 4 or 5 times, so in what scenario did this happen?

UPDATE
ok so i did a little research this is my code :
Code: Pascal  [Select]
  1. aresponseinfo.ContentType:='application/pdf';
  2. aresponseinfo.ContentDisposition:='attachment; filename="' + get_nip_from_id(arequestinfo.Params.Values['p']) + '.pdf"';
  3. aresponseinfo.ContentStream:=generate_report(arequestinfo.Params.Values['p']);
  4. aresponseinfo.WriteContent;
  5. aresponseinfo.ContentStream:=nil;
  6.  

if i comment "//" contentdisposition it went okay... but my response to client will be different from what i expected.
« Last Edit: September 05, 2018, 04:19:27 pm by epneeh »

Remy Lebeau

  • Sr. Member
  • ****
  • Posts: 448
    • Lebeau Software
Re: Indy HTTPserver TIdHTTPServer Session problem
« Reply #3 on: September 05, 2018, 07:03:02 pm »
so i managed to disabled track session by IP by editing idCustomHTTPServer

You edited the implementation of the TIdHTTPDefaultSessionList class, which is used only when you DON'T provide a custom class to replace it.  So why didn't you simply derive a new class from TIdHTTPCustomSessionList, like I suggested earlier?  Then you could have overridden the GetSession() to ignore the RemoteIP parameter, and not have to edit Indy itself at all.  For example:

Code: [Select]
type
  TMyHTTPSessionList = class(TIdHTTPDefaultSessionList)
  public
    function GetSession(const SessionID, RemoteIP: string): TIdHTTPSession; override;
  end;

function TMyHTTPSessionList.GetSession(const SessionID, RemoteIP: string): TIdHTTPSession;
begin
  Result := inherited GetSession(SessionID, '');
end;

...

IdHTTPServer1.SessionList := TMyHTTPSessionList.Create(IdHTTPServer1);
IdHTTPServer1.Active := True;

i know its not the best practice, but i need fast solution back there..

It would have been faster and easier to write a custom class directly in your project code and assign it to TIdHTTPServer, rather than editing, recompiling, and reinstalling Indy itself.

but there's another problem, when a GET request attempt from client the httpCommandGet method firing repeatedly like 4 or 5 times, so in what scenario did this happen?

I can't answer that without seeing the client's traffic.  Obviously it is making multiple requests to your server.  You will have to look at the details of each request to see exactly what it is really requesting.

ok so i did a little research this is my code :
Code: Pascal  [Select]
  1. aresponseinfo.ContentType:='application/pdf';
  2. aresponseinfo.ContentDisposition:='attachment; filename="' + get_nip_from_id(arequestinfo.Params.Values['p']) + '.pdf"';
  3. aresponseinfo.ContentStream:=generate_report(arequestinfo.Params.Values['p']);
  4. aresponseinfo.WriteContent;
  5. aresponseinfo.ContentStream:=nil;

You don't need the last 2 lines (especially since the last one is causing a memory leak).  Simply assign the ContentStream and then exit the OnCommandGet event handler.  TIdHTTPServer will then transmit the data for you, and free the stream when finished.

if i comment "//" contentdisposition it went okay... but my response to client will be different from what i expected.

The Content-Disposition header (or lack of one) will not cause the client to send multiple requests.  Something else is going on.
« Last Edit: September 05, 2018, 07:10:19 pm by Remy Lebeau »
Remy Lebeau
Lebeau Software - Owner, Developer
Internet Direct (Indy) - Admin, Developer (Support forum)

epneeh

  • New member
  • *
  • Posts: 5
Re: Indy HTTPserver TIdHTTPServer Session problem
« Reply #4 on: September 07, 2018, 04:46:51 am »
this is my code now:

Code: Pascal  [Select]
  1. add_log('is firing ' + arequestinfo.Command + ' with param ' + arequestinfo.Params.Text ,true);
  2. aresponseinfo.ContentType:='application/pdf';
  3. aresponseinfo.ContentDisposition:='attachment; filename="' + get_nip_from_id(arequestinfo.Params.Values['p']) + '.pdf"';
  4. aresponseinfo.ContentStream:=generate_report(arequestinfo.Params.Values['p']);
  5.  

basically add_log write a log to TMemo,

this is my html code :

Code: HTML5  [Select]
  1. <a class="button is-small is-primary" href="/download?p=2924">download pdf</a></td>
  2.  

attachment image is for traffic captured from firefox browser when i click "download pdf" button.

this is log from TMemo :

Code: [Select]
09:26:25 | 07/09/2018 : is firing GET with param p=2924

09:26:25 | 07/09/2018 : is firing GET with param p=2924

09:26:25 | 07/09/2018 : is firing GET with param p=2924

09:26:25 | 07/09/2018 : is firing GET with param p=2924

you can see, under 1 second there is 4 same requests firing, any ideas?

Remy Lebeau

  • Sr. Member
  • ****
  • Posts: 448
    • Lebeau Software
Re: Indy HTTPserver TIdHTTPServer Session problem
« Reply #5 on: September 07, 2018, 08:15:38 pm »
basically add_log write a log to TMemo,

But, is it doing that safely?  Remember, TIdHTTPServer is a multi-threaded component.  Does add_log() access the TMemo directly, or does it synchronize with the main UI thread?

attachment image is for traffic captured from firefox browser when i click "download pdf" button.

As you can see, there is only 1 HTTP request being made (as it should be).

this is log from TMemo :

Code: [Select]
09:26:25 | 07/09/2018 : is firing GET with param p=2924

09:26:25 | 07/09/2018 : is firing GET with param p=2924

09:26:25 | 07/09/2018 : is firing GET with param p=2924

09:26:25 | 07/09/2018 : is firing GET with param p=2924

Then there has to be a problem with how you are managing the logging.
Remy Lebeau
Lebeau Software - Owner, Developer
Internet Direct (Indy) - Admin, Developer (Support forum)

epneeh

  • New member
  • *
  • Posts: 5
Re: Indy HTTPserver TIdHTTPServer Session problem
« Reply #6 on: September 07, 2018, 09:46:03 pm »
this is add_log function

Code: Pascal  [Select]
  1.  procedure add_log(log : string;isSystem: boolean = False);
  2.   begin
  3.     if form1.chkShowlogs.Checked and isSystem then
  4.     begin
  5.      
  6.         TThread.Queue(nil,
  7.           procedure
  8.           begin
  9.             form1.cLog.Lines.Add(timetostr(now) + ' | ' +  datetostr(now) + ' : ' + log);
  10.           end
  11.         );
  12.      
  13.      
  14.     end;
  15.  
  16.   end;
  17.  

is it syncronize?

again, if i disabled the contentDisposisition and with or without logging, it is fine.

Remy Lebeau

  • Sr. Member
  • ****
  • Posts: 448
    • Lebeau Software
Re: Indy HTTPserver TIdHTTPServer Session problem
« Reply #7 on: September 08, 2018, 12:12:18 am »
Code: Pascal  [Select]
  1. if form1.chkShowlogs.Checked and isSystem then
  2.  

Accessing *any* UI control is not thread-safe and MUST be synchronized with the UI thread.  That includes reading properties of UI controls.

Code: Pascal  [Select]
  1.         TThread.Queue(nil,
  2.           procedure
  3.           begin
  4.             form1.cLog.Lines.Add(timetostr(now) + ' | ' +  datetostr(now) + ' : ' + log);
  5.           end
  6.         );
  7.  

That is fine in of itself, as far as threading is concerned.  Though, I would suggest using FormatDateTime() instead of TimeToStr() and DateToStr() separately, and to grab the timestamp before calling TThread.Queue(), eg:

Code: Pascal  [Select]
  1. procedure add_log(log : string;isSystem: boolean = False);
  2. var
  3.   msg: string;
  4. begin
  5.   if isSystem then
  6.   begin
  7.     msg := FormatDateTime('t"|"ddddd', now) + ' : ' + log;
  8.     TThread.Queue(nil,
  9.       procedure
  10.       begin
  11.         if form1.chkShowlogs.Checked then
  12.           form1.cLog.Lines.Add(msg);
  13.       end
  14.     );
  15.   end;
  16. end;
  17.  

again, if i disabled the contentDisposisition and with or without logging, it is fine.

That has absolutely nothing to do with your logging issue, and besides the lack of a ContentDisposition value CANNOT trigger a browser to issue multiple requests.  Something else is going on.
Remy Lebeau
Lebeau Software - Owner, Developer
Internet Direct (Indy) - Admin, Developer (Support forum)

epneeh

  • New member
  • *
  • Posts: 5
Re: Indy HTTPserver TIdHTTPServer Session problem
« Reply #8 on: September 08, 2018, 03:08:46 am »
Hi remy i think IDM is the culprit, as the server send response to client IDM dialog is launching and make a request to the server in milisecond manner, even worst it makes up to 5 request per dialog, do you have suggestion how to queue a request that has the same document and the same parameter?

Remy Lebeau

  • Sr. Member
  • ****
  • Posts: 448
    • Lebeau Software
Re: Indy HTTPserver TIdHTTPServer Session problem
« Reply #9 on: September 10, 2018, 07:05:48 pm »
Hi remy i think IDM is the culprit

I don't know what IDM is.

as the server send response to client IDM dialog is launching and make a request to the server in milisecond manner, even worst it makes up to 5 request per dialog

Please show the complete HTTP requests that are actually being made.  Maybe IDM is sending a request for different ranges of the file?  Who knows.  We can't see what you see.

do you have suggestion how to queue a request that has the same document and the same parameter?

You can't.  You must process each request individually and fully, you can't consolidate them.
Remy Lebeau
Lebeau Software - Owner, Developer
Internet Direct (Indy) - Admin, Developer (Support forum)

 

Recent

Get Lazarus at SourceForge.net. Fast, secure and Free Open Source software downloads Open Hub project report for Lazarus