Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.forth > #43868

Re: Writing (web)servers in Forth

Newsgroups comp.lang.forth
Date 2015-11-27 08:33 -0800
References <4e8b252d-3dd6-4e1d-b9b6-0457b8dadaf3@googlegroups.com>
Message-ID <3f524700-e761-4dd5-927e-e7d82dd57d8b@googlegroups.com> (permalink)
Subject Re: Writing (web)servers in Forth
From Howerd <howerdo@yahoo.co.uk>

Show all headers | View raw


On Thursday, 26 November 2015 21:14:42 UTC, Julian Fondren  wrote:
> Hello, clf,
> 
> Yes, it's happened again.  Someone has written another webserver in
> Forth.  I know, it's literally the first thing anyone does.  Can you
> all, possibly, get to work doing something useful instead of putting
> another webserver on GitHub?
> 
> I confess, this time it's me who wrote one.  You can find it here:
> https://bitbucket.org/demonview/forth-httpd
> 
> The core of this repository is an evolution of the pollserver I
> supplied in a previous post to this group.  I'll just put the entirety
> of pollserver.fs here:
> 
>   [defined] client 0= [if] abort
>     class client
>       : init ( pollfd -- ) remember pollfd and zero out any data structures, etc. ;
>       : connected ( -- )  pollfd now has a live socket ;
>       : reap ( -- ) clean up, log death, etc.  pollfd will be killed afterwards ;
>       : update ( -- ) you have input!  (or may now write).  deal with it ;
>     end-class
>   [then]
> 
>   class pollserver
>     max-clients 1+ pollfd builds[] pollfds
>     max-clients 1+ client builds[] clients
> 
>     : init-with ( socket -- )
>       max-clients 1+ 0 do
>         i pollfds init
>         i pollfds addr i clients socket !
>       loop  max-clients pollfds fd ! ;
>     : init ( port -- )  server-socket init-with ;
> 
>     : server ( -- server-socket )  max-clients pollfds fd @ ;
>     : accept? ( -- f )  max-clients pollfds ready? ;
>     : size ( -- n )  0 max-clients 0 do i pollfds alive? if 1+ then loop ;
> 
>     DEFER: too-many-connections ( socket -- )  close-file drop ;
>     : add ( socket -- )
>       max-clients 0 do
>         i pollfds dead? if
>           i pollfds fd !
>           i clients connected
>       unloop exit then loop  too-many-connections ;
> 
>     : /accepting ( -- )  accept? if /accept accepted add then ;
>     : /updating ( -- )
>       max-clients 0 do
>         i pollfds alive? if
>           i pollfds dying? if i clients reap pollfds kill
>           else i pollfds ready? if i clients update
>       then then then loop ;
> 
>     \ 'poll' in these definitions is the syscall
>     : poll-for ( timeout -- ior ) >r 0 pollfds addr max-clients 1+ r> poll ;
>     : poll ( -- ior )  0 pollfds addr max-clients 1+ -1 poll ;
> 
>     \ 'poll' in this definition is the method
>     : /serving ( -- )
>       begin poll 0< abort" poll failed"
>       /accepting /updating again ;
>   end-class
> 
> That's it.  It literally has nothing at all to do with HTTP, or
> document roots, or request routing, or 404 errors.  It's two arrays,
> one fed to poll(), and a mirroring array of client objects.  Which
> are defined elsewhere.  pollserver doesn't even know if clients are
> waiting for sockets to be ready for input vs. output.  Rather than tie
> server logic intimately with with this structure, the direction I was
> going in that earlier post, the logic is handled completely by the
> client objects.
> 
> The repo has a bunch of other stuff, including a README that goes into
> other details.
> 
> I was impressed, recently, by the Node.js community.  You could install
> a standalone webserver that would serve static files from the directory
> you ran it from, and which had a few options.  If you wanted to do a
> little more that than, you can do it nearly as rapidly with the Express
> framework.  If you wanted to get a server running and keep it running,
> 'forever' was an aptly-named tool for that.
> 
> I wasn't as impressed by Node.js itself.  For two reasons: my
> background is in system administration, and I'd used Erlang before.
> 
> So I wrote a little webserver-inna-script for Erlang, too:
> 
> https://bitbucket.org/demonview/http-server
> 
> And then I found some cheap micro-VPSes, and figured Forth would be
> more appropriate for these environments.
> 
> Here are a few routes in Express:
> 
>   var counter = 0
>   app.get('/counter.fs', function(req, res) {
>     res.type('text/plain')
>     res.status(200)
>     res.send(String(++counter))
>   })
> 
>   app.get('/ip.fs', function(req, res) {
>     res.type('text/plain')
>     res.status(200)
>     res.send(req.ip)
>   })
> 
> And the same routes in Forth:
> 
>   variable counter
>   simple :: counter-rule
>     if: m" /counter.fs" ;
>     do: counter ++ counter @ 0 .r ;
> 
>   simple :: ip-rule
>     if: m" /ip.fs" ;
>     do: client peer @ .ip ;
> 
> That's not so bad, is it
> 
> Well I'm not a big fan of the :: syntax, but I had a need to create a
> statically allocated object and also put its address on the stack, and
> SWOOP can do one or the other.
> 
> It's a work in progress.
> 
> Cheers,
> Julian

Hi Julian,

Nice one :-)

> Rather than tie
> server logic intimately with with this structure, the direction I was
> going in that earlier post, the logic is handled completely by the
> client objects.
I like this. It sounds like you are following the Forth principle of solving a simpler problem... And if if looks like a webserver, walks like a webserver and sounds like a webserver, then it *is* a webserver.

Best regards,
Howerd

Back to comp.lang.forth | Previous | Next — Previous in thread | Find similar | Unroll thread


Thread

Writing (web)servers in Forth Julian Fondren <julian.fondren@gmail.com> - 2015-11-26 13:14 -0800
  Re: Writing (web)servers in Forth Lars Brinkhoff <lars.spam@nocrew.org> - 2015-11-27 07:47 +0100
  Re: Writing (web)servers in Forth Howerd <howerdo@yahoo.co.uk> - 2015-11-27 08:29 -0800
  Re: Writing (web)servers in Forth Howerd <howerdo@yahoo.co.uk> - 2015-11-27 08:33 -0800

csiph-web