Eric Radman : a Journal

Ruby-CGI Tips

Stop Error Suppression

Producing a backtrace from a script can be a security hazard, but at least in the development stage it's very nice to see the error that the Ruby interpreter spits out. This can be done by wrapping the entire script in a block and then checking for exceptions. This ensures that the return code from the interpreter is always true. So in general this is the structure of a CGI that I employ:

#!/usr/local/bin/ruby
begin
    require "cgi"
    cgi = CGI.new
    puts "Content-type: text/html"
    puts
    puts "<html> ... </html>"
rescue Exception
    print "Content-Type: text/plain\r\n\r\n"
    puts $!.inspect, $!.backtrace
end

(In practice I don't actually indent this block.)

Use eRuby

It's great:

#!/usr/local/bin/ruby
require "eruby"
import
puts "Content-type: text/html"
puts
title = "My first page"
ERuby::import('template.rhtml')

No anything inside <% ... %> in template.rhtml is evaluated with the environment that called it.

Alias cgi-bin

I often keep CGI's in the cgi-bin folder, but I don't always deploy it that way. This what I do in Apache:

ScriptAlias /app/ "/home/eradman/public_html/cgi-bin/"

Or in thttpd a more general pattern:

cgipat=**.cgi|/cgi-bin/*|/app/*

Also in Apache there's a nice option that can be used in any virtual host entry that declares anything with executable permissions to be treated as a CGI.

XBitHack on

Use [sym]links

Hard links are slightly faster, but some versioning utilities (CVS) break the link by creating a new copy of the file. So sym-links provide a simple way to make simple URLs without complex rewrite rules. Just make sure Apache is told to use them:

Options FollowSymLinks

Now my directory listing might look something like this:

$ ls -ali | grep lrwx
2131786 lrwxr-xr-x  1 tei  users      11 Mar 24  2006 customer -> customer.rb
2131628 lrwxr-xr-x  1 tei  users      13 Apr 21  2006 delinquent -> delinquent.rb
2136943 lrwxr-xr-x  1 tei  users      11 Apr 28  2006 deposits -> deposits.rb
2131822 lrwxr-xr-x  1 tei  users       7 Mar 27  2006 main -> main.rb
2138537 lrwxr-xr-x  1 tei  users      11 Jul 14 11:27 orphaned -> orphaned.rb
2135727 lrwxr-xr-x  1 tei  users      11 Apr 26  2006 payments -> payments.rb
2131800 lrwxr-xr-x  1 tei  users       7 Mar 24  2006 user -> user.rb

Rewrite URL's

My favorite use of mod_rewrite is to pass part of a URL as an argument to a script:

RewriteEngine on
RewriteRule ^(.*)article/(.*)$  $1cgi-bin/article.rb?id=$2

Now any characters following article/ will be passed to article.rb's id parameter.

CGI Indexes

You may not realize that the Apache DirectoryIndex will accept pathnames as well as filenames, so you can use an absolute URL path to rest for a default script:

DirectoryIndex index.html /cgi-bin/index.rb

This is cool because it's a URL, not a file system path

Redirecting Output

If you need to capture the output of ERuby or the functions of another library you can assign a file handle to $stdout.

saved_stdout = $stdout
begin
    output = File.open("report.lout","w")
    $stdout = output
    ERuby::import('report.rl')
    output.close
end
$stdout = saved_stdout

Now when ERuby::import is called print calls are written to the open file. Always save the original value of $stdout so that you can restore it after the code block is finished.

$ Mon Jan 26 19:10:59 -0500 2009 $