Recent

Author Topic: Node like HTTPServer  (Read 1488 times)

Grahame Grieve

  • Sr. Member
  • ****
  • Posts: 379
Node like HTTPServer
« on: June 28, 2025, 11:13:48 pm »
I've been doing a lot of work with Claude writing code in java and javascript, and so I decided to test Claude out for free pascal, and it's done a pretty good job. What I asked it to do was write a Node.js like framework for an HTTP server that would run in either unix or windows

The outcome is here: https://github.com/HealthIntersections/fhirserver/tree/master/library/http

I'm wondering whether this is something that other people would find useful, and I should spin it out into its own space?

btw... why no HTTPS? I would never run my own server native on the web now - I always run it behind nginx, and let nginx handle basic things like web security and SSL.

Gustavo 'Gus' Carreno

  • Hero Member
  • *****
  • Posts: 1329
  • Professional amateur ;-P
Re: Node like HTTPServer
« Reply #1 on: June 29, 2025, 12:36:19 am »
Hey Grahame,

I've had a quick look at what you've done and I do like what I see!!
I'm giving it an A+ for effort !!  :-*

Having said that... You've duplicated something that already exists in Free Pascal.

The fp-web package, in it's latest incarnation, already provides a router based implementation.

It's no shame to re-invent the wheel when you're trying to learn stuff!!!
I'm always quite adamant on that!!
But you did re-invent the wheel ;)

Cheers,
Gus
Lazarus 4.99(main) FPC 3.3.1(main) Ubuntu 25.04 64b Dark Theme
http://github.com/gcarreno

Gustavo 'Gus' Carreno

  • Hero Member
  • *****
  • Posts: 1329
  • Professional amateur ;-P
Re: Node like HTTPServer
« Reply #2 on: June 29, 2025, 01:58:12 am »
Hey Grahame,

I felt I needed to include an example of using the routed version of fp-web.

Here's a quick example:
Code: Pascal  [Select][+][-]
  1. program fpwebserver;
  2.  
  3. {$mode objfpc}{$H+}
  4.  
  5. uses
  6.   {$IFDEF UNIX}
  7.   cmem,
  8.   cthreads,
  9.   BaseUnix,
  10.   {$ENDIF}
  11.   SysUtils,
  12.   fphttpapp,
  13.   HTTPDefs,
  14.   httproute;
  15.  
  16. const
  17.   cPort = 9191;
  18.  
  19. procedure DefaultRoute(ARequest: TRequest; AResponse: TResponse);
  20. begin
  21.   AResponse.Content:=
  22.     '<html>' +
  23.     '<head>' +
  24.     '<title>FP Web Server</title>' +
  25.     '</head>' +
  26.     '<body>' +
  27.     '<ul>' +
  28.     '<li><a href="/">Default</a></li>' +
  29.     '<li><a href="/about">About</a></li>' +
  30.     '</ul>' +
  31.     '<h1>FP Web Server</h1>' +
  32.     '<p>Default Route</>' +
  33.     '</body>' +
  34.     '</html>'
  35.   ;
  36. end;
  37.  
  38. procedure AboutRoute(ARequest: TRequest; AResponse: TResponse);
  39. begin
  40.   AResponse.Content:=
  41.     '<html>' +
  42.     '<head>' +
  43.     '<title>FP Web Server: About</title>' +
  44.     '</head>' +
  45.     '<body>' +
  46.     '<ul>' +
  47.     '<li><a href="/">Default</a></li>' +
  48.     '<li><a href="/about">About</a></li>' +
  49.     '</ul>' +
  50.     '<h1>FP Web Server: About</h1>' +
  51.     '<p>About Route</>' +
  52.     '</body>' +
  53.     '</html>'
  54.   ;
  55. end;
  56.  
  57. procedure RegisterRoutes;
  58. begin
  59.   // Responds to any method
  60.   HTTPRouter.RegisterRoute('/', rmAll, @DefaultRoute, True);
  61.   // Responds only to the GET method
  62.   HTTPRouter.RegisterRoute('/about', rmGet, @AboutRoute);
  63. end;
  64.  
  65. {$IFDEF UNIX}
  66. procedure CleanUp(ASignal: LongInt); cdecl;
  67. begin
  68.   WriteLn;
  69.   WriteLn('Cleaning');
  70.   Application.Terminate;
  71.   Halt(0);
  72. end;
  73. {$ENDIF UNIX}
  74.  
  75. begin
  76.   RegisterRoutes;
  77.  
  78.   {$IFDEF UNIX}
  79.   if FpSignal(SIGINT, @CleanUp) = signalhandler(SIG_ERR) then begin
  80.     WriteLn({$I %FILE%}, {$I %LINE%}, Format('Failed to install signal error: %d', [ fpGetErrno ]));
  81.     Halt(1);
  82.   end;
  83.   if FpSignal(SIGKILL, @CleanUp) = signalhandler(SIG_ERR) then begin
  84.     WriteLn({$I %FILE%}, {$I %LINE%}, Format('Failed to install signal error: %d', [ fpGetErrno ]));
  85.     Halt(1);
  86.   end;
  87.   {$ENDIF UNIX}
  88.  
  89.   Application.Title:= 'fp-web-httpserver';
  90.   Application.Port:= cPort;
  91.   Application.Threaded:= True;
  92.   Application.Initialize;
  93.   WriteLn(Format('Serving on http://localhost:%d', [cPort]));
  94.   Application.Run;
  95. end.
  96.  

Hope that helps compare your effort and what comes with Free Pascal.

Cheers,
Gus
Lazarus 4.99(main) FPC 3.3.1(main) Ubuntu 25.04 64b Dark Theme
http://github.com/gcarreno

Grahame Grieve

  • Sr. Member
  • ****
  • Posts: 379
Re: Node like HTTPServer
« Reply #3 on: June 29, 2025, 07:35:23 am »
> But you did re-invent the wheel

interesting - thanks. I did not know about FPWeb - or at least, I looked long ago and thought it wasn't what it is now, at least

Gustavo 'Gus' Carreno

  • Hero Member
  • *****
  • Posts: 1329
  • Professional amateur ;-P
Re: Node like HTTPServer
« Reply #4 on: June 29, 2025, 08:36:12 am »
Hey Grahame,

interesting - thanks.

You're more than welcome !!

I did not know about FPWeb - or at least, I looked long ago and thought it wasn't what it is now, at least

And you are correct. In the past we had to deal with WEB Modules and all that Jazz.
You can still do that, cuz backwards compatibility is a must.

But you can also do it routed, like on the code I provided!!

I'm guessing you haven't looked at it for quite a while :D

Cheers,
Gus
Lazarus 4.99(main) FPC 3.3.1(main) Ubuntu 25.04 64b Dark Theme
http://github.com/gcarreno

Grahame Grieve

  • Sr. Member
  • ****
  • Posts: 379
Re: Node like HTTPServer
« Reply #5 on: June 29, 2025, 02:18:48 pm »
The event signature is

Procedure (ARequest: TRequest; AResponse: TResponse) of object

how do I get the client IP?

Also, it looks like the request object parses the body and the URL - what happens if it's a POST and there are parameters in the both the URL and the body?


Gustavo 'Gus' Carreno

  • Hero Member
  • *****
  • Posts: 1329
  • Professional amateur ;-P
Re: Node like HTTPServer
« Reply #6 on: June 30, 2025, 09:53:47 am »
Hey Grahame,

The event signature is

Procedure (ARequest: TRequest; AResponse: TResponse) of object

how do I get the client IP?

I've never explored that, but I'm guessing that the ARequest variable will have something in there that will help.

Looking at the code:
Code: Pascal  [Select][+][-]
  1.   { THTTPHeader }
  2.  
  3.   THTTPHeader = class(TObject)
  4.   {...}
  5.   public
  6.   {...}
  7.     Property RemoteAddress : String Index Ord(hvRemoteAddress) read GetHTTPVariable Write SetHTTPVariable;
  8.     Property RemoteAddr : String Index Ord(hvRemoteAddress) read GetHTTPVariable Write SetHTTPVariable; // Alias, Delphi-compat
  9.     Property RemoteHost : String Index Ord(hvRemoteHost) read  GetHTTPVariable Write SetHTTPVariable;
  10.   {...}
  11.   end;
  12.   { TRequest }
  13.  
  14.   TRequest = class(THttpHeader)
  15.   {...}
  16.   end;

I would investigate the above properties.

Also, it looks like the request object parses the body and the URL - what happens if it's a POST and there are parameters in the both the URL and the body?

There's a good wiki post about fp-web: https://wiki.lazarus.freepascal.org/fpWeb_Tutorial

If you navigate to this section you'll find that those are in ARequest.QueryFields and .ARequest.ContentFields

These are all good questions. And the programmers that implement it this way were probably rather thorough. One just has to dig into the code to try and get some answers when the wiki is short.

Cheers,
Gus
Lazarus 4.99(main) FPC 3.3.1(main) Ubuntu 25.04 64b Dark Theme
http://github.com/gcarreno

 

TinyPortal © 2005-2018