CGIApache

Background

Euphoria, from Rapid Deployment Software, is a programming language that allows rapid development of almost any kind of application. A natural extension of this is server side scripting. This HOWTO explains how to use the Linux version of Euphoria with Apache version 2.

Various methods

Presented are two methods of accomplishing enabling Euphoria CGI support on Apache2, there are no doubt other methods.

ScriptAlias method

Prerequisites

  • A working installation of Euphoria (/usr/local/euphoria is assumed)
  • A working installation of Apache2
  • Root access to your server (ie total control).

Method

1. Make sure that mod_actions is loaded in your installation of Apache. On Debian the relevant information is:

look under /etc/apache2/mods-enabled for actions.load, eg

myhost:~# ls -l /etc/apache2/mods-enabled/ 
total 0 
lrwxrwxrwx 1 root root 30 Jul 25 14:57 actions.load -> '''../mods-available/actions.load''' 
lrwxrwxrwx 1 root root 26 Oct 7 2003 cgi.load -> ../mods-available/cgi.load 
lrwxrwxrwx 1 root root 30 Apr 11 2004 deflate.load -> ../mods-available/deflate.load 
lrwxrwxrwx 1 root root 30 Oct 28 2003 include.load -> ../mods-available/include.load 
lrwxrwxrwx 1 root root 27 Apr 11 2004 perl.load -> ../mods-available/perl.load 
lrwxrwxrwx 1 root root 30 Oct 20 2004 rewrite.load -> ../mods-available/rewrite.load 
lrwxrwxrwx 1 root root 26 Sep 15 2004 ssl.load -> ../mods-available/ssl.load 

If you do not see actions.load you have to enable it, thus:

myhost:~# cd /etc/apache2/mods-enabled 
myhost:/etc/apache2/mods-enabled# ln -s ../mods-available/actions.load 

RESTART APACHE (Debian: /etc/init.d/apache2 restart)

2. Configure Apache to run .exu type files. The method here is to use a wrapper script to run .exu files using the Actions module.

This assumes the following, YMMV.

  • cgi-bin is /usr/local/cgi-bin
  • exu is at /usr/local/euphoria/bin/exu
  • Simple server setup, no virtual hosts.

2a. Apache configuration Edit /etc/apache2/apache2.conf and look for the ScriptAlias directive defining your cgi-bin directory. This should have an AddHandler directive nearby which defines what CGI script extension are allowed on your system, otherwise find this AddHandler directive, ie:

ScriptAlias /cgi-bin/ /usr/lib/cgi-bin 
AddHandler cgi-script .cgi .pl 
Add after these lines:

AddHandler exu-file .exu 
Action exu-file /cgi-bin/runexu.cgi 
(You can add .ex to AddHandler as well, eg AddHandler exu-file .exu .ex)

2b. Create /cgi-bin/runexu.cgi This is a simple example, you may want to create a more elaborate wrapper, maybe in a shebanged Euphoria program itself. This example uses the bash shell.

runexu.cgi goes in the location identified by the ScriptAlias directive above. eg /usr/lib/cgi-bin/runexu.cgi

#!/bin/sh 
#runexu.cgi - wrapper to run a euphoria program without the need for #! 
 
# Naturally, use the path to YOUR exu on your system 
/usr/local/euphoria/bin/exu $PATH_TRANSLATED 
# END of runexu.cgi  

RESTART APACHE to get the Action directive to take effect.

3. Test setup You can use this Euphoria program to test whether this works. Create the file as test.exu in your cgi-bin directory:

Test
-- test program for euphoria cgi 
 
-- comment/uncomment the following to test the EUINC variable 
-- include misc.e   -- or whatever 
 
sequence cmd 
 
-- if val is a string, return it, otherwise "Undefined" 
function test_val(object val) 
    if atom(val) then 
        return "Undefined" 
    elsif object(val) then 
        for i = 1 to length(val) do 
            if not atom(val[i]) then 
                return "Invalid string sequence" 
            end if 
        end for 
        return val 
    else 
        return "Invalid type for string" 
    end if 
    return "foozle" -- never reached 
end function 
 
 
procedure env_dump(sequence val) 
     printf(1, "%s: %s\n", {val, test_val(getenv(val))} ) 
end procedure 
 
puts(1, "Content-Type: text/plain\n\n") 
puts(1, "Hello!\n\n") 
puts(1, "COMMAND LINE\n============\n\n") 
 
cmd = command_line() 
for i = 1 to length(cmd) do 
    printf(1, "%d: %s\n", {i, cmd[i]} ) 
end for 
 
puts(1, "\n\nREMOTE INFO\n===========\n") 
 
env_dump("REMOTE_IDENT") 
env_dump("REMOTE_USER") 
env_dump("REMOTE_HOST") 
env_dump("REMOTE_ADDR") 
 
puts(1, "\n\nSERVER INFO\n===========\n") 
env_dump("SERVER_SOFTWARE") 
env_dump("SERVER_NAME") 
env_dump("GATEWAY_INTERFACE") 
env_dump("SERVER_PROTOCOL") 
env_dump("SERVER_PORT") 
env_dump("REQUEST_METHOD") 
env_dump("PATH_INFO") 
env_dump("PATH_TRANSLATED") 
env_dump("SCRIPT_NAME") 
env_dump("QUERY_STRING") 
env_dump("AUTH_TYPE") 
env_dump("CONTENT_TYPE") 
env_dump("CONTENT_LENGTH") 
 
puts(1, "\n\nBROWSER INFO\n=============\n") 
env_dump("HTTP_ACCEPT") 
env_dump("HTTP_USER_AGENT") 

Open the URL http://yourserver.com/cgi-bin/test.exu and you should get something like:

Hello! 
 
COMMAND LINE 
============ 
 
1: /usr/local/euphoria/bin/exu 
2: /usr/lib/cgi-bin/test.exu 
 
REMOTE INFO 
=========== 
REMOTE_IDENT: Undefined 
REMOTE_USER: Undefined 
REMOTE_HOST: Undefined 
REMOTE_ADDR: XXX.XXX.XXX.XXX 
 
 
SERVER INFO 
=========== 
SERVER_SOFTWARE: Apache/2.0.47 (Debian GNU/Linux) mod_perl/1.99_13 Perl/v5.8.7 PHP/5.0.2 mod_ssl/2.0.47 OpenSSL/0.9.7b 
SERVER_NAME: yourserver.com 
GATEWAY_INTERFACE: CGI/1.1 
SERVER_PROTOCOL: HTTP/1.1 
SERVER_PORT: 80 
REQUEST_METHOD: GET 
PATH_INFO: /cgi-bin/test.exu 
PATH_TRANSLATED: /usr/lib/cgi-bin/test.exu 
SCRIPT_NAME: /cgi-bin/runexu.cgi 
QUERY_STRING: test%20query%20string 
AUTH_TYPE: Undefined 
CONTENT_TYPE: Undefined 
CONTENT_LENGTH: Undefined 
 
 
BROWSER INFO 
============= 
HTTP_ACCEPT: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/x-shockwave-flash, application/x-gsarcade-launch, application/vnd.ms-powerpoint, application/vnd.ms-excel, application/msword, */* 
HTTP_USER_AGENT: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 2.0.40607; .NET CLR 1.1.4322) 

Caveats

Note that SCRIPT_NAME is the name of the wrapper not your script at all. You need to use PATH_TRANSLATED to get the name of your script.

runexu.cgi should be secure as it can't be supplied with a command line from the web browser, but you should look into this for yourself and never trust anyone else's opinion about security.

Hosted environment

Getting the interpreter to work on a hosted environment can be tricky. Presented below is a tested method on a server running Linux and Apache2 (a cpanel based system). This is only a guideline, as your hosted account may be behave differently or have different restrictions.

This method relies on a shebang line in your Euphoria code to help run the interpreter. Euphoria supports this method by ignoring the shebang line when it is irrelevant. The shebang line uses a Perl interpreter to run the Euphoria script.

Overview

The following outline may help you diagnose problems if following this method does not work.

  • The Euphoria script is loaded by Apache, and being in the cgi-bin directory or associated with a cgi-script handler will look for the shebang line in the Euphoria script.
  • It will then call this script with the standard Common Gateway Interface environment variables set, eg REMOTE_ADDR, SCRIPT_FILENAME, etc.
  • The runexu script will use the SCRIPT_FILENAME variable to launch exu with the path to your script as an argument.
  • The runexu script captures STDOUT (the output) of your script and passes this straight to the web browser.

Method

  • Create a folder '''outside''' your html document root folder, eg called 'bin'.
  • Upload the unix exectuables (I think only exu is needed). You probably need to use the uncompressed versions.
  • Make sure the Euphoria executables are executable, use whatever method you have available (eg FTP, or cpanel filemanager) to chmod 755 the files.
  • Make another folder somewhere '''outside''' your document root for the Euphoria include files you will be using, eg 'include'
  • Upload the standard include files to that location. This is also a good place to keep other user contributed includes.
  • Create the following perl script in the 'bin' directory:

#!/usr/bin/perl 
# 
### Perl wrapper script for running the Euphoria interpreter www.rapidephoria.com 
##  use #!/path/to/runexu as the first line of your Euphoria script 
# 
 
use CGI::Carp qw(fatalsToBrowser); # optional 
 
# Tell this script where things are 
$exu_path = "/path/to/bin/exu"; 
$euinc_path = "/path/to/include"; 
 
# This relies on /bin/env being available (generally is) 
$cmdline = "/bin/env EUINC=$euinc_path $exu_path $ENV{'SCRIPT_FILENAME'}"; 
 
# Capture STDOUT from $cmdline 
$test = `$cmdline`; 
 
# Ouput raw STDOUT from Euphoria program 
print $test; 
 
### Debug code.  Use this to track down problems, eg SCRIPT_FILENAME etc 
##  Comment out the above two statements ($test=.. and print..) and uncomment the following. 
# 
#print "Content-Type: text/plain\n\n"; 
# 
#foreach $key (keys %ENV) { 
#   print "$key: $ENV{$key}\n"; 
#} 

  • Make sure runexu is executable (you may have to make sure it is not executable by group or others as well)
  • Use the above test program to test your setup, but you will have to add as the first line #!/path/to/runexu

Possible problems

  • It is possible that /bin/env is not available. In that case modify $cmdline so that it just reads $exu_path $ENV{'SCRIPT_FILENAME'}. You won't be able to rely on shared include files and will have to put the include file in the same folder as your script (UNTESTED: should they be in the 'bin' folder?)
  • You might not be able to upload executables to your host.
  • I used cpanel to set a handler for .exu files as 'cgi-script'. If you are unable to do this then you might have to name your files .cgi. In general though, any file in a ScriptAlias directory can be run (eg in the cgi-bin directory).

Method comments

  • If you are familiar with Perl you might be able to use exec instead of the backticks. This will replace the Perl interpreter with the Euphoria interpreter and should pass it things like the environment, STDOUT, STDERR etc. This means that the output won't be buffered by the perl script resulting in slightly snappier execution.
  • It is unknown what will happen with arguments to the script. Anything after a ? should be in QUERY_STRING, but how POST data will work is unknown at this stage.

Search



Quick Links

User menu

Not signed in.

Misc Menu