Running Racket on a web server

hello,

i have this problem when trying to run a Racket application from an Apache web server. I modify a PHP application that call a command line application (could be Fortran,Python,Scheme....)

the application caller in PHP looks like this:

function generateCmdField() {

  file_put_contents('php://stderr', print_r("generateCmdField  : CubeURL = $this->CubeURL\n", TRUE));


  //$this->cmd= "python -c \"print('Real Python')\""; // OK

  //$this->cmd= "/opt/homebrew/var/www/cgi-bin/test-cgi"; // KO

  $this->cmd= "/opt/homebrew/var/www/cgi-bin/interpole_fields"; // Scheme

if ($this->DebugShowCmd) {
    $this->warning .= " FORTRAN command=".$this->cmd;
  }

  file_put_contents('php://stderr', print_r("generateCmdField : this->cmd=$this->cmd\n", TRUE));
  file_put_contents('php://stderr', print_r("CoordinateSpecified  : this->warning=$this->warning\n", TRUE));
}

}


  // execute the command (interpolation)
  function GeneralReturn() {

    $test=0;
    $message="";
    $msg="";

    while (($test < 3) && (strpos(strtoupper($message),'CPU') === FALSE)) {
      sleep(3);
      $test+=1;
      if (file_exists($this->url_input.".txt")) { // input file 
        $message=exec($this->cmd." 0>&1",$outp,$retc); // execute the command line
        // $message=exec($this->cmd." 2>&1",$outp,$retc);		
        $msg = $msg.$message.'['.$retc.']|'; // concatenate return message
	file_put_contents('php://stderr', print_r("GeneralReturn  : msg=$msg\n outp=$outp\n", TRUE));
      }
	  //else {throw new SoapFault("1", "Writting pb");}
    }
    
    if ($test > 0) { $this->warning.=",TESTS=".$test." ".$msg; }
    
    exec("rm ".$this->url_input) ; // remove input file
    
    if (strpos(strtoupper($message),'CPU') === FALSE) {
      //CPU TIME is the last line of the code if it works
      //throw new SoapFault("1", "Interpolation error".$msg);
      $this->warning.="; Interpolation routines did not succeed";
    }
    
    if (strpos(strtoupper($message),"ERROR") !== FALSE) { throw new SoapFault("1", "Interpolation error ".$msg); }
    if (strpos(strtoupper($message),"WARNING") !== FALSE) { $this->warning.="; ".$message; }
    
    $ret="http://impex.latmos.ipsl.fr/getWSFile.php?location=".str_replace("/var/www/html/IMPEx/","",$this->url_output); // getWSFile.php ? return the raw output file or modified?
    
    if ($this->warning != "") {
      $header = new SoapHeader('http://impex.latmos.ipsl.fr/','warning',"WARNING:".$this->warning,false);
      $GLOBALS['server']->addSoapHeader($header);
    }
    
    return $ret;
  }

interpolate_fields is a Scheme program that will prepare data and call later Python code...

for now it is just this:

#! /usr/bin/env racket
#lang reader SRFI-105

;; interpolate field caller

;; Damien MATTEI


(module interpolate-field-caller racket
	
	(require Scheme+)

 (display "Scheme+ : interpole_fields") (newline)

) ; end module

i put this code in cgi-bin ,even if cgi-bin test has fail to allow code, there is no problem in running python or code from PHP, so i suppose,PHP has rights to run any code it want,and this is the case as it can run Python and Racket, but the problem is that my Racket code can not find some stuff to start...

The racket code run from command line ,the web server can run racket but i have an error.

First the command line test of my Racket code that works:

(base) mattei@MacBook-Pro-Touch-Bar cgi-bin % ls -la
total 40
drwxr-xr-x   7 mattei  admin   224 23 oct 11:17 .
drwxr-xr-x  37 mattei  admin  1184 23 oct 11:37 ..
-rwxr-xr-x@  1 mattei  admin   222 23 oct 11:03 interpole_fields
-rw-r--r--   1 mattei  admin   820 18 avr  2024 printenv
-rw-r--r--   1 mattei  admin  1074 18 avr  2024 printenv.vbs
-rw-r--r--   1 mattei  admin  1133 18 avr  2024 printenv.wsf
-rwxr-xr-x@  1 mattei  admin  1269 23 oct 11:17 test-cgi
(base) mattei@MacBook-Pro-Touch-Bar cgi-bin % ./interpole_fields
SRFI-105 Curly Infix parser for Racket Scheme by Damien MATTEI
(based on code from David A. Wheeler and Alan Manuel K. Gloria.)

Possibly skipping some header's lines containing space,tabs,new line,etc  or comments.

SRFI-105.rkt : number of skipped lines (comments, spaces, directives,...) at header's beginning : 9

Parsed curly infix code result = 

(module interpolate-field-caller racket
  (require Scheme+)
  (display "Scheme+ : interpole_fields")
  (newline))
Scheme+ : interpole_fields

the output is correct ,it display a single line.

but when ran from client that call the PHP code ,it ran racket but racket got problem to find all the normal stuff ,here the error in httpd log:

generateCmdField : this->cmd=/opt/homebrew/var/www/cgi-bin/interpole_fields
CoordinateSpecified  : this->warning= Following parameters ignored=OutputFileType;units=1; FORTRAN command=/opt/homebrew/var/www/cgi-bin/interpole_fields
standard-module-name-resolver: collection not found
  for module path: SRFI-105
  collection: "SRFI-105"
  in collection directories:
   /Users/mattei/Library/Racket/8.14/collects
   /Applications/Racket/collects/
   ... [170 additional linked and package directories]
  context...:
   /Applications/Racket/collects/syntax/module-reader.rkt:265:4: get
   /Applications/Racket/collects/syntax/module-reader.rkt:315:4: read-fn
[Wed Oct 23 11:37:46.077700 2024] [php:warn] [pid 22248] [client ::1:58578] PHP Warning:  Array to string conversion in /opt/homebrew/var/www/IMPExWS.php on line 801
GeneralReturn  : msg=[1]|
 outp=Array

note: forget FORTRAN text it is now Scheme code.

note i put the PHP code but it is not directly the problem seems Racket can not load my library the same way in GUI or command line when running on a web server

when writting that i think now of an authorisation problem : can Racket access /Users/mattei/Library/Racket/8.14/collects from a PHP call on a web server?

Update:

in fact there is no directory that search Racket:

(base) mattei@MacBook-Pro-Touch-Bar cgi-bin % ls -la  /Users/mattei/Library/Racket/8.14/collects
ls: /Users/mattei/Library/Racket/8.14/collects: No such file or directory
(base) mattei@MacBook-Pro-Touch-Bar cgi-bin % ls -la  /Users/mattei/Library/Racket/8.14/        
total 8
drwxr-xr-x@  6 mattei  staff  192 23 oct 10:54 .
drwxr-xr-x   4 mattei  staff  128 11 oct 15:10 ..
drwxr-xr-x@ 24 mattei  staff  768 23 oct 10:55 doc
-rw-r--r--@  1 mattei  staff  696 23 oct 10:54 links.rktd
drwxr-xr-x@ 15 mattei  staff  480 23 oct 10:54 pkgs
drwxr-xr-x@  3 mattei  staff   96 11 oct 15:11 share

why racket is it searching here? this error only happens when launching by httpd and PHP

update 2:

(base) mattei@MacBook-Pro-Touch-Bar cgi-bin % ls -la /Applications/Racket/collects/
total 0
drwxr-xr-x@  26 mattei  admin   832  9 aoĆ» 19:59 .
drwxr-xr-x@  16 mattei  admin   512 11 oct 15:07 ..
drwxr-xr-x@   4 mattei  admin   128  9 aoĆ» 19:59 acks
drwxr-xr-x@  17 mattei  admin   544  9 aoĆ» 19:59 compiler
drwxr-xr-x@   6 mattei  admin   192  9 aoĆ» 19:59 data
drwxr-xr-x@   3 mattei  admin    96  9 aoĆ» 19:59 db
drwxr-xr-x@   5 mattei  admin   160  9 aoĆ» 19:59 dynext
drwxr-xr-x@  12 mattei  admin   384  9 aoĆ» 19:59 ffi
drwxr-xr-x@  18 mattei  admin   576  9 aoĆ» 19:59 file
drwxr-xr-x@   4 mattei  admin   128  9 aoĆ» 19:59 info
drwxr-xr-x@   3 mattei  admin    96  9 aoĆ» 19:59 info-domain
drwxr-xr-x@   4 mattei  admin   128  9 aoĆ» 19:59 json
drwxr-xr-x@   6 mattei  admin   192  9 aoĆ» 19:59 launcher
drwxr-xr-x@  16 mattei  admin   512  9 aoĆ» 19:59 net
drwxr-xr-x@  13 mattei  admin   416  9 aoĆ» 19:59 openssl
drwxr-xr-x@  14 mattei  admin   448  9 aoĆ» 19:59 pkg
drwxr-xr-x@   9 mattei  admin   288  9 aoĆ» 19:59 planet
drwxr-xr-x@ 116 mattei  admin  3712  9 aoĆ» 19:59 racket
drwxr-xr-x@  12 mattei  admin   384  9 aoĆ» 19:59 raco
drwxr-xr-x@   3 mattei  admin    96  9 aoĆ» 19:59 reader
drwxr-xr-x@   3 mattei  admin    96  9 aoĆ» 19:59 realm
drwxr-xr-x@   3 mattei  admin    96  9 aoĆ» 19:59 s-exp
drwxr-xr-x@  38 mattei  admin  1216  9 aoĆ» 19:59 setup
drwxr-xr-x@  46 mattei  admin  1472  9 aoĆ» 19:59 syntax
drwxr-xr-x@   6 mattei  admin   192  9 aoĆ» 19:59 version
drwxr-xr-x@   9 mattei  admin   288  9 aoĆ» 19:59 xml

Update 3:

i think that my program comes from the user that ran the racket code is Apache user _www not me (mattei) and that my libraries are installed in my home dir...

so now the question is to install my libraries (SRFI-105 ,Scheme+) system wide or tell Racket to look in my home directory....

Update 4:

digging... and digging again... i find that my personnal modules are "linked" as installation :

> (current-library-collection-links)
'(#f #<path:/Users/mattei/Library/Racket/8.14/links.rktd> #<path:/Applications/Racket v8.14/collects/../share/links.rktd>)
less /Users/mattei/Library/Racket/8.14/links.rktd

(("scribble-math" (#"pkgs" #"scribble-math"))
 ("scribble-code-examples" (#"pkgs" #"scribble-code-examples"))
 ("scribble-code-examples" (#"pkgs" #"scribble-code-examples-lib"))
 ("Scheme+R6RS" (up up #"CloudStorage" #"Dropbox" #"git" #"Scheme-PLUS-for-Racket-R6RS"))
 (root (#"pkgs" #"reprovide-lang-lib"))
 (root (#"pkgs" #"lang-file-lib"))
 (root (#"pkgs" #"syntax-macro-lang"))
 (root (#"pkgs" #"sci"))
 (root (#"pkgs" #"pretty-format"))
 ("colors" (#"pkgs" #"colors"))
 (root (#"pkgs" #"debug"))
 ("SRFI-105" (up up #"CloudStorage" #"Dropbox" #"git" #"SRFI-105-for-Racket"))
 ("Scheme+" (up up #"CloudStorage" #"Dropbox" #"git" #"Scheme-PLUS-for-Racket" #"main" #"Scheme-PLUS-for-Racket")))

/Users/mattei/Library/Racket/8.14/links.rktd (END)

i suppose this is not used by "_www racket" , i will check that soon, in last solution i suppose making a standalone executable in Racket (i made it years ago for a command line application ,not web server) that incorporate all the libraries should works but this is not an easy develoment procedure as i must compile code many times in the day...

Update 5:

yes exactly the same on the client-server web application the PHP calls Racket that display those paths:

command=./cgi-bin/interpole_fields
GeneralReturn  : msg=Scheme+ : interpole_fields[0]|
 tmp3=Array
(
    [0] => (/Users/mattei/Library/Racket/8.14/lib /Applications/Racket/lib)
    [1] => (#f /Users/mattei/Library/Racket/8.14/links.rktd /Applications/Racket/collects/../share/links.rktd)
    [2] => Scheme+ : interpole_fields
)

when i launch :

#! /usr/bin/env racket

;;#lang reader SRFI-105

;; interpolate field caller

;; Damien MATTEI


(module interpolate-field-caller racket
	
	;;(require Scheme+)

	(require setup/dirs)
	(display (get-lib-search-dirs)) (newline)
	(display (current-library-collection-links)) (newline)
	(display "Scheme+ : interpole_fields") (newline)

) ; end module

i do not understand why it can not load SRFI-105 and Scheme+ as :

("SRFI-105" (up up #"CloudStorage" #"Dropbox" #"git" #"SRFI-105-for-Racket"))
 ("Scheme+" (up up #"CloudStorage" #"Dropbox" #"git" #"Scheme-PLUS-for-Racket" #"main" #"Scheme-PLUS-for-Racket"))

from /Users/mattei/Library/Racket/8.14/links.rktd if do: (up up #"CloudStorage" #"Dropbox" #"git" #"SRFI-105-for-Racket") i'm well in the SRFI-105 module source code:

(base) mattei@MacBook-Pro-Touch-Bar tmp % cd /Users/mattei/Library/Racket/8.14/          
(base) mattei@MacBook-Pro-Touch-Bar 8.14 % ls -la ../../CloudStorage/Dropbox/git/SRFI-105-for-Racket 
total 104
drwx------@ 12 mattei  staff    384  1 oct 12:00 .
drwxr-xr-x@ 23 mattei  staff    736  4 sep 21:58 ..
drwx------@ 13 mattei  staff    416 27 sep 11:39 .git
-rw-------@  1 mattei  staff  35149 20 aoĆ» 02:17 LICENSE
-rw-------@  1 mattei  staff    417  2 oct 08:47 README.md
drwx------@  7 mattei  staff    224 23 oct 10:54 compiled
drwx------@  4 mattei  staff    128 17 aoĆ» 23:06 deprecated
drwx------@ 14 mattei  staff    448  3 sep 11:22 doc
-rw-------@  1 mattei  staff    563 20 oct 01:08 info.rkt
-rw-------@  1 mattei  staff   7494 21 oct 00:31 main.rkt
drwx------@  4 mattei  staff    128  3 sep 11:22 scribblings
drwx------@  8 mattei  staff    256 18 oct 02:02 src

PHP :

$this->cmd= "/bin/ls /Users/mattei/Library/Racket/8.14/links.rktd";

tail -f /opt/homebrew/var/log/httpd/error_log :

command=/bin/ls /Users/mattei/Library/Racket/8.14/links.rktd
ls: /Users/mattei/Library/Racket/8.14/links.rktd: Permission denied

ah ah ah :grinning:

if the parent proccess has no right to access i'm sure the child can not access it too....

solution could be to create an executable ,stand-alone or distribution options in Racket->create executable in the Racket GUI program
but as i develop and test often my code i prefered to do the terrible thing of cutting the security of my system with two UNIX weapons ,chmod and groupmod by creating a path in the filesystem to my personal folder and even cloud box using chmod g+rx on directories and adding _www to my staff group : sudo dseditgroup -o edit -a _www -t user staff. For development stage this is supportable....

pleasure to see Scheme+ for Racket and SRFI-105 curly infix loaded on the web apps:

Scheme+ : interpole_fields[0]|
 tmp3=Array
(
    [0] => SRFI-105 Curly Infix parser for Racket Scheme by Damien MATTEI
    [1] => (based on code from David A. Wheeler and Alan Manuel K. Gloria.)
    [2] => 
    [3] => Possibly skipping some header's lines containing space,tabs,new line,etc  or comments.
    [4] => 
    [5] => SRFI-105.rkt : number of skipped lines (comments, spaces, directives,...) at header's beginning : 10
    [6] => 
    [7] => Parsed curly infix code result =
    [8] => 
    [9] => (module interpolate-field-caller racket
    [10] =>   (require Scheme+)
    [11] =>   (require setup/dirs)
    [12] =>   (display (get-lib-search-dirs))
    [13] =>   (newline)
    [14] =>   (display (current-library-collection-links))
    [15] =>   (newline)
    [16] =>   (display "Scheme+ : interpole_fields")
    [17] =>   (newline))
    [18] => (/Users/mattei/Library/Racket/8.14/lib /Applications/Racket/lib)
    [19] => (#f /Users/mattei/Library/Racket/8.14/links.rktd /Applications/Racket/collects/../share/links.rktd)
    [20] => Scheme+ : interpole_fields

Another solution might be to use "mount bind" to link your code directories to somewhere Apache allows you to access. I've used bind successfully to get around chroot jails when necessary.

I've never tried to launch Racket directly from Apache, but I have run "backend" Racket programs as system services and used Apache to redirect access to them over local ports.

You don't need to create executables ... you can run Racket directly as a service (or bg daemon), point it to your source, and let it compile on the fly.

My attempts to run Racket based web servers have resulted in "lock ups" where the program stops responding ... but I haven't tried since early 7.x [before the change to CS] so take my experience with salt as it may be no longer relevant.

An alternative is to run the Racket web server on a local port.
Then make nginx or Apache act as a proxy.

Another solution to use Scheme on web server would be to generate Java/Jakarta byte-code from a Scheme source file and run it on an apache tomcat web server.

I'm also upgrading a scheme based web application from Java to Jakarta that is compiled in Java/Jakarta classes packaged in a .war file and the application is hosted on a tomcat web server.

I had written when porting the original web application from microsoft windows ASP scripts,(and originally hosted on windows web server ) to scheme and java classes under Linux hoste with Tomcat a technical documentation still available.

I use scheme implementation that can generates Java/Jakarta classes: Kawa,Bigloo.
Since this i have written,a few years ago, a Scheme+ version for Kawa that can be compiled in Java/Jakarta classes,so i can even use Scheme+ to upgrade the application.

An interesting feature would be to be able to generate Java/Jakarta classes from Racket code.This would allow to host Racket application on Tomcat web server.

That's what I ended up doing.

When I tried serving HTTP directly from Racket programs, they inevitably would lock up after a while. Didn't matter encrypted or not. Sometimes they worked for many thousands of requests, but eventually they always stopped responding. However, they were not crashed: only the "web server" part stopped - other threads still ran and the program could be accessed via those threads (if designed properly).

Once I put them behind a proxy server [Apache] and removed the need to serve static pages, they worked like a charm. :thinking:

But note that this was with BC Racket. I have never tried serving HTTP directly with CS Racket.