plainblack.com
Username Password
search
Bookmark and Share

URL Handlers

WebGUI URL handlers serve the same purpose as a mod_perl handler in Apache. They allow you to attach some arbitrary functionality at a specific URL. For example, you can set up some code to apply WebGUI privileges to a filesystem folder full of files, or you can write a handler that will process SOAP requests using WebGUI's data, without going through WebGUI's normal request cycle.

 

You might think to yourself that since WebGUI is written in mod_perl, is itself a mod_perl handler, and URL handlers are the same as mod_perl handlers, why have them at all? Technically, there's no reason you couldn't write a mod_perl handler in place of a WebGUI URL handler, but as with every part of the WebGUI API, URL handlers set up a mechanism that is a bit more uniform and easy to use for WebGUI tasks. URL handlers give you access to the Apache request cycle, server config, and the WebGUI config, but it hides some of the rudimentary setup that you'd normally have to do so that you can get down to the business of writing your specific functionality. URL handlers also allow you to use Perl-based regular expressions to match URL's rather than the somewhat more obtuse POSIX regular expressions that Apache uses. If you'd prefer to write a mod_perl handler, there's no reason you can't; URL handlers simply give you one additional way to achieve your goals.

 

The Request Cycle

The following diagram depicts where URL handlers fit into the WebGUI request cycle.

 

 

As you can see, the URL handlers are the very first step in the the request cycle.

 

When to Use

There are three main reasons that you'd choose to write a URL handler. You may want to write an application outside of the Asset API. Maybe you don't want to deal with versioning, or you don't wish to conform to the Asset API. Perhaps you want to avoid the asset API because you want to avoid the memory or processing overhead of assets. Or, you may wish to avoid assets because your application is a singleton and there's no reason to ever deploy it to more than one URL.

 

Another reason to write a URL handler is to integrate an existing application with WebGUI. With a URL handler, you can write the code glue that will bind WebGUI privileges, templates, workflow, or other mechanisms with existing code or applications. This works not only with Perl applications, but also any application with a command line, C, or SOAP API, that you can write a Perl wrapper around.

 

You may also want to write a URL handler to provide privileges or other processing of external resources, such as a directory of files. Say you have a folder full of PDF's containing financial reports. You only want the people in your accounting department to be able to access those files, and it just so happens that you have a WebGUI group called “Accounting” which includes all the members of your accounting department. Using a URL handler you can place a filter on the folder so that only the accounting department can view those files. If this sounds interesting, stay tuned, because this example will be built later in this chapter.

 

Configuration

URL handlers are configured by adding a line to your WebGUI config file. The default configuration looks like this:

 

"urlHandlers" : [

{ "^/extras" : "WebGUI::URL::PassThru" },

{ "^/uploads/dictionaries" : "WebGUI::URL::Unauthorized" },

{ "^/uploads" : "WebGUI::URL::Uploads" },

{ "^/\\*give-credit-where-credit-is-due\\*$" : "WebGUI::URL::Credits" },

{ "^/abcdefghijklmnopqrstuvwxyz$" : "WebGUI::URL::Snoop" },

{ ".*" : "WebGUI::URL::Content" }

],



 

To add a new URL handler that you've written, simply add a line to the existing configuration. Each line consists of a regular expression pattern to match against, and the class name of the URL handler to use when that pattern is matched. Note that order is important here. If a URL handler that comes before yours has a pattern that matches your URL, then it will handle the URL you want your handler to handle. For the example of the accounting department file folder, the line might look like this:

 

{“^/sales-reports/” : “WebGUI::URL::SalesReports”},

 

After making any config file change, don't forget to restart your mod_perl server.

 

Examples

The following examples should get you started in writing your own URL handlers.

 

Hello World

Here's how you'd write a Hello World URL handler.

 

package WebGUI::URL::HelloWorld;



use strict;

use Apache2::Const -compile => qw(OK DECLINED);



sub handler {

my ($request, $server, $config) = @_;

$request->push_handlers(PerlAccessHandler => sub {

my $session = WebGUI::Session->open($server->dir_config('WebguiRoot'),

$config->getFilename, $request, $server);

$session->http->sendHeader;

$session->output->print(“Hello World”);

return Apache2::Const::OK;

});

return Apache2::Const::OK;

}

 

From the Core

WebGUI comes with many URL handlers, so when looking at how to build your own, it may be helpful to have a look at those that have already been created.

 

For example, WebGUI has a handler called PassThru, which does nothing more than tell Apache that WebGUI doesn't want to handle this URL itself. When Apache sees this, it takes the request back from WebGUI and continues its own processing.

 

There's another called WebGUI::URL::Content, which itself is just another plug-in mechanism. Instead of handling content based upon any specific URL, it hands off processing to another set of plugins which processes not only the URL, but the entire request to see if they can handle it. Assets are processed via this mechanism. See the chapter on Content Handlers for more information.

 

WebGUI also comes with a URL handler called WebGUI::URL::Uploads, which determines whether a particular user has permissions to access something in the /uploads folder. If the file has no privileges, or allows for people in the “Visitors” or “Everyone” group to access the file, then the file is served. Otherwise, a permission denied message is sent to the user.

 

Have a look at the WebGUI::URL::Uploads handler in detail. URL handlers are a standard Perl Module like everything else in WebGUI, so it starts out with the package and use declarations:

 

package WebGUI::URL::Uploads;

use strict;

use Apache2::Const -compile => qw(OK DECLINED NOT_FOUND AUTH_REQUIRED);

use WebGUI::Session;

 

In this example, a number of Apache constants that you want to use are declared. These constants allow you to control how Apache serves the file. You'll see them used as you move further into the handler.

 

Now, declare a single subroutine called “handler”; the name “handler” is required.

 

sub handler {

my ($request, $server, $config) = @_;

 

All URL handlers get the Apache $request, and Apache $server objects passed into them, along with a reference to the WebGUI config file for this host.

 

Next, declare what subroutine should handle privileges:

 

$request->push_handlers(PerlAccessHandler => sub { ... });

 

The reason you do this step, rather than just running the code to determine privileges, is because WebGUI URL handlers are actually called during the PerlInitHandler phase. This allows WebGUI URL handlers to control any aspect of the request that you want. Since the uploads handler is dealing specifically with permissions, it makes sense that it adds a PerlAccessHandler and not a PerlResponseHandler. After all, you want Apache to do what it does best: serve up the files after you determine if the user has the right to access it.

 

Take a look at what that subroutine looks like:

 

if (-e $request->filename) {

...

}

else {

return Apache2::Const::NOT_FOUND;

}

 

First, check to see that the file requested exists. If not, there's no point in checking privileges on it, so you can return a NOT_FOUND constant. Then, see if the folder containing the file has a .wgaccess file. If not, it's assumed that the file is accessible by everyone, and you can return the constant OK, telling Apache it can send the file.

 

my $path = $request->filename;

$path =~ s/^(\/.*\/).*$/$1/;

if (-e $path.".wgaccess") {

...

}

return Apache2::Const::OK;

 

Then, read in the contents of the .wgaccess file to see what privileges it says the file should have. If the group to view is 7 (the “Everyone” group) or 1 (the “Visitors” group), then again let Apache serve the file.

 

my $fileContents;

open(my $FILE, "<" ,$path.".wgaccess");

while (my $line = <$FILE>) {

$fileContents .= $line;

}

close($FILE);

my @privs = split("\n", $fileContents);

unless ($privs[1] eq "7" || $privs[1] eq "1") {

...

}

 

If the groups are anything else, then you have no choice but to instantiate a WebGUI Session and check to see if the user is a member of the appropriate group.

 

my $session = WebGUI::Session->open($server->dir_config('WebguiRoot'),

$config->getFilename, $request, $server);

my $hasPrivs = ($session->var->get("userId") eq $privs[0]

|| $session->user->isInGroup($privs[1])

|| $session->user->isInGroup($privs[2]));

$session->close();

unless ($hasPrivs) {

return Apache2::Const::AUTH_REQUIRED;

}

 

If the user doesn't pass the check, you return AUTH_REQUIRED so Apache can display the appropriate error message.

 

Finally, return the constant OK to Apache. This tells Apache that you are done with the Init phase. If you ultimately decide not to handle the Init phase you could return Apache2::Const::DECLINED instead.

 

return Apache2::Const::OK;

 

Custom Privileges

Let's say your boss tells you that you need to protect a folder full of PDF sales reports so that only people in the accounting and sales departments can view them. Being the enterprising developer that you are, you know that a list of who's in each of these departments is already maintained in your WebGUI intranet, so why reinvent the wheel, just use those lists.

 

Start out by building a base package:

 

package WebGUI::URL::SalesReports;

use strict;

use Apache2::Const -compile => qw(OK AUTH_REQUIRED);

use WebGUI::Session;



sub handler {

my ($request, $server, $config) = @_;

$request->push_handlers(PerlAccessHandler => sub {

... our code will go here ...

});

return Apache2::Const::DECLINED;

}



1;

 

Then, flesh out the handler() subroutine with the logic you need. Start with the group ID's for the groups that can access the files:

 

my $sales = “XXXXXXXXXXXXXXXXXXXXXX”;

my $accounting = “YYYYYYYYYYYYYYYYYYYYYY”;

 

Instantiate a session:

 

my $session = WebGUI::Session->open($server->dir_config('WebguiRoot'),

$config->getFilename, $request, $server);

 

The session already knows who the user is, so you can ask it for the user:

 

my $user = $session->user;

 

Then add your conditional statement for returning the file based upon user privileges:

 

if ($user->isInGroup($sales) || $user->isInGroup($accounting)) {

return Apache2::Const::OK;

}

else {

return Apache2::Const::AUTH_REQUIRED;

}

 

With just those few lines of code, you're done! See the section above for adding your handler to your config file. Here's the final code:

 

package WebGUI::URL::SalesReports;

use strict;

use Apache2::Const -compile => qw(OK AUTH_REQUIRED);

use WebGUI::Session;



sub handler {

my ($request, $server, $config) = @_;

$request->push_handlers(PerlAccessHandler => sub {

my $sales = “XXXXXXXXXXXXXXXXXXXXXX”;

my $accounting = “YYYYYYYYYYYYYYYYYYYYYY”;

my $session = WebGUI::Session->open($server->dir_config('WebguiRoot'),

$config->getFilename, $request, $server);

my $user = $session->user;

if ($user->isInGroup($sales) || $user->isInGroup($accounting)) {

return Apache2::Const::OK;

}

else {

return Apache2::Const::AUTH_REQUIRED;

}

});

return Apache2::Const::DECLINED;

}



1;

Keywords: apache API config file configuration permissions privileges request cycle

Search | Most Popular | Recent Changes | Wiki Home
© 2018 Plain Black Corporation | All Rights Reserved