package RDA::Web; # $Id: Web.pm,v 1.14 2009/01/13 16:46:12 mschenke Exp $ # ARCS: $Header: /u02/webapps/workbench/cvs/RDA_4/src/scripting/lib/RDA/Web.pm,v 1.14 2009/01/13 16:46:12 mschenke Exp $ # # Change History # 20090113 MSC Change the copyright notice. =head1 NAME RDA::Web - Package Used to Manage Web Access. =head1 SYNOPSIS require RDA::Web; =head1 DESCRIPTION The following method is available: =cut use strict; BEGIN { use Exporter; use File::Spec; use Socket; } # Define the global public variables use vars qw($VERSION); $VERSION = sprintf("%d.%02d", q$Revision: 1.14 $ =~ /(\d+)\.(\d+)/); # Define the global constants my $EOL = "\015\012"; my $TTL = "RDA Viewer"; my %tb_typ = ( bz2 => 'application/x-bzip2', css => 'text/css', gz => 'application/x-gzip', htm => 'text/html', html => 'text/html', tar => 'application/x-tar', tgz => 'application/x-gzip', txt => 'text/text', z => 'application/x-compress', zip => 'application/zip', ); # Report the module version number sub Version { $VERSION; } =head2 S This method starts a basic Web server to review the reports in the report directory structure. It uses basic authentication to restrict page access. If a password is not provided, then the Web server is not started. The user and password are displayed at server startup. The start page can be accessed using the following URL: http://:/display/ By default, port 8778 is used. You can specify an alternative port as an argument. =cut sub server { my $agt = shift; my ($acl, $cln, $dbg, $dft, $rpt, %tb_cln); # Initialisation $rpt = $agt->get_setting('RPT_DIRECTORY', 'output'); $dbg = $agt->get_setting('RDA_DEBUG'); $dft = $agt->get_setting('RPT_GROUP', 'RDA').'__start.htm'; $dft = lc($dft) unless $agt->get_setting('RDA_CASE', 1); # Treat the arguments my $prt = 8778; my $pwd = ''; foreach my $arg (@_) { if ($arg =~ m/\D/) { $pwd = $arg; } else { $prt = $arg; } } return 0 unless $pwd; $acl->{'rda'} = $pwd; # Start the service socket(SRV, PF_INET, SOCK_STREAM, getprotobyname('tcp')) || die "socket: $!"; setsockopt(SRV, SOL_SOCKET, SO_REUSEADDR, pack("l", 1)) || die "setsockopt: $!"; bind(SRV, sockaddr_in($prt, INADDR_ANY)) || die "bind: $!"; listen(SRV, SOMAXCONN) || die "listen: $!"; _dsp_msg("server started on port $prt: rda/$pwd"); # Treat the web requests while ($cln = accept(CLN, SRV)) { my ($adr, $htp, $nam, $req, $url); local $SIG{'PIPE'} = 'IGNORE'; # Get the client address if (exists($tb_cln{$cln})) { ($nam, $adr, $prt) = @{$tb_cln{$cln}}; } else { ($prt, $adr) = sockaddr_in($cln); $nam = gethostbyaddr($adr, AF_INET); $adr = inet_ntoa($adr); $nam = $adr unless defined($nam); $tb_cln{$cln} = [$nam, $adr, $prt]; } # Get the HTTP header $url = ''; $req = {}; binmode(CLN); while () { print "$$/Header: $_" if $dbg; s/[\n\r]+//; if (m#^([A-Z][A-Za-z\-]*):\s+(.*)$#) { $req->{$1} = $2; } elsif (m#^GET\s+(.*)\s+HTTP/(\d\.\d)$#) { ($url, $htp) = ($1, $2); } elsif (m#^$#) { last; } } _dsp_msg("Request from $nam [$adr] at port $prt:\n $url"); # Treat the request if (_need_authen($req, $acl)) { # Request an authentication print CLN "HTTP/1.0 401 Authentication required$EOL", "WWW-Authenticate: basic realm=\"RDA Viewer\"$EOL", "Content-Type: text/html; charset=UTF-8$EOL$EOL", "

$TTL

$EOL", "

HTTP Code 401: Authentication required

$EOL"; } elsif ($url =~ s#^/display/##) { my ($buf, $fil, $lgt, $suf, $typ); $url = $dft unless $url; $fil = File::Spec->catfile($rpt, split(/\//, $url)); if ($url !~ m#^\.# && $url !~ m#\/\.# && open(FIL, "<$fil")) { # Determine the MIME type $typ = 'application/octet-stream'; if ($fil =~ m/\.([a-z][a-z0-9]*)$/i) { $suf = lc($1); if (exists($tb_typ{$suf})) { $typ = $tb_typ{$suf} if exists($tb_typ{$suf}); } elsif ($suf eq 'dat') { $lgt = sysread(FIL, $buf, 4096); $typ = 'text/plain' unless $buf =~ m/[^\b\f\n\r\t\040-\176]/ } } # Generate the page print CLN "HTTP/1.0 200 OK$EOL", "Content-Type: $typ; charset=UTF-8$EOL$EOL"; print CLN $buf if $lgt; while ($lgt = sysread(FIL, $buf, 4096)) { print CLN $buf; } close(FIL); } else { print CLN "HTTP/1.0 404 Invalid page$EOL", "Content-Type: text/html; charset=UTF-8$EOL$EOL", "

$TTL

$EOL", "

HTTP Code 404: Invalid page

$EOL"; } } else { print CLN "HTTP/1.0 404 Invalid request$EOL", "Content-Type: text/html; charset=UTF-8$EOL$EOL", "

$TTL

$EOL", "

HTTP Code 404: Invalid request

$EOL"; } # Close the client socket close(CLN); } # Indicate that the setup must not be saved 0; } # Display a log message sub _dsp_msg { print "$$: @_ at ".scalar(gmtime)."\n"; } # Validate the authentication sub _need_authen { my ($req, $acl) = @_; my ($enc, $pwd, $str, $usr); # Check if an authentication is present return 1 unless exists($req->{'Authorization'}) && ($req->{'Authorization'} =~ m#^Basic\s+([A-Za-z0-9+/=]*)#i) && (length($enc = $1) % 4) == 0; # Decode the authentication local ($^W) = 0 ; $enc =~ s/=+$//; # Remove padding $enc =~ tr|A-Za-z0-9+/| -_|; # Convert to uuencode $str = ''; $str .= unpack('u', chr(32 + 3 * length($1) / 4).$1) while $enc =~ /(.{1,60})/gs; # Validate the authentication ($usr, $pwd) = split(/\:/, $str, 2); !exists($acl->{$usr}) || $acl->{$usr} ne $pwd; } 1; __END__ =head1 SEE ALSO L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, L =head1 COPYRIGHT NOTICE Copyright (c) 2002-2009, Oracle. All rights reserved. =head1 TRADEMARK NOTICE Oracle, JD Edwards, PeopleSoft, and Siebel are registered trademarks of Oracle Corporation and/or its affiliates. Other names may be trademarks of their respective owners. =cut