Next Previous Contents

4. Scripting examples

4.1 Pi3Perl

Redirection

This example shows how to perform a HTTP redirect using Pi3Perl. Compare this with the appropriate PSP example.


# change this to add your own folder to the perl library path
sub BEGIN { push @INC, qw ( . ); }

use strict;
use Pi3;

sub execute {
    my($obj) = shift;
    my($pihttp) = shift;
    my($iobuf) = shift;
    my($r) = Pi3::PIHTTP_getDB($pihttp, &Pi3::GETDB_RESPONSE);

    # Set the location header and the appropriate StatusCode (302 Found)
    my($l)= "http://localhost".Pi3::PIDB_lookup($r,&Pi3::PIDBTYPE_STRING,"PathInfo",&Pi3::PIDBFLAG_NONE);
    Pi3::PIDB_replace($r,&Pi3::PIDBTYPE_RFC822,"Location",$l,&Pi3::PIDBFLAG_NONE);
    Pi3::HTTPUtil_doHTTPError($pihttp,&Pi3::ST_FOUND);

    # Send HTTP status line and response headers
    Pi3::HTTPCore_sendGeneralHeaders($pihttp);
    Pi3::HTTPCore_sendEntityHeaders($pihttp, $r);
    return &Pi3::PIAPI_COMPLETED;
};

Basic authentication

This example shows how to perform a basic authentication using Pi3Perl. It includes the Base64 encoding/decoding routines.


my @Base64;
my @Plain;

sub BEGIN {
    my ( $Base64 ) =
        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
    @Base64 = split / */, $Base64;
    @Plain = (
        -1, -1, -1, -1, -1, -1, -1 ,-1, -1, -1, -1, -1, -1, -1, -1, -1,
        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63,
        52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1,  0, -1, -1,
        -1,  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14,
        15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1,
        -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
        41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1
        );
}

use strict;
use Pi3;

# +--
# Global configuration values
# --+
my $Realm;
my $AuthFile;

# +--
# Validate a user and password from the users (password) file.
# --+
sub validUser {
    my( $username ) = shift;
    my( $password ) = shift;
    open INP, "<$AuthFile" || return 0;
    foreach( <INP> ) {
        next if /^\#.*/;   # skip comments
        # get username, password, realms
        my( $user, $pass, $realmlist ) = split( / /, $_, 3 );
        if ( $user =~ $username ) {
            close INP;
            my( @realms ) = split( /,/, $realmlist );
            for(@realms) 
               { return 1 if (( $_ =~ $Realm ) && ( $pass =~ $password )); };
            return 0;
        };
    };
    close INP;
    return 0;
}

# +--
# Base64 encoding
# --+
sub Base64_encode {
    my( @plain ) = split / */, shift;
    my( $result ) = "";
    my( $len ) = @plain + 0;
    my( $state ) = 1;
    my( $i ) = 0;
    my( $iplain );

    for( ;; ) {
        my( $base64 );
        my( $c ) = ( $i < $len ) ? ord(@plain[$i]) : 0 ;
        if ( $state =~ 1 ) {
            if ( $i >= $len ) { return $result; };
            $base64 = ( $c >> 2 );
            $iplain = ( $c << 4 ) & 0x30;
            $i++;
            $state = 2;
        } elsif ( $state =~ 2 ) {
           $base64 = $iplain | ( $c >> 4 );
           $iplain = ( $c << 2 ) & 0x3C;
           $i++;
           $state = 3;
        } elsif ( $state =~ 3 ) {
           $base64 = $iplain | ( $c >> 6 );
           $iplain = $c & 0x3F;
           $i++;
           $state = 4;
        } elsif ( $state =~ 4 ) {
           $base64 = $iplain;
           $state = 1;
        };
        $result .= @Base64[$base64 & 0x3F];
        if ( $i > $len ) {
            if ( $state =~ 2 )
                { return $result."==="; }
            elsif ( $state =~ 3 )
                { return $result."=="; }
            elsif ( $state =~ 4 )
                { return $result."="; }
            };
        };
    return $result;
}

# +--
# Base64 decoding
# --+
sub Base64_decode {
    my( $pbase64 ) = split / */, shift;
    my( $ilen ) = @pbase64 + 0;
    my( $estate ) = 1;
    my( $idone ) = 0;
    my( $i );
    my( $result ) = "";
    my( $ilast );
    for( $i=0; $i<$ilen; $i++) {
        my( $c ) = @pbase64[$i];
        $_ = $c;

        last if ( !/[0-9a-zA-Z]/ &&  !/\+/ && !/\// );
        my( $iplain ) = $Plain[ord($c)];
        die( "assertion failure!" ) if $iplain =~ -1;
        if ( $estate =~ 1 ) {
            $ilast = ( $iplain << 2 ) & 0xFC;
            $estate = 2;
        } elsif ( $estate =~ 2 ) {
            $result = $result.chr( $ilast | ( ($iplain >> 4 ) & 0x03) );
            $ilast = ( $iplain << 4 ) & 0xF0;
            $estate = 4;
        } elsif ( $estate =~ 4 ) {
            $result = $result.chr( $ilast | ( ($iplain >> 2 ) & 0x0F) );
            $ilast = ( $iplain << 6 ) & 0xC0;
            $estate = 6;
        } elsif ( $estate =~ 6 ) {
            $result = $result.chr( $ilast | ( $iplain & 0x3F) );
            $estate = 1;
        };
        $_ = $c;
        last if /=/;
    };
    return $result;
};

# +--
# Initialize function to setup global variables with values from
# pi3 configuration file, i.e. password file and realm name.
#
# ** NOTE ** In this implementation all perl based handlers appear to 
# share the name global namespace, so multiple perl authentication handlers
# will clobber each others global data.
# --+
sub init {
    my( $obj ) = shift;
    my( $db ) = Pi3::PIObject_getDB( $obj );
    $Realm = Pi3::PIDB_lookup( $db, &Pi3::PIDBTYPE_RFC822, "Realm",
        &Pi3::PIDBFLAG_NONE );
    $AuthFile = Pi3::PIDB_lookup( $db, &Pi3::PIDBTYPE_RFC822, "AuthFile",
        &Pi3::PIDBFLAG_NONE );
    return &Pi3::PIAPI_COMPLETED;
}

# +--
# Function which is invoked to authenticate HTTP request using basic
# authentication. Usernames and passwords are read from a file.
# --+
sub execute {
    my( $obj ) = shift;
    my( $pihttp ) = shift;
    my( $piiobuf ) = shift;
    my($request_db ) = Pi3::PIHTTP_getDB( $pihttp, &Pi3::GETDB_REQUEST );
    my($response_db ) = Pi3::PIHTTP_getDB( $pihttp, &Pi3::GETDB_RESPONSE );

    # Lookup the realm set in the 'AuthenticationRealm' string variable of the response DB
    $_ = "";
    my( $authrealm );
    $authrealm = Pi3::PIDB_lookup( $response_db, &Pi3::PIDBTYPE_STRING,
        "AuthenticationRealm", &Pi3::PIDBFLAG_NONE );
    $_ = $authrealm;
    if ( ( length( $_ ) != 0 ) && !( $_ =~ $Realm ) ) {
        # This authentication handler does not apply
        return &Pi3::PIAPI_CONTINUE;
    };

    # Get browser authentication string from the rfc822 request header
    my( $authorization ) = "";
    $authorization = Pi3::PIDB_lookup( $request_db, &Pi3::PIDBTYPE_RFC822,
        "Authorization", &Pi3::PIDBFLAG_NONE );
    $_ = $authorization;
    if ( /^Basic .*/ ) {
        s/^Basic (.*)/$1/;
        my( $username, $password ) = split( /:/, Base64_decode( $_ ), 2 );
        if ( validUser( $username, $password) ) 
           { return &Pi3::PIAPI_COMPLETED; };
        # Otherwise fall through to challenge the authentication.
    };

    # Challenge the authentication
    Pi3::PIDB_replace( $response_db, &Pi3::PIDBTYPE_STRING, "AuthType",
        "Basic", &Pi3::PIDBFLAG_NONE );
    Pi3::PIDB_replace( $response_db, &Pi3::PIDBTYPE_RFC822,
        "WWW-Authenticate", 'Basic realm="'.$Realm.'"', 0 );
 
    # Redirect because of authentication failure
    Pi3::HTTPUtil_doHTTPError( $pihttp, &Pi3::ST_UNAUTHORIZED );
    return 1;   # INT_REDIRECT
}

4.2 PSP scripts

Generic example


#!/usr/local/psp
<%
sub pspLoad {
   $counter = 0;
   return 0;
}

sub pspSetResponse {
   $counter++;
   return 0;
}
%>
<html><body>
<h1>PSP example</h1>
<p><b>The name of PSP script is: </b><%= $pspRequest{"Path"}; %>
<p><b>I've been invoked: </b><%= $counter; %>
<p><b>The local time is: </b><%= localtime(); %>
<p><b>Your browser is: </b><%= $pspRequest{"User-Agent"}; %>
</body></html>

Example, how to use package Pi3::


#!/usr/local/psp
<%
# this may extend perl library path
BEGIN { push @INC, qw(/my/perl/libs); }
use Pi3;
sub pspSetResponse
{
   $piObject = shift;
   return 0;
}
%>
<html><body>
<h1>PSP example, which invokes Pi3::</h1>
<p><b>Your Pi3 platform is: </b><%= Pi3::PIPlatform_getDescription(); %>
<p><b>Your Pi3Web server is: </b><%= Pi3::HTTPCore_getServerStamp(); %>
<p><b>The Pi3Web handler is: </b><%= Pi3::PIObject_getName($piObject); %>
</body></html>

Example, how to perform redirection


#!/usr/local/psp
<%
sub pspSetResponse
{
   $pspResponse{"Location"} = "http://localhost".$pspRequest{"PathInfo"};
   $pspResponseStatus = 302;
   return 0;
}
%>
<html><body>
If automatic redirect doesn't work, use this <a href="<%= $pspResponse{"Location"} %>">link</a>.
</html></body>


Next Previous Contents