Making a Sinatra Web Application Work as a CGI

Here’s how I got a Sinatra version 1.0 web application to work via CGI using Rack version 1.1.0 behind an Apache httpd version 2.2.15 web server on Fedora 13 Linux. There are many ways to get a client request passed through to your application with httpd — it has a very flexible configuration — but the following is what I did, and should give you the general idea.

First, use the following command to check that httpd has the mod_rewrite module loaded:

$ apachectl -t -D DUMP_MODULES | grep rewrite_module
Syntax OK
  rewrite_module (shared)

Next, edit the relevant httpd configuration file (see the Apache documentation for your system), which for me was the /etc/httpd/conf/httpd.conf file, and add the following configuration items, where [path] is the absolute path to the directory of your Sinatra application, and [url] is the URL you want users to access your application with:

RewriteEngine On
RewriteRule ^[url].*$ [path]/dispatch.cgi [QSA,L]

<Directory [path]>
    AddHandler cgi-script .cgi
    Options +ExecCGI
</Directory>

You’ll see that the rewrite rule sends everything to a CGI file named dispatch.cgi along with any query strings. That’s the file that will kick start our application. So, let’s create that file and add the following lines to it:

#!/usr/local/bin/ruby

require "rubygems"
require "rack"
require File.join(File::dirname(__FILE__), "testapp.rb")

Rack::Handler::CGI.run(TestApp)

You can see that my ruby executable is in /usr/local/bin, which you can change as necessary. You can also see that I named my application’s main Sinatra::Base class TestApp, and that I named the file holding the TestApp class testapp.rb. Now, let’s create the testapp.rb file, and add the following lines:

require 'rubygems'
require 'sinatra'

class TestApp < Sinatra::Base
  get '' do
    "Hello from Sinatra!"
  end
end

Note that according to the Sinatra documentation, logging is “… disabled by default in Sinatra::Base subclasses” unlike when you run the application with something like ruby testapp.rb. In any event, you should be able to start creating your Sinatra application within TestApp now. Happy coding!

Making Ruby work with SELinux on Fedora

The version of Ruby that comes with Fedora 12 is:

$ yum info ruby
[...]
Version    : 1.8.6.383
[...]

I wanted to try some things with the latest version of Ruby which is 1.9.1-p376. So, I compiled it and installed it into /usr/local/ruby-1.9.1-p376 (which may not match the LFS — I’m not sure — but is my standard practice). However, since Fedora 12 ships with SELinux enabled, the Ruby shared libraries wouldn’t work (e.g. openssl.so). SELinux doesn’t like that they are relocatable shared libraries. To make SELinux happy, modified the persistent database of settings like this (Update: a “-a” flag may be necessary instead of a “-m” flag, depending on your situation):

$ sudo find /usr/local/ruby-1.9.1-p376/lib/ruby/1.9.1/i686-linux -name '*.so' -exec semanage fcontext -m -t textrel_shlib_t {} \;

…and then applied those settings to the files like this:

$ sudo find /usr/local/ruby-1.9.1-p376/lib/ruby/1.9.1/i686-linux -name '*.so' -exec restorecon -v {} \;

There may be a faster way of doing this, but what I did works:

$ ls -Z /usr/local/ruby-1.9.1-p376/lib/ruby/1.9.1/i686-linux/openssl.so
-rwxr-xr-x. root root system_u:object_r:textrel_shlib_t:s0 /usr/local/ruby-1.9.1-p376/lib/ruby/1.9.1/i686-linux/openssl.so

Whence Array#each_slice()?

I just ran into what looks like a documentation problem in Ruby 1.8.6 (maybe other versions). If you want to use:

Array#each_slice()

…you’ll need to:

require "enumerator"

…beforehand. However, the Ruby documentation doesn’t seem to mention anything about it.