Sign In/My Account | View Cart  
advertisement


Listen Print Discuss

Introducing mod_parrot
by Jeff Horwitz | Pages: 1, 2

Installing mod_parrot

You can download mod_parrot from the mod_parrot home page. Additionally, you'll need the following prerequisites (as of version 0.1):

  • Parrot 0.1.1 (Poicephalus)
  • Apache 2.0.50 or later
  • Perl 5.6.0 or later (for configuration only)
  • Apache::Test 1.13 or later (for the test suite)

Once you have all the prerequisite software, run the Configure.pl script. The arguments to this script will most certainly change in future releases, but for now, there are only two arguments:

  • --parrot-build-dir=path-to-parrot-source, the path to the top-level Parrot directory
  • --apxs=path-to-apxs, the path to Apache's apxs script, usually found in the bin directory under the Apache installation directory
$ perl Configure.pl --parrot-build-dir=../parrot \
  --apxs=/usr/local/apache2/bin/apxs

Generating Makefile...done.
Creating testing infrastructure...done.

Type 'make' to build mod_parrot.

When configuration completes, type make to build mod_parrot, then make test to run the tests. To install, become root and type make install. This will install the mod_parrot module into your Apache installation and activate the module in httpd.conf.

Writing a mod_parrot Handler

While there are currently no languages targeted to Parrot that have the object support to use mod_parrot (though Parakeet in the Parrot source looks promising), we can still write Apache handlers. In what language? In Parrot, of course! Well, actually, PIR. Here's a simple content handler that displays "Hello World," or if you pass it an query string in the URL, "Hello name," where name is the string you pass.

# this namespace is used to identify the handler
.namespace [ 'HelloWorld' ]

# the actual handler
.sub _handler
    # our Apache::RequestRec object
    .local pmc r

    # this will contain Apache constants
    .local pmc ap_constants

    # instantiate the Apache::RequestRec object
    find_type $I0, 'Apache::RequestRec'
    r = new $I0

    # who should we say hello to?
    $S0 = r.'args'( )
    $I0 = length $S0
    if $I0 > 0 goto say_hello
    $S0 = 'world'

say_hello:
    # call the puts method to send some output
    $S1 = 'Hello ' . $S0
    r.'puts'( $S1 )

    # tell Apache that we're finished with this phase
    find_global ap_constants, 'Apache::Constants', 'ap_constants'
    $I0 = ap_constants['OK']
    .pcc_begin_return
        .return $I0
    .pcc_end_return
.end

If you are at all familiar with mod_perl or the Apache API, this should look familiar to you, even if you don't know any Parrot. Let's go through the code to see how it works. Because this is not an article about Parrot itself, I'll glaze over the syntax and concentrate on what the code actually does.

The first line of code in the handler declares the namespace in which this handler exists. In this case, it is HelloWorld. This is important because namespaces differentiate one handler from another in httpd.conf.

Next comes the actual handler subroutine, which should always be named _handler. The first thing the subroutine does is to declare some locally scoped "variables." These are actually registers in Parrot, but PIR can abstract them with named variables as it were a higher level language. And ap_constants, a hash that will give access to Apache constants including OK and DECLINED, come next. Both are PMCs, or Parrot Magic Cookie, a special data type that implements the more complex data types of higher-level languages such as Perl or Python.

The code now checks for a query string using the args method of the Apache::RequestRec object and, if one exists, assigns it to the temporary string register $S0. If there is no query string, $S0 will contain world. Next, the code creates the output string, instantiates the Apache::RequestRec object, and calls the puts method to output "Hello World" or "Hello name". By default, the content type is text/html, so there's no need to set it here.

This is the end of the handler, so it's time to tell Apache that we're done and that it no longer needs to handle this phase of the request. This requires returning the Apache constant OK from the ap_constants hash in the Apache::Constants namespace.

To compile the handler into Parrot bytecode, save it in a file with a .imc extension (IMC is short for Intermediate Compiler). Then, compile it into Parrot bytecode (PBC) as follows (this step will be automatic in a future release):

$ parrot -o HelloWorld.pbc HelloWorld.imc

Configuring Apache to Use A Handler

Writing the handler was the hard part. Configuring Apache to use it is easy. The first thing to do is to initialize mod_parrot and load some bytecode libraries:

# mod_parrot initialization
ParrotInit /path/to/lib/ModParrot/init.pbc
ParrotLoad /path/to/lib/Apache/RequestRec.pbc
ParrotLoad /path/to/lib/Apache/Constants.pbc

# our handler
ParrotLoad /path/to/HelloWorld.pbc

ParrotInit tells mod_parrot where to find its initialization bytecode. A future release will probably handle this automatically, but for now explicitly set the path in httpd.conf. ParrotLoad tells mod_parrot to load a bytecode file. In this case, it loads the code that implements the Apache::RequestRec object and the constants hash, as well as the bytecode for the new handler.

Next, Apache needs a location for the handler to, well, handle. How about the location /hello:

<Location /hello>
    SetHandler parrot-code
    ParrotHandler HelloWorld
</Location>

First, this sets the Apache handler for the location to parrot-code. This is the official name of the mod_parrot handler. Then it sets the actual Parrot handler, which, as discussed in the previous section, is the namespace of the handler subroutine, HelloWorld. That's it. Save the configuration, restart Apache, point your browser to http://yourserver/hello (replacing yourserver with the name of your server), and you should see the "Hello World" message. Add a query string to see the output change: http://yourserver/hello?Joe should produce "Hello Joe."

Writing an Authentication Handler

Apache handlers do more than just generate content, of course, and this applies to mod_parrot as well. Here's an example of using an authentication handler to protect a private directory. It will use the HTTP basic authentication scheme, but instead of using a standard password file, it will accept any username as long as the password is "squawk." Here's the handler PIR code:

# this namespace is used to identify the handler
.namespace [ 'TestAuthHandler']

# the actual handler
.sub _handler
    # our Apache::RequestRec object
    .local pmc r
    .local string pw
    .local int status

    # this will contain Apache constants
    .local pmc ap_constants
    find_global ap_constants, 'Apache::Constants', 'ap_constants'

    # instantiate the Apache::RequestRec object
    find_type $I0, 'Apache::RequestRec'
    r = new $I0

    # check the password, ignoring the username
    (status, pw) = r.'get_basic_auth_pw'( )
    if pw != 'squawk' goto auth_failure
    $I0 = ap_constants['OK']
    goto auth_return_status

# authentication failed
auth_failure:
    $I0 = ap_constants['HTTP_UNAUTHORIZED']
    goto auth_return_status

# return our status code
auth_return_status:
    .pcc_begin_return
        .return $I0
    .pcc_end_return
.end

Here is the corresponding configuration in httpd.conf. Instead of using SetHandler and ParrotHandler here, set ParrotAuthenHandler to the namespace of the authentication handler:

<Directory /usr/local/apache/htdocs/private>
	ParrotAuthenHandler TestAuthHandler
	AuthType Basic
	AuthName Private
	Require valid-user
</Directory>

Remembering Why We're Here

Note the low-level nature of the two handlers. There are no else clauses; goto statements appear throughout the subroutine; and return values must be assigned to registers before being used in another operation. You can plainly see that this is only one step above writing assembly here, but remember that you won't have to worry about writing code at this level--you'll write in a high-level language such as Perl 6, and it will eventually compile down to Parrot assembler. Looking forward, the corresponding Perl 6 code for the HelloWorld handler might look a lot like this (as with all things Perl 6, this is subject to change):

use Apache::Constants ':common';
use Apache::RequestRec;

sub handler(Apache::RequestRec $r)
{
    my ($status, $pw) = $r.get_basic_auth_pw();
    return ($pw eq 'squawk') ? OK : HTTP_UNAUTHORIZED;
}

Future Directions

mod_parrot is still in its infancy. It's quite functional, but there is still a lot of work to do before it can power any serious applications. At this point in development, the primary goal is to finish hooking into all phases of the Apache request lifecycle, including support for the relevant Apache API functions. Windows support will also become a priority as mod_parrot becomes more functional.

You may also wonder about CGI scripts. As of this writing, there is no support for running CGI scripts in mod_parrot. mod_perl has Apache::Registry to help CGI scripts run in a persistent environment, and mod_parrot will need a similar infrastructure.

However, the real fun will begin when we have a high level language that we can use to write handlers. If the timelines work out as I hope they will, mod_parrot will be fully functional before the formal release of Perl 6 or any other mainstream Parrot-based language. Because the Apache/Parrot layer will have already been written, this will save quite a bit of development time for mod_perl, PHP, and other similar projects.

If you'd like to read more about mod_parrot, or would like to help with the project, visit the mod_parrot home page.