fcl-web TFPHttpServer component problem

classic Classic list List threaded Threaded
11 messages Options
Reply | Threaded
Open this post in threaded view
|

fcl-web TFPHttpServer component problem

Graeme Geldenhuys-2
Hi,

I was testing the newish HTTP Server component located in
fcl-web/src/fphttpserver.pp

I simply created a form with Start/Stop button. The problem is, that
once I call .Active := True, it never returns from that call, so my
test program (and thus any program using this server component) is
stuck in limbo land...

Is this a known problem? And more importantly, is there a work-around?
I'm using FPC 2.5.1 (the latest revision in the 2.6.0 fixes branch).


procedure TMainForm.ButtonClicked(Sender: TObject);
begin
  if Button1.Text = 'Start' then
  begin
    writeln('before start');
    FHTTPServer.Active := True;
    writeln('after start');
    Button1.Text := 'Stop';
  end
  else
  begin
    writeln('before stop');
    FHTTPServer.Active := False;
    writeln('after stop');
    Button1.Text := 'Start';
  end;
end;


Note:
Once the HTTP Server is running, it does correctly handle and respond
to HTTP requests, so the worker thread of the http server is working.
It is just that the program implementing the HTTP Server component is
frozen, and its process has to be killed to terminate the http server.


--
Regards,
  - Graeme -


_______________________________________________
fpGUI - a cross-platform Free Pascal GUI toolkit
http://fpgui.sourceforge.net
_______________________________________________
fpc-pascal maillist  -  [hidden email]
http://lists.freepascal.org/mailman/listinfo/fpc-pascal
Reply | Threaded
Open this post in threaded view
|

Re: fcl-web TFPHttpServer component problem

Leonardo M. Ramé
>________________________________
> From: Graeme Geldenhuys <[hidden email]>
>To: FPC-Pascal users discussions <[hidden email]>
>Sent: Monday, November 28, 2011 7:42 AM
>Subject: [fpc-pascal] fcl-web TFPHttpServer component problem
>
>Hi,
>
>I was testing the newish HTTP Server component located in
>fcl-web/src/fphttpserver.pp
>
>I simply created a form with Start/Stop button. The problem is, that
>once I call .Active := True, it never returns from that call, so my
>test program (and thus any program using this server component) is
>stuck in limbo land...
>
>Is this a known problem? And more importantly, is there a work-around?
>I'm using FPC 2.5.1 (the latest revision in the 2.6.0 fixes branch).
>
>
>procedure TMainForm.ButtonClicked(Sender: TObject);
>begin
>  if Button1.Text = 'Start' then
>  begin
>    writeln('before start');
>    FHTTPServer.Active := True;
>    writeln('after start');
>    Button1.Text := 'Stop';
>  end
>  else
>  begin
>    writeln('before stop');
>    FHTTPServer.Active := False;
>    writeln('after stop');
>    Button1.Text := 'Start';
>  end;
>end;
>
>
>Note:
>Once the HTTP Server is running, it does correctly handle and respond
>to HTTP requests, so the worker thread of the http server is working.
>It is just that the program implementing the HTTP Server component is
>frozen, and its process has to be killed to terminate the http server.
>
>
>--
>Regards,
>  - Graeme -
>
>


I think that class was meant to be used as the main program loop. Didn't tested, but what happens if you use it inside a TThread?.
 

-- 
Leonardo M. Ramé
http://leonardorame.blogspot.com
_______________________________________________
fpc-pascal maillist  -  [hidden email]
http://lists.freepascal.org/mailman/listinfo/fpc-pascal
Reply | Threaded
Open this post in threaded view
|

Re: fcl-web TFPHttpServer component problem

Graeme Geldenhuys-2
In reply to this post by Graeme Geldenhuys-2
On 28/11/2011, Graeme Geldenhuys <[hidden email]> wrote:
>
> I simply created a form with Start/Stop button. The problem is, that
> once I call .Active := True, it never returns from that call, so my
> test program (and thus any program using this server component) is
> stuck in limbo land...


I forgot to mention a few things. Here is the console output after I
clicked the Start button. Note the second writeln() statement is never
reached.

--------------------------------
[httpserver]$ ./testserver
before start

--------------------------------


I've test this under Ubuntu Linux (64-bit) and Windows 2000 (32-bit).
Both give the exact same behaviour.



--
Regards,
  - Graeme -


_______________________________________________
fpGUI - a cross-platform Free Pascal GUI toolkit
http://fpgui.sourceforge.net
_______________________________________________
fpc-pascal maillist  -  [hidden email]
http://lists.freepascal.org/mailman/listinfo/fpc-pascal
Reply | Threaded
Open this post in threaded view
|

Re: fcl-web TFPHttpServer component problem

Graeme Geldenhuys-2
In reply to this post by Leonardo M. Ramé
On 28/11/2011, Leonardo M. Ramé <martinrame@y.....> wrote:
>
> I think that class was meant to be used as the main program loop.

If so, that's a pretty dumb design. Also the HTTP server is
implemented as a component (TComponent descendant), so I gather the
thoughts was that some day they would like it to sit on the Lazarus
component palette, where it will be dropped onto some form or data
module - thus rendering that application frozen too.


>  Didn't tested, but what happens if you use it inside a TThread?.

I can't see how that would work either. For example, you can never
check for the Terminated boolean property (in the customary while
loop) inside the thread's Execute method, because as before, the call
to Active never returns. So you always need to kill the process - no
clean exit ever.


--
Regards,
  - Graeme -


_______________________________________________
fpGUI - a cross-platform Free Pascal GUI toolkit
http://fpgui.sourceforge.net
_______________________________________________
fpc-pascal maillist  -  [hidden email]
http://lists.freepascal.org/mailman/listinfo/fpc-pascal
Reply | Threaded
Open this post in threaded view
|

Re: fcl-web TFPHttpServer component problem

michael.vancanneyt


On Mon, 28 Nov 2011, Graeme Geldenhuys wrote:

> On 28/11/2011, Leonardo M. Ramé <martinrame@y.....> wrote:
>>
>> I think that class was meant to be used as the main program loop.
>
> If so, that's a pretty dumb design.

Ah. And why is that so ?

> Also the HTTP server is
> implemented as a component (TComponent descendant), so I gather the
> thoughts was that some day they would like it to sit on the Lazarus
> component palette, where it will be dropped onto some form or data
> module - thus rendering that application frozen too.

It was never meant as such.

It is meant as the "main program loop", as Leonardo surmised.
The component is meant to be simple.

And using a TComponent does not automatically mean that it will sit on the
component palette. I use TComponent because I like the automated memory
management it offers; e.g. it also means the TDatamodules it creates for
servicing requests can be owned by the server component itself.

If you want still to have a "main program", you should use a thread and
create the component in the thread. Which is exactly what happens in a
service application, the intended environment for the component.

Michael.
_______________________________________________
fpc-pascal maillist  -  [hidden email]
http://lists.freepascal.org/mailman/listinfo/fpc-pascal
Reply | Threaded
Open this post in threaded view
|

Re: fcl-web TFPHttpServer component problem

etrusco
>
>> Also the HTTP server is
>> implemented as a component (TComponent descendant), so I gather the
>> thoughts was that some day they would like it to sit on the Lazarus
>> component palette, where it will be dropped onto some form or data
>> module - thus rendering that application frozen too.
>
> It was never meant as such.
>
> It is meant as the "main program loop", as Leonardo surmised. The component
> is meant to be simple.
>
> And using a TComponent does not automatically mean that it will sit on the
> component palette. I use TComponent because I like the automated memory
> management it offers; e.g. it also means the TDatamodules it creates for
> servicing requests can be owned by the server component itself.
>
> If you want still to have a "main program", you should use a thread and
> create the component in the thread. Which is exactly what happens in a
> service application, the intended environment for the component.
>
> Michael.

I have to agree this is a very odd interface. IMHO setting a property
is expected to return quickly; a call that's meant to be used as
"program loop" should be a explicit method and named accordingly...
(Listen/Run/Execute/ActivateAndWait/etc)

-Flávio
_______________________________________________
fpc-pascal maillist  -  [hidden email]
http://lists.freepascal.org/mailman/listinfo/fpc-pascal
Reply | Threaded
Open this post in threaded view
|

Re: fcl-web TFPHttpServer component problem

Graeme Geldenhuys-2
In reply to this post by michael.vancanneyt
On 28/11/2011, [hidden email] <michael.vancanneyt@w.....> wrote:
>>
>> If so, that's a pretty dumb design.
>
> Ah. And why is that so ?

Now it's much less useful.

How are you supposed to "correctly" terminate the HTTP Server once
Active = True is called?


> If you want still to have a "main program", you should use a thread and
> create the component in the thread. Which is exactly what happens in a
> service application, the intended environment for the component.

I fail to see how this will resolve the problem, but that could be
contributed to my lack of experience with service-style projects. None
the less, I'll adapt my very simple test project and create the server
instance inside a thread, and see how it goes. Like I said, I still
can't see how you can cleanly terminate the HTTP server, because it
will never give the thread a chance to look at the value of
TThread.Terminated?

eg: (the following code is just from memory, not actually test)


procedure TMyThread.Execute;
begin
   while not Terminated do
   begin
     FHTTPServer.Active := True;       // We are stuck here forever
  end;
end;

or

procedure TMyThread.Execute;
begin
   FHTTPServer.Active := True;       // We are stuck here forever
   while not Terminated do
   begin
      // do something, but we will never get here
   end;
   FHTTPServer.Active := False;  // we will never get here either.
end;


--
Regards,
  - Graeme -


_______________________________________________
fpGUI - a cross-platform Free Pascal GUI toolkit
http://fpgui.sourceforge.net
_______________________________________________
fpc-pascal maillist  -  [hidden email]
http://lists.freepascal.org/mailman/listinfo/fpc-pascal
Reply | Threaded
Open this post in threaded view
|

Re: fcl-web TFPHttpServer component problem

michael.vancanneyt


On Mon, 28 Nov 2011, Graeme Geldenhuys wrote:

> On 28/11/2011, [hidden email] <michael.vancanneyt@w.....> wrote:
>>>
>>> If so, that's a pretty dumb design.
>>
>> Ah. And why is that so ?
>
> Now it's much less useful.
>
> How are you supposed to "correctly" terminate the HTTP Server once
> Active = True is called?

1. From a request.
2. From the main thread if the component is set to active in a thread.

>> If you want still to have a "main program", you should use a thread and
>> create the component in the thread. Which is exactly what happens in a
>> service application, the intended environment for the component.
>
> I fail to see how this will resolve the problem, but that could be
> contributed to my lack of experience with service-style projects. None
> the less, I'll adapt my very simple test project and create the server
> instance inside a thread, and see how it goes. Like I said, I still
> can't see how you can cleanly terminate the HTTP server, because it
> will never give the thread a chance to look at the value of
> TThread.Terminated?

The mistake you make is that you create a loop in the thread;
The thread does not need a loop. It just needs to set Active to true:

Procedure TMyServerThread.Execute;

begin
   MyServer.Active:=True;
end;

As soon as a request or the main thread sets active to false, the statement
will return and the thread will terminate.

To terminate the server, you should not set the thread to terminated, but set

MyServerThread.MyServer.Active:=False;

or implement

Procedure TMyServerThread.StopServer;

begin
   MyServer.Active:=False;
end;

and call

MyServerThread.StopServer;

Since this will happen from another thread or from a request handler,
you can do this without problem.

Michael.
_______________________________________________
fpc-pascal maillist  -  [hidden email]
http://lists.freepascal.org/mailman/listinfo/fpc-pascal
Reply | Threaded
Open this post in threaded view
|

Re: fcl-web TFPHttpServer component problem

Graeme Geldenhuys-2
On 28/11/2011, [hidden email] <michael.vancanneyt@....> wrote:
>
> The mistake you make is that you create a loop in the thread;
> The thread does not need a loop. It just needs to set Active to true:
>
> Procedure TMyServerThread.Execute;
>
> begin
>    MyServer.Active:=True;
> end;

OK thanks, I got it working now but it is not ideal yet.

It is still problematic if you try starting & stopping the HTTP Server
because if you stop it, TThread.Execute completes, thus you can't
restart it again, you need to create a new thread instance. I guess
not the end of the world for my simple example, but might be for other
more complex apps. But then, that was probably not the design goal of
this component.


--
Regards,
  - Graeme -


_______________________________________________
fpGUI - a cross-platform Free Pascal GUI toolkit
http://fpgui.sourceforge.net
_______________________________________________
fpc-pascal maillist  -  [hidden email]
http://lists.freepascal.org/mailman/listinfo/fpc-pascal
Reply | Threaded
Open this post in threaded view
|

Re: fcl-web TFPHttpServer component problem

Graeme Geldenhuys-2
In reply to this post by etrusco
On 28/11/2011, Flávio Etrusco <flavio.etrusco@....> wrote:
>
> I have to agree this is a very odd interface. IMHO setting a property
> is expected to return quickly; a call that's meant to be used as
> "program loop" should be a explicit method and named accordingly...
> (Listen/Run/Execute/ActivateAndWait/etc)


Definitely!  Currently  .Active := True   is a blocking call, but
.Active := False is not. And as you said, there is no hint that
calling Active := true starts it's own program loop.


--
Regards,
  - Graeme -


_______________________________________________
fpGUI - a cross-platform Free Pascal GUI toolkit
http://fpgui.sourceforge.net
_______________________________________________
fpc-pascal maillist  -  [hidden email]
http://lists.freepascal.org/mailman/listinfo/fpc-pascal
Reply | Threaded
Open this post in threaded view
|

Re: fcl-web TFPHttpServer component problem

michael.vancanneyt
In reply to this post by Graeme Geldenhuys-2


On Mon, 28 Nov 2011, Graeme Geldenhuys wrote:

> On 28/11/2011, [hidden email] <michael.vancanneyt@....> wrote:
>>
>> The mistake you make is that you create a loop in the thread;
>> The thread does not need a loop. It just needs to set Active to true:
>>
>> Procedure TMyServerThread.Execute;
>>
>> begin
>>    MyServer.Active:=True;
>> end;
>
> OK thanks, I got it working now but it is not ideal yet.
>
> It is still problematic if you try starting & stopping the HTTP Server
> because if you stop it, TThread.Execute completes, thus you can't
> restart it again, you need to create a new thread instance. I guess
> not the end of the world for my simple example, but might be for other
> more complex apps. But then, that was probably not the design goal of
> this component.

I am open for suggestions, but the possible solutions are IMHO not so simple:
- Either a thread must be created automatically to actually run the server when Active:=True
- Or the server must be made non-blocking and then you need to run an event loop.

Either way is a significant architectural change.

Michael.
_______________________________________________
fpc-pascal maillist  -  [hidden email]
http://lists.freepascal.org/mailman/listinfo/fpc-pascal