Thursday, February 22, 2007

Better APEX urls

I was cleaning up a webserver and found this code I wrote a few years ago to help make HTMLDB now Application Express entry points nicer. Hopefully everyone knows Application Express and uses it everyday, if not you should go sign up and kick the tires at apex.oracle.com. Prior to working on SQL Developer, I did some work in Application Express and built some internal systems with Carl and others. One issue I had was an easy way to map a url to an application in order to make the entry point nice and easy like http://myapp.mycompany.com which really point to http://apex.oracle.com/pls/otn/f?p=MYAPP:MYPAGE

Now you may think just a simple Apache re-write would solve this and you'd be correct but I had to add multiple re-write and didn't want to bounce Apache in order to add new ones or change existing ones. So the answer was in mod_perl. What I did was make a mapping file as follows:


mycompany.com;/pls/apex/f?p=3701:1
internal.mycompany.com;/pls/apex/f?p=3701:1
yourcompany.com;/pls/apex/f?p=111:1
/path;/pls/apex/f?p=1:1

You can see from the mapping file that it's fairly flexible. You can map /myapp or myapp.mycompany.com. The best part about this solution is that the perl code below re-reads the file every 5 minutes in case you added more mappings and no bounce of apache.

These 2 lines will have to be placed early in the httpd.conf so it can have the opportunity to look at all the incoming request. Here's the 2 lines needed to change in the httpd.conf file

PerlModule HTMLDB::VirtualServer
PerlTransHandler HTMLDB::VirtualServer

This code will have to be adjusted for location of the config file and maybe you'll adjust the reloading of the file but it should mostly work. This file will have to be placed into the perl library path with something like this:

SetEnv PERL5LIB  "/mypath/to/the/path"

package HTMLDB::VirtualServer;
#
#
# Apache httpd.conf entry
# PerlModule HTMLDB::VirtualServer
# PerlTransHandler HTMLDB::VirtualServer
#
#
# Sample config file
#mycompany.com;/pls/apex/f?p=3701:1
#internal.mycompany.com;/pls/apex/f?p=3701:1
#yourcompany.com;/pls/apex/f?p=111:1
#/path;/pls/apex/f?p=1:1
#
#
use Apache::Constants qw(REDIRECT DECLINED);
use strict;
# path to config file
my $configfile = "/export/home/oracle/HTMLDB/htmldbvirtual.conf";
my $debug = 0;
my $lastLoad;
my %names = ();


# simple routine to see what's going on
sub logMe{
my $logLine = shift;
if ( $debug eq 1 ) {
  # log file if $debug = 1
     open(L,'>>/tmp/htmldbvirtual.log');
print L $logLine;
close L;
}
}

# load the config file
sub loadConfigFile{
my $now = time;apex/home
# cache the config for 5 minutes then reload
if ( ( $now - $lastLoad ) > 600 ) {
open CONF,$configfile;
my $name;
my $uri;
while (){
chomp;
($name,$uri) = split /;/;
$names{$name} = $uri;
}
$lastLoad = time;
if ( $debug) {
while ( my ($key, $value) = each(%names) ) { logMe( "L:$key => $value\n"); }
}
}
%names;
}


sub handler {
my $r = shift;
my %names = loadConfigFile();
logMe("Request:" . $r->uri . "\n");

if ( $r->uri eq "/"
|| $r->uri eq "/index.html"
|| ( length($names{$r->uri}) > 0 || length($names{$r->uri."/index.html"} ) > 0 ) ) {

# grab vars for use.
my $s = $r->server();
my $hostname = $r->hostname();
my %args = $r->args;
my $base = $s->port() == 443 ? "https://" : "http://";

if ( length($hostname) > 0 ) {
$base = $base . $hostname;
} else {
$base = $base . $s->server_hostname();
}

if ( $s->port() != 80 && $s->port() != 443 ) {
$base = $base . ":" . $s->port();
}
logMe($base . "\n");

my $key = length($names{$r->uri} ) > 0 ? $r->uri : $hostname ;

if ( length($names{$key} ) > 0
&& ! $args {"p"} ) {
#$r->header_out(Location => $base . $hostname );
$r->header_out(Location => $base . $names{$key} );

logMe("HTMLDB::VirtualServer:". $base . $names{$key} . "\n");
return REDIRECT; # means we did a redirect
}
}
return DECLINED; # means we did not handle the request
}
1;

2 comments:

Anonymous said...

my $configfile = "/export/home/oracle/HTMLDB/htmldbvirtual.conf";

where i have to put this file on a windows system?
and the content would be:
/path;/pls/apex/f?p=1:1
?

Unknown said...

I've never tried on windows but you should be able to change that path to anyplace that's accessible to the user running the apache. Something like "C:\myconf.conf" would be fine. Perl will just do a normal file open on that file. Also you'll need to change the path of the log file from the example '/tmp/htmldbvirtual.log'.

-kris